Skip to content
/ GpCore2 Public

C++ library of low level components (reflection, multithreading, fibers, safe math etc.)

License

Notifications You must be signed in to change notification settings

ITBear/GpCore2

Repository files navigation

GPCore - C++ library of low level components (reflection, multithreading, fibers, safe math etc.)

GPCore is a C++20 library of low level components written for wide use cases. There are libraries built on top of GPCore like GpJson (classes mapper from/to json), GpNetwork (tcp, udp, http asynchronous server), GpDbConnector (lightweight database ORM) and other.

Library can be configured and build for Linux, Windows, MacOS, iOS, Android, Browser(wasm) and bare metal (cortex-m).

Key features

  • Reflection. Provides reflection tools. With it it is possible to bind class fields to a data-model descriptor and store it into a manager. Data-model manager gives R/W access to class fields through field names and access to data-model description. Reflection tools also support inheritance (not multiple), fully dynamic "on-fly" data-model builder. See examples or documentation.

  • Fibers. Provides tools for work with fibers: task manager, tasks that suspend and resume execution at certain locations (manual or by events). See examples or documentation.

  • Safe math. Provides tools for work safe with arithmetic types (std::is_arithmetic). For all operations that can cause overflow (addition, multiplication) or undefined behavior (overflows) library provides safe wrappers.If possible, checks will be done at a compile time, if not then at a runtime. If a runtime operation cause an error, then an exception will be thrown. examples or documentation.

  • Service lifetime (start, read config, start internal tasks, OS signals processing, stop)

  • UUIDs (include version 7)
  • Encoders (Base64, Base58)
  • String conversion
  • Enums
  • Date/time
  • Measure unit types

Using reflection

Documentation

Let's assume you have class:

class MyDataStruct
{
public:
   string         str;
   int32_t        i32 = 0;
   vector<string> vec_str;
}

Make it reflectable:

  • Inherits from GpTypeStructBase
  • Macros CLASS_DECLARE_DEFAULTS declares containers with MyDataStruct like shares pointers, vectors etc. (can be used: MyDataStruct::C::Vec::Val is equal to std::vector)
  • Macros TYPE_STRUCT_DECLARE declares all the reflection 'magic'. As in argument it takes UUID for data-model structure. By this UUID data-model can be accessed from the manager.
  • Declares default, copy and mode constructors
  • Macros TYPE_STRUCT_IMPLEMENT implements all the reflection 'magic'. As in arguments it takes name of the class (MyDataStruct) and group UUID for data-model structure (GP_MODULE_UUID - is just the global definition of "07d0903e-1195-4dcf-92d7-4f0db3f7e4f9"_sv). '_sv' is string literal for std::string_view
  • In method _SCollectStructProps binds class fields to data-model
class MyDataStruct final: public GpTypeStructBase
{
public:
   CLASS_DECLARE_DEFAULTS(MyDataStruct)
   TYPE_STRUCT_DECLARE("2bfadcf2-fe2a-4e10-a86c-78580fa1b6bb"_uuid)

public:           
                  MyDataStruct  (void) noexcept {}
                  MyDataStruct  (const MyDataStruct& aDesc):
                   str(aDesc.str), i32(aDesc.i32), vec_str(aDesc.vec_str) {}
                  MyDataStruct  (MyDataStruct&& aDesc) noexcept:
                   str(std::move(aDesc.str)), i32(aDesc.i32), vec_str(std::move(aDesc.vec_str)) {}
   virtual        ~MyDataStruct (void) noexcept override final {}

public:
   string         str;
   int32_t        i32 = 0;
   vector<string> vec_str;
};

TYPE_STRUCT_IMPLEMENT(MyDataStruct, GP_MODULE_UUID)

void    MyDataStruct::_SCollectStructProps (GpTypePropInfo::C::Vec::Val& aPropsOut)
{
   PROP(str);
   PROP(i32);
   PROP(vec_str);
}

After this you can get R/W access to fields throughout manager

