feat(reflect-cpp): Switched from glaze -> reflect cpp

A bug was discovered in glaze which prevented valid toml output. We have
switched to toml++ and reflect-cpp. The interface has remained the same
so this should not break any code
This commit is contained in:
2025-12-06 10:55:46 -05:00
parent 2b5abeae58
commit ec13264050
365 changed files with 63946 additions and 357 deletions

View File

@@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_ARRAY_HPP_
#define RFL_INTERNAL_ARRAY_HPP_
#include <cstddef>
#include <type_traits>
#include "to_std_array.hpp"
namespace rfl {
namespace internal {
template <class T>
requires std::is_array_v<T>
struct Array {
using Type = T;
using StdArrayType = to_std_array_t<T>;
Array() = default;
Array(const StdArrayType &_arr) : arr_(_arr) {}
Array(StdArrayType &&_arr) : arr_(std::move(_arr)) {}
Array(const T &_arr) : arr_(to_std_array(_arr)) {}
Array(T &&_arr) : arr_(to_std_array(_arr)) {}
~Array() = default;
StdArrayType arr_;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,18 @@
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#include <type_traits>
#include "copy_to_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using field_tuple_t =
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
}
} // namespace rfl
#endif

View File

@@ -0,0 +1,23 @@
#ifndef RFL_INTERNAL_FIELDS_HPP_
#define RFL_INTERNAL_FIELDS_HPP_
#include <array>
#include <cstdint>
#include <string>
#include <string_view>
#include <unordered_map>
namespace rfl {
namespace internal {
template <int N>
struct Fields {
std::array<std::string, N> names_;
std::unordered_map<std::string_view, std::int16_t> indices_;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,84 @@
#ifndef RFL_INTERNAL_GETTER_HPP_
#define RFL_INTERNAL_GETTER_HPP_
#include "../Tuple.hpp"
#include "StringLiteral.hpp"
#include "find_index.hpp"
namespace rfl::internal {
// ----------------------------------------------------------------------------
template <class NamedTupleType>
struct Getter;
// ----------------------------------------------------------------------------
/// Default case - anything that cannot be explicitly matched.
template <class NamedTupleType>
struct Getter {
public:
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline auto& get(NamedTupleType& _tup) {
return rfl::get<_index>(_tup.values());
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline auto& get(NamedTupleType& _tup) {
constexpr auto index =
find_index<_field_name, typename NamedTupleType::Fields>();
return Getter<NamedTupleType>::template get<index>(_tup);
}
/// Gets a field by the field type.
template <class Field>
static inline auto& get(NamedTupleType& _tup) {
constexpr auto index =
find_index<Field::name_, typename NamedTupleType::Fields>();
static_assert(
std::is_same<typename tuple_element_t<
index, typename NamedTupleType::Fields>::Type,
typename Field::Type>(),
"If two fields have the same name, "
"their type must be the same as "
"well.");
return Getter<NamedTupleType>::template get<index>(_tup);
}
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline const auto& get_const(const NamedTupleType& _tup) {
return rfl::get<_index>(_tup.values());
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline const auto& get_const(const NamedTupleType& _tup) {
constexpr auto index =
find_index<_field_name, typename NamedTupleType::Fields>();
return Getter<NamedTupleType>::template get_const<index>(_tup);
}
/// Gets a field by the field type.
template <class Field>
static inline const auto& get_const(const NamedTupleType& _tup) {
constexpr auto index =
find_index<Field::name_, typename NamedTupleType::Fields>();
static_assert(
std::is_same<typename tuple_element_t<
index, typename NamedTupleType::Fields>::Type,
typename Field::Type>(),
"If two fields have the same name, "
"their type must be the same as "
"well.");
return Getter<NamedTupleType>::template get_const<index>(_tup);
}
};
// ----------------------------------------------------------------------------
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,17 @@
#ifndef RFL_INTERNAL_HASVALIDATION_HPP_
#define RFL_INTERNAL_HASVALIDATION_HPP_
#include "../Result.hpp"
namespace rfl {
namespace internal {
template <class Class, typename T>
concept HasValidation = requires(Class obj, T value) {
{ Class::validate(value) } -> std::same_as<rfl::Result<T>>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,149 @@
#ifndef RFL_INTERNAL_SKIP_HPP_
#define RFL_INTERNAL_SKIP_HPP_
#include <optional>
#include <type_traits>
#include "../default.hpp"
namespace rfl::internal {
template <class T, bool _skip_serialization, bool _skip_deserialization>
class Skip {
private:
using SelfType = Skip<T, _skip_serialization, _skip_deserialization>;
public:
static constexpr bool skip_serialization_ = _skip_serialization;
static constexpr bool skip_deserialization_ = _skip_deserialization;
/// The underlying type.
using Type = T;
using ReflectionType = std::optional<T>;
Skip() : value_(Type()) {}
Skip(const Type& _value) : value_(_value) {}
Skip(ReflectionType&& _value) noexcept
: value_(_value ? std::move(*_value) : Type()) {}
Skip(const ReflectionType& _value) : value_(_value ? *_value : Type()) {}
Skip(Type&& _value) noexcept : value_(std::move(_value)) {}
Skip(SelfType&& _skip) noexcept = default;
Skip(const SelfType& _skip) = default;
template <class U, bool _skip_s, bool _skip_d>
Skip(const Skip<U, _skip_s, _skip_d>& _other) : value_(_other.get()) {}
template <class U, bool _skip_s, bool _skip_d>
Skip(Skip<U, _skip_s, _skip_d>&& _other) : value_(_other.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Skip(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Skip(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
template <class U, bool _skip_s, bool _skip_d,
typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Skip(const Skip<U, _skip_s, _skip_d>& _skip) : value_(_skip.value()) {}
/// Assigns the underlying object to its default value.
template <class U = Type,
typename std::enable_if<std::is_default_constructible_v<U>,
bool>::type = true>
Skip(const Default&) : value_(Type()) {}
~Skip() = default;
/// Returns the underlying object.
Type& get() { return value_; }
/// Returns the underlying object.
const Type& get() const { return value_; }
/// Returns the underlying object.
Type& operator()() { return value_; }
/// Returns the underlying object.
const Type& operator()() const { return value_; }
/// Assigns the underlying object.
auto& operator=(const Type& _value) {
value_ = _value;
return *this;
}
/// Assigns the underlying object.
auto& operator=(Type&& _value) noexcept {
value_ = std::move(_value);
return *this;
}
/// Assigns the underlying object.
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
auto& operator=(const U& _value) {
value_ = _value;
return *this;
}
/// Assigns the underlying object to its default value.
template <class U = Type,
typename std::enable_if<std::is_default_constructible_v<U>,
bool>::type = true>
auto& operator=(const Default&) {
value_ = Type();
return *this;
}
/// Assigns the underlying object.
SelfType& operator=(const SelfType& _other) = default;
/// Assigns the underlying object.
SelfType& operator=(SelfType&& _other) = default;
/// Assigns the underlying object.
template <class U, bool _skip_s, bool _skip_d>
auto& operator=(const Skip<U, _skip_s, _skip_d>& _skip) {
value_ = _skip.get();
return *this;
}
/// Assigns the underlying object.
template <class U, bool _skip_s, bool _skip_d>
auto& operator=(Skip<U, _skip_s, _skip_d>&& _skip) {
value_ = std::forward<T>(_skip.value_);
return *this;
}
/// Returns the ReflectionType - necessary for the serialization to work.
ReflectionType reflection() const { return value_; }
/// Assigns the underlying object.
void set(const Type& _value) { value_ = _value; }
/// Assigns the underlying object.
void set(Type&& _value) { value_ = std::move(_value); }
/// Returns the underlying object.
Type& value() { return value_; }
/// Returns the underlying object.
const Type& value() const { return value_; }
private:
/// The underlying value
T value_;
};
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,56 @@
#ifndef RFL_INTERNAL_STRINGLITERAL_HPP_
#define RFL_INTERNAL_STRINGLITERAL_HPP_
#include <algorithm>
#include <array>
#include <string>
#include <string_view>
namespace rfl {
namespace internal {
/// Normal strings cannot be used as template
/// parameters, but this can. This is needed
/// for the parameters names in the NamedTuples.
template <size_t N>
struct StringLiteral {
constexpr StringLiteral(const auto... _chars) : arr_{_chars..., '\0'} {}
constexpr StringLiteral(const std::array<char, N> _arr) : arr_(_arr) {}
constexpr StringLiteral(const char (&_str)[N]) {
std::copy_n(_str, N, std::data(arr_));
}
/// Returns the value as a string.
std::string str() const { return std::string(string_view()); }
/// Returns the value as a string.
constexpr std::string_view string_view() const {
return std::string_view(std::data(arr_), N - 1);
}
static constexpr size_t length = N - 1;
std::array<char, N> arr_{};
};
template <size_t N1, size_t N2>
constexpr inline bool operator==(const StringLiteral<N1>& _first,
const StringLiteral<N2>& _second) {
if constexpr (N1 != N2) {
return false;
}
return _first.string_view() == _second.string_view();
}
template <size_t N1, size_t N2>
constexpr inline bool operator!=(const StringLiteral<N1>& _first,
const StringLiteral<N2>& _second) {
return !(_first == _second);
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_VISITTREE_HPP_
#define RFL_INTERNAL_VISITTREE_HPP_
namespace rfl {
namespace internal {
struct VisitTree {
/// Evaluates a visitor pattern using a tree-like structure.
template <int _begin, int _end, class Visitor, class... Args>
static inline auto visit(const auto& _v, const int _i,
const Args&... _args) {
static_assert(_end > _begin, "_end needs to be greater than _begin.");
if constexpr (_end - _begin == 1) {
return _v.template visit<_begin>(_args...);
} else {
constexpr int middle = (_begin + _end) / 2;
if (_i < middle) {
return visit<_begin, middle, Visitor>(_v, _i, _args...);
} else {
return visit<middle, _end, Visitor>(_v, _i, _args...);
}
}
}
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_VISITORWRAPPER_HPP_
#define RFL_INTERNAL_VISITORWRAPPER_HPP_
#include "../Literal.hpp"
#include "../TaggedUnion.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
/// Necessary for the VisitTree structure.
template <class Visitor, internal::StringLiteral... _fields>
struct VisitorWrapper {
/// Calls the underlying visitor when required to do so.
template <int _i, class... Args>
inline auto visit(const Args&... _args) const {
return (*visitor_)(name_of<Literal<_fields...>, _i>(), _args...);
}
/// The underlying visitor.
const Visitor* visitor_;
};
} // namespace internal
} // namespace rfl
#endif // RFL_VISIT_HPP_

View File

@@ -0,0 +1,23 @@
#ifndef RFL_INTERNAL_ALLFIELDS_HPP_
#define RFL_INTERNAL_ALLFIELDS_HPP_
#include "../Tuple.hpp"
#include "is_field.hpp"
namespace rfl {
namespace internal {
template <class TupleType, int _i = 0>
constexpr bool all_fields() {
if constexpr (_i == rfl::tuple_size_v<TupleType>) {
return true;
} else {
using T = tuple_element_t<_i, TupleType>;
return is_field_v<T> && all_fields<TupleType, _i + 1>();
}
}
} // namespace internal
} // namespace rfl
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
#ifndef RFL_INTERNAL_COPY_FLATTENED_TUPLE_TO_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_COPY_FLATTENED_TUPLE_TO_NAMED_TUPLE_HPP_
#include <type_traits>
#include <utility>
#include "../Field.hpp"
#include "../make_named_tuple.hpp"
#include "lit_name.hpp"
namespace rfl {
namespace internal {
template <class FieldNames, int _i>
auto copy_one_element(const auto& _flattened_tuple) {
const auto name_literal = FieldNames::template name_of<_i>();
return rfl::make_field<
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
std::get<_i>(_flattened_tuple));
}
template <class FieldNames, class... Fields>
auto copy_flattened_tuple_to_named_tuple(const auto& _flattened_tuple) {
constexpr auto size =
rfl::tuple_size_v<std::remove_cvref_t<decltype(_flattened_tuple)>>;
return [&]<int... _i>(std::integer_sequence<int, _i...>) {
return make_named_tuple(
copy_one_element<FieldNames, _i>(_flattened_tuple)...);
}
(std::make_integer_sequence<int, size>());
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,20 @@
#ifndef RFL_INTERNAL_COPY_FROM_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_COPY_FROM_NAMED_TUPLE_HPP_
#include "move_from_named_tuple.hpp"
namespace rfl {
namespace internal {
/// Creates a struct of type T from a named tuple.
/// All fields of the struct must be an rfl::Field.
template <class T, class NamedTupleType>
T copy_from_named_tuple(const NamedTupleType& _n) {
auto n = _n;
return move_from_named_tuple<T>(std::move(n));
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,20 @@
#ifndef RFL_COPY_FROM_TUPLE_HPP_
#define RFL_COPY_FROM_TUPLE_HPP_
#include "move_from_tuple.hpp"
namespace rfl {
namespace internal {
/// Creates a struct of type T from a tuple by copying the underlying
/// fields.
template <class T, class TupleType>
T copy_from_tuple(const TupleType& _t) {
auto t = _t;
return move_from_tuple<T, TupleType>(std::move(t));
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,18 @@
#ifndef RFL_INTERNAL_COPY_TO_FIELD_TUPLE_HPP_
#define RFL_INTERNAL_COPY_TO_FIELD_TUPLE_HPP_
#include "move_to_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
auto copy_to_field_tuple(const T& _t) {
auto t = _t;
return move_to_field_tuple(std::move(t));
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_DEFINELITERAL_HPP_
#define RFL_INTERNAL_DEFINELITERAL_HPP_
#include "../Literal.hpp"
namespace rfl {
namespace internal {
/// Allows you to combine several literals.
template <class... LiteralTypes>
struct define_literal;
/// General case
template <StringLiteral... _content1, StringLiteral... _content2, class... Tail>
struct define_literal<Literal<_content1...>, Literal<_content2...>, Tail...> {
using type = typename define_literal<Literal<_content1..., _content2...>,
Tail...>::type;
};
/// Special case - only a single literal is left
template <StringLiteral... _content>
struct define_literal<Literal<_content...>> {
using type = Literal<_content...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,46 @@
#ifndef RFL_INTERNAL_DEFINENAMEDTUPLE_HPP_
#define RFL_INTERNAL_DEFINENAMEDTUPLE_HPP_
#include "../NamedTuple.hpp"
namespace rfl {
namespace internal {
template <class... FieldTypes>
struct define_named_tuple;
/// Allows you to combine several named tuples and/or additional fields.
/// Recursive case - all types are fields.
template <class Head, class... Tail>
struct define_named_tuple<Head, Tail...> {
using type = typename define_named_tuple<NamedTuple<Head>, Tail...>::type;
};
/// Allows you to combine several named tuples and/or additional fields.
/// Recursive case - first type is NamedTuple, second type is field.
template <class Head, class... TupContent, class... Tail>
struct define_named_tuple<NamedTuple<TupContent...>, Head, Tail...> {
using type = typename define_named_tuple<NamedTuple<TupContent..., Head>,
Tail...>::type;
};
/// Allows you to combine several named tuples and/or additional fields.
/// Recursive case - first type is NamedTuple, second type is also NamedTuple.
template <class... TupContent, class... TupContent2, class... Tail>
struct define_named_tuple<NamedTuple<TupContent...>, NamedTuple<TupContent2...>,
Tail...> {
using type =
typename define_named_tuple<NamedTuple<TupContent..., TupContent2...>,
Tail...>::type;
};
/// Allows you to combine several named tuples and/or additional fields.
template <class... TupContent>
struct define_named_tuple<NamedTuple<TupContent...>> {
using type = NamedTuple<TupContent...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,57 @@
#ifndef RFL_INTERNAL_DEFINETAGGEDUNION_HPP_
#define RFL_INTERNAL_DEFINETAGGEDUNION_HPP_
#include "../TaggedUnion.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
/// Allows you to combine several tagged unions.
template <StringLiteral _discriminator, class... TaggedUnionTypes>
struct define_tagged_union;
/// Recursive case - both tagged union.
template <StringLiteral _discriminator, class... NamedTupleTypes1,
class... NamedTupleTypes2, class... Tail>
struct define_tagged_union<
_discriminator, TaggedUnion<_discriminator, NamedTupleTypes1...>,
TaggedUnion<_discriminator, NamedTupleTypes2...>, Tail...> {
using type = typename define_tagged_union<
_discriminator,
TaggedUnion<_discriminator, NamedTupleTypes1..., NamedTupleTypes2...>,
Tail...>::type;
};
/// Recursive case - tagged union plus named tuple.
template <StringLiteral _discriminator, class... NamedTupleTypes,
class... FieldTypes, class... Tail>
struct define_tagged_union<_discriminator,
TaggedUnion<_discriminator, NamedTupleTypes...>,
NamedTuple<FieldTypes...>, Tail...> {
using type = typename define_tagged_union<
_discriminator,
TaggedUnion<_discriminator, NamedTupleTypes...,
NamedTuple<FieldTypes...>>,
Tail...>::type;
};
/// Recursive case - named tuple.
template <StringLiteral _discriminator, class... FieldTypes, class... Tail>
struct define_tagged_union<_discriminator, NamedTuple<FieldTypes...>, Tail...> {
using type = typename define_tagged_union<
_discriminator, TaggedUnion<_discriminator, NamedTuple<FieldTypes...>>,
Tail...>::type;
};
/// Special case - only a single TaggedUnion is left.
template <StringLiteral _discriminator, class... NamedTupleTypes>
struct define_tagged_union<_discriminator,
TaggedUnion<_discriminator, NamedTupleTypes...>> {
using type = TaggedUnion<_discriminator, NamedTupleTypes...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,42 @@
#ifndef RFL_INTERNAL_DEFINEVARIANT_HPP_
#define RFL_INTERNAL_DEFINEVARIANT_HPP_
#include <variant>
namespace rfl {
namespace internal {
/// Allows you to combine several variants.
template <class... Vars>
struct define_variant;
/// Recursive case - both variants.
template <class... Vars1, class... Vars2, class... Tail>
struct define_variant<std::variant<Vars1...>, std::variant<Vars2...>, Tail...> {
using type = typename define_variant<std::variant<Vars1..., Vars2...>,
Tail...>::type;
};
/// Recursive case - variant plus other type.
template <class... Vars, class Head, class... Tail>
struct define_variant<std::variant<Vars...>, Head, Tail...> {
using type =
typename define_variant<std::variant<Vars..., Head>, Tail...>::type;
};
/// Recursive case - other type.
template <class Head, class... Tail>
struct define_variant<Head, Tail...> {
using type = typename define_variant<std::variant<Head>, Tail...>::type;
};
/// Special case - only a single variant is left.
template <class... Vars>
struct define_variant<std::variant<Vars...>> {
using type = std::variant<Vars...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_ELEMENT_INDEX_HPP_
#define RFL_INTERNAL_ELEMENT_INDEX_HPP_
#include <type_traits>
namespace rfl::internal {
template <int _i, class T>
consteval int find_element_index() {
return -1;
}
template <int _i, class T, class Head, class... Tail>
consteval int find_element_index() {
if constexpr (std::is_same_v<T, Head>) {
return _i;
} else {
return find_element_index<_i + 1, T, Tail...>();
}
}
template <class T, class... AlternativeTypes>
consteval int element_index() {
return find_element_index<0, T, AlternativeTypes...>();
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,69 @@
#ifndef RFL_INTERNAL_ENUMS_NAMES_HPP_
#define RFL_INTERNAL_ENUMS_NAMES_HPP_
#include <array>
#include <string_view>
#include <type_traits>
#include <utility>
#include "../../Literal.hpp"
//#include "../../config.hpp"
//#include "../../define_literal.hpp"
#include "../../make_named_tuple.hpp"
//#include "../../thirdparty/enchantum/enchantum.hpp"
#include "../StringLiteral.hpp"
namespace rfl::internal::enums {
template <class EnumType, class LiteralType, size_t N, bool _is_flag,
auto... _enums>
struct Names {
/// Contains a collection of enums as compile-time strings.
using Literal = LiteralType;
/// The number of possible values
constexpr static size_t size = N;
/// A list of all the possible enums
constexpr static auto enums_ = std::array<EnumType, N>{_enums...};
};
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
auto... _enums>
auto names_to_enumerator_named_tuple(
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
return make_named_tuple(Field<_names, EnumType>{_enums}...);
}
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
auto... _enums>
auto names_to_underlying_enumerator_named_tuple(
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
return make_named_tuple(Field<_names, std::underlying_type_t<EnumType>>{
static_cast<std::underlying_type_t<EnumType>>(_enums)}...);
}
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
auto... _enums>
constexpr std::array<std::pair<std::string_view, EnumType>, N>
names_to_enumerator_array(
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
return {
std::make_pair(LiteralHelper<_names>::name_.string_view(), _enums)...};
}
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
auto... _enums>
constexpr std::array<
std::pair<std::string_view, std::underlying_type_t<EnumType>>, N>
names_to_underlying_enumerator_array(
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
return {
std::make_pair(LiteralHelper<_names>::name_.string_view(),
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
}
} // namespace rfl::internal::enums
#endif

View File

@@ -0,0 +1,129 @@
#ifndef RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
#define RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
// Enum values must be greater than or equal to RFL_ENUM_RANGE_MIN.
// By default, RFL_ENUM_RANGE_MIN is set to -256.
// To change the default minimum range for all enum types, redefine the macro
// RFL_ENUM_RANGE_MIN.
#if !defined(RFL_ENUM_RANGE_MIN)
#define RFL_ENUM_RANGE_MIN -256
#endif
// Enum values must be less than or equal to RFL_ENUM_RANGE_MAX.
// By default, RFL_ENUM_RANGE_MAX is set to 256.
// To change the default maximum range for all enum types, redefine the macro
// RFL_ENUM_RANGE_MAX.
#if !defined(RFL_ENUM_RANGE_MAX)
#define RFL_ENUM_RANGE_MAX 256
#endif
#ifdef ENCHANTUM_MIN_RANGE
#undef ENCHANTUM_MIN_RANGE
#endif
#define ENCHANTUM_MIN_RANGE RFL_ENUM_RANGE_MIN
#ifdef ENCHANTUM_MAX_RANGE
#undef ENCHANTUM_MAX_RANGE
#endif
#define ENCHANTUM_MAX_RANGE RFL_ENUM_RANGE_MAX
#include <concepts>
#include <utility>
#include "../../thirdparty/enchantum/enchantum.hpp"// NOLINT(unused-includes)
#include "../../Literal.hpp"
#include "Names.hpp"
#include "range_defined.hpp"
// https://en.cppreference.com/w/cpp/language/static_cast:
// 8) A value of integer or enumeration type can be converted to any complete
// enumeration type.
// If the underlying type is not fixed, the behavior is undefined if the value
// of expression is out of range (the range is all values possible for the
// smallest bit-field large enough to hold all enumerators of the target
// enumeration). If the underlying type is fixed, the result is the same as
// converting the original value first to the underlying type of the enumeration
// and then to the enumeration type.
// https://en.cppreference.com/w/cpp/language/enum
// enum struct|class name { enumerator = constexpr , enumerator = constexpr ,
// ... } (1)
// ...
// 1) declares a scoped enumeration type whose underlying type is int (the
// keywords class and struct are exactly equivalent)
//
// --> These rules taken together imply that if you EITHER fix the type OR you
// use a scoped integer, static_cast<MyEnum>(some_integer_value) will always be
// defined.
template <enchantum::Enum E>
requires requires(E e) {
{ e | e } -> std::same_as<E>;
}
constexpr inline bool enchantum::is_bitflag<E> = true;
// Specialize the enchantum EnumTraits further, so rfl::config::enum_range
// works.
namespace enchantum {
template <SignedEnum E>
requires rfl::internal::enums::range_defined<E>
struct enum_traits<E> {
static constexpr std::size_t prefix_length = 0;
static constexpr auto min = rfl::config::enum_range<E>::min;
static constexpr auto max = rfl::config::enum_range<E>::max;
};
template <UnsignedEnum E>
requires rfl::internal::enums::range_defined<E>
struct enum_traits<E> {
static constexpr std::size_t prefix_length = 0;
static constexpr auto min = rfl::config::enum_range<E>::min;
static constexpr auto max = rfl::config::enum_range<E>::max;
};
template <UnscopedEnum E>
requires SignedEnum<E> &&
(!EnumFixedUnderlying<E>) && rfl::internal::enums::range_defined<E>
struct enum_traits<E> {
static constexpr auto min = rfl::config::enum_range<E>::min;
static constexpr auto max = rfl::config::enum_range<E>::max;
};
template <UnscopedEnum E>
requires UnsignedEnum<E> &&
(!EnumFixedUnderlying<E>) && rfl::internal::enums::range_defined<E>
struct enum_traits<E> {
static constexpr auto min = rfl::config::enum_range<E>::min;
static constexpr auto max = rfl::config::enum_range<E>::max;
};
} // namespace enchantum
namespace rfl::internal::enums {
template <enchantum::Enum EnumType>
consteval auto get_enum_names() {
return []<std::size_t... Is>(std::index_sequence<Is...>) {
constexpr auto& entries = enchantum::entries<EnumType>;
constexpr auto to_str_lit =
[]<std::size_t... Js>(const char* name, std::index_sequence<Js...>) {
return StringLiteral<sizeof...(Js) + 1>{name[Js]...};
};
return Names<EnumType,
Literal<to_str_lit(
entries[Is].second.data(),
std::make_index_sequence<entries[Is].second.size()>{})...>,
entries.size(), enchantum::is_bitflag<EnumType>,
entries[Is].first...>{};
}(std::make_index_sequence<enchantum::count<EnumType>>{});
}
} // namespace rfl::internal::enums
#endif

View File

@@ -0,0 +1,17 @@
#ifndef RFL_INTERNAL_ENUMS_RANGE_DEFINED_HPP_
#define RFL_INTERNAL_ENUMS_RANGE_DEFINED_HPP_
#include "../../config.hpp"
namespace rfl::internal::enums {
template <class E>
concept range_defined = requires {
{ config::enum_range<E>::min };
{ config::enum_range<E>::max };
};
} // namespace rfl::internal::enums
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_EXTRACTDISTRIMINATORS_HPP_
#define RFL_INTERNAL_EXTRACTDISTRIMINATORS_HPP_
#include <type_traits>
#include "../TaggedUnion.hpp"
#include "../define_literal.hpp"
#include "../field_type.hpp"
namespace rfl {
namespace internal {
template <class TaggedUnionType>
struct extract_discriminators;
template <StringLiteral _discriminator, class... NamedTupleType>
struct extract_discriminators<TaggedUnion<_discriminator, NamedTupleType...>> {
using type = define_literal_t<
std::remove_cvref_t<field_type_t<_discriminator, NamedTupleType>>...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,18 @@
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#include <type_traits>
#include "copy_to_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using field_tuple_t =
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
}
} // namespace rfl
#endif

View File

@@ -0,0 +1,64 @@
#ifndef RFL_INTERNAL_FIELD_TYPE_HPP_
#define RFL_INTERNAL_FIELD_TYPE_HPP_
#include <type_traits>
#include <variant>
//#include "../NamedTuple.hpp"
#include "../TaggedUnion.hpp"
#include "../Tuple.hpp"
#include "../named_tuple_t.hpp"
#include "StringLiteral.hpp"
#include "find_index.hpp"
namespace rfl {
namespace internal {
template <class T, class... Ts>
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
/// Finds the type of the field signified by _field_name
template <StringLiteral _field_name, class T>
struct FieldType;
/// Default option - for named tuples.
template <StringLiteral _field_name, class T>
struct FieldType {
using NamedTupleType = named_tuple_t<T>;
static constexpr int field_ix_ =
internal::find_index<_field_name, typename NamedTupleType::Fields>();
using Type = typename tuple_element_t<field_ix_,
typename NamedTupleType::Fields>::Type;
};
/// For variants - in this case the FieldType returned by all options must be
/// the same.
template <StringLiteral _field_name, class FirstAlternativeType,
class... OtherAlternativeTypes>
struct FieldType<_field_name,
std::variant<FirstAlternativeType, OtherAlternativeTypes...>> {
constexpr static bool all_types_match = std::conjunction_v<std::is_same<
typename FieldType<_field_name, FirstAlternativeType>::Type,
typename FieldType<_field_name, OtherAlternativeTypes>::Type>...>;
static_assert(all_types_match, "All field types must be the same.");
using Type = typename FieldType<_field_name, FirstAlternativeType>::Type;
};
/// For tagged union - just defers to the variant.
template <StringLiteral _field_name, StringLiteral _discriminator_name,
class... VarTypes>
struct FieldType<_field_name, TaggedUnion<_discriminator_name, VarTypes...>> {
using Type =
typename FieldType<_field_name,
typename TaggedUnion<_discriminator_name,
VarTypes...>::VariantType>::Type;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,66 @@
#ifndef RFL_FIND_INDEX_HPP_
#define RFL_FIND_INDEX_HPP_
#include "../Tuple.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class FieldType, StringLiteral _field_name, int _i>
struct FieldWrapper {
constexpr static int i_ = _i;
};
template <StringLiteral _field_name, class F1, int _i1, class F2, int _i2>
constexpr auto operator|(const FieldWrapper<F1, _field_name, _i1>& _f1,
const FieldWrapper<F2, _field_name, _i2>& _f2) {
if constexpr (F1::name_ == _field_name) {
return _f1;
} else {
return _f2;
}
}
template <class Head, class... Tail>
constexpr auto find_matching_field(const Head& _head, const Tail&... _tail) {
return (_head | ... | _tail);
};
template <StringLiteral _field_name, class Fields, int... _is>
constexpr auto wrap_fields(std::integer_sequence<int, _is...>) {
return find_matching_field(FieldWrapper<rfl::tuple_element_t<_is, Fields>,
_field_name, _is>{}...)
.i_;
}
/// Finds the index of the field signified by _field_name
template <StringLiteral _field_name, class Fields>
constexpr static int find_index() {
constexpr int ix = wrap_fields<_field_name, Fields>(
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>());
static_assert(rfl::tuple_element_t<ix, Fields>::name_ == _field_name,
"No matching field found.");
return ix;
}
/// Finds the index of the field signified by _field_name or -1.
template <StringLiteral _field_name, class Fields>
constexpr static int find_index_or_minus_one() {
if constexpr (rfl::tuple_size_v<Fields> == 0) {
return -1;
} else {
constexpr int ix = wrap_fields<_field_name, Fields>(
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>());
if constexpr (rfl::tuple_element_t<ix, Fields>::name_ == _field_name) {
return ix;
} else {
return -1;
}
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,18 @@
#ifndef RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
#define RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
#include <type_traits>
#include "to_flattened_ptr_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using flattened_ptr_tuple_t =
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>), T>::type;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,18 @@
#ifndef RFL_INTERNAL_FLATTENED_TUPLE_T_HPP_
#define RFL_INTERNAL_FLATTENED_TUPLE_T_HPP_
#include "flattened_ptr_tuple_t.hpp"
#include "remove_ptrs_tup.hpp"
//#include "../to_named_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using flattened_tuple_t =
typename remove_ptrs_tup<flattened_ptr_tuple_t<T>>::TupleType;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,46 @@
#ifndef RFL_INTERNAL_GETFAKEOBJECT_HPP_
#define RFL_INTERNAL_GETFAKEOBJECT_HPP_
namespace rfl {
namespace internal {
#if __GNUC__
#ifndef __clang__
#pragma GCC system_header
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
#pragma clang diagnostic ignored "-Wundefined-internal"
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 7631)
#endif
template <class T>
struct wrapper {
const T value;
static const wrapper<T> report_if_you_see_a_link_error_with_this_object;
};
template <class T>
consteval const T& get_fake_object() noexcept {
return wrapper<T>::report_if_you_see_a_link_error_with_this_object.value;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,170 @@
#ifndef RFL_INTERNAL_GETFIELDNAMES_HPP_
#define RFL_INTERNAL_GETFIELDNAMES_HPP_
#include <type_traits>
#include <utility>
#if __has_include(<source_location>)
#include <source_location>
#endif
#include "../Literal.hpp"
#include "get_ith_field_from_fake_object.hpp"
#include "is_flatten_field.hpp"
#include "is_rename.hpp"
#include "num_fields.hpp"
#if __GNUC__
#ifndef __clang__
#pragma GCC system_header
#endif
#endif
namespace rfl::internal {
template <class T>
struct Wrapper {
using Type = T;
T v;
};
template <class T>
Wrapper(T) -> Wrapper<T>;
// This workaround is necessary for clang.
template <class T>
constexpr auto wrap(const T& arg) noexcept {
return Wrapper{arg};
}
template <class T, auto ptr>
consteval auto get_field_name_str_view() {
#if __cpp_lib_source_location >= 201907L
const auto func_name =
std::string_view{std::source_location::current().function_name()};
#elif defined(_MSC_VER)
// Officially, we only support MSVC versions that are modern enough to contain
// <source_location>, but inofficially, this might work.
const auto func_name = std::string_view{__FUNCSIG__};
#else
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
#endif
#if defined(__clang__)
const auto split = func_name.substr(0, func_name.size() - 2);
return split.substr(split.find_last_of(":.") + 1);
#elif defined(__GNUC__)
const auto split = func_name.substr(0, func_name.size() - 2);
return split.substr(split.find_last_of(":") + 1);
#elif defined(_MSC_VER)
const auto split = func_name.substr(0, func_name.size() - 7);
return split.substr(split.rfind("->") + 2);
#else
static_assert(false,
"You are using an unsupported compiler. Please use GCC, Clang "
"or MSVC or switch to the rfl::Field-syntax.");
#endif
}
template <class T, auto ptr>
consteval auto get_field_name_str_lit() {
constexpr auto name = get_field_name_str_view<T, ptr>();
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
return StringLiteral<sizeof...(Ns) + 1>{name[Ns]...};
};
return to_str_lit(std::make_index_sequence<name.size()>{});
}
template <class T>
auto get_field_names();
template <class T, auto ptr>
auto get_field_name() {
#if defined(__clang__)
using Type = std::remove_cvref_t<std::remove_pointer_t<
typename std::remove_pointer_t<decltype(ptr)>::Type>>;
#else
using Type = std::remove_cvref_t<std::remove_pointer_t<decltype(ptr)>>;
#endif
if constexpr (is_rename_v<Type>) {
using Name = typename Type::Name;
return Name();
} else if constexpr (is_flatten_field_v<Type>) {
return get_field_names<std::remove_cvref_t<typename Type::Type>>();
} else {
return rfl::Literal<get_field_name_str_lit<T, ptr>()>();
}
}
// We don't want the operator+ to apply to normal literals,
// so we introduce this wrapper.
template <StringLiteral... _names>
struct LiteralWrapper {
Literal<_names...> literal_;
};
template <StringLiteral... _names>
auto wrap_literal(const Literal<_names...>& _literal) {
return LiteralWrapper<_names...>{_literal};
}
template <StringLiteral... _names1, StringLiteral... _names2>
auto operator+(const LiteralWrapper<_names1...>&,
const LiteralWrapper<_names2...>&) {
return LiteralWrapper<_names1..., _names2...>{
rfl::Literal<_names1..., _names2...>::template from_value<0>()};
}
template <class Head, class... Tail>
auto concat_literals(const Head& _head, const Tail&... _tail) {
return (wrap_literal(_head) + ... + wrap_literal(_tail)).literal_;
}
// Special case - the struct does not contain rfl::Flatten.
template <StringLiteral _head, StringLiteral... _tail>
auto concat_literals(const rfl::Literal<_head>&,
const rfl::Literal<_tail>&...) {
return rfl::Literal<_head, _tail...>::template from_value<0>();
}
inline auto concat_literals() { return rfl::Literal<>(); }
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
#pragma clang diagnostic ignored "-Wundefined-inline"
#endif
template <class T>
#if __GNUC__
#ifndef __clang__
[[gnu::no_sanitize_undefined]]
#endif
#endif
auto get_field_names() {
using Type = std::remove_cvref_t<T>;
if constexpr (std::is_pointer_v<Type>) {
return get_field_names<std::remove_pointer_t<T>>();
} else {
#if defined(__clang__)
const auto get = []<std::size_t... _is>(std::index_sequence<_is...>) {
return concat_literals(
get_field_name<Type,
wrap(get_ith_field_from_fake_object<T, _is>())>()...);
};
#else
const auto get = []<std::size_t... _is>(std::index_sequence<_is...>) {
return concat_literals(
get_field_name<Type, get_ith_field_from_fake_object<T, _is>()>()...);
};
#endif
return get(std::make_index_sequence<num_fields<T>>());
}
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} // namespace rfl::internal
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_GETMETAFIELDS_HPP_
#define RFL_INTERNAL_GETMETAFIELDS_HPP_
#include <array>
#include <utility>
#include "../MetaField.hpp"
#include "../Tuple.hpp"
#include "../type_name_t.hpp"
namespace rfl {
namespace internal {
template <class NamedTupleType, class... AlreadyExtracted>
auto get_meta_fields(AlreadyExtracted&&... _already_extracted) {
constexpr size_t i = sizeof...(_already_extracted);
if constexpr (NamedTupleType::size() == i) {
return std::array<MetaField, i>{std::move(_already_extracted)...};
} else {
using FieldType = tuple_element_t<i, typename NamedTupleType::Fields>;
auto name = typename FieldType::Name().str();
auto type = type_name_t<typename FieldType::Type>().str();
return get_meta_fields<NamedTupleType>(
std::move(_already_extracted)...,
MetaField(std::move(name), std::move(type)));
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,63 @@
#ifndef RFL_INTERNAL_GETTYPENAME_HPP_
#define RFL_INTERNAL_GETTYPENAME_HPP_
#include <utility>
#include "StringLiteral.hpp"
#if __has_include(<source_location>)
#include <source_location>
#endif
namespace rfl {
namespace internal {
template <class T>
consteval auto get_type_name_str_view() {
#if __cpp_lib_source_location >= 201907L
const auto func_name =
std::string_view{std::source_location::current().function_name()};
#elif defined(_MSC_VER)
// Officially, we only support MSVC versions that are modern enough to contain
// <source_location>, but inofficially, this might work.
const auto func_name = std::string_view{__FUNCSIG__};
#else
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
#endif
#if defined(__clang__)
const auto split = func_name.substr(0, func_name.size() - 1);
return split.substr(split.find("T = ") + 4);
#elif defined(__GNUC__)
const auto split = func_name.substr(0, func_name.size() - 1);
return split.substr(split.find("T = ") + 4);
#elif defined(_MSC_VER)
auto split = func_name.substr(0, func_name.size() - 7);
split = split.substr(split.find("get_type_name_str_view<") + 23);
auto pos = split.find(" ");
if (pos != std::string_view::npos) {
return split.substr(pos + 1);
}
return split;
#else
static_assert(
false,
"You are using an unsupported compiler. Please use GCC, Clang "
"or MSVC or explicitly tag your structs using 'Tag' or 'Name'.");
#endif
}
template <class T>
consteval auto get_type_name() {
static_assert(get_type_name_str_view<int>() == "int",
"Expected 'int', got something else.");
constexpr auto name = get_type_name_str_view<T>();
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
return StringLiteral<sizeof...(Ns) + 1>{name[Ns]...};
};
return to_str_lit(std::make_index_sequence<name.size()>{});
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,23 @@
#ifndef RFL_INTERNAL_HASCUSTOMPARSER_HPP_
#define RFL_INTERNAL_HASCUSTOMPARSER_HPP_
#include <type_traits>
#include "../parsing/Parser.hpp"
namespace rfl::internal {
template <class R, class W, class T, class ProcessorsType>
concept has_custom_parser = requires(
const T& _t, const typename parsing::Parser<
R, W, T, ProcessorsType>::CustomParserHelperStruct& _h) {
{
std::remove_cvref_t<decltype(_h)>::from_class(_t)
} -> std::same_as<std::remove_cvref_t<decltype(_h)>>;
{ _h.to_class() } -> std::same_as<T>;
};
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_HASDEFAULTVALV_HPP_
#define RFL_HASDEFAULTVALV_HPP_
#include <type_traits>
#include "../NamedTuple.hpp"
#include "../named_tuple_t.hpp"
#include "is_default_val_v.hpp"
namespace rfl::internal {
template <class T>
struct HasDefaultVal;
template <class... Fields>
struct HasDefaultVal<NamedTuple<Fields...>> {
static constexpr bool value =
(false || ... ||
is_default_val_v<
std::remove_cvref_t<std::remove_pointer_t<typename Fields::Type>>>);
};
template <class T>
constexpr bool has_default_val_v = HasDefaultVal<named_tuple_t<T>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,80 @@
#ifndef RFL_INTERNAL_HASFIELDS_HPP_
#define RFL_INTERNAL_HASFIELDS_HPP_
#include <type_traits>
#include <utility>
#include "../Tuple.hpp"
//#include "all_fields.hpp"
#include "is_field.hpp"
#include "is_flatten_field.hpp"
#include "ptr_tuple_t.hpp"
#include "is_named_tuple.hpp"
namespace rfl {
namespace internal {
template <class TupleType>
constexpr bool all_fields_or_flatten() {
const auto is_true_for_one =
[]<int _i>(std::integral_constant<int, _i>) -> bool {
using T = std::remove_cvref_t<tuple_element_t<_i, TupleType>>;
if constexpr (is_flatten_field_v<T>) {
return all_fields_or_flatten<
ptr_tuple_t<typename std::remove_pointer_t<T>::Type>>();
} else {
return is_field_v<T>;
}
};
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return (true && ... && is_true_for_one(std::integral_constant<int, _is>{}));
}
(std::make_integer_sequence<int, rfl::tuple_size_v<TupleType>>());
}
template <class TupleType>
constexpr bool some_fields_or_flatten() {
const auto is_true_for_one =
[]<int _i>(std::integral_constant<int, _i>) -> bool {
using T = std::remove_cvref_t<tuple_element_t<_i, TupleType>>;
if constexpr (is_flatten_field_v<T>) {
return some_fields_or_flatten<
ptr_tuple_t<typename std::remove_pointer_t<T>::Type>>();
} else {
return is_field_v<T>;
}
};
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return (false || ... ||
is_true_for_one(std::integral_constant<int, _is>{}));
}
(std::make_integer_sequence<int, rfl::tuple_size_v<TupleType>>());
}
template <class T>
constexpr bool has_fields() {
if constexpr (is_named_tuple_v<T>) {
return true;
} else {
using TupleType = ptr_tuple_t<T>;
if constexpr (some_fields_or_flatten<TupleType>()) {
static_assert(
all_fields_or_flatten<TupleType>(),
"If some of your fields are annotated using rfl::Field<...>, "
"then you must annotate all of your fields. "
"Also, you cannot combine annotated and "
"unannotated fields using rfl::Flatten<...>.");
return true;
} else {
return false;
}
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,31 @@
#ifndef RFL_INTERNAL_HASFLATTENFIELDS_HPP_
#define RFL_INTERNAL_HASFLATTENFIELDS_HPP_
#include <type_traits>
#include <utility>
#include "../Tuple.hpp"
#include "is_flatten_field.hpp"
namespace rfl {
namespace internal {
template <class TupleType>
constexpr bool has_flatten_fields() {
const auto is_true_for_one =
[]<int _i>(std::integral_constant<int, _i>) -> bool {
using T = std::remove_cvref_t<tuple_element_t<_i, TupleType>>;
return is_flatten_field_v<T>;
};
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return (false || ... ||
is_true_for_one(std::integral_constant<int, _is>{}));
}
(std::make_integer_sequence<int, rfl::tuple_size_v<TupleType>>());
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,15 @@
#ifndef RFL_INTERNAL_HASREFLECTIONMETHODV_HPP_
#define RFL_INTERNAL_HASREFLECTIONMETHODV_HPP_
#include <concepts>
namespace rfl::internal {
template <class T>
constexpr bool has_reflection_method_v = requires(T t) {
{ t.reflection() } -> std::convertible_to<typename T::ReflectionType>;
};
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,20 @@
#ifndef RFL_HASREFLECTIONTYPEV_HPP_
#define RFL_HASREFLECTIONTYPEV_HPP_
#include <concepts>
namespace rfl::internal {
template <class T>
struct ReflectionTypeWrapper {};
template <typename T>
constexpr bool has_reflection_type_v = requires() {
{
ReflectionTypeWrapper<typename T::ReflectionType>{}
} -> std::same_as<ReflectionTypeWrapper<typename T::ReflectionType>>;
};
} // namespace rfl::internal
#endif // RFL_HASNAMEDTUPLETYPEV_HPP_

View File

@@ -0,0 +1,24 @@
#ifndef RFL_INTERNAL_HASREFLECTOR_HPP_
#define RFL_INTERNAL_HASREFLECTOR_HPP_
namespace rfl {
template <typename T>
struct Reflector;
namespace internal {
template <typename Type>
concept has_write_reflector = requires(Type&& item) {
Reflector<Type>::from(item);
};
template <typename Type>
concept has_read_reflector =
requires(const typename Reflector<Type>::ReflType& item) {
Reflector<Type>::to(item);
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,21 @@
#ifndef RFL_HASTAGV_HPP_
#define RFL_HASTAGV_HPP_
#include <concepts>
namespace rfl::internal {
template <class T>
struct TagWrapper {};
/// Used for tagged unions - determines whether a struct as a Tag.
template <typename T>
constexpr bool has_tag_v = requires() {
{
TagWrapper<typename T::Tag>{}
} -> std::same_as<TagWrapper<typename T::Tag>>;
};
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_HASTOCLASSMETHODV_HPP_
#define RFL_INTERNAL_HASTOCLASSMETHODV_HPP_
#include <type_traits>
namespace rfl {
namespace internal {
template <typename Wrapper>
using to_class_method_t = decltype(std::declval<const Wrapper>().to_class());
template <typename Wrapper, typename = std::void_t<>>
struct has_to_class_m : std::false_type {};
template <typename Wrapper>
struct has_to_class_m<Wrapper, std::void_t<to_class_method_t<Wrapper>>>
: std::true_type {};
/// Utility parameter for named tuple parsing, can be used by the
/// parsers to determine whether a class or struct has a method
/// called "to_class".
template <typename Wrapper>
constexpr bool has_to_class_method_v = has_to_class_m<Wrapper>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,40 @@
#ifndef RFL_INTERNAL_ISADDTAGSTOVARIANTS_HPP_
#define RFL_INTERNAL_ISADDTAGSTOVARIANTS_HPP_
#include <type_traits>
#include "../AddTagsToVariants.hpp"
namespace rfl ::internal {
template <class T>
class is_add_tags_to_variants;
template <class T>
class is_add_tags_to_variants : public std::false_type {};
template <>
class is_add_tags_to_variants<AddTagsToVariants> : public std::true_type {};
template <class T>
constexpr bool is_add_tags_to_variants_v = is_add_tags_to_variants<
std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
template <class T>
class is_add_namespaced_tags_to_variants;
template <class T>
class is_add_namespaced_tags_to_variants : public std::false_type {};
template <>
class is_add_namespaced_tags_to_variants<AddNamespacedTagsToVariants>
: public std::true_type {};
template <class T>
constexpr bool is_add_namespaced_tags_to_variants_v =
is_add_namespaced_tags_to_variants<
std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_ISALLOWRAWPTRS_HPP_
#define RFL_INTERNAL_ISALLOWRAWPTRS_HPP_
#include <type_traits>
#include "../AllowRawPtrs.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_allow_raw_ptrs;
template <class T>
class is_allow_raw_ptrs : public std::false_type {};
template <>
class is_allow_raw_ptrs<AllowRawPtrs> : public std::true_type {};
template <class T>
constexpr bool is_allow_raw_ptrs_v =
is_allow_raw_ptrs<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISARRAY_HPP_
#define RFL_INTERNAL_ISARRAY_HPP_
#include <type_traits>
#include "Array.hpp"
namespace rfl::internal {
template <class T>
class is_array;
template <class T>
class is_array : public std::false_type {};
template <class Type>
class is_array<Array<Type>> : public std::true_type {};
template <class T>
constexpr bool is_array_v =
is_array<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISATTRIBUTE_HPP_
#define RFL_INTERNAL_ISATTRIBUTE_HPP_
#include <type_traits>
#include "../Attribute.hpp"
//#include "../Field.hpp"
#include "remove_rename.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_attribute;
template <class T>
class is_attribute : public std::false_type {};
template <class Type>
class is_attribute<Attribute<Type>> : public std::true_type {};
template <class T>
constexpr bool is_attribute_v = is_attribute<remove_rename_t<T>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,20 @@
#ifndef RFL_INTERNAL_ISBASICTYPE_HPP_
#define RFL_INTERNAL_ISBASICTYPE_HPP_
#include <string>
#include <type_traits>
namespace rfl {
namespace internal {
template <class T>
constexpr bool is_basic_type_v =
std::is_floating_point_v<std::remove_cvref_t<T>> ||
std::is_integral_v<std::remove_cvref_t<T>> ||
std::is_same<std::remove_cvref_t<T>, std::string>() ||
std::is_same<std::remove_cvref_t<T>, bool>();
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISDEFAULTIFMISSING_HPP_
#define RFL_INTERNAL_ISDEFAULTIFMISSING_HPP_
#include <type_traits>
#include "../DefaultIfMissing.hpp"
namespace rfl::internal {
template <class T>
class is_default_if_missing;
template <class T>
class is_default_if_missing : public std::false_type {};
template <>
class is_default_if_missing<DefaultIfMissing> : public std::true_type {};
template <class T>
constexpr bool is_default_if_missing_v =
is_default_if_missing<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISDEFAULTVAL_HPP_
#define RFL_INTERNAL_ISDEFAULTVAL_HPP_
#include <type_traits>
#include "../DefaultVal.hpp"
namespace rfl::internal {
template <class T>
class is_default_val;
template <class T>
class is_default_val : public std::false_type {};
template <class T>
class is_default_val<DefaultVal<T>> : public std::true_type {};
template <class T>
constexpr bool is_default_val_v =
is_default_val<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISDESCRIPTION_HPP_
#define RFL_INTERNAL_ISDESCRIPTION_HPP_
#include <type_traits>
#include "../Description.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_description;
template <class T>
class is_description : public std::false_type {};
template <StringLiteral _name, class Type>
class is_description<Description<_name, Type>> : public std::true_type {};
template <class T>
constexpr bool is_description_v =
is_description<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISEMPTY_HPP_
#define RFL_INTERNAL_ISEMPTY_HPP_
#include <type_traits>
#include "../Tuple.hpp"
#include "is_named_tuple.hpp"
#include "ptr_tuple_t.hpp"
namespace rfl::internal {
template <class T>
constexpr bool is_empty() {
using U = std::remove_cvref_t<std::remove_pointer_t<T>>;
if constexpr (is_named_tuple_v<U>) {
return U::size() == 0;
} else {
using TupleType = ptr_tuple_t<U>;
return rfl::tuple_size_v<TupleType> == 0;
}
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISEXTRAFIELDS_HPP_
#define RFL_INTERNAL_ISEXTRAFIELDS_HPP_
#include <type_traits>
#include "../ExtraFields.hpp"
namespace rfl::internal {
template <class T>
class is_extra_fields;
template <class T>
class is_extra_fields : public std::false_type {};
template <class T>
class is_extra_fields<ExtraFields<T>> : public std::true_type {};
template <class T>
constexpr bool is_extra_fields_v =
is_extra_fields<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISFIELD_HPP_
#define RFL_INTERNAL_ISFIELD_HPP_
#include <type_traits>
#include "../Field.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_field;
template <class T>
class is_field : public std::false_type {};
template <StringLiteral _name, class Type>
class is_field<Field<_name, Type>> : public std::true_type {};
template <class T>
constexpr bool is_field_v =
is_field<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_ISFLATTENFIELD_HPP_
#define RFL_INTERNAL_ISFLATTENFIELD_HPP_
#include <type_traits>
#include "../Flatten.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_flatten_field;
template <class T>
class is_flatten_field : public std::false_type {};
template <class T>
class is_flatten_field<Flatten<T>> : public std::true_type {};
template <class T>
constexpr bool is_flatten_field_v =
is_flatten_field<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISLITERAL_HPP_
#define RFL_INTERNAL_ISLITERAL_HPP_
#include <type_traits>
#include "../Literal.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_literal;
template <class T>
class is_literal : public std::false_type {};
template <StringLiteral... _s>
class is_literal<Literal<_s...>> : public std::true_type {};
template <class T>
constexpr bool is_literal_v =
is_literal<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_IS_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_IS_NAMED_TUPLE_HPP_
#include <type_traits>
#include "../NamedTuple.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_named_tuple;
template <class T>
class is_named_tuple : public std::false_type {};
template <class... Fields>
class is_named_tuple<NamedTuple<Fields...>> : public std::true_type {};
template <class T>
constexpr bool is_named_tuple_v =
is_named_tuple<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_ISNOEXTRAFIELDS_HPP_
#define RFL_INTERNAL_ISNOEXTRAFIELDS_HPP_
#include <type_traits>
#include "../NoExtraFields.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_no_extra_fields;
template <class T>
class is_no_extra_fields : public std::false_type {};
template <>
class is_no_extra_fields<NoExtraFields> : public std::true_type {};
template <class T>
constexpr bool is_no_extra_fields_v =
is_no_extra_fields<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_ISNOFIELDNAMES_HPP_
#define RFL_INTERNAL_ISNOFIELDNAMES_HPP_
#include <type_traits>
#include "../NoFieldNames.hpp"
namespace rfl::internal {
template <class T>
class is_no_field_names;
template <class T>
class is_no_field_names : public std::false_type {};
template <>
class is_no_field_names<NoFieldNames> : public std::true_type {};
template <class T>
constexpr bool is_no_field_names_v =
is_no_field_names<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_ISNOOPTIONALS_HPP_
#define RFL_INTERNAL_ISNOOPTIONALS_HPP_
#include <type_traits>
#include "../NoOptionals.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_no_optionals;
template <class T>
class is_no_optionals : public std::false_type {};
template <>
class is_no_optionals<NoOptionals> : public std::true_type {};
template <class T>
constexpr bool is_no_optionals_v =
is_no_optionals<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISPATTERN_HPP_
#define RFL_INTERNAL_ISPATTERN_HPP_
#include <type_traits>
#include "../Pattern.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_pattern;
template <class T>
class is_pattern : public std::false_type {};
template <StringLiteral _regex, internal::StringLiteral _name>
class is_pattern<Pattern<_regex, _name>> : public std::true_type {};
template <class T>
constexpr bool is_pattern_v =
is_pattern<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISRENAME_HPP_
#define RFL_INTERNAL_ISRENAME_HPP_
#include <type_traits>
#include "../Rename.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_rename;
template <class T>
class is_rename : public std::false_type {};
template <StringLiteral _name, class Type>
class is_rename<Rename<_name, Type>> : public std::true_type {};
template <class T>
constexpr bool is_rename_v =
is_rename<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,26 @@
#ifndef RFL_INTERNAL_ISSKIP_HPP_
#define RFL_INTERNAL_ISSKIP_HPP_
#include <type_traits>
#include "Skip.hpp"
namespace rfl::internal {
template <class T>
class is_skip;
template <class T>
class is_skip : public std::false_type {};
template <class T, bool _skip_serialization, bool _skip_deserialization>
class is_skip<Skip<T, _skip_serialization, _skip_deserialization>>
: public std::true_type {};
template <class T>
constexpr bool is_skip_v =
is_skip<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,27 @@
#ifndef RFL_INTERNAL_ISUNDERLYINGENUMS_HPP_
#define RFL_INTERNAL_ISUNDERLYINGENUMS_HPP_
#include <type_traits>
#include "../UnderlyingEnums.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_underlying_enums;
template <class T>
class is_underlying_enums : public std::false_type {};
template <>
class is_underlying_enums<UnderlyingEnums> : public std::true_type {};
template <class T>
constexpr bool is_underlying_enums_v =
is_underlying_enums<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,28 @@
#ifndef RFL_INTERNAL_ISVALIDATOR_HPP_
#define RFL_INTERNAL_ISVALIDATOR_HPP_
#include <type_traits>
#include "../Validator.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
class is_validator;
template <class T>
class is_validator : public std::false_type {};
template <class T, class V, class... Vs>
class is_validator<Validator<T, V, Vs...>> : public std::true_type {};
template <class T>
constexpr bool is_validator_v =
is_validator<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,26 @@
#ifndef RFL_INTERNAL_ISVARIANT_HPP_
#define RFL_INTERNAL_ISVARIANT_HPP_
#include <type_traits>
#include <variant>
namespace rfl {
namespace internal {
template <class T>
class is_variant;
template <class T>
class is_variant : public std::false_type {};
template <class... T>
class is_variant<std::variant<T...>> : public std::true_type {};
template <class T>
constexpr bool is_variant_v =
is_variant<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,23 @@
#ifndef RFL_INTERNAL_LIT_NAME_HPP_
#define RFL_INTERNAL_LIT_NAME_HPP_
#include "../Literal.hpp"
namespace rfl {
namespace internal {
template <class T>
struct lit_name;
template <auto _name>
struct lit_name<rfl::Literal<_name>> {
constexpr static auto name_ = _name;
};
template <class LiteralType>
constexpr auto lit_name_v = lit_name<LiteralType>::name_;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,34 @@
#ifndef RFL_INTERNAL_MAKE_TAG_HPP_
#define RFL_INTERNAL_MAKE_TAG_HPP_
#include "../Literal.hpp"
#include "../field_names_t.hpp"
#include "../named_tuple_t.hpp"
#include "../to_view.hpp"
#include "StringLiteral.hpp"
#include "get_type_name.hpp"
#include "has_reflection_type_v.hpp"
#include "has_tag_v.hpp"
#include "remove_namespaces.hpp"
namespace rfl::internal {
template <internal::StringLiteral _discriminator, class T>
static inline auto make_tag(const T& _t) noexcept {
if constexpr (internal::has_reflection_type_v<T>) {
return make_tag<_discriminator>(_t.reflection());
} else if constexpr (named_tuple_t<T>::Names::template contains<
_discriminator>()) {
return *to_view(_t).template get<_discriminator>();
} else if constexpr (internal::has_tag_v<T>) {
using LiteralType = typename T::Tag;
return LiteralType::template name_of<0>();
} else {
return rfl::Literal<
internal::remove_namespaces<internal::get_type_name<T>()>()>();
}
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,35 @@
#ifndef RFL_INTERNAL_MOVE_AND_FLATTEN_FIELD_TUPLE_HPP_
#define RFL_INTERNAL_MOVE_AND_FLATTEN_FIELD_TUPLE_HPP_
#include "../Tuple.hpp"
#include "../tuple_cat.hpp"
#include "is_flatten_field.hpp"
#include "move_to_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class FieldTuple>
auto move_and_flatten_field_tuple(FieldTuple&& _t) {
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using T = tuple_element_t<_i, std::remove_cvref_t<FieldTuple>>;
if constexpr (is_flatten_field_v<T>) {
return move_and_flatten_field_tuple(
move_to_field_tuple(std::move(rfl::get<_i>(_t).value_)));
} else {
return rfl::make_tuple(std::move(rfl::get<_i>(_t)));
}
};
constexpr auto size = rfl::tuple_size_v<std::remove_cvref_t<FieldTuple>>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return rfl::tuple_cat(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, size>());
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_MOVE_FIELD_TUPLE_TO_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_MOVE_FIELD_TUPLE_TO_NAMED_TUPLE_HPP_
#include <type_traits>
#include "../Field.hpp"
#include "../Tuple.hpp"
#include "has_flatten_fields.hpp"
#include "move_and_flatten_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class FieldTuple>
auto move_field_tuple_to_named_tuple(FieldTuple&& _field_tuple) {
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
return make_named_tuple(std::move(_fields)...);
};
if constexpr (!has_flatten_fields<std::remove_cvref_t<FieldTuple>>()) {
return rfl::apply(ft_to_nt, std::move(_field_tuple));
} else {
auto flattened_tuple =
move_and_flatten_field_tuple(std::move(_field_tuple));
return rfl::apply(ft_to_nt, std::move(flattened_tuple));
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,93 @@
#ifndef RFL_MOVE_FROM_NAMED_TUPLE_HPP_
#define RFL_MOVE_FROM_NAMED_TUPLE_HPP_
#include <type_traits>
#include "../Tuple.hpp"
#include "../named_tuple_t.hpp"
#include "is_field.hpp"
#include "is_named_tuple.hpp"
#include "nt_to_ptr_named_tuple.hpp"
#include "ptr_field_tuple_t.hpp"
namespace rfl {
namespace internal {
template <class PtrFieldTupleType, class PtrNamedTupleType>
auto make_ptr_fields(PtrNamedTupleType& _n) {
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using Field = std::remove_cvref_t<tuple_element_t<_i, PtrFieldTupleType>>;
using T = std::remove_cvref_t<std::remove_pointer_t<typename Field::Type>>;
if constexpr (is_named_tuple_v<T>) {
using SubPtrNamedTupleType =
typename std::invoke_result<decltype(nt_to_ptr_named_tuple<T>),
T>::type;
return SubPtrNamedTupleType(_n).fields();
} else if constexpr (is_flatten_field<Field>::value) {
using SubPtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
return make_ptr_fields<SubPtrFieldTupleType>(_n);
} else {
return _n.template get_field<Field::name_>();
}
};
constexpr auto size =
rfl::tuple_size_v<std::remove_cvref_t<PtrFieldTupleType>>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return rfl::make_tuple(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, size>());
}
template <class T, class Pointers>
auto move_from_ptr_fields(Pointers& _ptrs) {
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using FieldType = tuple_element_t<_i, std::remove_cvref_t<Pointers>>;
if constexpr (is_field_v<FieldType>) {
return rfl::make_field<FieldType::name_>(
std::move(*rfl::get<_i>(_ptrs).value()));
} else {
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
using U = std::remove_cvref_t<std::remove_pointer_t<
typename tuple_element_t<_i, PtrFieldTupleType>::Type>>;
return move_from_ptr_fields<U>(rfl::get<_i>(_ptrs));
}
};
constexpr auto size = rfl::tuple_size_v<std::remove_cvref_t<Pointers>>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return T{std::move(get_one(std::integral_constant<int, _is>{}))...};
}
(std::make_integer_sequence<int, size>());
}
/// Creates a struct of type T from a named tuple by moving the underlying
/// fields.
template <class T, class NamedTupleType>
T move_from_named_tuple(NamedTupleType&& _n) {
using RequiredType = std::remove_cvref_t<named_tuple_t<T>>;
if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
return std::move(_n);
} else if constexpr (std::is_same<std::remove_cvref_t<NamedTupleType>,
RequiredType>()) {
auto ptr_named_tuple = nt_to_ptr_named_tuple(_n);
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
auto pointers = make_ptr_fields<PtrFieldTupleType>(ptr_named_tuple);
return move_from_ptr_fields<T>(pointers);
} else {
return move_from_named_tuple<T, RequiredType>(RequiredType(std::move(_n)));
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,135 @@
#ifndef RFL_MOVE_FROM_TUPLE_HPP_
#define RFL_MOVE_FROM_TUPLE_HPP_
#include <type_traits>
#include "../Tuple.hpp"
#include "../tuple_cat.hpp"
#include "Array.hpp"
#include "is_flatten_field.hpp"
#include "is_named_tuple.hpp"
#include "ptr_tuple_t.hpp"
#include "tup_to_ptr_tuple.hpp"
#include "tuple_t.hpp"
namespace rfl {
namespace internal {
template <class Tuple, int _i = 0>
constexpr int calc_flattened_size() {
if constexpr (_i == rfl::tuple_size_v<Tuple>) {
return 0;
} else {
using T = std::remove_pointer_t<tuple_element_t<_i, Tuple>>;
if constexpr (is_flatten_field_v<T>) {
return calc_flattened_size<ptr_tuple_t<typename T::Type>>() +
calc_flattened_size<Tuple, _i + 1>();
} else {
return 1 + calc_flattened_size<Tuple, _i + 1>();
}
}
}
// TODO: Non-recursive implementation
template <class TargetTupleType, class PtrTupleType, int _j = 0, class... Args>
auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {
constexpr auto i = sizeof...(Args);
constexpr auto size = rfl::tuple_size_v<std::remove_cvref_t<TargetTupleType>>;
if constexpr (i == size) {
return rfl::make_tuple(_args...);
} else {
using T = std::remove_cvref_t<
std::remove_pointer_t<tuple_element_t<i, TargetTupleType>>>;
if constexpr (is_flatten_field_v<T>) {
using SubTargetTupleType =
ptr_tuple_t<std::remove_pointer_t<typename T::Type>>;
constexpr int flattened_size = calc_flattened_size<SubTargetTupleType>();
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType,
_j + flattened_size>(
_t, _args...,
unflatten_ptr_tuple<SubTargetTupleType, PtrTupleType, _j>(_t));
} else {
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType, _j + 1>(
_t, _args..., std::get<_j>(_t));
}
}
}
template <class T, class Pointers, class... Args>
auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
constexpr auto i = sizeof...(Args);
if constexpr (i == rfl::tuple_size_v<std::remove_cvref_t<Pointers>>) {
return std::remove_cvref_t<T>{std::move(_args)...};
} else {
using FieldType = tuple_element_t<i, std::remove_cvref_t<Pointers>>;
if constexpr (std::is_pointer_v<FieldType>) {
return move_from_pointers<T>(_ptrs, std::move(_args)...,
std::move(*std::get<i>(_ptrs)));
} else {
using PtrTupleType = ptr_tuple_t<std::remove_cvref_t<T>>;
using U = std::remove_cvref_t<typename std::remove_pointer_t<
tuple_element_t<i, PtrTupleType>>::Type>;
return move_from_pointers<T>(_ptrs, std::move(_args)...,
move_from_pointers<U>(std::get<i>(_ptrs)));
}
}
}
template <class T>
auto flatten_array(T* _v) {
return rfl::make_tuple(_v);
}
template <class T, std::size_t _n>
auto flatten_array(std::array<T, _n>* _arr) {
const auto fct = [](auto&... _v) {
return rfl::tuple_cat(flatten_array(&_v)...);
};
return std::apply(fct, *_arr);
}
template <class T>
auto make_tuple_from_element(T _v) {
return rfl::make_tuple(_v);
}
template <class T>
auto make_tuple_from_element(Array<T>* _arr) {
return flatten_array(&(_arr->arr_));
}
auto flatten_c_arrays(const auto& _tup) {
const auto fct = [](auto... _v) {
return rfl::tuple_cat(make_tuple_from_element(_v)...);
};
return rfl::apply(fct, _tup);
}
/// Creates a struct of type T from a tuple by moving the underlying
/// fields.
template <class T, class TupleType>
auto move_from_tuple(TupleType&& _t) {
auto ptr_tuple = tup_to_ptr_tuple(_t);
using TargetTupleType = tuple_t<std::remove_cvref_t<T>>;
auto pointers =
flatten_c_arrays(unflatten_ptr_tuple<TargetTupleType>(ptr_tuple));
return move_from_pointers<T>(pointers);
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,45 @@
#ifndef RFL_INTERNAL_MOVE_TO_FIELD_TUPLE_HPP_
#define RFL_INTERNAL_MOVE_TO_FIELD_TUPLE_HPP_
#include <type_traits>
#include "../Tuple.hpp"
#include "../field_names_t.hpp"
#include "Array.hpp"
#include "bind_to_tuple.hpp"
#include "has_fields.hpp"
#include "is_empty.hpp"
#include "is_named_tuple.hpp"
#include "wrap_in_fields.hpp"
namespace rfl {
namespace internal {
template <class OriginalStruct>
auto move_to_field_tuple(OriginalStruct&& _t) {
using T = std::remove_cvref_t<OriginalStruct>;
if constexpr (is_named_tuple_v<T>) {
return _t.fields();
} else if constexpr (has_fields<T>()) {
return bind_to_tuple(_t, [](auto _ptr) { return std::move(*_ptr); });
} else if constexpr (is_empty<T>()) {
return rfl::Tuple();
} else {
using FieldNames = field_names_t<T>;
const auto fct = []<class T>(T* _ptr) {
using Type = std::remove_cvref_t<T>;
if constexpr (std::is_array_v<Type>) {
return Array<Type>(*_ptr);
} else {
return std::move(*_ptr);
}
};
auto tup = bind_to_tuple(_t, fct);
return wrap_in_fields<FieldNames>(std::move(tup));
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,55 @@
#ifndef RFL_INTERNAL_NO_DUPLICATE_FIELD_NAMES_HPP_
#define RFL_INTERNAL_NO_DUPLICATE_FIELD_NAMES_HPP_
#include "../Tuple.hpp"
namespace rfl {
namespace internal {
namespace no_duplicate_field_names_helpers {
template <class Fields, int _i, int _j>
constexpr inline void compare_two_fields() {
if constexpr (_j < _i) {
using FieldType1 = std::remove_cvref_t<tuple_element_t<_i, Fields>>;
using FieldType2 = std::remove_cvref_t<tuple_element_t<_j, Fields>>;
constexpr auto field_name_i = FieldType1::name_;
constexpr auto field_name_j = FieldType2::name_;
constexpr bool no_duplicate = (field_name_i != field_name_j);
static_assert(no_duplicate,
"Duplicate field names are not allowed in either named "
"tuples or Literals.");
}
}
template <class Fields, int _i, int... _js>
constexpr inline void iterate_over_j(std::integer_sequence<int, _js...>) {
(compare_two_fields<Fields, _i, _js>(), ...);
}
template <class Fields, int... _is>
constexpr inline void iterate_over_i(std::integer_sequence<int, _is...>) {
(iterate_over_j<Fields, _is>(std::make_integer_sequence<int, _is>()), ...);
}
} // namespace no_duplicate_field_names_helpers
template <class Fields>
constexpr inline bool no_duplicate_field_names() {
constexpr auto num_fields = rfl::tuple_size_v<Fields>;
if constexpr (num_fields <= 1) {
return true;
} else {
no_duplicate_field_names_helpers::iterate_over_i<Fields>(
std::make_integer_sequence<int, num_fields>());
return true;
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,54 @@
#ifndef RFL_INTERNAL_NT_TO_PTR_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_NT_TO_PTR_NAMED_TUPLE_HPP_
#include "../Field.hpp"
#include "../Tuple.hpp"
#include "../make_named_tuple.hpp"
namespace rfl {
namespace internal {
/// Generates a named tuple that contains pointers to the original values in
/// the struct from a named tuple.
template <class NamedTupleType>
auto nt_to_ptr_named_tuple(NamedTupleType& _nt) {
using Fields = typename NamedTupleType::Fields;
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using FieldType = tuple_element_t<_i, Fields>;
using T = std::remove_cvref_t<typename FieldType::Type>;
return Field<FieldType::name_, T*>(&rfl::get<_i>(_nt.values()));
};
constexpr auto num_fields = rfl::tuple_size_v<Fields>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return make_named_tuple(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, num_fields>());
}
/// Generates a named tuple that contains pointers to the original values in
/// the struct from a named tuple.
template <class NamedTupleType>
auto nt_to_ptr_named_tuple(const NamedTupleType& _nt) {
using Fields = typename NamedTupleType::Fields;
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using FieldType = tuple_element_t<_i, Fields>;
using T = std::remove_cvref_t<typename FieldType::Type>;
return Field<FieldType::name_, const T*>(&rfl::get<_i>(_nt.values()));
};
constexpr auto num_fields = rfl::tuple_size_v<Fields>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return make_named_tuple(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, num_fields>());
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,43 @@
#ifndef RFL_INTERNAL_NTH_ELEMENT_HPP_
#define RFL_INTERNAL_NTH_ELEMENT_HPP_
#include <utility>
namespace rfl::internal {
template <class T, int N, int _i>
struct ElementWrapper {
T t_;
};
template <int N, class T1, int _i1, class T2, int _i2>
constexpr auto operator|(const ElementWrapper<T1, N, _i1>& _e1,
const ElementWrapper<T2, N, _i2>& _e2) {
if constexpr (_i1 == N) {
return _e1;
} else {
return _e2;
}
}
template <class Head, class... Tail>
constexpr auto find_matching_element(const Head& _head, const Tail&... _tail) {
return (_head | ... | _tail);
};
template <int N, class... Ts, int... _is>
constexpr auto wrap_elements(Ts... _ts, std::integer_sequence<int, _is...>) {
return find_matching_element(ElementWrapper<Ts, N, _is>{_ts}...).t_;
}
template <int N, class... Ts>
constexpr auto nth_element(Ts... _ts) {
static_assert(N >= 0, "N out of bounds.");
static_assert(N < sizeof...(Ts), "N out of bounds.");
return wrap_elements<N, Ts...>(
_ts..., std::make_integer_sequence<int, sizeof...(Ts)>());
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_NTH_ELEMENT_T_HPP_
#define RFL_INTERNAL_NTH_ELEMENT_T_HPP_
#include "nth_element.hpp"
namespace rfl::internal {
#if defined(__clang__)
template <int N, class... Ts>
using nth_element_t = __type_pack_element<N, Ts...>;
#else
template <class T>
struct TypeWrapper {
using Type = T;
};
template <int N, class... Ts>
using nth_element_t =
typename std::invoke_result_t<decltype(nth_element<N, TypeWrapper<Ts>...>),
TypeWrapper<Ts>...>::Type;
#endif
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,216 @@
#ifndef RFL_INTERNAL_NUM_FIELDS_HPP_
#define RFL_INTERNAL_NUM_FIELDS_HPP_
/*
We infer the number of fields using by figuring out how many fields
we need to construct it. This is done by implementing the constructible
concept, see below.
However, there is a problem with C arrays. Suppose you have a struct
like this:
struct A{
int arr[3];
};
Then, the struct can be initialized like this:
const auto a = A{1, 2, 3};
This is a problem, because a naive logic would believe that A
has three fields, when in fact it has only one.
That is why we use the constructible concept to get the maximum
possible number of fields and then try to subdivide them into arrays
in order to figure out which of these fields is in fact an array.
Basically, for every field there is, we try to squeeze as many variables into
the potential array as we can without missing variables in subsequent fields.
This is the purpose of get_nested_array_size().
*/
#include <cstddef>
#include <type_traits>
#include <utility>
#if __GNUC__
#ifndef __clang__
#pragma GCC system_header
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"
#pragma clang diagnostic ignored "-Wundefined-inline"
#endif
namespace rfl {
namespace internal {
template <class Derived>
struct any_empty_base {
any_empty_base(std::size_t);
template <class Base>
requires(
std::is_empty_v<std::remove_cvref_t<Base>> &&
std::is_base_of_v<std::remove_cvref_t<Base>,
std::remove_cv_t<Derived>> &&
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
constexpr operator Base&() const noexcept;
};
template <class Derived>
struct any_base {
any_base(std::size_t);
template <class Base>
requires(
std::is_base_of_v<std::remove_cvref_t<Base>,
std::remove_cv_t<Derived>> &&
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
constexpr operator Base&() const noexcept;
};
struct any {
any(std::size_t);
template <typename T>
constexpr operator T() const noexcept;
};
template <typename T>
struct CountFieldsHelper {
template <std::size_t n>
static consteval bool constructible() {
return []<std::size_t... is>(std::index_sequence<is...>) {
return requires { T{any(is)...}; };
}(std::make_index_sequence<n>());
}
template <std::size_t l, std::size_t nested, std::size_t r>
static consteval bool constructible_with_nested() {
return []<std::size_t... i, std::size_t... j, std::size_t... k>(
std::index_sequence<i...>, std::index_sequence<j...>,
std::index_sequence<k...>) {
return requires { T{any(i)..., {any(j)...}, any(k)...}; };
}(std::make_index_sequence<l>(), std::make_index_sequence<nested>(),
std::make_index_sequence<r>());
}
template <std::size_t n = 0>
static consteval std::size_t count_max_args_in_agg_init() {
static_assert(n <= static_cast<std::size_t>(sizeof(T)));
if constexpr (constructible<n>() && !constructible<n + 1>()) {
return n;
} else {
return count_max_args_in_agg_init<n + 1>();
}
}
template <std::size_t index, std::size_t size, std::size_t rest>
static consteval std::size_t get_nested_array_size() {
if constexpr (size < 1) {
return 1;
} else if constexpr (constructible_with_nested<index, size, rest>() &&
!constructible_with_nested<index, size, rest + 1>()) {
return size;
} else {
return get_nested_array_size<index, size - 1, rest + 1>();
}
}
template <std::size_t max_args, std::size_t index = 0>
static consteval std::size_t find_the_sole_non_empty_base_index() {
static_assert(index < max_args);
constexpr auto check = []<std::size_t... l, std::size_t... r>(
std::index_sequence<l...>,
std::index_sequence<r...>) {
return requires {
T{any_empty_base<T>(l)..., any_base<T>(0), any_empty_base<T>(r)...};
};
};
if constexpr (check(std::make_index_sequence<index>(),
std::make_index_sequence<max_args - index - 1>())) {
return index;
} else {
return find_the_sole_non_empty_base_index<max_args, index + 1>();
}
}
template <std::size_t arg_index, std::size_t size = 0>
static consteval std::size_t get_nested_base_field_count() {
static_assert(size <= sizeof(T));
if constexpr (constructible_with_nested<arg_index, size, 0>() &&
!constructible_with_nested<arg_index, size + 1, 0>()) {
return size;
} else {
return get_nested_base_field_count<arg_index, size + 1>();
}
}
template <std::size_t n, std::size_t max_arg_num>
static consteval bool has_n_base_param() {
constexpr auto right_len = max_arg_num >= n ? max_arg_num - n : 0;
return []<std::size_t... l, std::size_t... r>(std::index_sequence<l...>,
std::index_sequence<r...>) {
return requires { T{any_base<T>(l)..., any(r)...}; };
}(std::make_index_sequence<n>(), std::make_index_sequence<right_len>());
}
template <std::size_t max_arg_num, std::size_t index = 0>
static consteval std::size_t base_param_num() {
if constexpr (!has_n_base_param<index + 1, max_arg_num>()) {
return index;
} else {
return base_param_num<max_arg_num, index + 1>();
}
}
template <std::size_t index, std::size_t max>
static consteval std::size_t constructible_no_brace_elision() {
static_assert(index <= max);
if constexpr (index == max) {
return 0;
} else {
return 1 +
constructible_no_brace_elision<
index + get_nested_array_size<index, max - index, 0>(), max>();
}
}
static consteval std::size_t count_fields() {
constexpr std::size_t max_agg_args = count_max_args_in_agg_init();
#if defined(REFLECT_CPP_C_ARRAYS_OR_INHERITANCE) || \
defined(REFLECTCPP_C_ARRAYS_OR_INHERITANCE)
constexpr std::size_t no_brace_ellison_args =
constructible_no_brace_elision<0, max_agg_args>();
constexpr std::size_t base_args = base_param_num<no_brace_ellison_args>();
if constexpr (no_brace_ellison_args == 0 && base_args == 0) {
// Empty struct
return 0;
} else if constexpr (base_args == no_brace_ellison_args) {
// Special case when the derived class is empty.
// In such cases the filed number is the fields in base class.
// Note that there should be only one base class in this case.
return get_nested_base_field_count<
find_the_sole_non_empty_base_index<max_agg_args>()>();
} else {
return no_brace_ellison_args - base_args;
}
#else
return max_agg_args;
#endif
}
};
template <class T>
constexpr std::size_t num_fields = CountFieldsHelper<T>::count_fields();
} // namespace internal
} // namespace rfl
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_PROCESSED_T_HPP_
#define RFL_INTERNAL_PROCESSED_T_HPP_
#include <type_traits>
#include "../Processors.hpp"
#include "ptr_named_tuple_t.hpp"
#include "remove_ptrs_nt.hpp"
namespace rfl::internal {
template <class StructType, class ProcessorsType>
struct Processed;
template <class StructType, class... Ps>
struct Processed<StructType, Processors<Ps...>> {
using PtrNamedTupleType = ptr_named_tuple_t<StructType>;
using type = typename remove_ptrs_nt<
std::invoke_result_t<decltype(Processors<Ps...>::template process<
StructType, PtrNamedTupleType>),
PtrNamedTupleType>>::NamedTupleType;
};
template <class StructType, class ProcessorsType>
using processed_t = typename Processed<StructType, ProcessorsType>::type;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,22 @@
#ifndef RFL_INTERNAL_PTRCAST_HPP_
#define RFL_INTERNAL_PTRCAST_HPP_
namespace rfl::internal {
/// Normally, we would use std::launder(reinterpret_cast<...>(...)),
/// but there are weird issues on GCC 12 under certain compiler settings,
/// so we are using this workaround instead.
template <class T1, class T2>
inline T1 ptr_cast(T2* _ptr) {
return static_cast<T1>(static_cast<void*>(_ptr));
}
template <class T1, class T2>
inline T1 ptr_cast(const T2* _ptr) {
return static_cast<T1>(static_cast<const void*>(_ptr));
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,15 @@
#ifndef RFL_INTERNAL_PTR_NAMED_TUPLE_T_HPP_
#define RFL_INTERNAL_PTR_NAMED_TUPLE_T_HPP_
#include "to_ptr_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using ptr_field_tuple_t = decltype(to_ptr_field_tuple(std::declval<T&>()));
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,19 @@
#ifndef RFL_INTERNAL_PTR_FIELD_TUPLE_T_HPP_
#define RFL_INTERNAL_PTR_FIELD_TUPLE_T_HPP_
#include <type_traits>
//#include "is_named_tuple.hpp"//Not here
#include "to_ptr_named_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using ptr_named_tuple_t =
std::invoke_result_t<decltype(to_ptr_named_tuple<T>), T>;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,15 @@
#ifndef RFL_INTERNAL_PTR_TUPLE_T_HPP_
#define RFL_INTERNAL_PTR_TUPLE_T_HPP_
#include "to_ptr_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
using ptr_tuple_t = decltype(to_ptr_tuple(std::declval<T&>()));
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,82 @@
#ifndef RFL_INTERNAL_REMOVEFIELDS_HPP_
#define RFL_INTERNAL_REMOVEFIELDS_HPP_
#include <type_traits>
#include "../NamedTuple.hpp"
#include "../Tuple.hpp"
#include "../define_named_tuple.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
/// Recursively builds a new NamedTuple type from the FieldTypes, leaving out
/// the field signified by _name.
template <class _OldNamedTupleType, StringLiteral _name,
class _NewNamedTupleType, int _i>
struct remove_single_field;
/// Special case - _i == 0
template <class _OldNamedTupleType, StringLiteral _name,
class _NewNamedTupleType>
struct remove_single_field<_OldNamedTupleType, _name, _NewNamedTupleType, 0> {
using type = _NewNamedTupleType;
};
/// General case.
template <class _OldNamedTupleType, StringLiteral _name,
class _NewNamedTupleType, int _i>
struct remove_single_field {
using OldNamedTupleType = std::remove_cvref_t<_OldNamedTupleType>;
constexpr static int num_fields =
rfl::tuple_size_v<typename OldNamedTupleType::Fields>;
using FieldType = std::remove_cvref_t<
tuple_element_t<num_fields - _i, typename OldNamedTupleType::Fields>>;
using NewNamedTupleType =
std::conditional_t<_name == FieldType::name_, _NewNamedTupleType,
define_named_tuple_t<_NewNamedTupleType, FieldType>>;
using type = typename remove_single_field<OldNamedTupleType, _name,
NewNamedTupleType, _i - 1>::type;
};
/// Recursively removes all of the fields signified by _head and _tail from the
/// NamedTupleType.
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
struct remove_fields;
/// Special case - only head is left.
template <class _NamedTupleType, StringLiteral _head>
struct remove_fields<_NamedTupleType, _head> {
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
constexpr static int num_fields =
rfl::tuple_size_v<typename NamedTupleType::Fields>;
using type = typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
num_fields>::type;
};
/// General case.
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
struct remove_fields {
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
constexpr static int num_fields =
rfl::tuple_size_v<typename NamedTupleType::Fields>;
using NewNamedTupleType =
typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
num_fields>::type;
using type = typename remove_fields<NewNamedTupleType, _tail...>::type;
};
} // namespace internal
} // namespace rfl
#endif // RFL_REMOVEFIELDS_HPP_

View File

@@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_REMOVE_NAMESPACES_HPP_
#define RFL_INTERNAL_REMOVE_NAMESPACES_HPP_
#include <string_view>
#include <utility>
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <StringLiteral _name>
consteval auto remove_namespaces() {
constexpr auto name = _name.string_view();
constexpr size_t pos = name.find_last_of(":");
if constexpr (pos == std::string_view::npos) {
return _name;
}
constexpr auto substr = name.substr(pos + 1);
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
return StringLiteral<sizeof...(Ns) + 1>{substr[Ns]...};
};
return to_str_lit(std::make_index_sequence<substr.size()>{});
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,34 @@
#ifndef RFL_INTERNAL_REMOVE_PTRS_NT_HPP_
#define RFL_INTERNAL_REMOVE_PTRS_NT_HPP_
#include <type_traits>
#include "../Field.hpp"
#include "../NamedTuple.hpp"
#include "StringLiteral.hpp"
#include "wrap_in_rfl_array_t.hpp"
namespace rfl::internal {
template <class T>
struct remove_ptr;
template <internal::StringLiteral _name, class T>
struct remove_ptr<Field<_name, T>> {
using FieldType =
Field<_name, internal::wrap_in_rfl_array_t<
std::remove_cvref_t<std::remove_pointer_t<T>>>>;
};
template <class T>
struct remove_ptrs_nt;
template <class... FieldTypes>
struct remove_ptrs_nt<NamedTuple<FieldTypes...>> {
using NamedTupleType =
NamedTuple<typename remove_ptr<FieldTypes>::FieldType...>;
};
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_REMOVE_PTRS_TUP_HPP_
#define RFL_INTERNAL_REMOVE_PTRS_TUP_HPP_
#include <type_traits>
#include "../Tuple.hpp"
#include "../to_named_tuple.hpp"
#include "ptr_tuple_t.hpp"
namespace rfl {
namespace internal {
template <class T>
struct remove_ptrs_tup;
template <class... Ts>
struct remove_ptrs_tup<rfl::Tuple<Ts...>> {
using TupleType =
rfl::Tuple<std::remove_cvref_t<std::remove_pointer_t<Ts>>...>;
};
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_REMOVERENAME_HPP_
#define RFL_INTERNAL_REMOVERENAME_HPP_
#include <type_traits>
#include "../Rename.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <class T>
struct remove_rename;
template <class T>
struct remove_rename {
using Type = T;
};
template <StringLiteral _name, class _Type>
struct remove_rename<Rename<_name, _Type>> {
using Type = _Type;
};
template <class T>
using remove_rename_t =
typename remove_rename<std::remove_cvref_t<std::remove_pointer_t<T>>>::Type;
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,31 @@
#ifndef RFL_INTERNAL_STRINGS_STRINGS_HPP_
#define RFL_INTERNAL_STRINGS_STRINGS_HPP_
#include <string>
#include <vector>
#include "../../common.hpp"
namespace rfl::internal::strings {
/// Joins a series of strings.
RFL_API std::string join(const std::string& _delimiter,
const std::vector<std::string>& _strings);
/// Replace all occurences of _from with _to.
RFL_API std::string replace_all(const std::string& _str, const std::string& _from,
const std::string& _to);
/// Splits _str along _delimiter.
RFL_API std::vector<std::string> split(const std::string& _str,
const std::string& _delimiter);
/// Transforms the string to camel case.
RFL_API std::string to_camel_case(const std::string& _str);
/// Transforms the string to pascal case.
RFL_API std::string to_pascal_case(const std::string& _str);
} // namespace rfl::internal::strings
#endif

View File

@@ -0,0 +1,16 @@
#ifndef RFL_INTERNAL_TAG_T_HPP_
#define RFL_INTERNAL_TAG_T_HPP_
#include <type_traits>
#include "StringLiteral.hpp"
#include "make_tag.hpp"
namespace rfl::internal {
template <internal::StringLiteral _discriminator, class T>
using tag_t = std::invoke_result_t<decltype(make_tag<_discriminator, T>), T>;
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,44 @@
#ifndef RFL_INTERNAL_TO_FLATTENED_PTR_TUPLE_HPP_
#define RFL_INTERNAL_TO_FLATTENED_PTR_TUPLE_HPP_
#include "../Tuple.hpp"
#include "../tuple_cat.hpp"
#include "has_flatten_fields.hpp"
#include "is_flatten_field.hpp"
#include "to_ptr_tuple.hpp"
namespace rfl {
namespace internal {
template <class PtrTuple>
auto flatten_ptr_tuple(PtrTuple&& _t) {
if constexpr (!has_flatten_fields<PtrTuple>()) {
return std::forward<PtrTuple>(_t);
} else {
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using T = tuple_element_t<_i, std::remove_cvref_t<PtrTuple>>;
if constexpr (is_flatten_field_v<T>) {
return flatten_ptr_tuple(to_ptr_tuple(rfl::get<_i>(_t)->get()));
} else {
return rfl::make_tuple(rfl::get<_i>(_t));
}
};
constexpr auto size = rfl::tuple_size_v<std::remove_cvref_t<PtrTuple>>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return rfl::tuple_cat(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, size>());
}
}
template <class T>
auto to_flattened_ptr_tuple(T&& _t) {
return flatten_ptr_tuple(to_ptr_tuple(_t));
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,41 @@
#ifndef RFL_INTERNAL_TOPTRFIELD_HPP_
#define RFL_INTERNAL_TOPTRFIELD_HPP_
#include <type_traits>
#include "../Field.hpp"
#include "../Flatten.hpp"
#include "../always_false.hpp"
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
template <internal::StringLiteral _name, class Type>
inline auto to_ptr_field(Field<_name, Type>& _field) {
using T = std::remove_reference_t<Type>;
return Field<_name, T*>(&_field.value_);
}
template <internal::StringLiteral _name, class Type>
inline auto to_ptr_field(const Field<_name, Type>& _field) {
using T = std::remove_cvref_t<Type>;
return Field<_name, const T*>(&_field.value_);
}
template <class Type>
inline auto to_ptr_field(Flatten<Type>& _field) {
using T = std::remove_reference_t<Type>;
return Flatten<T*>(&_field.value_);
}
template <class Type>
inline auto to_ptr_field(const Flatten<Type>& _field) {
using T = std::remove_cvref_t<Type>;
return Flatten<const T*>(&_field.value_);
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,39 @@
#ifndef RFL_INTERNAL_TO_PTR_FIELD_TUPLE_HPP_
#define RFL_INTERNAL_TO_PTR_FIELD_TUPLE_HPP_
#include <type_traits>
#include "../field_names_t.hpp"
#include "bind_to_tuple.hpp"
#include "has_fields.hpp"
#include "is_empty.hpp"
#include "is_named_tuple.hpp"
#include "nt_to_ptr_named_tuple.hpp"
#include "to_ptr_field.hpp"
#include "wrap_in_fields.hpp"
namespace rfl {
namespace internal {
template <class T>
auto to_ptr_field_tuple(T& _t) {
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
return to_ptr_field_tuple(*_t);
} else if constexpr (is_named_tuple_v<T>) {
return nt_to_ptr_named_tuple(_t).fields();
} else if constexpr (has_fields<T>()) {
return bind_to_tuple(_t, [](auto* _ptr) { return to_ptr_field(*_ptr); });
} else if constexpr (is_empty<T>()) {
return rfl::Tuple();
} else {
using FieldNames = field_names_t<T>;
auto tup =
bind_to_tuple(_t, [](auto* _ptr) { return to_ptr_field(*_ptr); });
return wrap_in_fields<FieldNames>(std::move(tup));
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,80 @@
#ifndef RFL_INTERNAL_TO_PTR_NAMED_TUPLE_HPP_
#define RFL_INTERNAL_TO_PTR_NAMED_TUPLE_HPP_
#include "../Tuple.hpp"
#include "../always_false.hpp"
#include "../field_names_t.hpp"
#include "../make_named_tuple.hpp"
#include "copy_flattened_tuple_to_named_tuple.hpp"
#include "has_fields.hpp"
#include "has_flatten_fields.hpp"
#include "is_empty.hpp"
#include "is_field.hpp"
#include "is_named_tuple.hpp"
#include "to_flattened_ptr_tuple.hpp"
#include "to_ptr_field_tuple.hpp"
namespace rfl {
namespace internal {
template <class PtrFieldTuple>
auto flatten_ptr_field_tuple(PtrFieldTuple& _t) {
const auto get_one = [&]<int _i>(std::integral_constant<int, _i>) {
using T = tuple_element_t<_i, std::remove_cvref_t<PtrFieldTuple>>;
if constexpr (internal::is_flatten_field<T>::value) {
auto subtuple = internal::to_ptr_field_tuple(*rfl::get<_i>(_t).get());
return flatten_ptr_field_tuple(subtuple);
} else {
return rfl::make_tuple(rfl::get<_i>(_t));
}
};
constexpr auto size = rfl::tuple_size_v<std::remove_cvref_t<PtrFieldTuple>>;
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
return rfl::tuple_cat(get_one(std::integral_constant<int, _is>{})...);
}
(std::make_integer_sequence<int, size>());
}
template <class PtrFieldTuple>
auto field_tuple_to_named_tuple(PtrFieldTuple& _ptr_field_tuple) {
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
return make_named_tuple(_fields...);
};
if constexpr (!has_flatten_fields<std::remove_cvref_t<PtrFieldTuple>>()) {
return rfl::apply(ft_to_nt, std::move(_ptr_field_tuple));
} else {
const auto flattened_tuple = flatten_ptr_field_tuple(_ptr_field_tuple);
return rfl::apply(ft_to_nt, flattened_tuple);
}
}
/// Generates a named tuple that contains pointers to the original values in
/// the struct.
template <class T>
auto to_ptr_named_tuple(T&& _t) {
if constexpr (has_fields<std::remove_cvref_t<T>>()) {
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
return to_ptr_named_tuple(*_t);
} else if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
return nt_to_ptr_named_tuple(_t);
} else {
auto ptr_field_tuple = to_ptr_field_tuple(_t);
return field_tuple_to_named_tuple(ptr_field_tuple);
}
} else if constexpr (is_empty<T>()) {
return rfl::NamedTuple<>();
} else {
using FieldNames = rfl::field_names_t<T>;
auto flattened_ptr_tuple = to_flattened_ptr_tuple(_t);
return copy_flattened_tuple_to_named_tuple<FieldNames>(flattened_ptr_tuple);
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,23 @@
#ifndef RFL_INTERNAL_TO_PTR_TUPLE_HPP_
#define RFL_INTERNAL_TO_PTR_TUPLE_HPP_
#include <type_traits>
#include "bind_to_tuple.hpp"
namespace rfl {
namespace internal {
template <class T>
auto to_ptr_tuple(T& _t) {
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
return to_ptr_tuple(*_t);
} else {
return bind_to_tuple(_t);
}
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,57 @@
#ifndef RFL_INTERNAL_TO_STD_ARRAY_HPP_
#define RFL_INTERNAL_TO_STD_ARRAY_HPP_
#include <array>
#include <cstddef>
#include <type_traits>
namespace rfl::internal {
template <class T>
struct StdArrayType {
using Type = T;
};
template <class T, size_t _n>
struct StdArrayType<T[_n]> {
using Type =
std::array<typename StdArrayType<std::remove_cvref_t<T>>::Type, _n>;
using ValueType = std::remove_cvref_t<T>;
constexpr static size_t size = _n;
};
template <class T>
using to_std_array_t = typename StdArrayType<T>::Type;
template <class T>
auto to_std_array(T&& _t) {
using Type = std::remove_cvref_t<T>;
if constexpr (std::is_array_v<Type>) {
constexpr size_t n = StdArrayType<Type>::size;
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
return to_std_array_t<Type>({to_std_array(
std::forward<typename StdArrayType<Type>::ValueType>(_t[_i]))...});
};
return fct(std::make_index_sequence<n>());
} else {
return std::forward<T>(_t);
}
}
template <class T>
auto to_std_array(const T& _t) {
using Type = std::remove_cvref_t<T>;
if constexpr (std::is_array_v<Type>) {
constexpr size_t n = StdArrayType<Type>::size;
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
return to_std_array_t<Type>({to_std_array(_t[_i])...});
};
return fct(std::make_index_sequence<n>());
} else {
return _t;
}
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,55 @@
#ifndef RFL_INTERNAL_TRANSFORMSNAKECASE_HPP_
#define RFL_INTERNAL_TRANSFORMSNAKECASE_HPP_
#include "StringLiteral.hpp"
namespace rfl::internal {
/// Capitalizes a lower-case character.
template <char c>
consteval char to_upper() {
if constexpr (c >= 'a' && c <= 'z') {
return c + ('A' - 'a');
} else {
return c;
}
}
template <char c>
consteval char to_lower() {
if constexpr (c >= 'A' && c <= 'Z') {
return c - ('A' - 'a');
} else {
return c;
}
}
/// Transforms the field name from snake case to camel case.
template <internal::StringLiteral _name, bool _capitalize, size_t _i = 0,
char... chars>
consteval auto transform_snake_case() {
if constexpr (_i == _name.arr_.size()) {
return StringLiteral<sizeof...(chars) + 1>(chars...);
} else if constexpr (_name.arr_[_i] == '_') {
return transform_snake_case<_name, true, _i + 1, chars...>();
} else if constexpr (_name.arr_[_i] == '\0') {
return transform_snake_case<_name, false, _name.arr_.size(), chars...>();
} else if constexpr (_capitalize) {
return transform_snake_case<_name, false, _i + 1, chars...,
to_upper<_name.arr_[_i]>()>();
} else if constexpr (sizeof...(chars) == 0) {
return transform_snake_case<_name, false, _i + 1,
to_lower<_name.arr_[_i]>()>();
} else {
return transform_snake_case<_name, false, _i + 1, chars...,
_name.arr_[_i]>();
}
}
} // namespace rfl::internal
#endif

View File

@@ -0,0 +1,25 @@
#ifndef RFL_INTERNAL_TUP_TO_PTR_TUPLE_HPP_
#define RFL_INTERNAL_TUP_TO_PTR_TUPLE_HPP_
#include "../Field.hpp"
#include "../Tuple.hpp"
#include "../apply.hpp"
#include "../make_named_tuple.hpp"
namespace rfl {
namespace internal {
/// Generates a named tuple that contains pointers to the original values in
/// the struct from a tuple.
template <class TupleType>
auto tup_to_ptr_tuple(TupleType& _t) {
const auto to_ptr = [](auto&... _fields) {
return rfl::make_tuple(&_fields...);
};
return rfl::apply(to_ptr, _t);
}
} // namespace internal
} // namespace rfl
#endif

View File

@@ -0,0 +1,38 @@
#ifndef RFL_INTERNAL_TUPLE_ACCUMULATE_SIZES_HPP_
#define RFL_INTERNAL_TUPLE_ACCUMULATE_SIZES_HPP_
#include <array>
namespace rfl::internal::tuple {
template <class T>
struct SizeWrapper {};
template <unsigned long _last, unsigned long... _is>
struct Sizes {
static consteval auto to_array() {
return std::array<unsigned long, sizeof...(_is) + 1>({_is..., _last});
}
};
template <class T, unsigned long _last, unsigned long... _is>
consteval auto operator+(const Sizes<_last, _is...>& /*_sizes*/,
const SizeWrapper<T>& /*_w*/) {
if constexpr (_last % alignof(T) == 0) {
constexpr auto last_new = _last + sizeof(T);
return Sizes<last_new, _is..., _last>{};
} else {
constexpr auto last_corrected = _last + alignof(T) - (_last % alignof(T));
constexpr auto last_new = last_corrected + sizeof(T);
return Sizes<last_new, _is..., last_corrected>{};
}
}
template <class... Types>
consteval auto accumulate_sizes() {
return (Sizes<0>{} + ... + SizeWrapper<Types>{}).to_array();
}
} // namespace rfl::internal::tuple
#endif

View File

@@ -0,0 +1,30 @@
#ifndef RFL_INTERNAL_TUPLE_APPLY_HPP_
#define RFL_INTERNAL_TUPLE_APPLY_HPP_
#include <utility>
#include "../../Tuple.hpp"
namespace rfl::internal::tuple {
template <class F, class... Types, int... _is>
auto apply(F&& _f, const rfl::Tuple<Types...>& _tup,
std::integer_sequence<int, _is...>) {
return _f(rfl::get<_is>(_tup)...);
}
template <class F, class... Types, int... _is>
auto apply(F&& _f, rfl::Tuple<Types...>& _tup,
std::integer_sequence<int, _is...>) {
return _f(rfl::get<_is>(_tup)...);
}
template <class F, class... Types, int... _is>
auto apply(F&& _f, rfl::Tuple<Types...>&& _tup,
std::integer_sequence<int, _is...>) {
return _f(std::move(rfl::get<_is>(_tup))...);
}
} // namespace rfl::internal::tuple
#endif

Some files were not shown because too many files have changed in this diff Show More