diff --git a/CMakeLists.txt b/CMakeLists.txt index 9165454c..e448f8b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(pip) set(pip_MAJOR 2) set(pip_MINOR 10) -set(pip_REVISION 0) +set(pip_REVISION 1) set(pip_SUFFIX ) set(pip_COMPANY SHS) set(pip_DOMAIN org.SHS) @@ -433,6 +433,9 @@ if (NOT CROSSTOOLS) # Test program if(PIP_UTILS) + #add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp") + #target_link_libraries(pip_plugin pip) + add_executable(pip_test "main.cpp") target_link_libraries(pip_test pip pip_cloud) if (LUA_FOUND) diff --git a/libs/main/code/picodeinfo.h b/libs/main/code/picodeinfo.h index 97506149..c95d58b0 100644 --- a/libs/main/code/picodeinfo.h +++ b/libs/main/code/picodeinfo.h @@ -174,6 +174,13 @@ inline const char * getMemberType(const char * class_name, const char * member_n PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name); + +template::value, int>::type = 0> +void serialize(PIByteArray & ret, const T & v) {ret << v;} + +template::value, int>::type = 0> +void serialize(PIByteArray & ret, const T & v) {} + } class PIP_EXPORT __PICodeInfoInitializer__ { diff --git a/libs/main/core/pibytearray.cpp b/libs/main/core/pibytearray.cpp index f939ef0a..3c4a01a9 100644 --- a/libs/main/core/pibytearray.cpp +++ b/libs/main/core/pibytearray.cpp @@ -401,3 +401,14 @@ PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) { } return s; } + + +PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) { + s << int(v.size_s()); + int os = s.size_s(); + if (v.size_s() > 0) { + s.enlarge(v.size_s()); + memcpy(s.data(os), v.data(), v.size()); + } + return s; +} diff --git a/libs/main/core/pibytearray.h b/libs/main/core/pibytearray.h index a5e9488d..ad00a8a1 100644 --- a/libs/main/core/pibytearray.h +++ b/libs/main/core/pibytearray.h @@ -175,27 +175,18 @@ inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v); //! \relatesalso PIByteArray \brief Store operator inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;} -//! \relatesalso PIByteArray \brief Store operator -inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;} - -//! \relatesalso PIByteArray \brief Store operator -template inline PIByteArray & operator <<(PIByteArray & s, const PIFlags & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;} - //! \relatesalso PIByteArray \brief Store operator for any trivial copyable type template::value, int>::type = 0> -inline PIByteArray & operator <<(PIByteArray & s, const T & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;} - -//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details -inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) { - s << int(v.size_s()); +inline PIByteArray & operator <<(PIByteArray & s, const T & v) { int os = s.size_s(); - if (v.size_s() > 0) { - s.enlarge(v.size_s()); - memcpy(s.data(os), v.data(), v.size()); - } + s.enlarge(sizeof(v)); + memcpy(s.data(os), &v, sizeof(v)); return s; } +//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details +PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v); + //! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) { int os = s.size_s(); @@ -264,15 +255,14 @@ inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= //! \relatesalso PIByteArray \brief Restore operator inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;} -//! \relatesalso PIByteArray \brief Restore operator -inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {assert(s.size() >= sizeof(v)); memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;} - //! \relatesalso PIByteArray \brief Restore operator for any trivial copyable type template::value, int>::type = 0> -inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;} - -//! \relatesalso PIByteArray \brief Restore operator -template inline PIByteArray & operator >>(PIByteArray & s, PIFlags & v) {memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;} +inline PIByteArray & operator >>(PIByteArray & s, T & v) { + assert(s.size() >= sizeof(v)); + memcpy((void*)(&v), s.data(), sizeof(v)); + s.remove(0, sizeof(v)); + return s; +} //! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v); diff --git a/libs/main/core/pichar.h b/libs/main/core/pichar.h index a01b07ce..a2b5dad2 100644 --- a/libs/main/core/pichar.h +++ b/libs/main/core/pichar.h @@ -32,8 +32,6 @@ extern PIP_EXPORT char * __utf8name__; class PIP_EXPORT PIChar { friend class PIString; - friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v); - friend PIByteArray & operator >>(PIByteArray & s, PIChar & v); friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v); public: //! Contructs ascii symbol diff --git a/libs/main/core/piflags.h b/libs/main/core/piflags.h index d7584dd5..6d824826 100644 --- a/libs/main/core/piflags.h +++ b/libs/main/core/piflags.h @@ -38,8 +38,6 @@ public: PIFlags(): flags(0) {;} //! Constructor with flags = Enum "e" PIFlags(Enum e): flags(e) {;} - //! Constructor with flags = PIFlags "f" - PIFlags(const PIFlags & f): flags(f.flags) {;} //! Constructor with flags = int "i" PIFlags(const int i): flags(i) {;} //! Set flags "f" to value "on" @@ -49,8 +47,6 @@ public: //! Set flag "i" to value "on" PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;} //! copy operator - void operator =(const PIFlags & f) {flags = f.flags;} - //! copy operator void operator =(const Enum & e) {flags = e;} //! copy operator void operator =(const int & i) {flags = i;} diff --git a/libs/main/core/piincludes.cpp b/libs/main/core/piincludes.cpp index 6b480a21..aa583426 100644 --- a/libs/main/core/piincludes.cpp +++ b/libs/main/core/piincludes.cpp @@ -79,6 +79,22 @@ PIString PIPVersion() { return ret; } + +void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) { + qsort(base, num, size, compar); +} + + +void randomize() { + srand(PISystemTime::current(true).nanoseconds); +} + + +int randomi() { + return rand(); +} + + /*! \class PICout * \brief Class for formatted output similar std::cout * @@ -131,6 +147,9 @@ PIString PIPVersion() { * * packets extractor (\a PIPacketExtractor) * * binary log (\a PIBinaryLog) * * complex I/O point (\a PIConnection) + * * Run-time libraries + * * abstract (\a PILibrary) + * * plugin (\a PIPluginLoader) * * connection quality diagnotic (\a PIDiagnostics) * * command-line arguments parser (\a PICLI) * * math evaluator (\a PIEvaluator) @@ -247,19 +266,3 @@ int main(int argc, char * argv[]) { /*! \page using_advanced Advanced using * Sorry, creativity crysis xD */ - - -void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) { - qsort(base, num, size, compar); -} - - -void randomize() { - srand(PISystemTime::current(true).nanoseconds); -} - - -int randomi() { - return rand(); -} - diff --git a/libs/main/core/pipropertystorage.h b/libs/main/core/pipropertystorage.h index c338b968..9dc4098c 100644 --- a/libs/main/core/pipropertystorage.h +++ b/libs/main/core/pipropertystorage.h @@ -162,12 +162,12 @@ public: */ void setPropertyComment(const PIString & name, const PIString & comment); - /** - * @brief Set flags of property with specific name if name is present in storage. - * - * @param name of property to set flags - * @param flags to set - */ + /** + * @brief Set flags of property with specific name if name is present in storage. + * + * @param name of property to set flags + * @param flags to set + */ void setPropertyFlags(const PIString & name, int flags); PIPropertyStorage & operator <<(const PIPropertyStorage::Property & p) {props << p; return *this;} diff --git a/libs/main/core/pitime.h b/libs/main/core/pitime.h index 90df73c7..9c9a959d 100644 --- a/libs/main/core/pitime.h +++ b/libs/main/core/pitime.h @@ -60,8 +60,6 @@ public: //! Contructs system time with s = "s" and ns = "ns" PISystemTime(int s, int ns) {seconds = s; nanoseconds = ns; checkOverflows();} - //! Contructs system time from another - PISystemTime(const PISystemTime & t) {seconds = t.seconds; nanoseconds = t.nanoseconds;} //! Returns stored system time value in seconds double toSeconds() const {return double(seconds) + nanoseconds / 1.e+9;} @@ -172,13 +170,6 @@ private: //! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;} -//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Output operator to PIByteArray -inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;} - -//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Input operator from PIByteArray -inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;} - - struct PIP_EXPORT PITime { @@ -199,8 +190,6 @@ PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1); inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);} inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);} inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);} -inline PIByteArray & operator <<(PIByteArray & s, const PITime & v) {s << v.hours << v.minutes << v.seconds << v.milliseconds; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PITime & v) {s >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;} //! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout PIP_EXPORT PICout operator <<(PICout s, const PITime & v); @@ -223,8 +212,6 @@ PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1); inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);} inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);} inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);} -inline PIByteArray & operator <<(PIByteArray & s, const PIDate & v) {s << v.year << v.month << v.day; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIDate & v) {s >> v.year >> v.month >> v.day; return s;} //! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout PIP_EXPORT PICout operator <<(PICout s, const PIDate & v); diff --git a/libs/main/core/pivariantsimple.h b/libs/main/core/pivariantsimple.h index 64114a4e..017872c2 100644 --- a/libs/main/core/pivariantsimple.h +++ b/libs/main/core/pivariantsimple.h @@ -40,12 +40,21 @@ public: virtual void deleteT(void *& ptr) {;} //virtual PIByteArray toData(const void * ptr) const {return PIByteArray();} //virtual void fromData(void *& ptr, PIByteArray ba) {;} - static PIMap & registered() {static PIMap ret; return ret;} + //static PIMap & registered() {static PIMap ret; return ret;} }; +/* +template +class __VariantFunctions__: public __VariantFunctionsBase__ { +public: + __VariantFunctionsBase__ * instance() final {static __VariantFunctions__ ret; return &ret;} + PIString typeName() const final {static PIString ret(typeid(T).name()); return ret;} + uint hash() const final {static uint ret = typeName().hash(); return ret;} +}; +*/ template -class __VariantFunctions__: public __VariantFunctionsBase__ { +class __VariantFunctions__/*::value>::type>*/: public __VariantFunctionsBase__ { public: __VariantFunctionsBase__ * instance() final {static __VariantFunctions__ ret; return &ret;} PIString typeName() const final {static PIString ret(typeid(T).name()); return ret;} @@ -58,6 +67,7 @@ public: //void fromData(void *& ptr, PIByteArray ba) final {ba >> *(T*)ptr;} }; + class PIVariantSimple { public: PIVariantSimple() {ptr = 0; f = 0;} @@ -129,6 +139,7 @@ public: private: template bool isMyType() const { + if (!f) return false; uint mh = f->hash(), th = __VariantFunctions__().instance()->hash(); if (mh == 0 || th == 0) return false; return mh == th; @@ -146,13 +157,13 @@ private: }; - +/* #define REGISTER_PIVARIANTSIMPLE_STREAM(Type) \ STATIC_INITIALIZER_BEGIN() \ __VariantFunctionsBase__ * f = __VariantFunctions__().instance(); \ __VariantFunctionsBase__::registered()[f->hash()] = f; \ STATIC_INITIALIZER_END() - +*/ #endif // PIVARIANTSIMPLE_H diff --git a/libs/main/io_devices/piethernet.h b/libs/main/io_devices/piethernet.h index bb9f988e..266134a0 100644 --- a/libs/main/io_devices/piethernet.h +++ b/libs/main/io_devices/piethernet.h @@ -65,8 +65,6 @@ public: //! \brief IPv4 network address, IP and port class PIP_EXPORT Address { friend class PIEthernet; - friend inline PIByteArray & operator <<(PIByteArray & s, const PIEthernet::Address & v); - friend inline PIByteArray & operator >>(PIByteArray & s, PIEthernet::Address & v); public: //! Contructs %Address with binary representation of IP and port @@ -519,7 +517,5 @@ inline PICout operator <<(PICout s, const PIEthernet::Address & v) {s.space(); s inline bool operator ==(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() == v1.ip() && v0.port() == v1.port());} inline bool operator !=(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() != v1.ip() || v0.port() != v1.port());} -inline PIByteArray & operator <<(PIByteArray & s, const PIEthernet::Address & v) {s << v.ip_ << v.port_; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIEthernet::Address & v) {s >> v.ip_ >> v.port_; return s;} #endif // PIETHERNET_H diff --git a/libs/main/math/pigeometry.h b/libs/main/math/pigeometry.h index ad2df750..65bf39d1 100644 --- a/libs/main/math/pigeometry.h +++ b/libs/main/math/pigeometry.h @@ -59,12 +59,6 @@ public: template PICout operator <<(PICout & s, const PIPoint & v) {s.setControl(0, true); s << "Point{" << v.x << ", " << v.y << "}"; s.restoreControl(); return s;} -template -inline PIByteArray & operator <<(PIByteArray & s, const PIPoint & v) {s << v.x << v.y; return s;} - -template -inline PIByteArray & operator >>(PIByteArray & s, PIPoint & v) {s >> v.x >> v.y; return s;} - typedef PIPoint PIPointi; typedef PIPoint PIPointu; @@ -145,12 +139,6 @@ public: template PICout operator <<(PICout & s, const PIRect & v) {s.setControl(0, true); s << "Rect{" << v.x0 << ", " << v.y0 << "; " << v.x1 - v.x0 << ", " << v.y1 - v.y0 << "}"; s.restoreControl(); return s;} -template -inline PIByteArray & operator <<(PIByteArray & s, const PIRect & v) {s << v.x0 << v.x1 << v.y0 << v.y1; return s;} - -template -inline PIByteArray & operator >>(PIByteArray & s, PIRect & v) {s >> v.x0 >> v.x1 >> v.y0 >> v.y1; return s;} - typedef PIRect PIRecti; typedef PIRect PIRectu; diff --git a/libs/main/math/pimathcomplex.h b/libs/main/math/pimathcomplex.h index 79e651d5..369513a4 100644 --- a/libs/main/math/pimathcomplex.h +++ b/libs/main/math/pimathcomplex.h @@ -69,20 +69,6 @@ inline complexd log10(const complexd & c) {return log(c) / M_LN10;} template inline PICout operator <<(PICout s, const complex & v) {s.space(); s.setControl(0, true); s << "(" << v.real() << "; " << v.imag() << ")"; s.restoreControl(); return s;} -//! \relatesalso PIByteArray \brief Store operator -inline PIByteArray & operator <<(PIByteArray & s, complexf v) {float t; t = v.real(); s << t; t = v.imag(); s << t; return s;} -//! \relatesalso PIByteArray \brief Store operator -inline PIByteArray & operator <<(PIByteArray & s, complexd v) {double t; t = v.real(); s << t; t = v.imag(); s << t; return s;} -//! \relatesalso PIByteArray \brief Store operator -inline PIByteArray & operator <<(PIByteArray & s, complexld v) {ldouble t; t = v.real(); s << t; t = v.imag(); s << t; return s;} - -//! \relatesalso PIByteArray \brief Restore operator -inline PIByteArray & operator >>(PIByteArray & s, complexf & v) {float t0, t1; s >> t0; s >> t1; v = complexf(t0, t1); return s;} -//! \relatesalso PIByteArray \brief Restore operator -inline PIByteArray & operator >>(PIByteArray & s, complexd & v) {double t0, t1; s >> t0; s >> t1; v = complexd(t0, t1); return s;} -//! \relatesalso PIByteArray \brief Restore operator -inline PIByteArray & operator >>(PIByteArray & s, complexld & v) {ldouble t0, t1; s >> t0; s >> t1; v = complexld(t0, t1); return s;} - inline PIVector abs(const PIVector & v) { PIVector result; diff --git a/libs/main/math/pimathvector.h b/libs/main/math/pimathvector.h index 7c4a9b41..09b8d07b 100644 --- a/libs/main/math/pimathvector.h +++ b/libs/main/math/pimathvector.h @@ -130,6 +130,7 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIMathVectorT inline PIByteArray & operator >>(PIByteArray & s, PIMathVectorT & v) {for (uint i = 0; i < Size; ++i) s >> v[i]; return s;} + template inline PIMathVectorT<2u, T> createVectorT2(T x, T y) {return PIMathVectorT<2u, T>(PIVector() << x << y);} template diff --git a/libs/main/system/pilibrary.h b/libs/main/system/pilibrary.h index 581fa5d1..17b61dc3 100644 --- a/libs/main/system/pilibrary.h +++ b/libs/main/system/pilibrary.h @@ -1,3 +1,6 @@ +/*! \file pilibrary.h +* \brief Dynamic library +*/ /* PIP - Platform Independent Primitives Dynamic library diff --git a/libs/main/system/piplugin.cpp b/libs/main/system/piplugin.cpp new file mode 100644 index 00000000..e93f6b37 --- /dev/null +++ b/libs/main/system/piplugin.cpp @@ -0,0 +1,338 @@ +/* + PIP - Platform Independent Primitives + Plugin helpers + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIP_FREERTOS + +#include "piplugin.h" +#include "pifile.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 cymbols 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) + + +PIPluginInfo::PIPluginInfo() { + in_plugin = false; +} + + +void PIPluginInfo::setUserVersion(const PIString & v) { + user_version[in_plugin ? 1 : 0] = v; +} + + +void PIPluginInfo::setStaticSection(int type, void * ptr) { + static_sections[in_plugin ? 1 : 0][type] = ptr; +} + + +PIString PIPluginInfo::userVersion(bool plugin) const { + return user_version[plugin ? 1 : 0]; +} + + +PIMap PIPluginInfo::staticSections(bool plugin) const { + return static_sections[plugin ? 1 : 0]; +} + + +void PIPluginInfo::enterPlugin() { + in_plugin = true; +} + + +PIPluginInfo * PIPluginInfo::instance() { + static PIPluginInfo ret; + return &ret; +} + + + + +PIPluginLoader::PIPluginLoader(const PIString & name) { + func_loader_version = nullptr; + func_plugin_info = nullptr; + func_static_merge = nullptr; + plugin_info = nullptr; + loaded = false; + if (!name.isEmpty()) + load(name); +} + + +PIPluginLoader::~PIPluginLoader() { + lib.unload(); +} + + +bool PIPluginLoader::load(const PIString & name) { + unload(); + if (!lib.load(findLibrary(name))) return false; + //piCout << "loading" << lib.path() << "..."; + func_loader_version = (FunctionLoaderVersion)lib.resolve(STR(__PIP_PLUGIN_LOADER_VERSION_FUNC__)); + if (!func_loader_version) { + piCout << "Load plugin \"" << name << "\" error: can`t find" << STR(__PIP_PLUGIN_LOADER_VERSION_FUNC__); + unload(); + return false; + } + if (__PIP_PLUGIN_LOADER_VERSION__ != func_loader_version()) { + piCout << "Load plugin \"" << name << "\" error: invalid loader version: plugin" << __PIP_PLUGIN_LOADER_VERSION__ << "!=" << func_loader_version(); + unload(); + return false; + } + func_plugin_info = (FunctionPluginInfo)lib.resolve(STR(__PIP_PLUGIN_PLUGIN_INFO_FUNC__)); + if (!func_plugin_info) { + piCout << "Load plugin \"" << name << "\" error: can`t find" << STR(__PIP_PLUGIN_PLUGIN_INFO_FUNC__); + unload(); + return false; + } + plugin_info = func_plugin_info(); + if (!plugin_info) { + piCout << "Load plugin \"" << name << "\" error: null PIPluginInfo"; + unload(); + return false; + } + if (PIPluginInfo::instance()->userVersion(false).size_s() > 1) { + PIString pversion = plugin_info->userVersion(true), lversion = PIPluginInfo::instance()->userVersion(false); + if (pversion != lversion) { + piCout << "Load plugin \"" << name << "\" error: invalid user version: plugin" << pversion << "!=" << lversion; + unload(); + return false; + } + } + func_static_merge = (FunctionStaticMerge)lib.resolve(STR(__PIP_PLUGIN_STATIC_MERGE_FUNC__)); + if (func_static_merge) { + auto pss = plugin_info->staticSections(true), lss = PIPluginInfo::instance()->staticSections(false); + piCout << lss.keys() << pss.keys(); + + auto it = lss.makeIterator(); + while (it.next()) { + if (!pss.contains(it.key())) + continue; + void * from = pss.value(it.key()), * to = it.value(); + if (from != to) + func_static_merge(it.key(), from, to); + } + } + loaded = true; + return true; +} + + +void PIPluginLoader::unload() { + lib.unload(); + plugin_info = nullptr; + loaded = false; +} + + +bool PIPluginLoader::isLoaded() const { + return loaded; +} + + +PIString PIPluginLoader::libPath() { + return lib.path(); +} + + +void * PIPluginLoader::resolve(const char * name) { + if (!loaded) return nullptr; + return lib.resolve(name); +} + + +void PIPluginLoader::mergeStatic() { + if (!loaded || !func_static_merge || !plugin_info) return; + auto pss = plugin_info->staticSections(true), lss = PIPluginInfo::instance()->staticSections(false); + auto it = lss.makeIterator(); + while (it.next()) { + if (!pss.contains(it.key())) + continue; + void * from = it.value(), * to = pss.value(it.key()); + if (from != to) + func_static_merge(it.key(), from, to); + } +} + + +PIString PIPluginLoader::findLibrary(const PIString & path) { + static const PIStringList prefixes({"", "lib"}); + static const PIStringList suffixes({"", libExtension()}); + PIFile::FileInfo fi(path); + PIString dir = fi.dir(), name = fi.name(); + piForeachC (PIString & p, prefixes) { + piForeachC (PIString & s, suffixes) { + PIString fn = dir + p + name + s; + if (PIFile::isExists(fn)) + return fn; + } + } + return PIString(); +} + + +PIString PIPluginLoader::libExtension() { + return +#ifdef WINDOWS + ".dll" +#elif defined(MAC_OS) + ".dylib" +#else + ".so" +#endif + ; +} + + +#endif // PIP_FREERTOS diff --git a/libs/main/system/piplugin.h b/libs/main/system/piplugin.h new file mode 100644 index 00000000..df313b2c --- /dev/null +++ b/libs/main/system/piplugin.h @@ -0,0 +1,178 @@ +/*! \file piplugin.h +* \brief Plugin helpers +*/ +/* + PIP - Platform Independent Primitives + Plugin helpers + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIPLUGIN_H +#define PIPLUGIN_H + +#ifndef PIP_FREERTOS + +#include "pilibrary.h" +#include "pistringlist.h" + +#ifdef DOXYGEN + + +//! Declare plugin export functions, should be used before other PIP_PLUGIN_* macros +//! \relatedalso PIPluginLoader +#define PIP_PLUGIN + +//! Set user version to check it while loading +//! \relatedalso PIPluginLoader +#define PIP_PLUGIN_SET_USER_VERSION(version) + +//! Add pointer to future merge with plugin. Type is integer +//! \relatedalso PIPluginLoader +#define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) + +//! Declare function to merge static sections. This is functions +//! with 3 arguments: (int type, void * from, void * to). +//! This function invoked first while loading plugin with +//! "from" - plugin scope, "to" - application scope, and second +//! (optionally) on \a PIPluginLoader::mergeStatic() method with +//! "from" - application scope, "to" - plugin scope. So with macro +//! you can merge application and plugin static data. +//! \relatedalso PIPluginLoader +#define PIP_PLUGIN_STATIC_SECTION_MERGE + +//! Mark method to export +//! \relatedalso PIPluginLoader +#define PIP_PLUGIN_EXPORT + + +#else + + +#ifdef WINDOWS +# define PIP_PLUGIN_EXPORT __declspec(dllexport) +#else +# define PIP_PLUGIN_EXPORT +#endif + +#define __PIP_PLUGIN_LOADER_VERSION_FUNC__ pip_loader_version +#define __PIP_PLUGIN_PLUGIN_INFO_FUNC__ pip_plugin_info +#define __PIP_PLUGIN_STATIC_MERGE_FUNC__ pip_merge_static +#define __PIP_PLUGIN_LOADER_VERSION__ 1 + +#define PIP_PLUGIN_SET_USER_VERSION(v) \ + STATIC_INITIALIZER_BEGIN \ + PIPluginInfo::instance()->setUserVersion(v); \ + STATIC_INITIALIZER_END + +#define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) \ + STATIC_INITIALIZER_BEGIN \ + PIPluginInfo::instance()->setStaticSection(type, ptr); \ + STATIC_INITIALIZER_END + +#define PIP_PLUGIN \ + STATIC_INITIALIZER_BEGIN \ + PIPluginInfo::instance()->enterPlugin(); \ + STATIC_INITIALIZER_END \ + extern "C" { \ + PIP_PLUGIN_EXPORT int __PIP_PLUGIN_LOADER_VERSION_FUNC__() {return __PIP_PLUGIN_LOADER_VERSION__;} \ + PIP_PLUGIN_EXPORT PIPluginInfo * __PIP_PLUGIN_PLUGIN_INFO_FUNC__() {return PIPluginInfo::instance();} \ + } + +#define PIP_PLUGIN_STATIC_SECTION_MERGE \ + extern "C" { \ + PIP_PLUGIN_EXPORT void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to); \ + } \ + void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to) + + +#endif + + + +class PIP_EXPORT PIPluginInfo { +public: + PIPluginInfo(); + + void setUserVersion(const PIString & v); + void setStaticSection(int type, void * ptr); + PIString userVersion(bool plugin) const; + PIMap staticSections(bool plugin) const; + void enterPlugin(); + + static PIPluginInfo * instance(); + +private: + PIString user_version[2]; + PIMap static_sections[2]; + bool in_plugin; + +}; + + + + +class PIP_EXPORT PIPluginLoader { +public: + typedef int(*FunctionLoaderVersion)(); + typedef PIPluginInfo*(*FunctionPluginInfo)(); + typedef void(*FunctionStaticMerge)(int, void *, void *); + + //! Contruscts loader with filename "name" + PIPluginLoader(const PIString & name = PIString()); + + //! Destructor + ~PIPluginLoader(); + + + //! Load plugin with base filename "name". Loader try prefix "lib" + //! and suffix ".dll", ".so" or ".dylib", depends on platform + bool load(const PIString & name); + + //! Unload plugin and free library + void unload(); + + //! Returns if plugin is successfully loaded + bool isLoaded() const; + + //! Returns loaded plugin library path + PIString libPath(); + + //! Resolve symbol "name" from plugin library + void * resolve(const char * name); + + //! Invoke plugin PIP_PLUGIN_STATIC_SECTION_MERGE function + //! on every common type, with "from" - application scope, + //! "to" - plugin scope + void mergeStatic(); + +private: + NO_COPY_CLASS(PIPluginLoader) + + PIString findLibrary(const PIString & path); + static PIString libExtension(); + + PILibrary lib; + FunctionLoaderVersion func_loader_version; + FunctionPluginInfo func_plugin_info; + FunctionStaticMerge func_static_merge; + PIPluginInfo * plugin_info; + bool loaded; + +}; + + +#endif // PIP_FREERTOS +#endif // PIPLUGIN_H diff --git a/main.cpp b/main.cpp index 28bd520d..732d268d 100644 --- a/main.cpp +++ b/main.cpp @@ -74,6 +74,14 @@ inline PICout operator <<(PICout c, const SwitchChannel & v) { int Acnt = 0; +struct MM { + int x; + double y; + char c; + PIPointd h; +}; + + class A { public: A() {moved = false; i = "constructor"; piCout << "A()"; ++Acnt;} @@ -86,10 +94,12 @@ public: A & operator =(A && a) {piSwap(i, a.i); a.moved = true; piCout << "= A&&)"; return *this;} PIString i; bool moved; + MM m; static void F(int) {} }; -PIByteArray & operator <<(PIByteArray & ba, const A & v) {ba << v.i; return ba;} -PIByteArray & operator >>(PIByteArray & ba, A & v) {ba >> v.i; return ba;} + +inline PIByteArray & operator <<(PIByteArray & ba, const A & v) {ba << v.i << v.m; return ba;} +inline PIByteArray & operator >>(PIByteArray & ba, A & v) {ba >> v.i >> v.m; return ba;} int main() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 07693426..bebb15da 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,4 +17,3 @@ endmacro() # Concurrent tests pip_test(concurrent "") pip_test(math "") -#pip_test(core "") diff --git a/utils/code_model_generator/main.cpp b/utils/code_model_generator/main.cpp index b207d679..8742ef26 100755 --- a/utils/code_model_generator/main.cpp +++ b/utils/code_model_generator/main.cpp @@ -325,7 +325,7 @@ void makeGetterValue(PIFile & f, const PICodeParser::Entity * e) { piForeachC (PICodeParser::Member & m, e->members) { if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public)) continue; - f << "\tif (strcmp(name, \"" << m.name << "\") == 0) {ret << o->" << m.name << "; return ret;}\n"; + f << "\tif (strcmp(name, \"" << m.name << "\") == 0) {serialize(ret, o->" << m.name << "); return ret;}\n"; } f << "\treturn ret;\n}\n"; }