Files
NANOKVM-MaixCDK-MIRROR/components/basic/include/maix_api_example.hpp

443 lines
16 KiB
C++

/**
* @file maix_py_example.hpp
* @brief This is an example of how to export API to MaixPy
* 1. Create a C++ header file(.hpp) in anywhere of components' include path, like this hpp file.
* 2. Add C++ API in this hpp file, and API should be in maix namespace. API can be class or function etc. See below examples.
* 3. Add comments for each API like normal C++ API(doxygen style).
* !! Be attention, parameter MUST add value range or value attention, and return value the same.
* !! Only doc with detail meaning and value attention will actually help user to understand and easily use API.
* e.g. "@param age age of person" is bad, because developer can't know if age have limit or not. So better is:
* "@param age age of person, value range is [0, 100]".
* 4. And add @maixpy keyword in comments, this will inform generator to generate MaixPy API, format see below examples.
* 4. Compile MaixPy project, and then you can use these APIs in MaixPy.
* @attention MaixPy API code will be automatically generated by `components/maix/gen_api.py` script,
* to avoid trigger unexpected BUG, please:
* 1. Define one module in one header file !
* 2. DO NOT use complex C++ grammar and hierarchy !
* 3. Only the below grammar was tested !
* @author neucrack@sipeed
* @license Apache 2.0
* @update 2023.9.8: Add framework, create this file.
*/
#pragma once
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
#include <vector>
#include <valarray>
#include <functional>
#include "maix_type.hpp"
// using namespace std; // !! not recommend, because it will pollute global namespace
namespace maix
{
/**
* example module, this will be maix.example module in MaixPy, maix::example namespace in MaixCDK
* @maixpy maix.example
*/
namespace example
{
/**
* Test class
* @maixpy maix.example.Test
*/
class Test
{
public:
/**
* Test constructor
* @maixpy maix.example.Test.__init__
* @maixcdk maix.example.Test.Test
*/
Test()
{
data = new int[1024 * 1024];
printf("Test() new data: %p, size: %d\n", data, 1024 * 1024);
}
~Test()
{
printf("~Test() delete data: %p\n", data);
delete[] (int *)data;
}
private:
void *data;
};
/**
* @brief Example enum(not recommend! See Kind2)
* @maixpy maix.example.Kind
*/
enum Kind
{
KIND_NONE = 0, /** Kind none, value always 0, other enum value will auto increase */
KIND_DOG, /** Kind dog*/
KIND_CAT, // Kind cat, value is auto generated according to KING_DOG
KIND_BIRD,
KIND_MAX /* Max Kind quantity,
You can get max Kind value by KIND_MAX - 1
*/
};
/**
* @brief Example enum class(recommend!)
* @maixpy maix.example.Kind2
*/
enum class Kind2
{
NONE = 0, /** Kind none, value always 0, other enum value will auto increase */
DOG, /** Kind dog*/
CAT, // Kind cat, value is auto generated according to KING_DOG
BIRD,
MAX /* Max Kind quantity,
You can get max Kind value by KIND_MAX - 1
*/
};
/**
* @brief Example module variable
* @attention It's a copy of this variable in MaixPy,
* so change it in C++ (e.g. update var in hello function) will not take effect the var inMaixPy.
* So we add const for this var to avoid this mistake.
* @maixpy maix.example.var1
*/
const std::string var1 = "Sipeed";
/**
* Tensor data type size in bytes
* @attention DO NOT use C/C++ array directly for python API, the python wrapper not support it.
* Use std::vector instead.
* @attention It's a copy of this variable in MaixPy,
* so change it in C++ (e.g. update var in hello function) will not take effect the var inMaixPy.
* So we add const for this var to avoid this mistake.
* @maixpy maix.example.list_var
*/
const std::vector<int> list_var = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
/**
* @brief Example module variable test_var
* @attention It's a copy of this variable in MaixPy, so if you change it in C++, it will not take effect in MaixPy.
* And change it in MaixPy will not take effect in C++ as well !!!
* If you want to use vars shared between C++ and MaixPy, you can create a class and use its member.
* @maixpy maix.example.test_var
*/
int test_var = 100;
/**
* @brief say hello to someone
* @param[in] name name of someone, string type
* @return string type, content is hello + name
* @maixpy maix.example.hello
*/
std::string hello(std::string name)
{
return "hello " + name + ", " + std::to_string(test_var);
}
/**
* This is an API only for MaixCDK, MaixPy can't use it.
* Only item with `maixcdk` or `maixpy` keyword will be exported as MaixCDK API.
* @maixcdk maix.example.hello_maixcdk
*/
std::string hello_maixcdk(std::string name)
{
return "hello " + name + " from MaixCDK";
}
/**
* @brief Example class
* this class will be export to MaixPy as maix.example.Example
* @maixpy maix.example.Example
*/
class Example
{
public:
/**
* @brief Example constructor
* this constructor will be export to MaixPy as maix.example.Example.__init__
* @param[in] name name of Example, string type
* @param[in] age age of Example, int type, default is 18, value range is [0, 100]
* @attention to make auto generate code work, param Kind should with full namespace name `example::Kind` instead of `Kind`,
* namespace `maix` can be ignored.
* @maixpy maix.example.Example.__init__
* @maixcdk maix.example.Example.Example
*/
Example(std::string &name, int age = 18, example::Kind pet = example::KIND_NONE)
{
if (age < 0 || age > 100)
{
// throw exception will automatically translate to Python exception in MaixPy
throw std::invalid_argument("age should be in [0, 100]");
}
this->name = name;
this->age = age;
this->_pet = pet;
}
~Example()
{
}
/**
* @brief get name of Example
* you can also get name by property `name`.
* @return name of Example, string type
* @maixpy maix.example.Example.get_name
*/
std::string get_name()
{
return this->name;
}
/**
* @brief get age of Example
* @return age of Example, int type, value range is [0, 100]
* @maixpy maix.example.Example.get_age
*/
int get_age()
{
return this->age;
}
/**
* @brief set name of Example
* @param name name of Example, string type
* @maixpy maix.example.Example.set_name
*/
void set_name(std::string name)
{
this->name = name;
}
/**
* @brief set age of Example
* @param age age of Example, int type, value range is [0, 100]
* @maixpy maix.example.Example.set_age
*/
void set_age(int age)
{
this->age = age;
}
/**
* @brief Example enum member
* @attention
* @maixpy maix.example.Example.set_pet
*/
void set_pet(example::Kind pet)
{
_pet = pet;
}
/**
* @brief Example enum member
*
* @maixpy maix.example.Example.get_pet
*/
example::Kind get_pet()
{
return _pet;
}
/**
* get_pet overload function, only can be used in C++.
* if there are many overload functions, only the one can be export to MaixPy.
* @param pet pet of Example, enum type, default is KIND_DOG
*/
example::Kind get_pet(example::Kind pet)
{
if (_pet == example::KIND_NONE)
_pet = pet;
return _pet;
}
/**
* @brief get list example
* @param[in] in input list, items are int type.
* In MaixPy, you can pass list or tuple to this API
* @return list, items are int type, content is [1, 2, 3] + in. Alloc item, del in MaixPy will auto free memory.
* @maixpy maix.example.Example.get_list
*/
std::vector<int> *get_list(std::vector<int> in)
{
std::vector<int> *final = new std::vector<int>;
final->push_back(1);
final->push_back(2);
final->push_back(3);
for (auto i : in)
{
final->push_back(i);
}
return final;
}
/**
* @brief Example dict API
* @param[in] in input dict, key is string type, value is int type.
* In MaixPy, you can pass `dict` to this API
* @return dict, key is string type, value is int type, content is {"a": 1} + in
* In MaixPy, return type is `dict` object
* @maixpy maix.example.Example.get_dict
*/
std::map<std::string, int> get_dict(std::map<std::string, int> &in)
{
std::map<std::string, int> final = {{"a", 1}};
for (auto i : in)
{
final[i.first] = i.second;
}
return final;
}
/**
* @brief say hello to someone
* @param name name of someone, string type
* @return string type, content is Example::hello_str + name
* @maixpy maix.example.Example.hello
*/
static std::string hello(std::string name)
{
return Example::hello_str + name;
}
/**
* @brief param is bytes example
* @param bytes bytes type param
* @return bytes type, return value is bytes changed value
* @maixpy maix.example.Example.hello_bytes
*/
static Bytes *hello_bytes(Bytes &bytes)
{
printf("hello_bytes: %ld\n", bytes.size());
for (auto i : bytes)
{
printf("%02x ", i);
}
printf("\n");
// change bytes will not affect the original bytes in MaixPy
bytes.data[0] = 0x11;
bytes.data[1] = 0x22;
return new Bytes(bytes.data, bytes.size(), true, true);
}
/**
* Callback example
* @param cb callback function, param is two int type, return is int type
* @return int type, return value is cb's return value.
* @maixpy maix.example.Example.callback
*/
static int callback(std::function<int(int, int)> cb)
{
return cb(1, 2);
}
/**
* Callback example
* @param cb callback function, param is a int list type and int type, return is int type
* @return int type, return value is cb's return value.
* @maixpy maix.example.Example.callback2
*/
static int callback2(std::function<int(std::vector<int>, int)> cb)
{
std::vector<int> a;
a.push_back(1);
return cb(a, 2);
}
/**
* Dict param example
* @param dict dict type param, key is string type, value is int type
* @maixpy maix.example.Example.hello_dict
*/
static std::map<std::string, int> *hello_dict(std::map<std::string, int> *dict)
{
printf("hello_dict: %ld\n", dict->size());
for (auto i : *dict)
{
printf("%s: %d\n", i.first.c_str(), i.second);
}
// change dict value will not affect the original dict in MaixPy
(*dict)["a"] = 100;
return dict;
}
/**
* @brief name member of Example
* @maixpy maix.example.Example.name
*/
std::string name;
/**
* @brief age member of Example, value range should be [0, 100]
* @maixpy maix.example.Example.age
*/
int age;
/**
* @brief hello_str member of Example, default value is "hello "
* @maixpy maix.example.Example.hello_str
*/
static std::string hello_str;
/**
* @brief Example module readonly variable
* @maixpy maix.example.Example.var1
*/
const std::string var1 = "Example.var1";
/**
* @brief Example module readonly variable
* @maixpy maix.example.Example.var2
* :readonly
*/
std::string var2 = "Example.var2";
/**
* dict_test, return dict type, and element is pointer type(alloc in C++).
* Here when the returned Tensor object will auto delete by Python GC.
* @maixpy maix.example.Example.dict_test
*/
static std::map<std::string, example::Test *> *dict_test()
{
std::map<std::string, example::Test *> *dict = new std::map<std::string, example::Test *>;
(*dict)["a"] = new Test();
return dict;
}
private:
Kind _pet;
};
std::string Example::hello_str = "hello ";
/**
* Change arg name example
* @param e Example object
* @return same as arg
* @maixpy maix.example.change_arg_name
*/
example::Example *change_arg_name(example::Example *e)
{
e->name = "changed_name";
return e;
}
/**
* Change arg name example
* @param e Example object
* @maixpy maix.example.change_arg_name2
*/
void change_arg_name2(example::Example &e)
{
e.name = "changed_name2";
}
} // namespace example
} // namespace maix