diff --git a/libs/main/system/pilibrary.cpp b/libs/main/system/pilibrary.cpp index e8afdc1d..b02c52c2 100644 --- a/libs/main/system/pilibrary.cpp +++ b/libs/main/system/pilibrary.cpp @@ -26,6 +26,107 @@ #endif +//! \addtogroup System +//! \{ +//! \class PILibrary pilibrary.h +//! +//! \~\brief +//! \~english Run-time library +//! \~russian Run-time библиотека +//! +//! \~\details +//! \~english \section _sec0 Synopsis +//! \~russian \section _sec0 Краткий обзор +//! \~english +//! %PILibrary allow you dynamically load external library and use +//! some methods from it. %PILibrary instance contains library +//! pointer and unload library on destructor, so recommended +//! to use it with \b new creation. +//! +//! Main method of %PILibrary is \a resolve(const char *), which returns +//! "void*" pointer to requested method. One should test it +//! to \c nullptr and convert it in pointer to the required method. +//! +//! In case of C++ libraries it`s very important to use C-linkage +//! of exported methods! You may also need to mark methods for +//! export, e.g. \с __declspec(dllexport) +//! +//! \~russian +//! %PILibrary позволяет динамически загружать стороннюю библиотеку +//! и использовать оттуда методы. Экземпляр %PILibrary содержит +//! указатель на библиотеку и выгружает её в деструкторе, поэтому +//! рекомендуется создавать её с помощью \b new. +//! +//! Основной метод %PILibrary - это \a resolve(const char *), который возвращает +//! "void*" указатель на запрошенный метод. Необходимо проверить его +//! на \c nullptr и преобразовать в указатель на нужный метод. +//! +//! В случае C++ библиотеки очень важно использовать C-linkage +//! для экспортируемых методов! Также может понадобиться пометить +//! методы на экспорт, например, \с __declspec(dllexport) +//! +//! \~\code +//! extern "C" { +//! __declspec(dllexport) int exportedSum(int,int); +//! __declspec(dllexport) int exportedMul(int,int); +//! } +//! \endcode +//! +//! \~english \section _sec1 Usage +//! \~russian \section _sec1 Использование +//! +//! \~english Library: +//! \~russian Библиотека: +//! \~\code +//! #include +//! +//! extern "C" { +//! PIP_PLUGIN_EXPORT int exportedSum(int,int); +//! PIP_PLUGIN_EXPORT int exportedMul(int,int); +//! } +//! +//! int exportedSum(int a, int b) { +//! return a + b; +//! } +//! int exportedMul(int a, int b) { +//! return a * b; +//! } +//! \endcode +//! +//! \~english Program: +//! \~russian Программа: +//! \~\code +//! int main(int argc, char * argv[]) { +//! typedef int(*MyFunc)(int,int); +//! PILibrary * lib = new PILibrary(); +//! if (lib->load("mylib.dll")) { +//! MyFunc fadd = (MyFunc)lib->resolve("exportedSum"); +//! MyFunc fmul = (MyFunc)lib->resolve("exportedMul"); +//! if (fadd) { +//! int sum = fadd(1, 2); +//! piCout << "sum =" << sum; +//! } else { +//! piCout << "Can`t resolve" << "exportedSum"; +//! } +//! if (fmul) { +//! int mul = fadd(10, 20); +//! piCout << "mul =" << mul; +//! } else { +//! piCout << "Can`t resolve" << "exportedMul"; +//! } +//! } else { +//! piCout << lib->lastError(); +//! } +//! delete lib; +//! } +//! +//! // sum = 3 +//! // mul = 30 +//! \endcode +//! +//! \} + + PRIVATE_DEFINITION_START(PILibrary) #ifdef WINDOWS HMODULE diff --git a/libs/main/system/pilibrary.h b/libs/main/system/pilibrary.h index 88158850..ee882561 100644 --- a/libs/main/system/pilibrary.h +++ b/libs/main/system/pilibrary.h @@ -32,16 +32,43 @@ class PIP_EXPORT PILibrary { public: + + //! \~english Constructs %PILibrary and load if "path_" not empty + //! \~russian Создает %PILibrary и загружает если "path_" не пустой PILibrary(const PIString & path_ = PIString()); + + //! \~english Destroy %PILibrary, unload if library was loaded + //! \~russian Уничтожает %PILibrary и выгружает библиотеку, если она была загружена ~PILibrary(); + + //! \~english Load library with relative or absolute path "path_" + //! \~russian Загружает библиотеку по относительному или абсолютному пути "path_" bool load(const PIString & path_); + + //! \~english Load library with \a path() path + //! \~russian Загружает библиотеку по пути \a path() bool load(); + + //! \~english Unload library if it was loaded + //! \~russian Выгружает библиотеку, если она была загружена void unload(); + + //! \~english Obtain exported library method with name "symbol" + //! \~russian Получает экспортированный метод библиотеки с именем "symbol" void * resolve(const char * symbol); + + //! \~english Returns if library successfully loaded + //! \~russian Возвращает успешно ли загружена библиотека bool isLoaded() const; + + //! \~english Returns library path + //! \~russian Возвращает путь к библиотеке PIString path() const {return libpath;} + + //! \~english Returns last occured error in human-readable format + //! \~russian Возвращает последнюю ошибку в читаемом виде PIString lastError() const {return liberror;} private: diff --git a/libs/main/system/piplugin.cpp b/libs/main/system/piplugin.cpp index 25f9fb60..444049c4 100644 --- a/libs/main/system/piplugin.cpp +++ b/libs/main/system/piplugin.cpp @@ -24,139 +24,144 @@ #include "pidir.h" #include "piincludes_p.h" -/*! \class PIPluginLoader - * \brief Plugin loader - * - * \section PIPluginLoader_sec0 Synopsis - * This class provides several macro to define plugin and %PIPluginLoader - class - * to load and check plugin. - * - * \section PIPluginLoader_sec1 Plugin side - * Plugin is a shared library that can be loaded in run-time. - * This is only PIP_PLUGIN macro necessary to define plugin. - * If you want to set and check some version, use macro - * \a PIP_PLUGIN_SET_USER_VERSION(version). Also you can - * define a function to merge static sections between application - * and plugin with macro \a PIP_PLUGIN_STATIC_SECTION_MERGE. Before - * merge, you should set pointers to that sections with macro - * \a PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr). - * - * \section PIPluginLoader_sec2 Application side - * Application should use class \a PIPluginLoader to load - * plugin. Main function is \a load(PIString name). - * "name" is base name of library, %PIPluginLoader - * try to use sevaral names, \, lib\ and - * "dll", "so" and "dylib" extensions, depends on system. - * For example: - * \code - * PIPluginLoader l; - * l.load("foo"); - * \endcode - * On Windows, try to open "foo", "libfoo", "foo.dll" and - * "libfoo.dll". - * If you using user version check, you should set it - * with macro \a PIP_PLUGIN_SET_USER_VERSION(version). - * When plugin is successfully loaded and checked, - * you can load your custom symbols with function - * \a resolve(name), similar to PILibrary. - * \note You should use PIP_PLUGIN_EXPORT and "export "C"" - * with functions you want to use with \a resolve(name)! - * - * \section PIPluginLoader_sec3 Static sections - * Macro \a PIP_PLUGIN_STATIC_SECTION_MERGE defines function - * with arguments (int type, void * from, void * to), so you - * can leave this macro as declaration or define its body next: - * \code - * PIP_PLUGIN_STATIC_SECTION_MERGE() { - * switch (type) { - * ... - * } - * } - * \endcode - * \note If you using singletones, remember that cpp-defined - * singletones in shared libraries are single for whole application, - * including plugins! But if you use h-defined singletones or - * static linking, there are many objects in application and you - * should merge their content with this macro. - * - * Anyway, if this is macro \a PIP_PLUGIN_STATIC_SECTION_MERGE, it - * called once while loading plugin with "from" - plugin side - * and "to" - application side, and second (optionally) on method - * \a mergeStatic() with "from" - application side and "to" - plugin side. - * First direction allow you to copy all defined static content from plugin - * to application, and second - after loading all plugins (for example) - * to copy static content from application (and all plugins) to plugin. - * - * \section PIPluginLoader_sec4 Examples - * Simple plugin: - * \code - * #include - * - * PIP_PLUGIN - * - * extern "C" { - * PIP_PLUGIN_EXPORT void myFunc() { - * piCout << "Hello plugin!"; - * } - * } - * \endcode - * - * Application: - * \code - * #include - * int main() { - * PIPluginLoader pl; - * pl.load("your_lib"); - * if (pl.isLoaded()) { - * typedef void(*MyFunc)(); - * MyFunc f = (MyFunc)pl.resolve("myFunc"); - * if (f) f(); - * } - * return 0; - * } - * \endcode - * - * Complex plugin: - * \code - * #include - * - * PIStringList global_list; - * - * PIP_PLUGIN - * PIP_PLUGIN_SET_USER_VERSION("1.0.0") - * PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list) - * - * STATIC_INITIALIZER_BEGIN - * global_list << "plugin_init"; - * STATIC_INITIALIZER_END - * - * PIP_PLUGIN_STATIC_SECTION_MERGE { - * PIStringList * sfrom = (PIStringList*)from, * sto = (PIStringList*)to; - * *sto << *sfrom; - * sto->removeDuplicates(); - * } - * \endcode - * - * Application: - * \code - * #include - * - * PIStringList global_list; - * - * PIP_PLUGIN_SET_USER_VERSION("1.0.0"); - * PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list); - * - * int main() { - * global_list << "app"; - * PIPluginLoader pl; - * pl.load("your_lib"); - * pl.mergeStatic(); - * piCout << "list =" << global_list; - * return 0; - * } - * \endcode - * - */ +//! \addtogroup System +//! \{ +//! \class PIPluginLoader piplugin.h +//! +//! \brief +//! \~english Plugin loader +//! \~russian Загрузчик плагина +//! +//! \section PIPluginLoader_sec0 Synopsis +//! This class provides several macro to define plugin and %PIPluginLoader - class +//! to load and check plugin. +//! +//! \section PIPluginLoader_sec1 Plugin side +//! Plugin is a shared library that can be loaded in run-time. +//! This is only PIP_PLUGIN macro necessary to define plugin. +//! If you want to set and check some version, use macro +//! \a PIP_PLUGIN_SET_USER_VERSION(version). Also you can +//! define a function to merge static sections between application +//! and plugin with macro \a PIP_PLUGIN_STATIC_SECTION_MERGE. Before +//! merge, you should set pointers to that sections with macro +//! \a PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr). +//! +//! \section PIPluginLoader_sec2 Application side +//! Application should use class \a PIPluginLoader to load +//! plugin. Main function is \a load(PIString name). +//! "name" is base name of library, %PIPluginLoader +//! try to use sevaral names, \, lib\ and +//! "dll", "so" and "dylib" extensions, depends on system. +//! For example: +//! \code +//! PIPluginLoader l; +//! l.load("foo"); +//! \endcode +//! On Windows, try to open "foo", "libfoo", "foo.dll" and +//! "libfoo.dll". +//! If you using user version check, you should set it +//! with macro \a PIP_PLUGIN_SET_USER_VERSION(version). +//! When plugin is successfully loaded and checked, +//! you can load your custom symbols with function +//! \a resolve(name), similar to PILibrary. +//! \note You should use PIP_PLUGIN_EXPORT and "export "C"" +//! with functions you want to use with \a resolve(name)! +//! +//! \section PIPluginLoader_sec3 Static sections +//! Macro \a PIP_PLUGIN_STATIC_SECTION_MERGE defines function +//! with arguments (int type, void * from, void * to), so you +//! can leave this macro as declaration or define its body next: +//! \code +//! PIP_PLUGIN_STATIC_SECTION_MERGE() { +//! switch (type) { +//! ... +//! } +//! } +//! \endcode +//! \note If you using singletones, remember that cpp-defined +//! singletones in shared libraries are single for whole application, +//! including plugins! But if you use h-defined singletones or +//! static linking, there are many objects in application and you +//! should merge their content with this macro. +//! +//! Anyway, if this is macro \a PIP_PLUGIN_STATIC_SECTION_MERGE, it +//! called once while loading plugin with "from" - plugin side +//! and "to" - application side, and second (optionally) on method +//! \a mergeStatic() with "from" - application side and "to" - plugin side. +//! First direction allow you to copy all defined static content from plugin +//! to application, and second - after loading all plugins (for example) +//! to copy static content from application (and all plugins) to plugin. +//! +//! \section PIPluginLoader_sec4 Examples +//! Simple plugin: +//! \code +//! #include +//! +//! PIP_PLUGIN +//! +//! extern "C" { +//! PIP_PLUGIN_EXPORT void myFunc() { +//! piCout << "Hello plugin!"; +//! } +//! } +//! \endcode +//! +//! Application: +//! \code +//! #include +//! int main() { +//! PIPluginLoader pl; +//! pl.load("your_lib"); +//! if (pl.isLoaded()) { +//! typedef void(*MyFunc)(); +//! MyFunc f = (MyFunc)pl.resolve("myFunc"); +//! if (f) f(); +//! } +//! return 0; +//! } +//! \endcode +//! +//! Complex plugin: +//! \code +//! #include +//! +//! PIStringList global_list; +//! +//! PIP_PLUGIN +//! PIP_PLUGIN_SET_USER_VERSION("1.0.0") +//! PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list) +//! +//! STATIC_INITIALIZER_BEGIN +//! global_list << "plugin_init"; +//! STATIC_INITIALIZER_END +//! +//! PIP_PLUGIN_STATIC_SECTION_MERGE { +//! PIStringList * sfrom = (PIStringList*)from, * sto = (PIStringList*)to; +//! *sto << *sfrom; +//! sto->removeDuplicates(); +//! } +//! \endcode +//! +//! Application: +//! \code +//! #include +//! +//! PIStringList global_list; +//! +//! PIP_PLUGIN_SET_USER_VERSION("1.0.0"); +//! PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list); +//! +//! int main() { +//! global_list << "app"; +//! PIPluginLoader pl; +//! pl.load("your_lib"); +//! pl.mergeStatic(); +//! piCout << "list =" << global_list; +//! return 0; +//! } +//! \endcode +//! +//! \} #define STR_WF(s) #s #define STR(s) STR_WF(s) diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 7cd87d95..47fabe6c 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -209,7 +209,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun //! If "func" if not null this function will be executed after \a run(). //! //! ThreadFunc is any static function with format "void func(void * data)", or -//! lambda-function with format [...]( ){...}. +//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) with format [...]( ){...}. //! "Data" is custom data set from constructor or with \a setData() function. //! //! Also you can connect to event \a started(), but in this case you should to white @@ -221,7 +221,7 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun //! если "ThreadFunc" существует, он будет вызываться после \a run(). //! //! ThreadFunc может быть любым статическим методом в формате "void func(void * data)", либо -//! лямбда-функцией в формате [...]( ){...}. +//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) в формате [...]( ){...}. //! "Data" является произвольным указателем, задаваемым в конструкторе или методом \a setData(). //! //! Также можно присоединиться к событию \a started(), но в этом случае надо будет своими силами @@ -273,8 +273,8 @@ __THREAD_FUNC_RET__ thread_function_once(void * t) {((PIThread*)t)->__thread_fun //! // thread run 1 //! \endcode //! -//! \~english Using with lambda-function -//! \~russian Использование с лямбда-функцией +//! \~english Using with [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) +//! \~russian Использование с [лямбда-выражением](https://ru.cppreference.com/w/cpp/language/lambda) //! \~\code{.cpp} //! int main(int argc, char * argv[]) { //! int cnt = 0; @@ -971,13 +971,13 @@ void PIThread::runOnce(PIObject * object, const char * handler, const PIString & //! \~\details //! \~english //! This method create %PIThread with name "name" and execute -//! lambda-function "func" in this thread.\n +//! [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in this thread.\n //! This %PIThread automatically delete on function finish.\n //! "func" shouldn`t have arguments. //! //! \~russian //! Этот метод создает %PIThread с именем "name" и выполняет -//! лямбда-функцию "func" в этом потоке.\n +//! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в этом потоке.\n //! %PIThread автоматически удаляется после завершения функции.\n //! "func" не должна иметь аргументов. //! diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 573e48ec..9fffaadd 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -173,8 +173,8 @@ public: //! \~russian Вызывает обработчик "handler" объекта "object" в отдельном потоке static void runOnce(PIObject * object, const char * handler, const PIString & name = PIString()); - //! \~english Call lambda-function "func" in separate thread - //! \~russian Вызывает лямбда-функцию "func" в отдельном потоке + //! \~english Call [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "func" in separate thread + //! \~russian Вызывает [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "func" в отдельном потоке static void runOnce(std::function func, const PIString & name = PIString()); //! \handlers diff --git a/libs/main/thread/pithreadnotifier.cpp b/libs/main/thread/pithreadnotifier.cpp index 8e04d15b..9eb1aba1 100644 --- a/libs/main/thread/pithreadnotifier.cpp +++ b/libs/main/thread/pithreadnotifier.cpp @@ -28,25 +28,63 @@ //! \~russian Класс для простого уведомления и ожидания в различных потоках //! //! \~\details -//! \~english -//! -//! \~russian -//! -//! //! \~english \section PIThreadNotifier_sec0 Synopsis //! \~russian \section PIThreadNotifier_sec0 Краткий обзор //! \~english +//! This class used as event mechanism between threads. One thread wait for some event, +//! and another send this event, unblocking first thread. It is useful to +//! syncronize some actions in several threads. //! //! \~russian -//! +//!Этот класс используется как событийный механизм между потоками. +//! Один поток ждёт некоторого события и другой его отправляет, разблокируя первый. +//! Это полезно для синхронизации действий в нескольких потоках. //! //! \~english \section PIThreadNotifier_sec1 Usage //! \~russian \section PIThreadNotifier_sec1 Использование -//! \~english +//! \~\code +//! PIThreadNotifier notifier; +//! PITimeMeasurer time; //! -//! \~russian +//! class Worker: public PIThread { +//! PIOBJECT_SUBCLASS(Worker, PIThread) +//! public: +//! Worker(const PIString & n) { +//! setName(n); +//! } +//! void run() override { +//! piCoutObj << (int)time.elapsed_m() << "wait ..."; +//! notifier.wait(); +//! piCoutObj << (int)time.elapsed_m() << "done"; +//! }; +//! }; //! //! +//! int main(int argc, char * argv[]) { +//! PIVector workers; +//! +//! // create 2 threads +//! for (auto n: {"first ", "second"}) +//! workers << new Worker(n); +//! +//! // start them +//! for (auto * w: workers) +//! w->startOnce(); +//! +//! piMSleep(500); +//! notifier.notifyOnce(); // notify one of them after 500 ms +//! piMSleep(500); +//! notifier.notifyOnce(); // notify one of them after 1000 ms +//! +//! for (auto * w: workers) +//! w->waitForFinish(); +//! } +//! +//! // [Worker "first "] 0 wait ... +//! // [Worker "second"] 0 wait ... +//! // [Worker "second"] 500 done +//! // [Worker "first "] 1000 done +//! \endcode //! \} diff --git a/libs/main/thread/pithreadpoolloop.h b/libs/main/thread/pithreadpoolloop.h index 8231fd47..6937814d 100644 --- a/libs/main/thread/pithreadpoolloop.h +++ b/libs/main/thread/pithreadpoolloop.h @@ -43,8 +43,8 @@ public: virtual ~PIThreadPoolLoop(); - //! \~english Set threads function to "f" with format [ ](int){ ... } - //! \~russian Устанавливает функцию потоков на "f" в формате [ ](int){ ... } + //! \~english Set threads function to [lambda expression](https://en.cppreference.com/w/cpp/language/lambda) "f" with format [ ](int){ ... } + //! \~russian Устанавливает функцию потоков на [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda) "f" в формате [ ](int){ ... } void setFunction(std::function f); //! \~english Wait for all threads stop diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index 1a5c1d2f..2e3a925f 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -49,7 +49,7 @@ //! \~russian \section PITimer_sec1 Варианты уведомления //! \~english //! Notify variants: -//! * "slot" - static function with format void func(void * data, int delimiter) or lambda-function; +//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda expression](https://en.cppreference.com/w/cpp/language/lambda); //! * event - \a tickEvent(); //! * virtual function - \a tick(). //! @@ -58,7 +58,7 @@ //! All these variants are equivalent, use most applicable. //! \~russian //! Варианты уведомления: -//! * "slot" - статический метод в формате void func(void * data, int delimiter) или лямбда-функция; +//! * "slot" - статический метод в формате void func(void * data, int delimiter) или [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda); //! * event - \a tickEvent(); //! * виртуальный метод - \a tick(). //! diff --git a/utils/code_model_generator/main.cpp b/utils/code_model_generator/main.cpp index 54c37395..1a473200 100755 --- a/utils/code_model_generator/main.cpp +++ b/utils/code_model_generator/main.cpp @@ -48,6 +48,7 @@ const char help_string[] = "You can override ID with PIMETA(id=). If in class or struct\n" "PIMETA(simple-stream) presence, then variables stored/restored\n" "with simple << and >> operators.\n" +"If PIMETA(no-stream) presence, then class or struct ignored.\n" "\n" "-G (Getter functions)\n" "Generate anonymous access methods for member typenames and values.\n"