An open API service indexing awesome lists of open source software.

https://github.com/wenzhang-dev/reflpp

A C++20 library for fast serialization and deserialization using reflection
https://github.com/wenzhang-dev/reflpp

aggregate-struct cxx20 header-only json modern-cpp non-intrusive reflection

Last synced: 3 months ago
JSON representation

A C++20 library for fast serialization and deserialization using reflection

Awesome Lists containing this project

README

          

# reflpp

reflpp is a lightweight, non-intrusive reflection library. It is implemented based on cxx20. The library makes it easy to iterate over the members of a struct, get the number of members, get the name of the member, and json serialization and deserialization. The most important feature is that it is non-intrusive. There is no need to use macros or registers to declare which fields the struct has, the address offset of each field.

While everything looks nice, it's limited to the aggregate type.

# Dependency

- cxx20
- fmtlib

# Example

```c++
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include
#include

template
struct fmt::formatter> {
constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }

template
auto format(const std::unique_ptr& ptr, FormatContext& ctx) const {
if (ptr)
return fmt::format_to(ctx.out(), "{}", *ptr);
else
return fmt::format_to(ctx.out(), "null");
}
};

template
struct fmt::formatter> {
constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }

template
auto format(const std::shared_ptr& ptr, FormatContext& ctx) const {
if (ptr)
return fmt::format_to(ctx.out(), "{}", *ptr);
else
return fmt::format_to(ctx.out(), "null");
}
};

struct Foo {
int a;
bool b;
double c;

std::string d;
std::vector e;
std::array f;

std::map g;
std::set h;

std::optional i;
std::unique_ptr j;
};

struct Bar {
Foo foo;

double f64;
std::string str;
};

int main() {
std::cout << "The number of fields for Foo: "
<< ::reflpp::FieldsCount() << std::endl;
std::cout << "The number of fields for Bar: "
<< ::reflpp::FieldsCount() << std::endl;

std::cout << "The field names of Foo: "
<< fmt::format("{}", ::reflpp::kFieldNames) << std::endl;
std::cout << "The field names of Bar: "
<< fmt::format("{}", ::reflpp::kFieldNames) << std::endl;

// clang-format off
Bar bar{
.foo={
1,
false,
3.14,
"456",
{"789", "123", "456"},
{7, 8, 9},
{std::make_pair("1", "2"), std::make_pair("3", "4")},
{7, 8, 9},
1,
std::make_unique("234")
},
.f64=1.23,
.str="789"
};
// clang-format on

std::cout << "Iterate Foo struct: " << std::endl;
::reflpp::ForEach(bar.foo, [](auto idx, const auto& v) {
std::cout << fmt::format("The field idx: {}, value: {}", idx, v)
<< std::endl;
});

std::cout << "Json serialization: " << std::endl;

::reflpp::json::CompactJsonFormatter stream;
::reflpp::json::ToJson(stream, bar);

std::cout << stream << std::endl;

std::cout << "Json deserialization: " << std::endl;
Bar bar1;

std::string_view json_str = R"""(
{"foo":{"a":1,"b":false,"c":3.14,"d":"456","e":["789","123","456"],"f":[7,8,9],"g":{"1":"2","3":"4"},"h":[7,8,9],"i":1,"j":"234"},"f64":1.23,"str":"789"}
)""";
auto ec = ::reflpp::json::FromJson(json_str, bar1);
REFLPP_ASSERT(!ec);

::reflpp::ForEach(bar1.foo, [](auto idx, const auto& v) {
std::cout << fmt::format("The field idx: {}, value: {}", idx, v)
<< std::endl;
});

return 0;
}
```

The output from the example program is as follows:

```txt
The number of fields for Foo: 10
The number of fields for Bar: 3
The field names of Foo: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
The field names of Bar: ["foo", "f64", "str"]
Iterate Foo struct:
The field idx: 0, value: 1
The field idx: 1, value: false
The field idx: 2, value: 3.14
The field idx: 3, value: 456
The field idx: 4, value: ["789", "123", "456"]
The field idx: 5, value: [7, 8, 9]
The field idx: 6, value: {"1": "2", "3": "4"}
The field idx: 7, value: {7, 8, 9}
The field idx: 8, value: optional(1)
The field idx: 9, value: 234
Json serialization:
{"foo":{"a":1,"b":false,"c":3.14,"d":"456","e":["789","123","456"],"f":[7,8,9],"g":{"1":"2","3":"4"},"h":[7,8,9],"i":1,"j":"234"},"f64":1.23,"str":"789"}
Json deserialization:
The field idx: 0, value: 1
The field idx: 1, value: false
The field idx: 2, value: 3.14
The field idx: 3, value: 456
The field idx: 4, value: ["789", "123", "456"]
The field idx: 5, value: [7, 8, 9]
The field idx: 6, value: {"1": "2", "3": "4"}
The field idx: 7, value: {7, 8, 9}
The field idx: 8, value: optional(1)
The field idx: 9, value: 234
```

For non-aggragate types, it is possible to use reflpp::Value to complete serialization. Here's an example:

```c++
#include
#include
#include
#include

#include
#include
#include
#include
#include
#include
#include

template
struct fmt::formatter> {
constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }

template
auto format(const std::unique_ptr& ptr, FormatContext& ctx) const {
if (ptr)
return fmt::format_to(ctx.out(), "{}", *ptr);
else
return fmt::format_to(ctx.out(), "null");
}
};

template
struct fmt::formatter> {
constexpr auto parse(fmt::format_parse_context& ctx) { return ctx.begin(); }

template
auto format(const std::shared_ptr& ptr, FormatContext& ctx) const {
if (ptr)
return fmt::format_to(ctx.out(), "{}", *ptr);
else
return fmt::format_to(ctx.out(), "null");
}
};

class ComplexBaseClass {
public:
virtual ~ComplexBaseClass() {}
virtual void DoSomething() = 0;
};

class ComplexClass : public ComplexBaseClass {
public:
ComplexClass(int a, bool b, double c, std::string_view d)
: a_(a), b_(b), c_(c), d_(d) {}

void DoSomething() override {
std::cout << a_ << b_ << c_ << d_ << std::endl;
}

void Dump(::reflpp::Value& v) {
auto& d = v.AsDirectory();
d["a"] = a_;
d["b"] = b_;
d["c"] = c_;
d["d"] = d_;
}

private:
int a_;
bool b_;
double c_;
std::string d_;
};

int main() {
std::cout << "Json serialization: " << std::endl;

ComplexClass cc(1, false, 3.14, "456");
::reflpp::Value v;

cc.Dump(v);

::reflpp::json::CompactJsonFormatter stream;
::reflpp::json::ToJson(stream, v);

std::cout << stream << std::endl;

std::cout << "Json deserialization" << std::endl;

::reflpp::Value v1;
auto json_str = R"""({"a":1,"b":false,"c":3.14,"d":"456"})""";
auto ec = ::reflpp::json::FromJson(json_str, v1);
REFLPP_ASSERT(!ec);

auto& dict = *v1.ToDirectory();
for(auto& kv : dict) {
std::cout << "key: " << kv.first << std::endl;
}

return 0;
}
```

The output from the example program is as follows:

```txt
Json serialization:
{"a":1,"b":false,"c":3.14,"d":"456"}
Json deserialization
key: a
key: b
key: c
key: d
```