...
void    Foo (GpTypeStructBase& aStruct)
{
   //Get data-model info
   const GpTypeStructInfo& typeStructInfo = aStruct.TypeStructInfo();

   //Get references to class fields
   auto& str     = typeStructInfo.Prop("str"_sv).Value_String(aStruct.DataPtr());
   auto& i32     = typeStructInfo.Prop("i32"_sv).Value_UInt32(aStruct.DataPtr());
   auto& vec_str = typeStructInfo.Prop("vec_str"_sv).Vec_String(aStruct.DataPtr());

   //Read values from fields
   std::cout
       << str << "\n"
       << i32 << "\n"
       << vec_str.at(0) << "\n" << std::endl;

   //Write values to fields
   str = "456";
   i32 = -456;
   vec_str = {"ABC", "DEF"};
}

int main (int aArgc, char** aArgv)
{
   MyDataStruct s;
   s.str = "123";
   s.i32 = 123;
   s.vec_str = {"First", "2", "3"};

   std::cout << "Call Foo...\n";
   Foo(s);
   std::cout << "Return...\n"
       << s.str << "\n"
       << s.i32 << "\n"
       << s.vec_str.at(0) << "\n" << std::endl;

   return 0;
}

Will be printed

Call Foo...
123
123
First

Return...
456
-456
ABC

Using fibers

Documentation

//Simple fiber task
class MyTask final: public GpTaskFiberBase
{
public:
   CLASS_DECLARE_DEFAULTS(MyTask)

public:
                         MyTask  (void) noexcept:GpTaskFiberBase("test task"_sv) {}
                         ~MyTask (void) noexcept override final {}

   virtual void          OnStart (void) override final {std::cout << "Start task..." << std::endl;}
   virtual GpTaskDoRes  OnStep  (EventOptRefT /*aEvent*/) override final;
   virtual void         OnStop  (void) noexcept override final {std::cout << "Stop task..." << std::endl;}
};

GpTaskDoRes    MyTask::OnStep (EventOptRefT /*aEvent*/)
{
   int k = 0;
   std::cout << "Task step " << k++ << std::endl;
   YELD_READY();
   std::cout << "Task step " << k++ << std::endl;
   YELD_READY();
   std::cout << "Task step " << k++ << std::endl;

   return GpTaskDoRes::DONE;
}

int main (int aArgc, char** aArgv)
{
   //Initialize fiber manager (1024 fibers max, stack size 512kB per fiber)
   GpTaskFiberManager::S().Init(1024_cnt, 512_kB);

   //Initialize task scheduler
   GpTaskScheduler::SP taskScheduler = MakeSP<GpTaskScheduler>();
   taskScheduler->Start(taskScheduler, 8_cnt);

   //Create and add task to manager
   taskScheduler->ToReady(MakeSP<MyTask>());

   std::this_thread::sleep_for(std::chrono::seconds(5));

   //Stop task scheduler
   taskScheduler->RequestStop();
   taskScheduler->Join();

   return 0;
}

Will be printed

Start task...
Task step 0
Task step 1
Task step 2
Stop task...

Using safe-math

Documentation

Base class for safe math operations is GpNumericOps. Provides functions for:

  • SAdd - addition of two arithmetic values of the same type
  • SSub - subtraction of two arithmetic values of the same type
  • SMul - multiplication of two arithmetic values of the same type
  • SDiv - division of two arithmetic values of the same type
  • SConvertSafe - conversion between two arithmetic values of any types
...
constexpr std::int8_t res = NumOps::SAdd(std::int8_t(100), std::int8_t(100));
...

Will cause an error at a compile time because of int8_t have range -128...127 and result of addition will be 200

...
std::int8_t res = NumOps::SAdd(std::int8_t(100), std::int8_t(100));
...

Will cause an error at a runtime time because of int8_t have range -128...127 the result will be out of range

Build notes

QMake is used as building tool. Supported compillers are g++ (v. 10+) and clang (v 11+)

Dependencies

  • boost context - for fibers context switching (only if GP_USE_MULTITHREADING_FIBERS flag is set)
  • gmp and gmpxx - for Base58 encoder (only if GP_USE_BASE58 flag is set)

Documentation

Libraries are built on top of GPCore

About

C++ library of low level components (reflection, multithreading, fibers, safe math etc.)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published