Skip to content
/ fmp Public

Advanced Reflection and Serialization Library in C++26♦️

License

Notifications You must be signed in to change notification settings

deepgrace/fmp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fmp LICENSE Language Platform

Flat Memberwise Pack

Overview

#include <cassert>
#include <iostream>
#include <fmp.hpp>

struct W
{
    int rank;
    std::string key;
    std::string val;
};

struct X
{
    float f;
    std::string s;
};

struct Y
{
    int i;
    double d;
    char c;
    X x;
};

int main(int argc, char* argv[])
{
    static_assert(fmp::member_name_v<1, W> == "key");
    static_assert(fmp::member_name<int, W>() == "rank");

    static_assert(fmp::member_index<int, W>() == 0);
    static_assert(fmp::member_index<W>("val") == 2);

    static_assert(std::is_same_v<fmp::member_t<0, W>, int>);
    static_assert(std::is_same_v<fmp::member_t<fmp::member_index<W>("val"), W>, std::string>);

    X x { 15.32f, "template" };
    Y y { 2048, 12.14, '+', { 27.85f, "fmp" } };

    x.*fmp::get<0, X>() = 30.18f;
    fmp::get<1>(fmp::get<X>(y)) = "Stateful";

    auto ns = fmp::member_names_v<W>;
    assert(fmp::get<0>(ns) == "rank");

    assert(fmp::member_name_v<1, W> == "key");
    assert(fmp::member_name_v<2, W> == "val");

    assert(x.f == 30.18f);
    assert(y.x.s == "Stateful");

    assert(fmp::index(&X::s) == 1);
    assert(fmp::index(&Y::x) == 3);

    static_assert(fmp::tuple_size_v<X> == 2);
    static_assert(fmp::tuple_size_v<Y> == 4);

    static_assert(std::is_same_v<fmp::tuple_element_t<0, X>, float>);
    static_assert(std::is_same_v<fmp::tuple_element_t<1, Y>, double>);

    auto f = fmp::tie_fuple(x);
    auto t = fmp::tie_tuple(y);

    fmp::get<std::string&>(f) = "Dark Army";
    std::get<X&>(t) = { 72.68f, "Programs" };

    assert(x.s == "Dark Army");

    assert(y.x.f == 72.68f);
    assert(y.x.s == "Programs");

    x.*fmp::get<0, X>() = 48.65f;
    x.*fmp::get<1, X>() = "transformer";

    assert(fmp::get<1>(f) == "transformer");
    assert(fmp::get<float>(f) == 48.65f);

    y.*fmp::get<3, Y>() = { 25.65f, "Template" };

    assert(std::get<3>(t).f == 25.65f);
    assert(std::get<X&>(t).s == "Template");

    W w1;
    W w2;

    std::stringstream ss1;
    std::stringstream ss2;

    std::string str1 = "100, \"Modern C++ Template\", \"MetaProgramming Library\"";
    std::string str2 = "101, \"Modern C++ Stateful\", \"MetaProgramming Framework\"";

    ss1 << str1;
    ss1 >> fmp::io(w1);

    ss2 << str2;
    ss2 >> fmp::io(w2);

    std::cout << fmp::io(w1) << std::endl;
    std::cout << fmp::io(w2) << std::endl;

    /* outputs
    100, "Modern C++ Template", "MetaProgramming Library"
    101, "Modern C++ Stateful", "MetaProgramming Framework"
    */

    assert(w1.rank == 100);
    assert(w2.rank == 101);

    assert(w1.key == "Modern C++ Template");
    assert(w2.key == "Modern C++ Stateful");

    assert(w1.val == "MetaProgramming Library");
    assert(w2.val == "MetaProgramming Framework");

    std::cout << "fmp::lt " << fmp::lt(w1, w2) << std::endl;
    std::cout << "fmp::le " << fmp::le(w1, w2) << std::endl;

    std::cout << "fmp::ne " << fmp::ne(w1, w2) << std::endl;
    std::cout << "fmp::eq " << fmp::eq(w1, w2) << std::endl;

    std::cout << "fmp::ge " << fmp::ge(w1, w2) << std::endl;
    std::cout << "fmp::gt " << fmp::gt(w1, w2) << std::endl;

    auto f1 = fmp::tie_fuple(w1);
    auto f2 = fmp::tie_fuple(w2);

    auto t1 = fmp::tie_tuple(w1);
    auto t2 = fmp::tie_tuple(w2);

    std::cout << "f1 <  f2 " << (f1 <  f2) << std::endl;
    std::cout << "f1 <= f2 " << (f1 <= f2) << std::endl;

    std::cout << "f1 != f2 " << (f1 != f2) << std::endl;
    std::cout << "f1 == f2 " << (f1 == f2) << std::endl;

    std::cout << "f1 >= f2 " << (f1 >= f2) << std::endl;
    std::cout << "f1 >  f2 " << (f1 >  f2) << std::endl;

    std::cout << "t1 <  t2 " << (t1 <  t2) << std::endl;
    std::cout << "t1 <= t2 " << (t1 <= t2) << std::endl;

    std::cout << "t1 != t2 " << (t1 != t2) << std::endl;
    std::cout << "t1 == t2 " << (t1 == t2) << std::endl;

    std::cout << "t1 >= t2 " << (t1 >= t2) << std::endl;
    std::cout << "t1 >  t2 " << (t1 >  t2) << std::endl;

    int fr = 0;
    int tr = 0;

    std::string fk;
    std::string tk;

    std::string fv;
    std::string tv;

    fmp::ref_fuple(fr, fk, fv) = w1;
    fmp::ref_tuple(tr, tk, tv) = w2;

    assert(fr == 100);
    assert(tr == 101);

    assert(fk == "Modern C++ Template");
    assert(tk == "Modern C++ Stateful");

    assert(fv == "MetaProgramming Library");
    assert(tv == "MetaProgramming Framework");

    auto print_backward = []<typename... Args>(Args&&... args)
    {
        const char* sep = " ";

        ((std::cout << args << sep, sep) = ... = " ");
        std::cout << std::endl;
    };

    fmp::for_each(print_backward, w1);
    std::cout << std::endl;

    fmp::for_each(print_backward, w2);
    std::cout << std::endl;

    auto mptrs_backward = []<typename T>(T&& t)
    {
        return [&]<typename... Args>(Args&&... args)
        {
            const char* sep = " ";

            ((std::cout << t.*args << sep, sep) = ... = " ");
            std::cout << std::endl;
        };
    };

    fmp::for_mptr(mptrs_backward(w1), w1);
    std::cout << std::endl;

    fmp::for_mptr(mptrs_backward(w2), w2);
    std::cout << std::endl;

    fmp::apply(print_backward, w1);
    fmp::apply(print_backward, w2);

    std::cout << std::endl;
    fmp::zip(print_backward, w1, w2, x, y);

    // marshal and unmarshal a structure

    std::string xs = fmp::marshal(x);
    std::string ys = fmp::marshal(y);

    X x0 = fmp::unmarshal<X>(xs);
    Y y0 = fmp::unmarshal<Y>(ys);

    assert(fmp::eq(x, x0));

    assert(y.i == y0.i);
    assert(y.d == y0.d);

    assert(y.c == y0.c);
    assert(fmp::eq(y.x, y0.x));

    // marshal and unmarshal with allocated structure

    X x1;
    std::string s0;

    fmp::marshal(s0, x);
    fmp::unmarshal(s0, x1);

    assert(fmp::eq(x1, x));

    Y y1;
    std::string s1 = "prefix";

    size_t prelen = s1.length();
    size_t length = s1.length();

    fmp::marshal(s1, y);
    fmp::unmarshal(length, s1, y1);

    assert(y.i == y1.i);
    assert(y.d == y1.d);

    assert(y.c == y1.c);
    assert(fmp::eq(y.x, y1.x));

    assert(length == s1.length());
    assert(fmp::marshal(y).length() == length - prelen);

    auto y2 = fmp::unmarshal<Y>(s1.substr(prelen));

    assert(y.i == y2.i);
    assert(y.d == y2.d);

    assert(y.c == y2.c);
    assert(fmp::eq(y.x, y2.x));

    // marshal and unmarshal a fmp::fuple or std::tuple

    std::string ws1 = fmp::marshal(f1);
    std::string ws2 = fmp::marshal(t2);

    auto w3 = fmp::unmarshal<W>(ws1);
    auto w4 = fmp::unmarshal<W>(ws2);

    assert(fmp::eq(w1, w3));
    assert(fmp::eq(w2, w4));

    auto f0 = fmp::make_fuple(1, 2.0f, std::string("marshal"), 'X', std::make_tuple(100.3, std::string("Unmarshal")));
    auto t0 = std::make_tuple(2, 3.0f, std::string("Marshal"), 'Y', fmp::make_fuple(200.3, std::string("unmarshal")));

    std::string fs0 = fmp::marshal(f0);
    std::string ts0 = fmp::marshal(t0);

    auto f3 = fmp::unmarshal<decltype(f0)>(fs0);
    auto t3 = fmp::unmarshal<decltype(t0)>(ts0);

    assert(f3 == f0);
    assert(t3 == t0);

    assert(std::get<std::string>(fmp::get<4>(f3)) == std::get<1>(fmp::get<4>(f0)));
    assert(fmp::get<1>(std::get<4>(t3)) == fmp::get<std::string>(std::get<4>(t0)));

    return 0;
}

Introduction

fmp is a reflection and serialization library, which is header-only, extensible and modern C++ oriented.
It exhibits a form of stateless metaprogramming of compile time type list, meta information extractor and provides many powerful algorithms for manipulating structure elements, marshaling and unmarshaling a structure, fmp::fuple or std::tuple.

fmp is mainly consist of two parts:

  • fuple A flat tuple implemented with multiple inheritance is a drop-in replacement for std::tuple
  • reflect A reflection, marshaling and unmarshaling library enable you to manipulate structure elements by index or type and provides many std::tuple like methods

Compiler requirements

The library relies on a C++26 compiler and standard library, but nothing else is required.

More specifically, fmp requires a compiler supporting the following C++26 features (non-exhaustively):

  • structured bindings with a pack

Building

fmp is header-only. To use it just add the necessary #include line to your source files, like this:

#include <fmp.hpp>

To build the example with cmake, cd to the root of the project and setup the build directory:

mkdir build
cd build
cmake ..

Make and install the executables:

make -j4
make install

The executables are now located at the bin directory of the root of the project.
The example can also be built with the script build.sh, just run it, the executables will be put at the /tmp directory.

Full example

Please see example.

License

fmp is licensed as Boost Software License 1.0.