Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ jobs:
echo '```' >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=field_dispatch >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=person_read >> $GITHUB_STEP_SUMMARY
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
echo '```' >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=field_dispatch >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=person_read >> $GITHUB_STEP_SUMMARY
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jobs:
echo '```' >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=canada_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=field_dispatch >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_read >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=licenses_write >> $GITHUB_STEP_SUMMARY
./build/benchmarks/all/reflect-cpp-all-format-benchmarks --benchmark_filter=person_read >> $GITHUB_STEP_SUMMARY
Expand Down
76 changes: 76 additions & 0 deletions benchmarks/all/field_dispatch.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef BENCHMARK_FIELD_DISPATCH_HPP_
#define BENCHMARK_FIELD_DISPATCH_HPP_
#include <benchmark/benchmark.h>

#include <cstdint>
#include <vector>
namespace field_dispatch {
struct Record2 {
float field0 = 0;
float field1 = 1;
bool operator==(const Record2&) const = default;
};
struct Record16 {
float field0 = 0;
float field1 = 1;
float field2 = 2;
float field3 = 3;
float field4 = 4;
float field5 = 5;
float field6 = 6;
float field7 = 7;
float field8 = 8;
float field9 = 9;
float field10 = 10;
float field11 = 11;
float field12 = 12;
float field13 = 13;
float field14 = 14;
float field15 = 15;
bool operator==(const Record16&) const = default;
};
template <class Record>
struct Data {
std::vector<Record> records;
bool operator==(const Data&) const = default;
};
template <class Record>
auto make_data(std::size_t size) {
Data<Record> data;
data.records.resize(size);
for (std::size_t i = 0; i < size; ++i) {
data.records[i].field0 = static_cast<float>(i) * 0.5f;
data.records[i].field1 = -static_cast<float>(i) * 0.25f;
}
return data;
}
template <class Record, class Write, class Read>
void run(benchmark::State& state, Write write, Read read) {
const auto input = make_data<Record>(state.range(0));
const auto bytes = write(input);
{
const auto result = read(bytes);
if (!result) {
state.SkipWithError(result.error().what());
return;
}
if (*result != input) {
state.SkipWithError("Fields changed during round trip");
return;
}
}
for (auto _ : state) {
auto result = read(bytes);
if (!result) {
state.SkipWithError(result.error().what());
break;
}
benchmark::DoNotOptimize(result);
}
state.SetItemsProcessed(state.iterations() * state.range(0));
state.SetBytesProcessed(state.iterations() *
static_cast<std::int64_t>(bytes.size()));
state.counters["serialized_bytes"] = static_cast<double>(bytes.size());
}
} // namespace field_dispatch
#endif
20 changes: 20 additions & 0 deletions benchmarks/all/field_dispatch_avro.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <rfl/avro.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record>
void BM_field_dispatch_avro(benchmark::State& state) {
const auto schema = rfl::avro::to_schema<Data<Record>>();
run<Record>(
state, [&](const auto& input) { return rfl::avro::write(input, schema); },
[&](const auto& bytes) {
return rfl::avro::read<Data<Record>>(bytes, schema);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_avro, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_avro, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
20 changes: 20 additions & 0 deletions benchmarks/all/field_dispatch_boost_serialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <rfl/boost_serialization.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record>
void BM_field_dispatch_boost_serialization(benchmark::State& state) {
run<Record>(
state,
[&](const auto& input) { return rfl::boost_serialization::write(input); },
[&](const auto& bytes) {
return rfl::boost_serialization::read<Data<Record>>(bytes);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_boost_serialization, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_boost_serialization, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
21 changes: 21 additions & 0 deletions benchmarks/all/field_dispatch_capnproto.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <rfl/capnproto.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record>
void BM_field_dispatch_capnproto(benchmark::State& state) {
const auto schema = rfl::capnproto::to_schema<Data<Record>>();
run<Record>(
state,
[&](const auto& input) { return rfl::capnproto::write(input, schema); },
[&](const auto& bytes) {
return rfl::capnproto::read<Data<Record>>(bytes, schema);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_capnproto, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_capnproto, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
19 changes: 19 additions & 0 deletions benchmarks/all/field_dispatch_cereal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <rfl/cereal.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record>
void BM_field_dispatch_cereal(benchmark::State& state) {
run<Record>(
state, [&](const auto& input) { return rfl::cereal::write(input); },
[&](const auto& bytes) {
return rfl::cereal::read<Data<Record>>(bytes);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_cereal, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_cereal, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
57 changes: 57 additions & 0 deletions benchmarks/all/field_dispatch_no_field_names.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <rfl/json.hpp>
#include <rfl/msgpack.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record, class... Ps>
void BM_field_dispatch_json_no_field_names(benchmark::State& state) {
run<Record>(
state,
[](const auto& input) {
return rfl::json::write<rfl::NoFieldNames, Ps...>(input);
},
[](const auto& bytes) {
return rfl::json::read<Data<Record>, rfl::NoFieldNames, Ps...>(bytes);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_json_no_field_names, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_json_no_field_names, Record2,
rfl::DefaultIfMissing)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_json_no_field_names, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_json_no_field_names, Record16,
rfl::DefaultIfMissing)
->Arg(100000)
->Unit(benchmark::kMillisecond);
template <class Record, class... Ps>
void BM_field_dispatch_msgpack_no_field_names(benchmark::State& state) {
run<Record>(
state,
[](const auto& input) {
return rfl::msgpack::write<rfl::NoFieldNames, Ps...>(input);
},
[](const auto& bytes) {
return rfl::msgpack::read<Data<Record>, rfl::NoFieldNames, Ps...>(
bytes);
});
}
BENCHMARK_TEMPLATE(BM_field_dispatch_msgpack_no_field_names, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_msgpack_no_field_names, Record2,
rfl::DefaultIfMissing)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_msgpack_no_field_names, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_msgpack_no_field_names, Record16,
rfl::DefaultIfMissing)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
17 changes: 17 additions & 0 deletions benchmarks/all/field_dispatch_yas.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <rfl/yas.hpp>

#include "field_dispatch.hpp"
namespace field_dispatch {
template <class Record>
void BM_field_dispatch_yas(benchmark::State& state) {
run<Record>(
state, [&](const auto& input) { return rfl::yas::write(input); },
[&](const auto& bytes) { return rfl::yas::read<Data<Record>>(bytes); });
}
BENCHMARK_TEMPLATE(BM_field_dispatch_yas, Record2)
->Arg(100000)
->Unit(benchmark::kMillisecond);
BENCHMARK_TEMPLATE(BM_field_dispatch_yas, Record16)
->Arg(100000)
->Unit(benchmark::kMillisecond);
} // namespace field_dispatch
27 changes: 27 additions & 0 deletions include/rfl/avro/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>

#include "../Result.hpp"
#include "../always_false.hpp"
Expand Down Expand Up @@ -274,6 +275,32 @@ struct Reader {
return Error(std::string(__FUNCTION__) + " error(" + std::to_string(res) +
"): " + avro_strerror());
}
if constexpr (requires {
std::make_integer_sequence<int, ObjectReader::size()>{};
}) {
if (size == ObjectReader::size()) {
std::optional<Error> err;
const auto read_field =
[&]<int i>(std::integral_constant<int, i> index) {
if (err) {
return;
}
avro_value_t element;
const int result =
avro_value_get_by_index(_obj.val_, i, &element, nullptr);
if (result != 0) {
err = Error(std::string("read_object error(") +
std::to_string(result) + "): " + avro_strerror());
return;
}
_object_reader.read(index, InputVarType{&element});
};
[&]<int... Is>(std::integer_sequence<int, Is...>) {
(read_field(std::integral_constant<int, Is>{}), ...);
}(std::make_integer_sequence<int, ObjectReader::size()>{});
return err;
}
}
for (size_t ix = 0; ix < size; ++ix) {
avro_value_t element;
res = avro_value_get_by_index(_obj.val_, ix, &element, nullptr);
Expand Down
13 changes: 13 additions & 0 deletions include/rfl/boost_serialization/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>

#include "../Result.hpp"
#include "../always_false.hpp"
Expand Down Expand Up @@ -181,6 +182,18 @@ struct Reader {
template <class ObjectReader>
std::optional<Error> read_object(const ObjectReader& _object_reader,
const InputObjectType& _obj) const noexcept {
if constexpr (requires {
std::make_integer_sequence<int, ObjectReader::size()>{};
}) {
if (_obj.size == ObjectReader::size()) {
[&]<int... Is>(std::integer_sequence<int, Is...>) {
(_object_reader.read(std::integral_constant<int, Is>{},
InputVarType{_obj.ar}),
...);
}(std::make_integer_sequence<int, ObjectReader::size()>{});
return std::nullopt;
}
}
for (size_t i = 0; i < _obj.size; ++i) {
auto var = InputVarType{_obj.ar};
_object_reader.read(static_cast<int>(i), var);
Expand Down
16 changes: 15 additions & 1 deletion include/rfl/capnproto/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <optional>
#include <string>
#include <type_traits>
#include <utility>

#include "../Bytestring.hpp"
#include "../Result.hpp"
Expand Down Expand Up @@ -178,8 +179,21 @@ class RFL_API Reader {
template <class ObjectReader>
std::optional<Error> read_object(const ObjectReader& _object_reader,
const InputObjectType& _obj) const noexcept {
const auto fields = _obj.val_.getSchema().getFields();
if constexpr (requires {
std::make_integer_sequence<int, ObjectReader::size()>{};
}) {
if (fields.size() == ObjectReader::size()) {
[&]<int... Is>(std::integer_sequence<int, Is...>) {
(_object_reader.read(std::integral_constant<int, Is>{},
InputVarType{_obj.val_.get(fields[Is])}),
...);
}(std::make_integer_sequence<int, ObjectReader::size()>{});
return std::nullopt;
}
}
int i = 0;
for (auto field : _obj.val_.getSchema().getFields()) {
for (auto field : fields) {
_object_reader.read(i++, InputVarType{_obj.val_.get(field)});
}
return std::nullopt;
Expand Down
8 changes: 5 additions & 3 deletions include/rfl/cereal/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>

#include "../Bytestring.hpp"
#include "../Result.hpp"
Expand Down Expand Up @@ -171,9 +172,10 @@ struct Reader {
std::optional<Error> read_object(const ObjectReader& _object_reader,
const InputObjectType& _obj) const noexcept {
try {
for (size_t i = 0; i < ObjectReader::size(); ++i) {
_object_reader.read(i, InputVarType{_obj.archive_});
}
[&]<int... Is>(std::integer_sequence<int, Is...>) {
(_object_reader.read(std::integral_constant<int, Is>{},
InputVarType{_obj.archive_}), ...);
}(std::make_integer_sequence<int, ObjectReader::size()>{});
return std::nullopt;
} catch (std::exception& e) {
return Error(std::string("Cereal object read error: ") + e.what());
Expand Down
7 changes: 7 additions & 0 deletions include/rfl/parsing/ViewReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ class ViewReader {
std::make_integer_sequence<int, size_>());
}

// Positional readers already know the field at compile time.
template <int i>
void read(std::integral_constant<int, i>, const InputVarType& _var) const {
assign_to_matching_field(*r_, i, _var, view_, errors_, found_, set_,
std::integer_sequence<int, i>());
}

/**
* @brief Returns the size of the view.
*
Expand Down
Loading
Loading