lots of stuff

This commit is contained in:
Mars 2024-05-31 22:59:00 -04:00
parent e8fb8ec19f
commit 791e237470
Signed by: pupbrained
GPG key ID: 874E22DF2F9DFCB5
224 changed files with 19811 additions and 129 deletions

View file

@ -2,3 +2,4 @@
Language: Cpp
BasedOnStyle: Chromium
SpaceBeforeCpp11BracedList: true
NamespaceIndentation: All

View file

@ -114,6 +114,7 @@
++ (lib.optionals pkgs.hostPlatform.isLinux [playerctl]);
buildInputs = [
boost185
libcpr
tomlplusplus
];

5797
include/ctre.hpp Normal file

File diff suppressed because it is too large Load diff

65
include/rfl.hpp Normal file
View file

@ -0,0 +1,65 @@
#ifndef RFL_RFL_HPP_
#define RFL_RFL_HPP_
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244)
#pragma warning(disable : 4101)
#endif
#include "rfl/AddStructName.hpp"
#include "rfl/AllOf.hpp"
#include "rfl/AnyOf.hpp"
#include "rfl/Attribute.hpp"
#include "rfl/Box.hpp"
#include "rfl/Description.hpp"
#include "rfl/Field.hpp"
#include "rfl/Flatten.hpp"
#include "rfl/Literal.hpp"
#include "rfl/NamedTuple.hpp"
#include "rfl/NoOptionals.hpp"
#include "rfl/OneOf.hpp"
#include "rfl/Pattern.hpp"
#include "rfl/PatternValidator.hpp"
#include "rfl/Processors.hpp"
#include "rfl/Ref.hpp"
#include "rfl/Rename.hpp"
#include "rfl/Size.hpp"
#include "rfl/Skip.hpp"
#include "rfl/SnakeCaseToCamelCase.hpp"
#include "rfl/SnakeCaseToPascalCase.hpp"
#include "rfl/TaggedUnion.hpp"
#include "rfl/Timestamp.hpp"
#include "rfl/Validator.hpp"
#include "rfl/Variant.hpp"
#include "rfl/always_false.hpp"
#include "rfl/as.hpp"
#include "rfl/comparisons.hpp"
#include "rfl/default.hpp"
#include "rfl/define_literal.hpp"
#include "rfl/define_named_tuple.hpp"
#include "rfl/define_tagged_union.hpp"
#include "rfl/define_variant.hpp"
#include "rfl/enums.hpp"
#include "rfl/extract_discriminators.hpp"
#include "rfl/field_type.hpp"
#include "rfl/fields.hpp"
#include "rfl/from_named_tuple.hpp"
#include "rfl/get.hpp"
#include "rfl/make_named_tuple.hpp"
#include "rfl/name_t.hpp"
#include "rfl/named_tuple_t.hpp"
#include "rfl/parsing/CustomParser.hpp"
#include "rfl/patterns.hpp"
#include "rfl/remove_fields.hpp"
#include "rfl/replace.hpp"
#include "rfl/to_named_tuple.hpp"
#include "rfl/to_view.hpp"
#include "rfl/type_name_t.hpp"
#include "rfl/visit.hpp"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif

View file

@ -0,0 +1,32 @@
#ifndef RFL_ADDSTRUCTNAME_HPP_
#define RFL_ADDSTRUCTNAME_HPP_
#include <tuple>
#include "Field.hpp"
#include "Literal.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/get_type_name.hpp"
#include "internal/remove_namespaces.hpp"
#include "make_named_tuple.hpp"
namespace rfl {
template <internal::StringLiteral field_name_>
struct AddStructName {
/// Adds the name of the struct as a new field.
template <class StructType>
static auto process(auto&& _view) {
using LiteralType = Literal<
internal::remove_namespaces<internal::get_type_name<StructType>()>()>;
using FieldType = Field<field_name_, LiteralType>;
const auto add_new_field = [](auto&&... _fields) {
return make_named_tuple(FieldType(LiteralType()), std::move(_fields)...);
};
return std::apply(add_new_field, std::move(_view.fields()));
}
};
} // namespace rfl
#endif

40
include/rfl/AllOf.hpp Normal file
View file

@ -0,0 +1,40 @@
#ifndef RFL_ALLOF_HPP_
#define RFL_ALLOF_HPP_
#include <vector>
#include "Result.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
/// Requires that all of the contraints C and Cs be true.
template <class C, class... Cs>
struct AllOf {
template <class T>
static rfl::Result<T> validate(T _value) noexcept {
return validate_impl<T, C, Cs...>(_value);
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto types = std::vector<ValidationType>(
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
return ValidationType{ValidationType::AllOf{.types_ = types}};
}
private:
template <class T, class Head, class... Tail>
static rfl::Result<T> validate_impl(T _value) noexcept {
if constexpr (sizeof...(Tail) == 0) {
return Head::validate(_value);
} else {
return Head::validate(_value).and_then(validate_impl<T, Tail...>);
}
}
};
} // namespace rfl
#endif

58
include/rfl/AnyOf.hpp Normal file
View file

@ -0,0 +1,58 @@
#ifndef RFL_ANYOF_HPP_
#define RFL_ANYOF_HPP_
#include <string>
#include <utility>
#include <vector>
#include "Result.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
/// Requires that all of the contraints C and Cs be true.
template <class C, class... Cs>
struct AnyOf {
template <class T>
static rfl::Result<T> validate(const T& _value) noexcept {
return validate_impl<T, C, Cs...>(_value, {});
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto types = std::vector<ValidationType>(
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
return ValidationType{ValidationType::AnyOf{.types_ = types}};
}
private:
static Error make_error_message(const std::vector<Error>& _errors) {
std::string msg =
"Expected at least one of the following validations to pass, but none "
"of them did:";
for (size_t i = 0; i < _errors.size(); ++i) {
msg += "\n" + std::to_string(i + 1) + ") " + _errors.at(i).what();
}
return Error(msg);
}
template <class T, class Head, class... Tail>
static rfl::Result<T> validate_impl(const T& _value,
std::vector<Error> _errors) {
const auto handle_err = [&](Error&& _err) {
_errors.push_back(std::forward<Error>(_err));
if constexpr (sizeof...(Tail) == 0) {
return make_error_message(_errors);
} else {
return validate_impl<T, Tail...>(
_value, std::forward<std::vector<Error>>(_errors));
}
};
return Head::validate(_value).or_else(handle_err);
}
};
} // namespace rfl
#endif

136
include/rfl/Attribute.hpp Normal file
View file

@ -0,0 +1,136 @@
#ifndef RFL_ATTRIBUTE_HPP_
#define RFL_ATTRIBUTE_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include "Literal.hpp"
#include "default.hpp"
namespace rfl {
template <class T>
struct Attribute {
using Type = T;
using ReflectionType = T;
Attribute() : value_(Type()) {}
Attribute(const Type& _value) : value_(_value) {}
Attribute(Type&& _value) noexcept : value_(std::move(_value)) {}
Attribute(Attribute<T>&& _attr) noexcept = default;
Attribute(const Attribute<Type>& _attr) = default;
template <class U>
Attribute(const Attribute<U>& _attr) : value_(_attr.get()) {}
template <class U>
Attribute(Attribute<U>&& _attr) : value_(_attr.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Attribute(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Attribute(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Attribute(const Attribute<U>& _attr) : value_(_attr.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>
Attribute(const Default& _default) : value_(Type()) {}
~Attribute() = default;
/// 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& _default) {
value_ = Type();
return *this;
}
/// Assigns the underlying object.
Attribute<T>& operator=(const Attribute<T>& _attr) = default;
/// Assigns the underlying object.
Attribute<T>& operator=(Attribute<T>&& _attr) = default;
/// Assigns the underlying object.
template <class U>
auto& operator=(const Attribute<U>& _attr) {
value_ = _attr.get();
return *this;
}
/// Assigns the underlying object.
template <class U>
auto& operator=(Attribute<U>&& _attr) {
value_ = std::forward<T>(_attr.value_);
return *this;
}
/// We want all parsers other than the XML parser to treat attributes like
/// normal fields, so we just implement the reflection interface.
const 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_; }
/// The underlying value.
Type value_;
};
} // namespace rfl
#endif

125
include/rfl/Box.hpp Normal file
View file

@ -0,0 +1,125 @@
#ifndef RFL_BOX_HPP_
#define RFL_BOX_HPP_
#include <memory>
#include <stdexcept>
#include "Result.hpp"
namespace rfl {
/// The Box class behaves very similarly to the unique_ptr, but unlike the
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
/// tries to access it after calling std::move does something else that is
/// clearly bad practice).
template <class T>
class Box {
public:
/// The only way of creating new boxes is
/// Box<T>::make(...).
template <class... Args>
static Box<T> make(Args&&... _args) {
return Box<T>(std::make_unique<T>(std::forward<Args>(_args)...));
}
/// You can generate them from unique_ptrs as well, in which case it will
/// return an Error, if the unique_ptr is not set.
static Result<Box<T>> make(std::unique_ptr<T>&& _ptr) {
if (!_ptr) {
return Error("std::unique_ptr was a nullptr.");
}
return Box<T>(std::move(_ptr));
}
Box() : ptr_(std::make_unique<T>()) {}
Box(const Box<T>& _other) = delete;
Box(Box<T>&& _other) = default;
template <class U>
Box(Box<U>&& _other) noexcept
: ptr_(std::forward<std::unique_ptr<U>>(_other.ptr())) {}
~Box() = default;
/// Returns a pointer to the underlying object
T* get() const { return ptr_.get(); }
/// Copy assignment operator
Box<T>& operator=(const Box<T>& _other) = delete;
/// Move assignment operator
Box<T>& operator=(Box<T>&& _other) noexcept = default;
/// Move assignment operator
template <class U>
Box<T>& operator=(Box<U>&& _other) noexcept {
ptr_ = std::forward<std::unique_ptr<U>>(_other.ptr());
return *this;
}
/// Returns the underlying object.
T& operator*() { return *ptr_; }
/// Returns the underlying object.
T& operator*() const { return *ptr_; }
/// Returns the underlying object.
T* operator->() { return ptr_.get(); }
/// Returns the underlying object.
T* operator->() const { return ptr_.get(); }
/// Returns the underlying unique_ptr
std::unique_ptr<T>& ptr() { return ptr_; }
/// Returns the underlying unique_ptr
const std::unique_ptr<T>& ptr() const { return ptr_; }
private:
/// Only make is allowed to use this constructor.
explicit Box(std::unique_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
private:
/// The underlying unique_ptr_
std::unique_ptr<T> ptr_;
};
/// Generates a new Ref<T>.
template <class T, class... Args>
auto make_box(Args&&... _args) {
return Box<T>::make(std::forward<Args>(_args)...);
}
template <class T1, class T2>
inline auto operator<=>(const Box<T1>& _b1, const Box<T2>& _b2) {
return _b1.ptr() <=> _b2.ptr();
}
template <class CharT, class Traits, class T>
inline std::basic_ostream<CharT, Traits>& operator<<(
std::basic_ostream<CharT, Traits>& _os, const Box<T>& _b) {
_os << _b.get();
return _os;
}
} // namespace rfl
namespace std {
template <class T>
struct hash<rfl::Box<T>> {
size_t operator()(const rfl::Box<T>& _b) const {
return hash<unique_ptr<T>>()(_b.ptr());
}
};
template <class T>
inline void swap(rfl::Box<T>& _b1, rfl::Box<T>& _b2) {
return swap(_b1.ptr(), _b2.ptr());
}
} // namespace std
#endif

150
include/rfl/Description.hpp Normal file
View file

@ -0,0 +1,150 @@
#ifndef RFL_DESCRIPTION_HPP_
#define RFL_DESCRIPTION_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include "Literal.hpp"
#include "default.hpp"
#include "internal/StringLiteral.hpp"
namespace rfl {
/// Used to add a description to the field - this is only relevant for the JSON
/// schema and will be ignored by the normal serialization routines.
template <internal::StringLiteral _description, class T>
struct Description {
/// The underlying type.
using Type = T;
/// The description of the field.
using Content = rfl::Literal<_description>;
using ReflectionType = Type;
Description() : value_(Type()) {}
Description(const Type& _value) : value_(_value) {}
Description(Type&& _value) noexcept : value_(std::move(_value)) {}
Description(Description<_description, T>&& _field) noexcept = default;
Description(const Description<_description, Type>& _field) = default;
template <class U>
Description(const Description<_description, U>& _field)
: value_(_field.get()) {}
template <class U>
Description(Description<_description, U>&& _field) : value_(_field.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Description(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Description(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Description(const Description<_description, U>& _field)
: value_(_field.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>
Description(const Default& _default) : value_(Type()) {}
~Description() = default;
/// The description of the field, for internal use.
constexpr static const internal::StringLiteral description_ = _description;
/// 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& _default) {
value_ = Type();
return *this;
}
/// Assigns the underlying object.
Description<_description, T>& operator=(
const Description<_description, T>& _field) = default;
/// Assigns the underlying object.
Description<_description, T>& operator=(
Description<_description, T>&& _field) = default;
/// Assigns the underlying object.
template <class U>
auto& operator=(const Description<_description, U>& _field) {
value_ = _field.get();
return *this;
}
/// Assigns the underlying object.
template <class U>
auto& operator=(Description<_description, U>&& _field) {
value_ = std::forward<T>(_field.value_);
return *this;
}
/// Returns the underlying object - necessary for the reflection to work.
const Type& 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_; }
/// The underlying value.
Type value_;
};
} // namespace rfl
#endif

154
include/rfl/Field.hpp Normal file
View file

@ -0,0 +1,154 @@
#ifndef RFL_FIELD_HPP_
#define RFL_FIELD_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include "Literal.hpp"
#include "default.hpp"
#include "internal/Array.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/to_std_array.hpp"
#include "internal/wrap_in_rfl_array_t.hpp"
namespace rfl {
/// Used to define a field in the NamedTuple.
template <internal::StringLiteral _name, class T>
struct Field {
/// The underlying type.
using Type = internal::wrap_in_rfl_array_t<T>;
/// The name of the field.
using Name = rfl::Literal<_name>;
Field(const Type& _value) : value_(_value) {}
Field(Type&& _value) noexcept : value_(std::move(_value)) {}
Field(Field<_name, T>&& _field) noexcept = default;
Field(const Field<_name, T>& _field) = default;
template <class U>
Field(const Field<_name, U>& _field) : value_(_field.get()) {}
template <class U>
Field(Field<_name, U>&& _field) : value_(_field.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Field(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Field(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Field(const Field<_name, U>& _field) : value_(_field.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>
Field(const Default& _default) : value_(Type()) {}
~Field() = default;
/// The name of the field, for internal use.
constexpr static const internal::StringLiteral name_ = _name;
/// Returns the underlying object.
const Type& get() const { return value_; }
/// The name of the field.
constexpr static std::string_view name() { return name_.string_view(); }
/// 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& _default) {
value_ = Type();
return *this;
}
/// Assigns the underlying object.
Field<_name, T>& operator=(const Field<_name, T>& _field) = default;
/// Assigns the underlying object.
Field<_name, T>& operator=(Field<_name, T>&& _field) = default;
/// Assigns the underlying object.
template <class U>
auto& operator=(const Field<_name, U>& _field) {
value_ = _field.get();
return *this;
}
/// Assigns the underlying object.
template <class U>
auto& operator=(Field<_name, U>&& _field) {
value_ = std::forward<T>(_field.value_);
return *this;
}
/// 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_; }
/// The underlying value.
Type value_;
};
template <internal::StringLiteral _name, class T>
inline auto make_field(T&& _value) {
using T0 = std::remove_cvref_t<T>;
if constexpr (std::is_array_v<T0>) {
return Field<_name, T0>(internal::Array<T0>(std::forward<T>(_value)));
} else {
return Field<_name, T0>(std::forward<T>(_value));
}
}
} // namespace rfl
#endif // RFL_FIELD_HPP_

106
include/rfl/Flatten.hpp Normal file
View file

@ -0,0 +1,106 @@
#ifndef RFL_FLATTEN_HPP_
#define RFL_FLATTEN_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
namespace rfl {
/// Used to embed another struct into the generated output.
template <class T>
struct Flatten {
/// The underlying type.
using Type = std::remove_cvref_t<T>;
Flatten(const Type& _value) : value_(_value) {}
Flatten(Type&& _value) noexcept : value_(std::forward<Type>(_value)) {}
Flatten(const Flatten<T>& _f) = default;
Flatten(Flatten<T>&& _f) noexcept = default;
template <class U>
Flatten(const Flatten<U>& _f) : value_(_f.get()) {}
template <class U>
Flatten(Flatten<U>&& _f) : value_(_f.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Flatten(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Flatten(U&& _value) : value_(_value) {}
~Flatten() = 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.
Flatten<T>& operator=(const T& _value) {
value_ = _value;
return *this;
}
/// Assigns the underlying object.
Flatten<T>& operator=(T&& _value) {
value_ = std::forward<Type>(_value);
return *this;
}
/// Assigns the underlying object.
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Flatten<T>& operator=(const U& _value) {
value_ = _value;
return *this;
}
/// Assigns the underlying object.
Flatten<T>& operator=(const Flatten<T>& _f) = default;
/// Assigns the underlying object.
Flatten<T>& operator=(Flatten<T>&& _f) = default;
/// Assigns the underlying object.
template <class U>
Flatten<T>& operator=(const Flatten<U>& _f) {
value_ = _f.get();
return *this;
}
/// Assigns the underlying object.
template <class U>
Flatten<T>& operator=(Flatten<U>&& _f) {
value_ = std::forward<U>(_f);
return *this;
}
/// Assigns the underlying object.
void set(const Type& _value) { value_ = _value; }
/// Assigns the underlying object.
void set(Type&& _value) { value_ = std::forward<Type>(_value); }
/// The underlying value.
Type value_;
};
} // namespace rfl
#endif

374
include/rfl/Literal.hpp Normal file
View file

@ -0,0 +1,374 @@
#ifndef RFL_LITERAL_HPP_
#define RFL_LITERAL_HPP_
#include <cstdint>
#include <functional>
#include <limits>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include "Result.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/VisitTree.hpp"
namespace rfl {
template <internal::StringLiteral _field>
struct LiteralHelper {
constexpr static internal::StringLiteral field_ = _field;
};
template <internal::StringLiteral... fields_>
class Literal {
using FieldsType = std::tuple<LiteralHelper<fields_>...>;
public:
using ValueType =
std::conditional_t<sizeof...(fields_) <=
std::numeric_limits<std::uint8_t>::max(),
std::uint8_t, std::uint16_t>;
/// The number of different fields or different options that the literal
/// can assume.
static constexpr ValueType num_fields_ = sizeof...(fields_);
using ReflectionType = std::string;
/// Constructs a Literal from another literal.
Literal(const Literal<fields_...>& _other) = default;
/// Constructs a Literal from another literal.
Literal(Literal<fields_...>&& _other) noexcept = default;
Literal(const std::string& _str) : value_(find_value(_str).value()) {}
/// A single-field literal is special because it
/// can also have a default constructor.
template <ValueType num_fields = num_fields_,
typename = std::enable_if_t<num_fields <= 1>>
Literal() : value_(0) {}
~Literal() = default;
/// Constructs a new Literal.
template <internal::StringLiteral _name>
static Literal<fields_...> make() {
return Literal(Literal<fields_...>::template value_of<_name>());
}
/// Constructs a new Literal, equivalent to make, for reasons of consistency.
template <internal::StringLiteral _name>
static Literal<fields_...> from_name() {
return Literal<fields_...>::template make<_name>();
}
/// Constructs a new Literal.
template <ValueType _value>
static Literal<fields_...> from_value() {
static_assert(_value < num_fields_,
"Value cannot exceed number of fields.");
return Literal<fields_...>(_value);
}
/// Constructs a new Literal.
static Result<Literal<fields_...>> from_value(ValueType _value) {
if (_value >= num_fields_) {
return Error("Value cannot exceed number of fields.");
}
return Literal<fields_...>(_value);
}
/// Determines whether the literal contains the string.
static bool contains(const std::string& _str) {
bool found = false;
has_value(_str, &found);
return found;
}
/// Determines whether the literal contains the string at compile time.
template <internal::StringLiteral _name>
static constexpr bool contains() {
return find_value_of<_name>() != -1;
}
/// Determines whether the literal contains any of the strings in the other
/// literal at compile time.
template <class OtherLiteralType, int _i = 0>
static constexpr bool contains_any() {
if constexpr (_i == num_fields_) {
return false;
} else {
constexpr auto name = find_name_within_own_fields<_i>();
return OtherLiteralType::template contains<name>() ||
contains_any<OtherLiteralType, _i + 1>();
}
}
/// Determines whether the literal contains all of the strings in the other
/// literal at compile time.
template <class OtherLiteralType, int _i = 0, int _n_found = 0>
static constexpr bool contains_all() {
if constexpr (_i == num_fields_) {
return _n_found == OtherLiteralType::num_fields_;
} else {
constexpr auto name = find_name_within_own_fields<_i>();
if constexpr (OtherLiteralType::template contains<name>()) {
return contains_all<OtherLiteralType, _i + 1, _n_found + 1>();
} else {
return contains_all<OtherLiteralType, _i + 1, _n_found>();
}
}
}
/// Determines whether the literal has duplicate strings at compile time.
/// These is useful for checking collections of strings in other contexts.
static constexpr bool has_duplicates() { return has_duplicate_strings(); }
/// Constructs a Literal from a string. Returns an error if the string
/// cannot be found.
static Result<Literal> from_string(const std::string& _str) {
const auto to_literal = [](const auto& _v) {
return Literal<fields_...>(_v);
};
return find_value(_str).transform(to_literal);
};
/// The name defined by the Literal.
std::string name() const { return find_name(); }
/// Returns all possible values of the literal as a std::vector<std::string>.
static std::vector<std::string> names() { return allowed_strings_vec(); }
/// Helper function to retrieve a name at compile time.
template <int _value>
constexpr static auto name_of() {
constexpr auto name = find_name_within_own_fields<_value>();
return Literal<name>();
}
/// Assigns from another literal.
Literal<fields_...>& operator=(const Literal<fields_...>& _other) = default;
/// Assigns from another literal.
Literal<fields_...>& operator=(Literal<fields_...>&& _other) noexcept =
default;
/// Assigns the literal from a string
Literal<fields_...>& operator=(const std::string& _str) {
value_ = find_value(_str);
return *this;
}
/// <=> for other Literals with the same fields.
auto operator<=>(const Literal<fields_...>& _other) const {
return value() <=> _other.value();
}
/// <=> for other Literals with different fields.
template <internal::StringLiteral... _fields>
inline auto operator<=>(const Literal<_fields...>& _l2) const {
return name() <=> _l2.name();
}
/// <=> for strings.
inline auto operator<=>(const std::string& _str) const {
return name() <=> _str;
}
/// <=> for const char*.
template <internal::StringLiteral... other_fields>
inline auto operator<=>(const char* _str) const {
return name() <=> _str;
}
/// Equality operator.
template <class Other>
bool operator==(const Other& _other) const {
return (*this <=> _other) == 0;
}
/// Alias for .name().
std::string reflection() const { return name(); }
/// Returns the number of fields in the Literal.
static constexpr size_t size() { return num_fields_; }
/// Alias for .name().
std::string str() const { return name(); }
/// Alias for .names().
static std::vector<std::string> strings() { return allowed_strings_vec(); }
/// Returns the value actually contained in the Literal.
ValueType value() const { return value_; }
/// Returns the value of the string literal in the template.
template <internal::StringLiteral _name>
static constexpr ValueType value_of() {
constexpr auto value = find_value_of<_name>();
static_assert(value >= 0, "String not supported.");
return value;
}
private:
/// Only the static methods are allowed to access this.
Literal(const ValueType _value) : value_(_value) {}
/// Returns all of the allowed fields.
static std::string allowed_strings() {
const auto vec = allowed_strings_vec();
std::string str;
for (size_t i = 0; i < vec.size(); ++i) {
const auto head = "'" + vec[i] + "'";
str += i == 0 ? head : (", " + head);
}
return str;
}
/// Returns all of the allowed fields.
template <int _i = 0>
static std::vector<std::string> allowed_strings_vec(
std::vector<std::string> _values = {}) {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
const auto head = FieldType::field_.str();
_values.push_back(head);
if constexpr (_i + 1 < num_fields_) {
return allowed_strings_vec<_i + 1>(std::move(_values));
} else {
return _values;
}
}
/// Whether the Literal contains duplicate strings.
template <int _i = 1>
constexpr static bool has_duplicate_strings() {
if constexpr (_i >= num_fields_) {
return false;
} else {
return is_duplicate<_i>() || has_duplicate_strings<_i + 1>();
}
}
template <int _i, int _j = _i - 1>
constexpr static bool is_duplicate() {
using FieldType1 = typename std::tuple_element<_i, FieldsType>::type;
using FieldType2 = typename std::tuple_element<_j, FieldsType>::type;
if constexpr (FieldType1::field_ == FieldType2::field_) {
return true;
} else if constexpr (_j > 0) {
return is_duplicate<_i, _j - 1>();
} else {
return false;
}
}
/// Finds the correct index associated with
/// the string at run time.
template <int _i = 0>
std::string find_name() const {
if (_i == value_) {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
return FieldType::field_.str();
}
if constexpr (_i + 1 == num_fields_) {
return "";
} else {
return find_name<_i + 1>();
}
}
/// Finds the correct index associated with
/// the string at compile time within the Literal's own fields.
template <int _i>
constexpr static auto find_name_within_own_fields() {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
return FieldType::field_;
}
/// Finds the correct value associated with
/// the string at run time.
template <int _i = 0>
static Result<int> find_value(const std::string& _str) {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
if (FieldType::field_.str() == _str) {
return _i;
}
if constexpr (_i + 1 == num_fields_) {
return Error(
"Literal does not support string '" + _str +
"'. The following strings are supported: " + allowed_strings() + ".");
} else {
return find_value<_i + 1>(_str);
}
}
/// Finds the value of a string literal at compile time.
template <internal::StringLiteral _name, int _i = 0>
static constexpr int find_value_of() {
if constexpr (_i == num_fields_) {
return -1;
} else {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
if constexpr (FieldType::field_ == _name) {
return _i;
} else {
return find_value_of<_name, _i + 1>();
}
}
}
/// Whether the literal contains this string.
template <int _i = 0>
static void has_value(const std::string& _str, bool* _found) {
if constexpr (_i == num_fields_) {
*_found = false;
return;
} else {
using FieldType = typename std::tuple_element<_i, FieldsType>::type;
if (FieldType::field_.str() == _str) {
*_found = true;
return;
}
return has_value<_i + 1>(_str, _found);
}
}
static_assert(sizeof...(fields_) <= std::numeric_limits<ValueType>::max(),
"Too many fields.");
static_assert(sizeof...(fields_) <= 1 || !has_duplicates(),
"Duplicate strings are not allowed in a Literal.");
private:
/// The underlying value.
ValueType value_;
};
/// Helper function to retrieve a name at compile time.
template <class LiteralType, int _value>
inline constexpr auto name_of() {
return LiteralType::template name_of<_value>();
}
/// Helper function to retrieve a value at compile time.
template <class LiteralType, internal::StringLiteral _name>
inline constexpr auto value_of() {
return LiteralType::template value_of<_name>();
}
} // namespace rfl
namespace std {
template <rfl::internal::StringLiteral... fields>
struct hash<rfl::Literal<fields...>> {
size_t operator()(const rfl::Literal<fields...>& _l) const {
return hash<int>()(static_cast<int>(_l.value()));
}
};
} // namespace std
#endif // RFL_LITERAL_HPP_

32
include/rfl/MetaField.hpp Normal file
View file

@ -0,0 +1,32 @@
#ifndef RFL_METAFIELD_HPP_
#define RFL_METAFIELD_HPP_
#include <string>
namespace rfl {
/// Contains meta-information about a field in a struct.
class MetaField {
public:
MetaField(const std::string& _name, const std::string& _type)
: name_(_name), type_(_type) {}
~MetaField() = default;
/// The name of the field we describe.
const std::string& name() const { return name_; };
/// The type of the field we describe.
const std::string& type() const { return type_; };
private:
/// The name of the field we describe.
std::string name_;
/// The type of the field we describe.
std::string type_;
};
} // namespace rfl
#endif // RFL_TAGGEDUNION_HPP_

683
include/rfl/NamedTuple.hpp Normal file
View file

@ -0,0 +1,683 @@
#ifndef RFL_NAMEDTUPLE_HPP_
#define RFL_NAMEDTUPLE_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include "Field.hpp"
#include "Literal.hpp"
#include "get.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/find_index.hpp"
#include "internal/no_duplicate_field_names.hpp"
namespace rfl {
/// A named tuple behaves like std::tuple,
/// but the fields have explicit names, which
/// allows for reflection.
/// IMPORTANT: We have two template specializations. One with fields, one
/// without fields.
template <class... FieldTypes>
class NamedTuple;
// ----------------------------------------------------------------------------
template <class... FieldTypes>
class NamedTuple {
public:
using Fields = std::tuple<std::remove_cvref_t<FieldTypes>...>;
using Names = Literal<std::remove_cvref_t<FieldTypes>::name_...>;
using Values = std::tuple<typename std::remove_cvref_t<FieldTypes>::Type...>;
public:
/// Construct from the values.
NamedTuple(typename std::remove_cvref<FieldTypes>::type::Type&&... _values)
: values_(
std::forward<typename std::remove_cvref<FieldTypes>::type::Type>(
_values)...) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Construct from the values.
NamedTuple(
const typename std::remove_cvref<FieldTypes>::type::Type&... _values)
: values_(std::make_tuple(_values...)) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Construct from the fields.
NamedTuple(FieldTypes&&... _fields)
: values_(std::make_tuple(std::move(_fields.value_)...)) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Construct from the fields.
NamedTuple(const FieldTypes&... _fields)
: values_(std::make_tuple(_fields.value_...)) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Construct from a tuple containing fields.
NamedTuple(std::tuple<FieldTypes...>&& _tup)
: NamedTuple(std::make_from_tuple<NamedTuple<FieldTypes...>>(
std::forward<std::tuple<FieldTypes...>>(_tup))) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Construct from a tuple containing fields.
NamedTuple(const std::tuple<FieldTypes...>& _tup)
: NamedTuple(std::make_from_tuple<NamedTuple<FieldTypes...>>(_tup)) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Copy constructor.
NamedTuple(const NamedTuple<FieldTypes...>& _other) = default;
/// Move constructor.
NamedTuple(NamedTuple<FieldTypes...>&& _other) = default;
/// Copy constructor.
template <class... OtherFieldTypes>
NamedTuple(const NamedTuple<OtherFieldTypes...>& _other)
: NamedTuple(retrieve_fields(_other.fields())) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
/// Move constructor.
template <class... OtherFieldTypes>
NamedTuple(NamedTuple<OtherFieldTypes...>&& _other)
: NamedTuple(retrieve_fields(_other.fields())) {
static_assert(no_duplicate_field_names(),
"Duplicate field names are not allowed");
}
~NamedTuple() = default;
/// Returns a new named tuple with additional fields.
template <internal::StringLiteral _name, class FType, class... Tail>
auto add(Field<_name, FType>&& _head, Tail&&... _tail) {
using Head = Field<_name, FType>;
if constexpr (sizeof...(Tail) > 0) {
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
make_fields<1, Head>(std::forward<Head>(_head)))
.add(std::forward<Tail>(_tail)...);
} else {
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
make_fields<1, Head>(std::forward<Head>(_head)));
}
}
/// Returns a new named tuple with additional fields.
template <internal::StringLiteral _name, class FType, class... Tail>
auto add(Field<_name, FType> _head, const Tail&... _tail) const {
using Head = Field<_name, FType>;
if constexpr (sizeof...(Tail) > 0) {
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
make_fields<1, Head>(_head))
.add(_tail...);
} else {
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
make_fields<1, Head>(_head));
}
}
/// Template specialization for std::tuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(std::tuple<TupContent...>&& _tuple, Tail&&... _tail) {
if constexpr (sizeof...(Tail) > 0) {
return add_tuple(std::forward<std::tuple<TupContent...>>(_tuple))
.add(std::forward<Tail>(_tail)...);
} else {
return add_tuple(std::forward<std::tuple<TupContent...>>(_tuple));
}
}
/// Template specialization for std::tuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(std::tuple<TupContent...> _tuple, const Tail&... _tail) const {
if constexpr (sizeof...(Tail) > 0) {
return add_tuple(std::move(_tuple)).add(_tail...);
} else {
return add_tuple(std::move(_tuple));
}
}
/// Template specialization for NamedTuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(NamedTuple<TupContent...>&& _named_tuple, Tail&&... _tail) {
return add(std::forward<std::tuple<TupContent...>>(_named_tuple.fields()),
std::forward<Tail>(_tail)...);
}
/// Template specialization for NamedTuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(NamedTuple<TupContent...> _named_tuple, const Tail&... _tail) const {
return add(_named_tuple.fields(), _tail...);
}
/// Creates a new named tuple by applying the supplied function to
/// field. The function is expected to return a named tuple itself.
template <typename F>
auto and_then(const F& _f) {
const auto transform_field = [&_f](auto... _fields) {
return std::tuple_cat(_f(std::move(_fields)).fields()...);
};
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
return NamedTuple<NewFields...>(_tup);
};
auto new_fields = std::apply(transform_field, std::move(fields()));
return to_nt(std::move(new_fields));
}
/// Creates a new named tuple by applying the supplied function to
/// field. The function is expected to return a named tuple itself.
template <typename F>
auto and_then(const F& _f) const {
const auto transform_field = [&_f](auto... _fields) {
return std::tuple_cat(_f(std::move(_fields)).fields()...);
};
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
return NamedTuple<NewFields...>(_tup);
};
auto new_fields = std::apply(transform_field, std::move(fields()));
return to_nt(std::move(new_fields));
}
/// Invokes a callable object once for each field in order.
template <typename F>
void apply(F&& _f) {
const auto apply_to_field =
[&_f]<typename... AFields>(AFields&&... fields) {
((_f(std::forward<AFields>(fields))), ...);
};
std::apply(apply_to_field, fields());
}
/// Invokes a callable object once for each field in order.
template <typename F>
void apply(F&& _f) const {
const auto apply_to_field = [&_f](const auto&... fields) {
((_f(fields)), ...);
};
std::apply(apply_to_field, fields());
}
/// Returns a tuple containing the fields.
Fields fields() { return make_fields(); }
/// Returns a tuple containing the fields.
Fields fields() const { return make_fields(); }
/// Gets a field by index.
template <int _index>
auto& get() {
return rfl::get<_index>(*this);
}
/// Gets a field by name.
template <internal::StringLiteral _field_name>
auto& get() {
return rfl::get<_field_name>(*this);
}
/// Gets a field by the field type.
template <class Field>
auto& get() {
return rfl::get<Field>(*this);
}
/// Gets a field by index.
template <int _index>
const auto& get() const {
return rfl::get<_index>(*this);
}
/// Gets a field by name.
template <internal::StringLiteral _field_name>
const auto& get() const {
return rfl::get<_field_name>(*this);
}
/// Gets a field by the field type.
template <class Field>
const auto& get() const {
return rfl::get<Field>(*this);
}
/// Returns the results wrapped in a field.
template <internal::StringLiteral _field_name>
auto get_field() const {
return rfl::make_field<_field_name>(rfl::get<_field_name>(*this));
}
/// Copy assignment operator.
NamedTuple<FieldTypes...>& operator=(
const NamedTuple<FieldTypes...>& _other) = default;
/// Move assignment operator.
NamedTuple<FieldTypes...>& operator=(
NamedTuple<FieldTypes...>&& _other) noexcept = default;
/// Equality operator
inline auto operator==(const rfl::NamedTuple<FieldTypes...>& _other) const {
return values() == _other.values();
}
/// Inequality operator
inline auto operator!=(const rfl::NamedTuple<FieldTypes...>& _other) const {
return !(*this == _other);
}
/// Replaces one or several fields, returning a new version
/// with the non-replaced fields left unchanged.
template <internal::StringLiteral _name, class FType, class... OtherRFields>
auto replace(Field<_name, FType>&& _field, OtherRFields&&... _other_fields) {
using RField = Field<_name, FType>;
constexpr auto num_other_fields = sizeof...(OtherRFields);
if constexpr (num_other_fields == 0) {
return replace_value<RField>(_field.value_);
} else {
return replace_value<RField>(_field.value_)
.replace(std::forward<OtherRFields>(_other_fields)...);
}
}
/// Replaces one or several fields, returning a new version
/// with the non-replaced fields left unchanged.
template <internal::StringLiteral _name, class FType, class... OtherRFields>
auto replace(Field<_name, FType> _field,
const OtherRFields&... _other_fields) const {
using RField = Field<_name, FType>;
constexpr auto num_other_fields = sizeof...(OtherRFields);
if constexpr (num_other_fields == 0) {
return replace_value<RField>(std::move(_field.value_));
} else {
return replace_value<RField>(std::move(_field.value_))
.replace(_other_fields...);
}
}
/// Template specialization for std::tuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto replace(std::tuple<TupContent...>&& _tuple, Tail&&... _tail) {
if constexpr (sizeof...(Tail) > 0) {
return replace_tuple(std::forward<std::tuple<TupContent...>>(_tuple))
.replace(std::forward<Tail>(_tail)...);
} else {
return replace_tuple(std::forward<std::tuple<TupContent...>>(_tuple));
}
}
/// Template specialization for std::tuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto replace(std::tuple<TupContent...> _tuple, const Tail&... _tail) const {
if constexpr (sizeof...(Tail) > 0) {
return replace_tuple(std::move(_tuple)).replace(_tail...);
} else {
return replace_tuple(std::move(_tuple));
}
}
/// Template specialization for NamedTuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto replace(NamedTuple<TupContent...>&& _named_tuple, Tail&&... _tail) {
return replace(
std::forward<NamedTuple<TupContent...>>(_named_tuple).fields(),
std::forward<Tail>(_tail)...);
}
/// Template specialization for NamedTuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto replace(NamedTuple<TupContent...> _named_tuple,
const Tail&... _tail) const {
return replace(_named_tuple.fields(), _tail...);
}
/// Returns the size of the named tuple
static constexpr size_t size() { return std::tuple_size_v<Values>; }
/// Creates a new named tuple by applying the supplied function to every
/// field.
template <typename F>
auto transform(const F& _f) {
const auto transform_field = [&_f](auto... fields) {
return std::make_tuple(_f(std::move(fields))...);
};
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
return NamedTuple<NewFields...>(_tup);
};
auto new_fields = std::apply(transform_field, std::move(fields()));
return to_nt(std::move(new_fields));
}
/// Creates a new named tuple by applying the supplied function to every
/// field.
template <typename F>
auto transform(const F& _f) const {
const auto transform_field = [&_f](auto... fields) {
return std::make_tuple(_f(std::move(fields))...);
};
const auto to_nt = []<class... NewFields>(std::tuple<NewFields...>&& _tup) {
return NamedTuple<NewFields...>(_tup);
};
auto new_fields = std::apply(transform_field, std::move(fields()));
return to_nt(std::move(new_fields));
}
/// Returns the underlying std::tuple.
Values& values() { return values_; }
/// Returns the underlying std::tuple.
const Values& values() const { return values_; }
private:
/// Adds the elements of a tuple to a newly created named tuple,
/// and other elements to a newly created named tuple.
template <class... TupContent>
constexpr auto add_tuple(std::tuple<TupContent...>&& _tuple) {
const auto a = [this](auto&&... _fields) {
return this->add(std::forward<TupContent>(_fields)...);
};
return std::apply(a, std::forward<std::tuple<TupContent...>>(_tuple));
}
/// Adds the elements of a tuple to a newly created named tuple,
/// and other elements to a newly created named tuple.
template <class... TupContent>
constexpr auto add_tuple(std::tuple<TupContent...>&& _tuple) const {
const auto a = [this](auto&&... _fields) {
return this->add(std::forward<TupContent>(_fields)...);
};
return std::apply(a, std::forward<std::tuple<TupContent...>>(_tuple));
}
/// Generates the fields.
template <int num_additional_fields = 0, class... Args>
auto make_fields(Args&&... _args) {
constexpr auto size = sizeof...(Args) - num_additional_fields;
constexpr auto num_fields = std::tuple_size_v<Fields>;
constexpr auto i = num_fields - size - 1;
constexpr bool retrieved_all_fields = size == num_fields;
if constexpr (retrieved_all_fields) {
return std::make_tuple(std::forward<Args>(_args)...);
} else {
// When we add additional fields, it is more intuitive to add
// them to the end, that is why we do it like this.
using FieldType = typename std::tuple_element<i, Fields>::type;
using T = std::remove_cvref_t<typename FieldType::Type>;
return make_fields<num_additional_fields>(
FieldType(std::forward<T>(std::get<i>(values_))),
std::forward<Args>(_args)...);
}
}
/// Generates the fields.
template <int num_additional_fields = 0, class... Args>
auto make_fields(Args... _args) const {
constexpr auto size = sizeof...(Args) - num_additional_fields;
constexpr auto num_fields = std::tuple_size_v<Fields>;
constexpr auto i = num_fields - size - 1;
constexpr bool retrieved_all_fields = size == num_fields;
if constexpr (retrieved_all_fields) {
return std::make_tuple(std::move(_args)...);
} else {
// When we add additional fields, it is more intuitive to add
// them to the end, that is why we do it like this.
using FieldType = typename std::tuple_element<i, Fields>::type;
return make_fields<num_additional_fields>(FieldType(std::get<i>(values_)),
std::move(_args)...);
}
}
/// Generates a new named tuple with one value replaced with a new value.
template <int _index, class V, class T, class... Args>
auto make_replaced(V&& _values, T&& _val, Args&&... _args) const {
constexpr auto size = sizeof...(Args);
constexpr bool retrieved_all_fields = size == std::tuple_size_v<Fields>;
if constexpr (retrieved_all_fields) {
return NamedTuple<FieldTypes...>(std::forward<Args>(_args)...);
} else {
using FieldType = typename std::tuple_element<size, Fields>::type;
if constexpr (size == _index) {
return make_replaced<_index, V, T>(
std::forward<V>(_values), std::forward<T>(_val),
std::forward<Args>(_args)..., FieldType(std::forward<T>(_val)));
} else {
using U = typename FieldType::Type;
return make_replaced<_index, V, T>(
std::forward<V>(_values), std::forward<T>(_val),
std::forward<Args>(_args)...,
FieldType(std::forward<U>(std::get<size>(_values))));
}
}
}
/// We cannot allow duplicate field names.
constexpr static bool no_duplicate_field_names() {
return internal::no_duplicate_field_names<Fields>();
}
/// Replaced the field signified by the field type.
template <class Field, class T>
NamedTuple<FieldTypes...> replace_value(T&& _val) {
using FieldType = std::remove_cvref_t<Field>;
constexpr auto index = internal::find_index<FieldType::name_, Fields>();
return make_replaced<index, Values, T>(std::forward<Values>(values_),
std::forward<T>(_val));
}
/// Replaced the field signified by the field type.
template <class Field, class T>
NamedTuple<FieldTypes...> replace_value(T&& _val) const {
using FieldType = std::remove_cvref_t<Field>;
constexpr auto index = internal::find_index<FieldType::name_, Fields>();
auto values = values_;
return make_replaced<index, Values, T>(std::move(values),
std::forward<T>(_val));
}
/// Adds the elements of a tuple to a newly created named tuple,
/// and other elements to a newly created named tuple.
template <class... TupContent>
auto replace_tuple(std::tuple<TupContent...>&& _tuple) {
const auto r = [this](auto&&... _fields) {
return this->replace(std::forward<TupContent>(_fields)...);
};
return std::apply(r, std::forward<std::tuple<TupContent...>>(_tuple));
}
/// Adds the elements of a tuple to a newly created named tuple,
/// and other elements to a newly created named tuple.
template <class... TupContent>
auto replace_tuple(std::tuple<TupContent...>&& _tuple) const {
const auto r = [this](auto&&... _fields) {
return this->replace(std::forward<TupContent>(_fields)...);
};
return std::apply(r, std::forward<std::tuple<TupContent...>>(_tuple));
}
/// Retrieves the fields from another tuple.
template <class... OtherFieldTypes, class... Args>
constexpr static Fields retrieve_fields(
std::tuple<OtherFieldTypes...>&& _other_fields, Args&&... _args) {
constexpr auto size = sizeof...(Args);
constexpr bool retrieved_all_fields = size == std::tuple_size_v<Fields>;
if constexpr (retrieved_all_fields) {
return std::make_tuple(std::forward<Args>(_args)...);
} else {
constexpr auto field_name = std::tuple_element<size, Fields>::type::name_;
constexpr auto index =
internal::find_index<field_name, std::tuple<OtherFieldTypes...>>();
using FieldType = typename std::tuple_element<size, Fields>::type;
using T = std::remove_cvref_t<typename FieldType::Type>;
return retrieve_fields(
std::forward<std::tuple<OtherFieldTypes...>>(_other_fields),
std::forward<Args>(_args)...,
FieldType(std::forward<T>(std::get<index>(_other_fields).value_)));
}
}
private:
/// The values actually contained in the named tuple.
/// As you can see, a NamedTuple is just a normal tuple under-the-hood,
/// everything else is resolved at compile time. It should have no
/// runtime overhead over a normal std::tuple.
Values values_;
};
// ----------------------------------------------------------------------------
/// We need a special template instantiation for empty named tuples.
template <>
class NamedTuple<> {
public:
using Fields = std::tuple<>;
using Names = Literal<>;
using Values = std::tuple<>;
NamedTuple(){};
~NamedTuple() = default;
/// Returns a new named tuple with additional fields.
template <internal::StringLiteral _name, class FType, class... Tail>
auto add(Field<_name, FType> _head, const Tail&... _tail) const {
if constexpr (sizeof...(Tail) > 0) {
return NamedTuple<Field<_name, FType>>(std::move(_head)).add(_tail...);
} else {
return NamedTuple<Field<_name, FType>>(std::move(_head));
}
}
/// Template specialization for std::tuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(std::tuple<TupContent...> _tuple, const Tail&... _tail) const {
if constexpr (sizeof...(Tail) > 0) {
return NamedTuple<TupContent...>(std::move(_tuple)).add(_tail...);
} else {
return NamedTuple<TupContent...>(std::move(_tuple));
}
}
/// Template specialization for NamedTuple, so we can pass fields from other
/// named tuples.
template <class... TupContent, class... Tail>
auto add(NamedTuple<TupContent...> _named_tuple, const Tail&... _tail) const {
return add(_named_tuple.fields(), _tail...);
}
/// Returns an empty named tuple.
template <typename F>
auto and_then(const F& _f) const {
return NamedTuple<>();
}
/// Does nothing at all.
template <typename F>
void apply(F&& _f) const {}
/// Returns an empty tuple.
auto fields() const { return std::tuple(); }
/// Must always be 0.
static constexpr size_t size() { return 0; }
/// Returns an empty named tuple.
template <typename F>
auto transform(const F& _f) const {
return NamedTuple<>();
}
/// Returns an empty tuple.
auto values() const { return std::tuple(); }
};
// ----------------------------------------------------------------------------
template <internal::StringLiteral _name1, class Type1,
internal::StringLiteral _name2, class Type2>
inline auto operator*(const rfl::Field<_name1, Type1>& _f1,
const rfl::Field<_name2, Type2>& _f2) {
return NamedTuple(_f1, _f2);
}
template <internal::StringLiteral _name, class Type, class... FieldTypes>
inline auto operator*(const NamedTuple<FieldTypes...>& _tup,
const rfl::Field<_name, Type>& _f) {
return _tup.add(_f);
}
template <internal::StringLiteral _name, class Type, class... FieldTypes>
inline auto operator*(const rfl::Field<_name, Type>& _f,
const NamedTuple<FieldTypes...>& _tup) {
return NamedTuple(_f).add(_tup);
}
template <class... FieldTypes1, class... FieldTypes2>
inline auto operator*(const NamedTuple<FieldTypes1...>& _tup1,
const NamedTuple<FieldTypes2...>& _tup2) {
return _tup1.add(_tup2);
}
template <internal::StringLiteral _name1, class Type1,
internal::StringLiteral _name2, class Type2>
inline auto operator*(rfl::Field<_name1, Type1>&& _f1,
rfl::Field<_name2, Type2>&& _f2) {
return NamedTuple(std::forward<Field<_name1, Type1>>(_f1),
std::forward<Field<_name2, Type2>>(_f2));
}
template <internal::StringLiteral _name, class Type, class... FieldTypes>
inline auto operator*(NamedTuple<FieldTypes...>&& _tup,
rfl::Field<_name, Type>&& _f) {
return _tup.add(std::forward<Field<_name, Type>>(_f));
}
template <internal::StringLiteral _name, class Type, class... FieldTypes>
inline auto operator*(rfl::Field<_name, Type>&& _f,
NamedTuple<FieldTypes...>&& _tup) {
return NamedTuple(std::forward<Field<_name, Type>>(_f))
.add(std::forward<NamedTuple<FieldTypes...>>(_tup));
}
template <class... FieldTypes1, class... FieldTypes2>
inline auto operator*(NamedTuple<FieldTypes1...>&& _tup1,
NamedTuple<FieldTypes2...>&& _tup2) {
return _tup1.add(std::forward<NamedTuple<FieldTypes2...>>(_tup2));
}
} // namespace rfl
#endif // RFL_NAMEDTUPLE_HPP_

View file

@ -0,0 +1,18 @@
#ifndef RFL_NOOPTIONALS_HPP_
#define RFL_NOOPTIONALS_HPP_
namespace rfl {
/// This is a "fake" processor - it doesn't do much in itself, but its
/// inclusion instructs the parsers to require the inclusion of all fields.
struct NoOptionals {
public:
template <class StructType>
static auto process(auto&& _named_tuple) {
return _named_tuple;
}
};
} // namespace rfl
#endif

72
include/rfl/OneOf.hpp Normal file
View file

@ -0,0 +1,72 @@
#ifndef RFL_ONEOF_HPP_
#define RFL_ONEOF_HPP_
#include <string>
#include <utility>
#include <vector>
#include "Result.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
/// Requires that all of the contraints C and Cs be true.
template <class C, class... Cs>
struct OneOf {
template <class T>
static rfl::Result<T> validate(const T& _value) noexcept {
return validate_impl<T, C, Cs...>(_value, {});
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto types = std::vector<ValidationType>(
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
return ValidationType{ValidationType::OneOf{.types_ = types}};
}
private:
static Error make_error_message(const std::vector<Error>& _errors) {
std::string msg = "Expected exactly 1 out of " +
std::to_string(sizeof...(Cs) + 1) +
" validations to pass, but " +
std::to_string(sizeof...(Cs) + 1 - _errors.size()) +
" of them did. The following errors were generated: ";
for (size_t i = 0; i < _errors.size(); ++i) {
msg += "\n" + std::to_string(i + 1) + ") " + _errors.at(i).what();
}
return Error(msg);
}
template <class T, class Head, class... Tail>
static rfl::Result<T> validate_impl(const T& _value,
std::vector<Error> _errors) {
const auto push_back = [&](Error&& _err) -> rfl::Result<T> {
_errors.emplace_back(std::forward<Error>(_err));
return _err;
};
const auto next_validation = [&](rfl::Result<T>&& _r) -> rfl::Result<T> {
_r.or_else(push_back);
if constexpr (sizeof...(Tail) == 0) {
if (_errors.size() == sizeof...(Cs)) {
return _value;
}
return make_error_message(_errors);
} else {
return validate_impl<T, Tail...>(
_value, std::forward<std::vector<Error>>(_errors));
}
};
return Head::validate(_value)
.and_then(next_validation)
.or_else(next_validation);
}
};
} // namespace rfl
#endif

14
include/rfl/Pattern.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef RFL_PATTERN_HPP_
#define RFL_PATTERN_HPP_
#include "PatternValidator.hpp"
#include "Validator.hpp"
namespace rfl {
template <internal::StringLiteral _regex, internal::StringLiteral _name>
using Pattern = Validator<std::string, PatternValidator<_regex, _name>>;
} // namespace rfl
#endif

View file

@ -0,0 +1,37 @@
#ifndef RFL_PATTERNVALIDATOR_HPP_
#define RFL_PATTERNVALIDATOR_HPP_
#include <string>
#include "../ctre.hpp"
#include "Literal.hpp"
#include "Result.hpp"
#include "internal/StringLiteral.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
template <internal::StringLiteral _regex, internal::StringLiteral _name>
struct PatternValidator {
using Name = Literal<_name>;
using Regex = Literal<_regex>;
static Result<std::string> validate(const std::string& _str) noexcept {
if (ctre::match<_regex.arr_>(_str)) {
return _str;
} else {
return rfl::Error("String '" + _str + "' did not match format '" +
_name.str() + "': '" + _regex.str() + "'.");
}
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
return ValidationType{ValidationType::Regex{.pattern_ = Regex().str()}};
}
};
} // namespace rfl
#endif

View file

@ -0,0 +1,38 @@
#ifndef RFL_INTERNAL_PROCESSORS_HPP_
#define RFL_INTERNAL_PROCESSORS_HPP_
#include <type_traits>
#include "internal/is_no_optionals_v.hpp"
namespace rfl {
template <class... Ps>
struct Processors;
template <>
struct Processors<> {
static constexpr bool all_required_ = false;
template <class T, class NamedTupleType>
static auto process(NamedTupleType&& _named_tuple) {
return _named_tuple;
}
};
template <class Head, class... Tail>
struct Processors<Head, Tail...> {
static constexpr bool all_required_ =
std::disjunction_v<internal::is_no_optionals<Head>,
internal::is_no_optionals<Tail>...>;
template <class T, class NamedTupleType>
static auto process(NamedTupleType&& _named_tuple) {
return Processors<Tail...>::template process<T>(
Head::template process<T>(std::move(_named_tuple)));
}
};
} // namespace rfl
#endif

148
include/rfl/Ref.hpp Normal file
View file

@ -0,0 +1,148 @@
#ifndef RFL_REF_HPP_
#define RFL_REF_HPP_
#include <memory>
#include <stdexcept>
#include "Result.hpp"
namespace rfl {
/// The Ref class behaves very similarly to the shared_ptr, but unlike the
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
/// tries to access it after calling std::move does something else that is
/// clearly bad practice).
template <class T>
class Ref {
public:
/// The default way of creating new references is
/// Ref<T>::make(...) or make_ref<T>(...).
template <class... Args>
static Ref<T> make(Args&&... _args) {
return Ref<T>(std::make_shared<T>(std::forward<Args>(_args)...));
}
/// You can generate them from shared_ptrs as well, in which case it will
/// return an Error, if the shared_ptr is not set.
static Result<Ref<T>> make(std::shared_ptr<T>&& _ptr) {
if (!_ptr) {
return Error("std::shared_ptr was a nullptr.");
}
return Ref<T>(std::move(_ptr));
}
/// You can generate them from shared_ptrs as well, in which case it will
/// return an Error, if the shared_ptr is not set.
static Result<Ref<T>> make(const std::shared_ptr<T>& _ptr) {
if (!_ptr) {
return Error("std::shared_ptr was a nullptr.");
}
return Ref<T>(_ptr);
}
Ref() : ptr_(std::make_shared<T>()) {}
Ref(const Ref<T>& _other) = default;
Ref(Ref<T>&& _other) = default;
template <class U>
Ref(const Ref<U>& _other) : ptr_(_other.ptr()) {}
template <class U>
Ref(Ref<U>&& _other) noexcept
: ptr_(std::forward<std::shared_ptr<U>>(_other.ptr())) {}
~Ref() = default;
/// Returns a pointer to the underlying object
T* get() const { return ptr_.get(); }
/// Returns the underlying object.
T& operator*() { return *ptr_; }
/// Returns the underlying object.
T& operator*() const { return *ptr_; }
/// Returns the underlying object.
T* operator->() { return ptr_.get(); }
/// Returns the underlying object.
T* operator->() const { return ptr_.get(); }
/// Returns the underlying shared_ptr
std::shared_ptr<T>& ptr() { return ptr_; }
/// Returns the underlying shared_ptr
const std::shared_ptr<T>& ptr() const { return ptr_; }
/// Copy assignment operator.
template <class U>
Ref<T>& operator=(const Ref<U>& _other) {
ptr_ = _other.ptr();
return *this;
}
/// Move assignment operator
template <class U>
Ref<T>& operator=(Ref<U>&& _other) noexcept {
ptr_ = std::forward<std::shared_ptr<U>>(_other.ptr());
return *this;
}
/// Move assignment operator
Ref<T>& operator=(Ref<T>&& _other) noexcept = default;
/// Copy assignment operator
Ref<T>& operator=(const Ref<T>& _other) = default;
private:
/// Only make is allowed to use this constructor.
explicit Ref(std::shared_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
/// Only make is allowed to use this constructor.
explicit Ref(const std::shared_ptr<T>& _ptr) : ptr_(_ptr) {}
private:
/// The underlying shared_ptr_
std::shared_ptr<T> ptr_;
};
/// Generates a new Ref<T>.
template <class T, class... Args>
auto make_ref(Args&&... _args) {
return Ref<T>::make(std::forward<Args>(_args)...);
}
template <class T1, class T2>
inline auto operator<=>(const Ref<T1>& _t1, const Ref<T2>& _t2) {
return _t1.ptr() <=> _t2.ptr();
}
template <class CharT, class Traits, class T>
inline std::basic_ostream<CharT, Traits>& operator<<(
std::basic_ostream<CharT, Traits>& _os, const Ref<T>& _b) {
_os << _b.get();
return _os;
}
} // namespace rfl
namespace std {
template <class T>
struct hash<rfl::Ref<T>> {
size_t operator()(const rfl::Ref<T>& _r) const {
return hash<shared_ptr<T>>()(_r.ptr());
}
};
template <class T>
inline void swap(rfl::Ref<T>& _r1, rfl::Ref<T>& _r2) {
return swap(_r1.ptr(), _r2.ptr());
}
} // namespace std
#endif // RFL_REF_HPP_

141
include/rfl/Rename.hpp Normal file
View file

@ -0,0 +1,141 @@
#ifndef RFL_RENAME_HPP_
#define RFL_RENAME_HPP_
#include <algorithm>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include "Literal.hpp"
#include "default.hpp"
#include "internal/StringLiteral.hpp"
namespace rfl {
/// Used to assign a new name to a field, which is different from the name
/// inside the struct.
template <internal::StringLiteral _name, class T>
struct Rename {
/// The underlying type.
using Type = T;
/// The name of the field.
using Name = rfl::Literal<_name>;
Rename() : value_(Type()) {}
Rename(const Type& _value) : value_(_value) {}
Rename(Type&& _value) noexcept : value_(std::move(_value)) {}
Rename(Rename<_name, T>&& _field) noexcept = default;
Rename(const Rename<_name, Type>& _field) = default;
template <class U>
Rename(const Rename<_name, U>& _field) : value_(_field.get()) {}
template <class U>
Rename(Rename<_name, U>&& _field) : value_(_field.get()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Rename(const U& _value) : value_(_value) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Rename(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
bool>::type = true>
Rename(const Rename<_name, U>& _field) : value_(_field.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>
Rename(const Default& _default) : value_(Type()) {}
~Rename() = default;
/// The name of the field, for internal use.
constexpr static const internal::StringLiteral name_ = _name;
/// 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& _default) {
value_ = Type();
return *this;
}
/// Assigns the underlying object.
Rename<_name, T>& operator=(const Rename<_name, T>& _field) = default;
/// Assigns the underlying object.
Rename<_name, T>& operator=(Rename<_name, T>&& _field) = default;
/// Assigns the underlying object.
template <class U>
auto& operator=(const Rename<_name, U>& _field) {
value_ = _field.get();
return *this;
}
/// Assigns the underlying object.
template <class U>
auto& operator=(Rename<_name, U>&& _field) {
value_ = std::forward<T>(_field.value_);
return *this;
}
/// 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_; }
/// The underlying value.
Type value_;
};
} // namespace rfl
#endif

353
include/rfl/Result.hpp Normal file
View file

@ -0,0 +1,353 @@
#ifndef RFL_RESULT_HPP_
#define RFL_RESULT_HPP_
#include <array>
#include <iostream>
#include <optional>
#include <ranges>
#include <span>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <variant>
#include <vector>
#include "internal/is_array.hpp"
#include "internal/to_std_array.hpp"
namespace rfl {
/// To be returned
class Error {
public:
Error(const std::string& _what) : what_(_what) {}
~Error() = default;
/// Returns the error message, equivalent to .what() in std::exception.
const std::string& what() const { return what_; }
private:
/// Documents what went wrong
std::string what_;
};
/// Can be used when we are simply interested in whether an operation was
/// successful.
struct Nothing {};
/// The Result class is used for monadic error handling.
template <class T>
class Result {
static_assert(!std::is_same<T, Error>(), "The result type cannot be Error.");
using TOrErr = std::array<unsigned char, std::max(sizeof(T), sizeof(Error))>;
public:
using Type = T;
Result(const T& _val) : success_(true) { new (&get_t()) T(_val); }
Result(T&& _val) noexcept : success_(true) {
new (&get_t()) T(std::move(_val));
}
Result(const Error& _err) : success_(false) { new (&get_err()) Error(_err); }
Result(Error&& _err) noexcept : success_(false) {
new (&get_err()) Error(std::move(_err));
}
Result(Result<T>&& _other) noexcept : success_(_other.success_) {
move_from_other(_other);
}
Result(const Result<T>& _other) : success_(_other.success_) {
copy_from_other(_other);
}
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
Result(Result<U>&& _other) : success_(_other && true) {
auto temp = std::forward<Result<U>>(_other).transform(
[](U&& _u) { return T(std::forward<U>(_u)); });
move_from_other(temp);
}
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
Result(const Result<U>& _other) : success_(_other && true) {
auto temp = _other.transform([](const U& _u) { return T(_u); });
move_from_other(temp);
}
~Result() { destroy(); }
/// Returns Result<U>, if successful and error otherwise.
/// Inspired by .and(...) in the Rust std::result type.
template <class U>
Result<U> and_other(const Result<U>& _r) const noexcept {
const auto f = [&](const auto& _) { return _r; };
return and_then(f);
}
/// Monadic operation - F must be a function of type T -> Result<U>.
template <class F>
auto and_then(const F& _f) {
/// Result_U is expected to be of type Result<U>.
using Result_U = typename std::invoke_result<F, T>::type;
if (success_) {
return Result_U(_f(std::forward<T>(get_t())));
} else {
return Result_U(std::forward<Error>(get_err()));
}
}
/// Monadic operation - F must be a function of type T -> Result<U>.
template <class F>
auto and_then(const F& _f) const {
/// Result_U is expected to be of type Result<U>.
using Result_U = typename std::invoke_result<F, T>::type;
if (success_) {
return Result_U(_f(get_t()));
} else {
return Result_U(get_err());
}
}
/// Results types can be iterated over, which even make it possible to use
/// them within a std::range.
T* begin() noexcept {
if (success_) {
return &get_t();
} else {
return nullptr;
}
}
/// Results types can be iterated over, which even make it possible to use
/// them within a std::range.
const T* begin() const noexcept {
if (success_) {
return &get_t();
} else {
return nullptr;
}
}
/// Results types can be iterated over, which even make it possible to use
/// them within a std::range.
T* end() noexcept {
if (success_) {
return &get_t() + 1;
} else {
return nullptr;
}
}
/// Results types can be iterated over, which even make it possible to use
/// them within a std::range.
const T* end() const noexcept {
if (success_) {
return &get_t() + 1;
} else {
return nullptr;
}
}
/// Returns an std::optional<error> if this does in fact contain an error
/// or std::nullopt otherwise.
std::optional<Error> error() const noexcept {
if (success_) {
return std::nullopt;
} else {
return get_err();
}
}
/// Returns true if the result contains a value, false otherwise.
operator bool() const noexcept { return success_; }
/// Allows access to the underlying value. Careful: Will result in undefined
/// behavior, if the result contains an error.
T& operator*() noexcept { return get_t(); }
/// Allows read access to the underlying value. Careful: Will result in
/// undefined behavior, if the result contains an error.
const T& operator*() const noexcept { return get_t(); }
/// Assigns the underlying object.
Result<T>& operator=(const Result<T>& _other) {
if (this == &_other) {
return *this;
}
destroy();
success_ = _other.success_;
copy_from_other(_other);
return *this;
}
/// Assigns the underlying object.
Result<T>& operator=(Result<T>&& _other) noexcept {
if (this == &_other) {
return *this;
}
destroy();
success_ = _other.success_;
move_from_other(_other);
return *this;
}
/// Assigns the underlying object.
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
auto& operator=(const Result<U>& _other) {
const auto to_t = [](const U& _u) -> T { return _u; };
t_or_err_ = _other.transform(to_t).t_or_err_;
return *this;
}
/// Expects a function that takes of type Error -> Result<T> and returns
/// Result<T>.
template <class F>
Result<T> or_else(const F& _f) {
if (success_) {
return std::forward<T>(get_t());
} else {
return _f(std::forward<Error>(get_err()));
}
}
/// Expects a function that takes of type Error -> Result<T> and returns
/// Result<T>.
template <class F>
Result<T> or_else(const F& _f) const {
if (success_) {
return get_t();
} else {
return _f(get_err());
}
}
/// Returns the value contained if successful or the provided result r if
/// not.
Result<T> or_other(const Result<T>& _r) const noexcept {
const auto f = [&](const auto& _) { return _r; };
return or_else(f);
}
/// Functor operation - F must be a function of type T -> U.
template <class F>
auto transform(const F& _f) {
/// Result_U is expected to be of type Result<U>.
using U = typename std::invoke_result<F, T>::type;
if (success_) {
return rfl::Result<U>(_f(std::forward<T>(get_t())));
} else {
return rfl::Result<U>(std::forward<Error>(get_err()));
}
}
/// Functor operation - F must be a function of type T -> U.
template <class F>
auto transform(const F& _f) const {
/// Result_U is expected to be of type Result<U>.
using U = typename std::invoke_result<F, T>::type;
if (success_) {
return rfl::Result<U>(_f(get_t()));
} else {
return rfl::Result<U>(get_err());
}
}
/// Returns the value if the result does not contain an error, throws an
/// exceptions if not. Similar to .unwrap() in Rust.
T& value() {
if (success_) {
return get_t();
} else {
throw std::runtime_error(get_err().what());
}
}
/// Returns the value if the result does not contain an error, throws an
/// exceptions if not. Similar to .unwrap() in Rust.
const T& value() const {
if (success_) {
return get_t();
} else {
throw std::runtime_error(get_err().what());
}
}
/// Returns the value or a default.
T value_or(T&& _default) noexcept {
if (success_) {
return std::forward<T>(get_t());
} else {
return std::forward<T>(_default);
}
}
/// Returns the value or a default.
T value_or(const T& _default) const noexcept {
if (success_) {
return get_t();
} else {
return _default;
}
}
private:
void copy_from_other(const Result<T>& _other) {
if (success_) {
new (&get_t()) T(_other.get_t());
} else {
new (&get_err()) Error(_other.get_err());
}
}
void destroy() {
if (success_) {
if constexpr (std::is_destructible_v<T> /*&& !internal::is_array_v<T>*/) {
get_t().~T();
}
} else {
get_err().~Error();
}
}
T& get_t() noexcept { return *(reinterpret_cast<T*>(t_or_err_.data())); }
const T& get_t() const noexcept {
return *(reinterpret_cast<const T*>(t_or_err_.data()));
}
Error& get_err() noexcept {
return *(reinterpret_cast<Error*>(t_or_err_.data()));
}
const Error& get_err() const noexcept {
return *(reinterpret_cast<const Error*>(t_or_err_.data()));
}
void move_from_other(Result<T>& _other) {
if (success_) {
new (&get_t()) T(std::move(_other.get_t()));
} else {
new (&get_err()) Error(std::move(_other.get_err()));
}
}
private:
/// Signifies whether this was a success.
bool success_;
/// The underlying data, can either be T or Error.
alignas(std::max(alignof(T), alignof(Error))) TOrErr t_or_err_;
};
} // namespace rfl
#endif

32
include/rfl/Size.hpp Normal file
View file

@ -0,0 +1,32 @@
#ifndef RFL_SIZE_HPP_
#define RFL_SIZE_HPP_
#include <map>
#include "Ref.hpp"
#include "Result.hpp"
#include "parsing/Parser.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
template <class V>
struct Size {
template <class T>
static rfl::Result<T> validate(const T& _t) {
const auto to_t = [&](const auto& _v) { return _t; };
const auto embellish_error = [](const auto& _err) {
return Error("Size validation failed: " + _err.what());
};
return V::validate(_t.size()).transform(to_t).or_else(embellish_error);
}
template <class T>
static parsing::schema::ValidationType to_schema() {
return V::template to_schema<size_t>();
}
};
} // namespace rfl
#endif

20
include/rfl/Skip.hpp Normal file
View file

@ -0,0 +1,20 @@
#ifndef RFL_SKIP_HPP_
#define RFL_SKIP_HPP_
#include "internal/Skip.hpp"
namespace rfl {
template <class T>
using Skip = internal::Skip<T, true, true>;
template <class T>
using SkipSerialization = internal::Skip<T, true, false>;
template <class T>
using SkipDeserialization = internal::Skip<T, false, true>;
} // namespace rfl
#endif

View file

@ -0,0 +1,38 @@
#ifndef RFL_SNAKECASETOCAMELCASE_HPP_
#define RFL_SNAKECASETOCAMELCASE_HPP_
#include "Field.hpp"
#include "internal/transform_snake_case.hpp"
namespace rfl {
struct SnakeCaseToCamelCase {
public:
/// Replaces all instances of snake_case field names with camelCase.
template <class StructType>
static auto process(auto&& _named_tuple) {
const auto handle_one = []<class FieldType>(FieldType&& _f) {
if constexpr (FieldType::name() != "xml_content") {
return handle_one_field(std::move(_f));
} else {
return std::move(_f);
}
};
return _named_tuple.transform(handle_one);
}
private:
/// Applies the logic to a single field.
template <class FieldType>
static auto handle_one_field(FieldType&& _f) {
using NewFieldType =
Field<internal::transform_snake_case<FieldType::name_,
/*capitalize=*/false>(),
typename FieldType::Type>;
return NewFieldType(_f.value());
}
};
} // namespace rfl
#endif

View file

@ -0,0 +1,38 @@
#ifndef RFL_SNAKECASETOPASCALCASE_HPP_
#define RFL_SNAKECASETOPASCALCASE_HPP_
#include "Field.hpp"
#include "internal/transform_snake_case.hpp"
namespace rfl {
struct SnakeCaseToPascalCase {
public:
/// Replaces all instances of snake_case field names with PascalCase.
template <class StructType>
static auto process(auto&& _named_tuple) {
const auto handle_one = []<class FieldType>(FieldType&& _f) {
if constexpr (FieldType::name() != "xml_content") {
return handle_one_field(std::move(_f));
} else {
return std::move(_f);
}
};
return _named_tuple.transform(handle_one);
}
private:
/// Applies the logic to a single field.
template <class FieldType>
static auto handle_one_field(FieldType&& _f) {
using NewFieldType =
Field<internal::transform_snake_case<FieldType::name_,
/*capitalize=*/true>(),
typename FieldType::Type>;
return NewFieldType(_f.value());
}
};
} // namespace rfl
#endif

157
include/rfl/TaggedUnion.hpp Normal file
View file

@ -0,0 +1,157 @@
#ifndef RFL_TAGGEDUNION_HPP_
#define RFL_TAGGEDUNION_HPP_
#include <variant>
#include "define_literal.hpp"
#include "internal/Getter.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/tag_t.hpp"
namespace rfl {
// https://serde.rs/enum-representations.html
template <internal::StringLiteral _discriminator, class... Ts>
struct TaggedUnion {
static constexpr internal::StringLiteral discrimininator_ = _discriminator;
/// The type of the underlying variant.
using VariantType = std::variant<Ts...>;
/// A literal containing all the tags that are possible
using PossibleTags = define_literal_t<internal::tag_t<_discriminator, Ts>...>;
TaggedUnion(const VariantType& _variant) : variant_(_variant) {}
TaggedUnion(VariantType&& _variant) noexcept
: variant_(std::move(_variant)) {}
TaggedUnion(const TaggedUnion<_discriminator, Ts...>& _tagged_union) =
default;
TaggedUnion(TaggedUnion<_discriminator, Ts...>&& _tagged_union) noexcept =
default;
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
TaggedUnion(const T& _t) : variant_(_t) {}
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
TaggedUnion(T&& _t) noexcept : variant_(std::forward<T>(_t)) {}
~TaggedUnion() = default;
/// Assigns the underlying object.
TaggedUnion<_discriminator, Ts...>& operator=(const VariantType& _variant) {
variant_ = _variant;
return *this;
}
/// Assigns the underlying object.
TaggedUnion<_discriminator, Ts...>& operator=(VariantType&& _variant) {
variant_ = std::move(_variant);
return *this;
}
/// Assigns the underlying object.
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
TaggedUnion<_discriminator, Ts...>& operator=(T&& _variant) {
variant_ = std::forward<T>(_variant);
return *this;
}
/// Assigns the underlying object.
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
TaggedUnion<_discriminator, Ts...>& operator=(const T& _variant) {
variant_ = _variant;
return *this;
}
/// Assigns the underlying object.
TaggedUnion<_discriminator, Ts...>& operator=(
const TaggedUnion<_discriminator, Ts...>& _other) = default;
/// Assigns the underlying object.
TaggedUnion<_discriminator, Ts...>& operator=(
TaggedUnion<_discriminator, Ts...>&& _other) = default;
/// Returns the underlying variant.
VariantType& variant() { return variant_; }
/// Returns the underlying variant.
const VariantType& variant() const { return variant_; }
static_assert(!PossibleTags::has_duplicates(),
"Duplicate tags are not allowed inside tagged unions.");
/// The underlying variant - a TaggedUnion is a thin wrapper
/// around a variant that is mainly used for parsing.
VariantType variant_;
};
namespace internal {
template <StringLiteral _discriminator, class... NamedTupleTypes>
struct Getter<TaggedUnion<_discriminator, NamedTupleTypes...>> {
public:
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline auto& get(
TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get<_index>(
_tu.variant_);
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline auto& get(
TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get<_field_name>(
_tu.variant_);
}
/// Gets a field by the field type.
template <class Field>
static inline auto& get(
TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get<Field>(
_tu.variant_);
}
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline const auto& get_const(
const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get_const<_index>(
_tu.variant_);
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline const auto& get_const(
const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get_const<
_field_name>(_tu.variant_);
}
/// Gets a field by the field type.
template <class Field>
static inline const auto& get_const(
const TaggedUnion<_discriminator, NamedTupleTypes...>& _tu) {
return Getter<std::variant<NamedTupleTypes...>>::template get_const<Field>(
_tu.variant_);
}
};
} // namespace internal
} // namespace rfl
#endif // RFL_TAGGEDUNION_HPP_

96
include/rfl/Timestamp.hpp Normal file
View file

@ -0,0 +1,96 @@
#ifndef RFL_TIMESTAMP_HPP_
#define RFL_TIMESTAMP_HPP_
#include <ctime>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <locale>
#include <sstream>
#include <stdexcept>
#include <string>
#include "Result.hpp"
#include "internal/StringLiteral.hpp"
namespace rfl {
/// For serializing and deserializing time stamps.
template <internal::StringLiteral _format>
class Timestamp {
constexpr static const internal::StringLiteral format_ = _format;
public:
using Format = rfl::Literal<_format>;
using ReflectionType = std::string;
Timestamp(const char* _str) : tm_(std::tm{}) {
const auto r = strptime(_str, _format.str().c_str(), &tm_);
if (r == NULL) {
throw std::runtime_error("String '" + std::string(_str) +
"' did not match format '" + Format().str() +
"'.");
}
}
Timestamp(const std::string& _str) : Timestamp(_str.c_str()) {}
Timestamp(const std::tm& _tm) : tm_(_tm) {}
~Timestamp() = default;
/// Returns a result containing the timestamp when successful or an Error
/// otherwise.
static Result<Timestamp> from_string(const char* _str) noexcept {
try {
return Timestamp(_str);
} catch (std::exception& e) {
return Error(e.what());
}
}
/// Returns a result containing the timestamp when successful or an Error
/// otherwise.
static Result<Timestamp> from_string(const std::string& _str) {
return from_string(_str.c_str());
}
/// Necessary for the serialization to work.
ReflectionType reflection() const {
char outstr[200];
strftime(outstr, 200, format_.str().c_str(), &tm_);
return std::string(outstr);
}
/// Expresses the underlying timestamp as a string.
std::string str() const { return reflection(); }
/// Trivial accessor to the underlying time stamp.
std::tm& tm() { return tm_; }
/// Trivial (const) accessor to the underlying time stamp.
const std::tm& tm() const { return tm_; }
private:
#ifdef _MSC_VER
// This workaround is necessary, because MSVC doesn't support strptime.
char* strptime(const char* _s, const char* _f, std::tm* _tm) {
std::istringstream input(_s);
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
input >> std::get_time(_tm, _f);
if (input.fail()) {
return NULL;
}
return (char*)(_s + input.tellg());
}
#endif
private:
/// The underlying time stamp.
std::tm tm_;
};
} // namespace rfl
#endif

138
include/rfl/Validator.hpp Normal file
View file

@ -0,0 +1,138 @@
#ifndef RFL_VALIDATOR_HPP_
#define RFL_VALIDATOR_HPP_
#include <concepts>
#include <functional>
#include <optional>
#include <regex>
#include <string>
#include <type_traits>
#include <utility>
#include "AllOf.hpp"
#include "Result.hpp"
#include "internal/HasValidation.hpp"
#include "internal/StringLiteral.hpp"
namespace rfl {
template <class T, class V, class... Vs>
requires internal::HasValidation<AllOf<V, Vs...>, T>
struct Validator {
public:
using ReflectionType = T;
using ValidationType =
std::conditional_t<sizeof...(Vs) == 0, V, AllOf<V, Vs...>>;
/// Exception-free validation.
static Result<Validator<T, V, Vs...>> from_value(const T& _value) noexcept {
try {
return Validator<T, V, Vs...>(_value);
} catch (std::exception& e) {
return Error(e.what());
}
}
Validator() : value_(ValidationType::validate(T()).value()) {}
Validator(Validator<T, V, Vs...>&& _other) noexcept = default;
Validator(const Validator<T, V, Vs...>& _other) = default;
Validator(T&& _value) : value_(ValidationType::validate(_value).value()) {}
Validator(const T& _value)
: value_(ValidationType::validate(_value).value()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
Validator(U&& _value)
: value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {}
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
Validator(const U& _value)
: value_(ValidationType::validate(T(_value)).value()) {}
~Validator() = default;
/// Assigns the underlying object.
auto& operator=(const T& _value) {
value_ = ValidationType::validate(_value).value();
return *this;
}
/// Assigns the underlying object.
auto& operator=(T&& _value) {
value_ = ValidationType::validate(std::forward<T>(_value)).value();
return *this;
}
/// Assigns the underlying object.
Validator<T, V, Vs...>& operator=(const Validator<T, V, Vs...>& _other) =
default;
/// Assigns the underlying object.
Validator<T, V, Vs...>& operator=(Validator<T, V, Vs...>&& _other) noexcept =
default;
/// Assigns the underlying object.
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
auto& operator=(U&& _value) noexcept {
value_ = ValidationType::validate(T(std::forward<U>(_value))).value();
return *this;
}
/// Assigns the underlying object.
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
bool>::type = true>
auto& operator=(const U& _value) {
value_ = ValidationType::validate(T(_value)).value();
return *this;
}
/// Equality operator other Validators.
bool operator==(const Validator<T, V, Vs...>& _other) const {
return value() == _other.value();
}
/// Exposes the underlying value.
T& value() { return value_; }
/// Exposes the underlying value.
const T& value() const { return value_; }
/// Necessary for the serialization to work.
const T& reflection() const { return value_; }
private:
/// The underlying value.
T value_;
};
template <class T, class V, class... Vs>
inline auto operator<=>(const Validator<T, V, Vs...>& _v1,
const Validator<T, V, Vs...>& _v2) {
return _v1.value() <=> _v2.value();
}
template <class T, class V, class... Vs>
inline auto operator<=>(const Validator<T, V, Vs...>& _v, const T& _t) {
return _v.value() <=> _t;
}
} // namespace rfl
namespace std {
template <class T, class V, class... Vs>
struct hash<rfl::Validator<T, V, Vs...>> {
size_t operator()(const rfl::Validator<T, V, Vs...>& _v) const {
return hash<T>()(_v.value());
}
};
} // namespace std
#endif

84
include/rfl/Variant.hpp Normal file
View file

@ -0,0 +1,84 @@
#ifndef RFL_VARIANT_HPP_
#define RFL_VARIANT_HPP_
#include <variant>
namespace rfl {
template <class... AlternativeTypes>
struct Variant {
/// The type of the underlying variant.
using VariantType = std::variant<AlternativeTypes...>;
Variant(const VariantType& _variant) : variant_(_variant) {}
Variant(VariantType&& _variant) noexcept : variant_(std::move(_variant)) {}
Variant(const Variant<AlternativeTypes...>& _variant) = default;
Variant(Variant<AlternativeTypes...>&& _variant) noexcept = default;
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
Variant(const T& _t) : variant_(_t) {}
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
Variant(T&& _t) noexcept : variant_(std::forward<T>(_t)) {}
~Variant() = default;
/// Assigns the underlying object.
Variant<AlternativeTypes...>& operator=(const VariantType& _variant) {
variant_ = _variant;
return *this;
}
/// Assigns the underlying object.
Variant<AlternativeTypes...>& operator=(VariantType&& _variant) {
variant_ = std::move(_variant);
return *this;
}
/// Assigns the underlying object.
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
Variant<AlternativeTypes...>& operator=(T&& _variant) {
variant_ = std::forward<T>(_variant);
return *this;
}
/// Assigns the underlying object.
template <class T,
typename std::enable_if<std::is_convertible_v<T, VariantType>,
bool>::type = true>
Variant<AlternativeTypes...>& operator=(const T& _variant) {
variant_ = _variant;
return *this;
}
/// Assigns the underlying object.
Variant<AlternativeTypes...>& operator=(
const Variant<AlternativeTypes...>& _other) = default;
/// Assigns the underlying object.
Variant<AlternativeTypes...>& operator=(
Variant<AlternativeTypes...>&& _other) = default;
/// Returns the underlying variant.
VariantType& variant() { return variant_; }
/// Returns the underlying variant.
const VariantType& variant() const { return variant_; }
/// The underlying variant - a Variant is a thin wrapper
/// around a variant that is mainly used for parsing.
VariantType variant_;
};
} // namespace rfl
#endif

View file

@ -0,0 +1,12 @@
#ifndef RFL_ALWAYSFALSE_HPP_
#define RFL_ALWAYSFALSE_HPP_
namespace rfl {
/// To be used inside visitor patterns
template <class>
inline constexpr bool always_false_v = false;
} // namespace rfl
#endif // RFL_ALWAYSFALSE_HPP_

35
include/rfl/as.hpp Normal file
View file

@ -0,0 +1,35 @@
#ifndef RFL_AS_HPP_
#define RFL_AS_HPP_
#include "from_named_tuple.hpp"
#include "make_named_tuple.hpp"
#include "to_named_tuple.hpp"
namespace rfl {
/// Generates a type T from the input values.
template <class T, class Head, class... Tail>
T as(Head&& _head, Tail&&... _tail) {
if constexpr (sizeof...(_tail) == 0) {
return from_named_tuple<T>(to_named_tuple(std::forward<Head>(_head)));
} else {
return from_named_tuple<T>(
to_named_tuple(std::forward<Head>(_head))
.add(to_named_tuple(std::forward<Tail>(_tail))...));
}
}
/// Generates a type T from the input values.
template <class T, class Head, class... Tail>
T as(const Head& _head, const Tail&... _tail) {
if constexpr (sizeof...(_tail) == 0) {
return from_named_tuple<T>(to_named_tuple(_head));
} else {
return from_named_tuple<T>(
to_named_tuple(_head).add(to_named_tuple(_tail)...));
}
}
} // namespace rfl
#endif

157
include/rfl/comparisons.hpp Normal file
View file

@ -0,0 +1,157 @@
#ifndef RFL_COMPARISONS_HPP_
#define RFL_COMPARISONS_HPP_
#include <type_traits>
#include "Result.hpp"
#include "parsing/schema/ValidationType.hpp"
namespace rfl {
template <auto _threshold>
struct EqualTo {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value != threshold) {
return Error("Value expected to be equal to " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::EqualTo{.value_ = value}};
}
};
template <auto _threshold>
struct Minimum {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value < threshold) {
return Error("Value expected to be greater than or equal to " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::Minimum{.value_ = value}};
}
};
template <auto _threshold>
struct ExclusiveMinimum {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value <= threshold) {
return Error("Value expected to be greater than " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::ExclusiveMinimum{.value_ = value}};
}
};
template <auto _threshold>
struct Maximum {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value > threshold) {
return Error("Value expected to be less than or equal to " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::Maximum{.value_ = value}};
}
};
template <auto _threshold>
struct ExclusiveMaximum {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value >= threshold) {
return Error("Value expected to be less than " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::ExclusiveMaximum{.value_ = value}};
}
};
template <auto _threshold>
struct NotEqualTo {
template <class T>
static Result<T> validate(T _value) noexcept {
constexpr auto threshold = static_cast<T>(_threshold);
if (_value == threshold) {
return Error("Value expected to not be equal to " +
std::to_string(threshold) + ", but got " +
std::to_string(_value) + ".");
}
return _value;
}
template <class T>
static parsing::schema::ValidationType to_schema() {
using ValidationType = parsing::schema::ValidationType;
const auto value =
std::is_floating_point_v<T>
? std::variant<double, int>(static_cast<double>(_threshold))
: std::variant<double, int>(static_cast<int>(_threshold));
return ValidationType{ValidationType::NotEqualTo{.value_ = value}};
}
};
} // namespace rfl
#endif

14
include/rfl/default.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef RFL_DEFAULT_HPP_
#define RFL_DEFAULT_HPP_
namespace rfl {
/// Helper class that can be passed to a field
/// to trigger the default value of the type.
struct Default {};
inline static const auto default_value = Default{};
} // namespace rfl
#endif

View file

@ -0,0 +1,16 @@
#ifndef RFL_DEFINELITERAL_HPP_
#define RFL_DEFINELITERAL_HPP_
#include "Literal.hpp"
#include "internal/define_literal.hpp"
namespace rfl {
/// Allows you to combine several literal types.
template <class... LiteralTypes>
using define_literal_t =
typename internal::define_literal<LiteralTypes...>::type;
} // namespace rfl
#endif // RFL_DEFINELITERAL_HPP_

View file

@ -0,0 +1,15 @@
#ifndef RFL_DEFINENAMEDTUPLE_HPP_
#define RFL_DEFINENAMEDTUPLE_HPP_
#include "NamedTuple.hpp"
#include "internal/define_named_tuple.hpp"
namespace rfl {
template <class... FieldTypes>
using define_named_tuple_t =
typename internal::define_named_tuple<FieldTypes...>::type;
} // namespace rfl
#endif // RFL_DEFINENAMEDTUPLE_HPP_

View file

@ -0,0 +1,17 @@
#ifndef RFL_DEFINETAGGEDUNION_HPP_
#define RFL_DEFINETAGGEDUNION_HPP_
#include "TaggedUnion.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/define_tagged_union.hpp"
namespace rfl {
template <internal::StringLiteral _discriminator, class... TaggedUnionTypes>
using define_tagged_union_t =
typename internal::define_tagged_union<_discriminator,
TaggedUnionTypes...>::type;
} // namespace rfl
#endif

View file

@ -0,0 +1,15 @@
#ifndef RFL_DEFINEVARIANT_HPP_
#define RFL_DEFINEVARIANT_HPP_
#include <variant>
#include "internal/define_variant.hpp"
namespace rfl {
template <class... Vars>
using define_variant_t = typename internal::define_variant<Vars...>::type;
} // namespace rfl
#endif // RFL_DEFINEVARIANT_HPP_

64
include/rfl/enums.hpp Normal file
View file

@ -0,0 +1,64 @@
#ifndef RFL_ENUMS_HPP_
#define RFL_ENUMS_HPP_
#include <string>
#include "Result.hpp"
#include "internal/enums/StringConverter.hpp"
#include "internal/enums/get_enum_names.hpp"
#include "internal/enums/is_flag_enum.hpp"
#include "internal/enums/is_scoped_enum.hpp"
namespace rfl {
// Converts an enum value to a string.
template <internal::enums::is_scoped_enum EnumType>
std::string enum_to_string(EnumType _enum) {
return rfl::internal::enums::StringConverter<EnumType>::enum_to_string(_enum);
}
// Converts a string to a value of the given enum type.
template <internal::enums::is_scoped_enum EnumType>
rfl::Result<EnumType> string_to_enum(const std::string& _str) {
return rfl::internal::enums::StringConverter<EnumType>::string_to_enum(_str);
}
// Returns a named tuple mapping names of enumerators of the given enum type to
// their values.
template <internal::enums::is_scoped_enum EnumType>
auto get_enumerators() {
constexpr auto names = internal::enums::get_enum_names<
EnumType, internal::enums::is_flag_enum<EnumType>>();
return internal::enums::names_to_enumerator_named_tuple(names);
}
// Returns a named tuple mapping names of enumerators of the given enum type to
// their underlying values.
template <internal::enums::is_scoped_enum EnumType>
auto get_underlying_enumerators() {
constexpr auto names = internal::enums::get_enum_names<
EnumType, internal::enums::is_flag_enum<EnumType>>();
return internal::enums::names_to_underlying_enumerator_named_tuple(names);
}
// Returns an std::array containing pairs of enumerator names (as
// std::string_view) and values.
template <internal::enums::is_scoped_enum EnumType>
constexpr auto get_enumerator_array() {
constexpr auto names = internal::enums::get_enum_names<
EnumType, internal::enums::is_flag_enum<EnumType>>();
return internal::enums::names_to_enumerator_array(names);
}
// Returns an std::array containing pairs of enumerator names (as
// std::string_view) and underlying values.
template <internal::enums::is_scoped_enum EnumType>
constexpr auto get_underlying_enumerator_array() {
constexpr auto names = internal::enums::get_enum_names<
EnumType, internal::enums::is_flag_enum<EnumType>>();
return internal::enums::names_to_underlying_enumerator_array(names);
}
} // namespace rfl
#endif // RFL_ENUMS_HPP_

View file

@ -0,0 +1,20 @@
#ifndef RFL_EXTRACTDISTRIMINATORS_HPP_
#define RFL_EXTRACTDISTRIMINATORS_HPP_
#include <type_traits>
#include "TaggedUnion.hpp"
#include "define_literal.hpp"
#include "field_type.hpp"
#include "internal/extract_discriminators.hpp"
namespace rfl {
/// Extracts a Literal containing all of the discriminators from a TaggedUnion.
template <class TaggedUnionType>
using extract_discriminators_t =
typename internal::extract_discriminators<TaggedUnionType>::type;
} // namespace rfl
#endif // RFL_EXTRACTDISTRIMINATORS_HPP_

View file

@ -0,0 +1,18 @@
#ifndef RFL_FIELD_NAMES_T_HPP_
#define RFL_FIELD_NAMES_T_HPP_
#include <functional>
#include <type_traits>
#include "internal/get_field_names.hpp"
namespace rfl {
/// Returns a rfl::Literal containing the field names of struct T.
template <class T>
using field_names_t = typename std::invoke_result<
decltype(internal::get_field_names<std::remove_cvref_t<T>>)>::type;
} // namespace rfl
#endif

View file

@ -0,0 +1,18 @@
#ifndef RFL_FIELD_TYPE_HPP_
#define RFL_FIELD_TYPE_HPP_
#include <tuple>
#include <type_traits>
#include <variant>
#include "internal/StringLiteral.hpp"
#include "internal/field_type.hpp"
namespace rfl {
template <internal::StringLiteral _field_name, class T>
using field_type_t = typename internal::FieldType<_field_name, T>::Type;
} // namespace rfl
#endif

17
include/rfl/fields.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef RFL_FIELDS_HPP_
#define RFL_FIELDS_HPP_
#include "internal/get_meta_fields.hpp"
#include "named_tuple_t.hpp"
namespace rfl {
/// Returns meta-information about the fields.
template <class T>
auto fields() {
return internal::get_meta_fields<named_tuple_t<T>>();
}
} // namespace rfl
#endif

View file

@ -0,0 +1,53 @@
#ifndef RFL_FROM_NAMED_TUPLE_HPP_
#define RFL_FROM_NAMED_TUPLE_HPP_
#include <type_traits>
#include "internal/copy_from_named_tuple.hpp"
#include "internal/copy_from_tuple.hpp"
#include "internal/has_fields.hpp"
#include "internal/move_from_named_tuple.hpp"
#include "internal/move_from_tuple.hpp"
#include "named_tuple_t.hpp"
namespace rfl {
/// Generates the struct T from a named tuple.
template <class T, class NamedTupleType>
auto from_named_tuple(NamedTupleType&& _n) {
using RequiredType = std::remove_cvref_t<rfl::named_tuple_t<T>>;
if constexpr (!std::is_same<std::remove_cvref_t<NamedTupleType>,
RequiredType>()) {
return from_named_tuple<T>(RequiredType(std::forward<NamedTupleType>(_n)));
} else if constexpr (internal::has_fields<T>()) {
if constexpr (std::is_lvalue_reference<NamedTupleType>{}) {
return internal::copy_from_named_tuple<T>(_n);
} else {
return internal::move_from_named_tuple<T>(_n);
}
} else {
if constexpr (std::is_lvalue_reference<NamedTupleType>{}) {
return internal::copy_from_tuple<T>(_n.values());
} else {
return internal::move_from_tuple<T>(std::move(_n.values()));
}
}
}
/// Generates the struct T from a named tuple.
template <class T, class NamedTupleType>
auto from_named_tuple(const NamedTupleType& _n) {
using RequiredType = std::remove_cvref_t<rfl::named_tuple_t<T>>;
if constexpr (!std::is_same<std::remove_cvref_t<NamedTupleType>,
RequiredType>()) {
return from_named_tuple<T>(RequiredType(_n));
} else if constexpr (internal::has_fields<T>()) {
return internal::copy_from_named_tuple<T>(_n);
} else {
return internal::copy_from_tuple<T>(_n.values());
}
}
} // namespace rfl
#endif

48
include/rfl/get.hpp Normal file
View file

@ -0,0 +1,48 @@
#ifndef RFL_GET_HPP_
#define RFL_GET_HPP_
#include "internal/Getter.hpp"
#include "internal/StringLiteral.hpp"
namespace rfl {
/// Gets a field by index.
template <int _index, class NamedTupleType>
inline auto& get(NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get<_index>(_tup);
}
/// Gets a field by name.
template <internal::StringLiteral _field_name, class NamedTupleType>
inline auto& get(NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get<_field_name>(_tup);
}
/// Gets a field by the field type.
template <class Field, class NamedTupleType>
inline auto& get(NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get<Field>(_tup);
}
/// Gets a field by index.
template <int _index, class NamedTupleType>
inline const auto& get(const NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get_const<_index>(_tup);
}
/// Gets a field by name.
template <internal::StringLiteral _field_name, class NamedTupleType>
inline const auto& get(const NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get_const<_field_name>(
_tup);
}
/// Gets a field by the field type.
template <class Field, class NamedTupleType>
inline const auto& get(const NamedTupleType& _tup) {
return internal::Getter<NamedTupleType>::template get_const<Field>(_tup);
}
} // namespace rfl
#endif

View file

@ -0,0 +1,33 @@
#ifndef RFL_INTERNAL_ARRAY_HPP_
#define RFL_INTERNAL_ARRAY_HPP_
#include <array>
#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,20 @@
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#include <functional>
#include <tuple>
#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,156 @@
#ifndef RFL_INTERNAL_GETTER_HPP_
#define RFL_INTERNAL_GETTER_HPP_
#include <tuple>
#include <variant>
#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 std::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 std::tuple_element<
index, typename NamedTupleType::Fields>::type::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 std::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 std::tuple_element<
index, typename NamedTupleType::Fields>::type::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);
}
};
// ----------------------------------------------------------------------------
/// For handling std::variant.
template <class... NamedTupleTypes>
struct Getter<std::variant<NamedTupleTypes...>> {
public:
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline auto& get(std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](auto& _t) -> auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_t)>;
return Getter<NamedTupleType>::template get<_index>(_t);
};
return std::visit(apply, _tup);
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline auto& get(std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](auto& _t) -> auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_t)>;
return Getter<NamedTupleType>::template get<_field_name>(_t);
};
return std::visit(apply, _tup);
}
/// Gets a field by the field type.
template <class Field>
static inline auto& get(std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](auto& _t) -> auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_t)>;
return Getter<NamedTupleType>::template get<Field>(_t);
};
return std::visit(apply, _tup);
}
/// Retrieves the indicated value from the tuple.
template <int _index>
static inline const auto& get_const(
const std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](const auto& _tup) -> const auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_tup)>;
return Getter<NamedTupleType>::template get_const<_index>(_tup);
};
return std::visit(apply, _tup);
}
/// Gets a field by name.
template <StringLiteral _field_name>
static inline const auto& get_const(
const std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](const auto& _t) -> const auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_t)>;
return Getter<NamedTupleType>::template get_const<_field_name>(_t);
};
return std::visit(apply, _tup);
}
/// Gets a field by the field type.
template <class Field>
static inline const auto& get_const(
const std::variant<NamedTupleTypes...>& _tup) {
const auto apply = [](const auto& _t) -> const auto& {
using NamedTupleType = std::remove_cvref_t<decltype(_t)>;
return Getter<NamedTupleType>::template get_const<Field>(_t);
};
return std::visit(apply, _tup);
}
};
// ----------------------------------------------------------------------------
} // namespace rfl::internal
#endif

View file

@ -0,0 +1,19 @@
#ifndef RFL_INTERNAL_HASVALIDATION_HPP_
#define RFL_INTERNAL_HASVALIDATION_HPP_
#include <type_traits>
#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,53 @@
#ifndef RFL_INTERNAL_MEMOIZATION_HPP_
#define RFL_INTERNAL_MEMOIZATION_HPP_
#include <atomic>
#include <mutex>
namespace rfl {
namespace internal {
/// For a thread-safe memoization pattern.
template <class T>
class Memoization {
public:
Memoization() { flag_.clear(); }
~Memoization() = default;
public:
/// Returns the underlying value.
template <class F>
const T& value(const F& _f) {
if (flag_.test()) {
return value_;
}
std::lock_guard<std::mutex> guard(mtx_);
if (flag_.test()) {
return value_;
}
_f(&value_);
flag_.test_and_set();
return value_;
}
private:
/// Signifies whether t_ has been set.
std::atomic_flag flag_;
/// A mutex, only needed for writing.
std::mutex mtx_;
/// The type to be initialized.
T value_;
};
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,146 @@
#ifndef RFL_INTERNAL_SKIP_HPP_
#define RFL_INTERNAL_SKIP_HPP_
#include <optional>
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& _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& _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,54 @@
#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(std::data(arr_), N - 1); }
/// Returns the value as a string.
constexpr std::string_view string_view() const {
return std::string_view(std::data(arr_), 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,26 @@
#ifndef RFL_INTERNAL_ALLFIELDS_HPP_
#define RFL_INTERNAL_ALLFIELDS_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#include "is_field.hpp"
namespace rfl {
namespace internal {
template <class TupleType, int _i = 0>
constexpr bool all_fields() {
if constexpr (_i == std::tuple_size_v<TupleType>) {
return true;
} else {
using T = std::tuple_element_t<_i, TupleType>;
return is_field_v<T> && all_fields<TupleType, _i + 1>();
}
}
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,584 @@
#ifndef RFL_INTERNAL_BIND_FAKE_OBJECT_TO_TUPLE_HPP_
#define RFL_INTERNAL_BIND_FAKE_OBJECT_TO_TUPLE_HPP_
#include <cstddef>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../always_false.hpp"
#include "get_fake_object.hpp"
#include "num_fields.hpp"
namespace rfl {
namespace internal {
template <class T, std::size_t n>
struct fake_object_tuple_view_helper {
static consteval auto tuple_view() {
static_assert(
rfl::always_false_v<T>,
"\n\nThis error occurs for one of two reasons:\n\n"
"1) You have created a struct with more than 100 fields, which is "
"unsupported. Please split up your struct into several "
"smaller structs and then use rfl::Flatten<...> to combine them. "
"Refer "
"to the documentation on rfl::Flatten<...> for details.\n\n"
"2) You have added a custom constructor to your struct, which you "
"shouldn't do either. Please refer to the sections on custom "
"classes or custom parsers in the documentation "
"for solutions to this problem.\n\n");
}
};
template <class T>
struct fake_object_tuple_view_helper<T, 0> {
static consteval auto tuple_view() { return std::tie(); }
};
#define RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(n, ...) \
template <class T> \
struct fake_object_tuple_view_helper<T, n> { \
static consteval auto tuple_view() { \
const auto& [__VA_ARGS__] = get_fake_object<std::remove_cvref_t<T>>(); \
const auto ref_tup = std::tie(__VA_ARGS__); \
const auto get_ptrs = [](const auto&... _refs) { \
return std::make_tuple(&_refs...); \
}; \
return std::apply(get_ptrs, ref_tup); \
} \
}
/*The following boilerplate code was generated using a Python script:
macro = "RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER"
with open("generated_code4.cpp", "w", encoding="utf-8") as codefile:
codefile.write(
"\n".join(
[
f"{macro}({i}, {', '.join([f'f{j}' for j in range(i)])});"
for i in range(1, 101)
]
)
)
*/
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(1, f0);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(2, f0, f1);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(3, f0, f1, f2);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(4, f0, f1, f2, f3);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(5, f0, f1, f2, f3, f4);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(6, f0, f1, f2, f3, f4, f5);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(7, f0, f1, f2, f3, f4, f5,
f6);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(8, f0, f1, f2, f3, f4, f5, f6,
f7);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(9, f0, f1, f2, f3, f4, f5, f6,
f7, f8);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(10, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(11, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(12, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(13, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11,
f12);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(14, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(15, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(16, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(17, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(18, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(19, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(20, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(21, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(22, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(23, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(24, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(25, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(26, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(27, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(28, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(29, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(30, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(31, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(32, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(33, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31, f32);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(34, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31, f32, f33);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(35, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(36, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(37, f0, f1, f2, f3, f4, f5,
f6, f7, f8, f9, f10, f11, f12,
f13, f14, f15, f16, f17, f18,
f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
38, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
39, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
40, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
41, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
42, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
43, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
44, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
45, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
46, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
47, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
48, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
49, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
50, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
51, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
52, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
53, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
54, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
55, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
56, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
57, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
58, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
59, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
60, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
61, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
62, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
63, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
64, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
65, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
66, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
67, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
68, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
69, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
70, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
71, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
72, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
73, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
74, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
75, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
76, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
77, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
78, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
79, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
80, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
81, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
82, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
83, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
84, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
85, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
86, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
87, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
88, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
89, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
90, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
91, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
92, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
93, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
94, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
95, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
96, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
97, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
98, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
99, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97, f98);
RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER(
100, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97, f98, f99);
#undef RFL_INTERNAL_DEFINE_FAKE_OBJECT_TUPLE_VIEW_HELPER
template <class T>
consteval auto bind_fake_object_to_tuple() {
return fake_object_tuple_view_helper<T, num_fields<T>>::tuple_view();
}
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,603 @@
#ifndef RFL_INTERNAL_BIND_TO_TUPLE_HPP_
#define RFL_INTERNAL_BIND_TO_TUPLE_HPP_
#include <cstddef>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../always_false.hpp"
#include "is_named_tuple.hpp"
#include "num_fields.hpp"
namespace rfl {
namespace internal {
template <std::size_t n>
struct tuple_view_helper {
template <class T>
static constexpr auto tuple_view(T&) {
static_assert(
rfl::always_false_v<T>,
"\n\nThis error occurs for one of two reasons:\n\n"
"1) You have created a struct with more than 100 fields, which is "
"unsupported. Please split up your struct into several "
"smaller structs and then use rfl::Flatten<...> to combine them. "
"Refer "
"to the documentation on rfl::Flatten<...> for details.\n\n"
"2) You have added a custom constructor to your struct, which you "
"shouldn't do either. Please refer to the sections on custom "
"classes or custom parsers in the documentation "
"for solutions to this problem.\n\n");
}
};
template <>
struct tuple_view_helper<0> {
static constexpr auto tuple_view(auto&) { return std::tie(); }
};
#define RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(n, ...) \
template <> \
struct tuple_view_helper<n> { \
static constexpr auto tuple_view(auto& t) { \
auto& [__VA_ARGS__] = t; \
return std::tie(__VA_ARGS__); \
} \
}
/*The following boilerplate code was generated using a Python script:
macro = "RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER"
with open("generated_code4.cpp", "w", encoding="utf-8") as codefile:
codefile.write(
"\n".join(
[
f"{macro}({i}, {', '.join([f'f{j}' for j in range(i)])});"
for i in range(1, 101)
]
)
)
*/
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(1, f0);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(2, f0, f1);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(3, f0, f1, f2);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(4, f0, f1, f2, f3);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(5, f0, f1, f2, f3, f4);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(6, f0, f1, f2, f3, f4, f5);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(7, f0, f1, f2, f3, f4, f5, f6);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(8, f0, f1, f2, f3, f4, f5, f6, f7);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(9, f0, f1, f2, f3, f4, f5, f6, f7, f8);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(10, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(11, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(12, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(13, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(14, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(15, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(16, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(17, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(18, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(19, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(20, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(21, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(22, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(23, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(24, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(25, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(26, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(27, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(28, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(29, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(30, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(31, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(32, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(33, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(34, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(35, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(36, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(37, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(38, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(39, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(40, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(41, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(42, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(43, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(44, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(45, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(46, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(47, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(48, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(49, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(50, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(51, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(52, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(53, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(54, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(55, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(56, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(57, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55, f56);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
58, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
59, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
60, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
61, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(62, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55, f56,
f57, f58, f59, f60, f61);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(63, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55, f56,
f57, f58, f59, f60, f61, f62);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(64, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55, f56,
f57, f58, f59, f60, f61, f62, f63);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(65, f0, f1, f2, f3, f4, f5, f6, f7, f8,
f9, f10, f11, f12, f13, f14, f15, f16,
f17, f18, f19, f20, f21, f22, f23, f24,
f25, f26, f27, f28, f29, f30, f31, f32,
f33, f34, f35, f36, f37, f38, f39, f40,
f41, f42, f43, f44, f45, f46, f47, f48,
f49, f50, f51, f52, f53, f54, f55, f56,
f57, f58, f59, f60, f61, f62, f63, f64);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
66, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
67, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
68, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
69, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
70, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
71, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
72, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
73, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
74, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
75, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
76, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
77, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
78, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
79, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
80, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
81, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
82, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
83, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
84, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
85, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
86, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
87, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
88, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
89, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
90, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
91, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
92, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
93, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
94, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
95, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
96, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
97, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
98, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
99, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97, f98);
RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER(
100, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15,
f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30,
f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44, f45,
f46, f47, f48, f49, f50, f51, f52, f53, f54, f55, f56, f57, f58, f59, f60,
f61, f62, f63, f64, f65, f66, f67, f68, f69, f70, f71, f72, f73, f74, f75,
f76, f77, f78, f79, f80, f81, f82, f83, f84, f85, f86, f87, f88, f89, f90,
f91, f92, f93, f94, f95, f96, f97, f98, f99);
#undef RFL_INTERNAL_DEFINE_TUPLE_VIEW_HELPER
template <class T>
constexpr auto tuple_view(T& t) {
return tuple_view_helper<num_fields<T>>::tuple_view(t);
}
template <class T, typename F>
constexpr auto bind_to_tuple(T& _t, const F& _f) {
auto view = tuple_view(_t);
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::make_tuple(_f(std::get<Is>(view))...);
}
(std::make_index_sequence<std::tuple_size_v<decltype(view)>>());
}
} // namespace internal
} // namespace rfl
#endif

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 <functional>
#include <tuple>
#include <type_traits>
#include "../Field.hpp"
#include "lit_name.hpp"
#include "../make_named_tuple.hpp"
namespace rfl {
namespace internal {
template <class FieldNames, class... Fields>
auto copy_flattened_tuple_to_named_tuple(const auto& _flattened_tuple,
Fields&&... _fields) {
constexpr auto size =
std::tuple_size_v<std::remove_cvref_t<decltype(_flattened_tuple)>>;
constexpr auto i = sizeof...(_fields);
if constexpr (i == size) {
return make_named_tuple(std::move(_fields)...);
} else {
const auto name_literal = FieldNames::template name_of<i>();
auto new_field = rfl::make_field<
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
std::get<i>(_flattened_tuple));
return copy_flattened_tuple_to_named_tuple<FieldNames>(
_flattened_tuple, std::move(_fields)..., std::move(new_field));
}
}
} // 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,76 @@
#ifndef RFL_INTERNAL_ENUMS_NAMES_HPP_
#define RFL_INTERNAL_ENUMS_NAMES_HPP_
#include <algorithm>
#include <array>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include "../../Literal.hpp"
#include "../../define_literal.hpp"
#include "../../make_named_tuple.hpp"
#include "../StringLiteral.hpp"
namespace rfl {
namespace internal {
namespace enums {
template <class EnumType, class LiteralType, size_t N, 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 std::array<EnumType, N> enums_ =
std::array<EnumType, N>{_enums...};
static_assert(N == 0 || LiteralType::size() == N,
"Size of literal and enum do not match.");
template <class NewLiteral, auto _new_enum>
using AddOneType = std::conditional_t<
N == 0, Names<EnumType, NewLiteral, 1, _new_enum>,
Names<EnumType, define_literal_t<LiteralType, NewLiteral>, N + 1,
_enums..., _new_enum>>;
};
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
auto names_to_enumerator_named_tuple(
Names<EnumType, Literal<_names...>, N, _enums...>) {
return make_named_tuple(Field<_names, EnumType>{_enums}...);
}
template <class EnumType, size_t N, StringLiteral... _names, auto... _enums>
auto names_to_underlying_enumerator_named_tuple(
Names<EnumType, Literal<_names...>, N, _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, StringLiteral... _names, auto... _enums>
constexpr std::array<std::pair<std::string_view, EnumType>, N>
names_to_enumerator_array(Names<EnumType, Literal<_names...>, N, _enums...>) {
return {
std::make_pair(LiteralHelper<_names>::field_.string_view(), _enums)...};
}
template <class EnumType, size_t N, 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, _enums...>) {
return {
std::make_pair(LiteralHelper<_names>::field_.string_view(),
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
}
} // namespace enums
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,132 @@
#ifndef RFL_INTERNAL_ENUMS_STRINGCONVERTER_HPP_
#define RFL_INTERNAL_ENUMS_STRINGCONVERTER_HPP_
#include <algorithm>
#include <array>
#include <string>
#include <string_view>
#include <type_traits>
#include "../../Result.hpp"
#include "../../internal/strings/join.hpp"
#include "../../internal/strings/split.hpp"
#include "../../type_name_t.hpp"
#include "get_enum_names.hpp"
#include "is_flag_enum.hpp"
namespace rfl {
namespace internal {
namespace enums {
template <class EnumType>
class StringConverter {
public:
static constexpr bool is_flag_enum_ = is_flag_enum<EnumType>;
static constexpr auto names_ = get_enum_names<EnumType, is_flag_enum_>();
using NamesLiteral = typename decltype(names_)::Literal;
public:
/// Transform an enum to a matching string.
static std::string enum_to_string(const EnumType _enum) {
if constexpr (is_flag_enum_) {
return flag_enum_to_string(_enum);
} else {
return enum_to_single_string(_enum);
}
}
/// Transforms a string to the matching enum.
static Result<EnumType> string_to_enum(const std::string& _str) {
static_assert(names_.size != 0,
"No enum could be identified. Please choose enum values "
"between 0 to 127 or for flag enums choose 1,2,4,8,16,...");
if constexpr (is_flag_enum_) {
return string_to_flag_enum(_str);
} else {
return single_string_to_enum(_str);
}
}
private:
/// Iterates through the enum bit by bit and matches it against the flags.
static std::string flag_enum_to_string(const EnumType _e) {
using T = std::underlying_type_t<EnumType>;
auto val = static_cast<T>(_e);
int i = 0;
std::vector<std::string> flags;
while (val != 0) {
const auto bit = val & static_cast<T>(1);
if (bit == 1) {
auto str = enum_to_single_string(
static_cast<EnumType>(static_cast<T>(1) << i));
flags.emplace_back(std::move(str));
}
++i;
val >>= 1;
}
return strings::join("|", flags);
}
/// This assumes that _enum can be exactly matched to one of the names and
/// does not have to be combined using |.
static std::string enum_to_single_string(const EnumType _enum) {
const auto to_str = [](const auto _l) { return _l.str(); };
for (size_t i = 0; i < names_.size; ++i) {
if (names_.enums_[i] == _enum) {
return NamesLiteral::from_value(
static_cast<typename NamesLiteral::ValueType>(i))
.transform(to_str)
.value();
}
}
return std::to_string(static_cast<std::underlying_type_t<EnumType>>(_enum));
}
/// Finds the enum matching the literal.
static EnumType literal_to_enum(const NamesLiteral _lit) noexcept {
return names_.enums_[_lit.value()];
}
/// This assumes that _enum can be exactly matched to one of the names and
/// does not have to be combined using |.
static Result<EnumType> single_string_to_enum(const std::string& _str) {
const auto r = NamesLiteral::from_string(_str).transform(literal_to_enum);
if (r) {
return r;
} else {
try {
return static_cast<EnumType>(std::stoi(_str));
} catch (std::exception& exp) {
return Error(exp.what());
}
}
}
/// Only relevant if this is a flag enum - combines the different matches
/// using |.
static Result<EnumType> string_to_flag_enum(
const std::string& _str) noexcept {
using T = std::underlying_type_t<EnumType>;
const auto split = strings::split(_str, "|");
auto res = static_cast<T>(0);
for (const auto& s : split) {
const auto r = single_string_to_enum(s);
if (r) {
res |= static_cast<T>(*r);
} else {
return r;
}
}
return static_cast<EnumType>(res);
}
};
} // namespace enums
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,151 @@
#ifndef RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
#define RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
#include <limits>
#include <source_location>
#include <type_traits>
#include "../../Literal.hpp"
#include "../../define_literal.hpp"
#include "../../internal/remove_namespaces.hpp"
#include "Names.hpp"
#include "is_scoped_enum.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.
namespace rfl {
namespace internal {
namespace enums {
template <auto e>
consteval auto get_enum_name_str_view() {
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
// Clang on Windows. For all other compilers, function_name works as intended.
#if defined(__clang__) && defined(_MSC_VER)
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
#else
const auto func_name =
std::string_view{std::source_location::current().function_name()};
#endif
#if defined(__clang__)
const auto split = func_name.substr(0, func_name.size() - 1);
return split.substr(split.find("e = ") + 4);
#elif defined(__GNUC__)
const auto split = func_name.substr(0, func_name.size() - 1);
return split.substr(split.find("e = ") + 4);
#elif defined(_MSC_VER)
const auto split = func_name.substr(0, func_name.size() - 7);
return split.substr(split.find("get_enum_name_str_view<") + 23);
#else
static_assert(false,
"You are using an unsupported compiler. Please use GCC, Clang "
"or MSVC or use rfl::Literal.");
#endif
}
template <auto e>
consteval auto get_enum_name() {
constexpr auto name = get_enum_name_str_view<e>();
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>
consteval T calc_greatest_power_of_two() {
if constexpr (std::is_signed_v<T>) {
return static_cast<T>(1) << (sizeof(T) * 8 - 2);
} else {
return static_cast<T>(1) << (sizeof(T) * 8 - 1);
}
}
template <class T, bool _is_flag>
consteval T get_max() {
if constexpr (_is_flag) {
return calc_greatest_power_of_two<T>();
} else {
return std::numeric_limits<T>::max() > 127 ? static_cast<T>(127)
: std::numeric_limits<T>::max();
}
}
template <class T, bool _is_flag, int _i>
consteval T calc_j() {
if constexpr (_is_flag) {
return static_cast<T>(1) << _i;
} else {
return static_cast<T>(_i);
}
}
template <class EnumType, class NamesType, auto _max, bool _is_flag, int _i>
consteval auto get_enum_names_impl() {
using T = std::underlying_type_t<EnumType>;
constexpr T j = calc_j<T, _is_flag, _i>();
constexpr auto name = get_enum_name<static_cast<EnumType>(j)>();
if constexpr (std::get<0>(name.arr_) == '(') {
if constexpr (j == _max) {
return NamesType{};
} else {
return get_enum_names_impl<EnumType, NamesType, _max, _is_flag, _i + 1>();
}
} else {
using NewNames = typename NamesType::template AddOneType<
Literal<remove_namespaces<name>()>, static_cast<EnumType>(j)>;
if constexpr (j == _max) {
return NewNames{};
} else {
return get_enum_names_impl<EnumType, NewNames, _max, _is_flag, _i + 1>();
}
}
}
template <class EnumType, bool _is_flag>
consteval auto get_enum_names() {
static_assert(is_scoped_enum<EnumType>,
"You must use scoped enums (using class or struct) for the "
"parsing to work!");
static_assert(std::is_integral_v<std::underlying_type_t<EnumType>>,
"The underlying type of any Enum must be integral!");
constexpr auto max = get_max<std::underlying_type_t<EnumType>, _is_flag>();
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
return get_enum_names_impl<EnumType, EmptyNames, max, _is_flag, 0>();
}
} // namespace enums
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,22 @@
#ifndef RFL_INTERNAL_ENUMS_IS_FLAG_ENUM_HPP_
#define RFL_INTERNAL_ENUMS_IS_FLAG_ENUM_HPP_
#include <concepts>
#include "is_scoped_enum.hpp"
namespace rfl {
namespace internal {
namespace enums {
template <class EnumType>
concept is_flag_enum = is_scoped_enum<EnumType> &&
requires(EnumType e1, EnumType e2) {
{ e1 | e2 } -> std::same_as<EnumType>;
};
} // namespace enums
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,19 @@
#ifndef RFL_INTERNAL_ENUMS_IS_SCOPED_ENUM_HPP_
#define RFL_INTERNAL_ENUMS_IS_SCOPED_ENUM_HPP_
#include <concepts>
#include <type_traits>
namespace rfl {
namespace internal {
namespace enums {
template <class EnumType>
concept is_scoped_enum = std::is_enum_v<EnumType> &&
!std::is_convertible_v<EnumType, std::underlying_type_t<EnumType>>;
} // namespace enums
} // namespace internal
} // namespace rfl
#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,20 @@
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
#include <functional>
#include <tuple>
#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,63 @@
#ifndef RFL_INTERNAL_FIELD_TYPE_HPP_
#define RFL_INTERNAL_FIELD_TYPE_HPP_
#include <tuple>
#include <type_traits>
#include <variant>
#include "../NamedTuple.hpp"
#include "../TaggedUnion.hpp"
#include "StringLiteral.hpp"
#include "find_index.hpp"
#include "../named_tuple_t.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 std::tuple_element<
field_ix_, typename NamedTupleType::Fields>::type::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,39 @@
#ifndef RFL_FIND_INDEX_HPP_
#define RFL_FIND_INDEX_HPP_
#include <tuple>
#include <type_traits>
#include "StringLiteral.hpp"
namespace rfl {
namespace internal {
/// Finds the index of the field signified by _field_name
template <StringLiteral _field_name, class Fields, int I = 0>
constexpr static int find_index() {
using FieldType =
std::remove_cvref_t<typename std::tuple_element<I, Fields>::type>;
constexpr bool name_i_matches = (FieldType::name_ == _field_name);
if constexpr (name_i_matches) {
return I;
} else {
constexpr bool out_of_range = I + 1 == std::tuple_size_v<Fields>;
static_assert(!out_of_range, "Field name not found!");
if constexpr (out_of_range) {
// This is to avoid very confusing error messages.
return I;
} else {
return find_index<_field_name, Fields, I + 1>();
}
}
}
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,19 @@
#ifndef RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
#define RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
#include <functional>
#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,22 @@
#ifndef RFL_INTERNAL_FLATTENED_TUPLE_T_HPP_
#define RFL_INTERNAL_FLATTENED_TUPLE_T_HPP_
#include <functional>
#include <tuple>
#include <type_traits>
#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,156 @@
#ifndef RFL_INTERNAL_GETFIELDNAMES_HPP_
#define RFL_INTERNAL_GETFIELDNAMES_HPP_
#include <array>
#include <iostream>
#include <memory>
#include <source_location>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../Literal.hpp"
#include "bind_fake_object_to_tuple.hpp"
#include "get_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() {
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
// Clang on Windows. For all other compilers, function_name works as intended.
#if defined(__clang__) && defined(_MSC_VER)
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
#else
const auto func_name =
std::string_view{std::source_location::current().function_name()};
#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>()>();
}
}
template <StringLiteral... _names1, StringLiteral... _names2>
auto concat_two_literals(const rfl::Literal<_names1...>& _lit1,
const rfl::Literal<_names2...>& _lit2) {
return rfl::Literal<_names1..., _names2...>::template from_value<0>();
}
template <class Head, class... Tail>
auto concat_literals(const Head& _head, const Tail&... _tail) {
if constexpr (sizeof...(_tail) == 0) {
return _head;
} else {
return concat_two_literals(_head, concat_literals(_tail...));
}
}
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(std::get<Is>(
bind_fake_object_to_tuple<T>()))>()...);
};
#else
const auto get = []<std::size_t... Is>(std::index_sequence<Is...>) {
return concat_literals(
get_field_name<Type,
std::get<Is>(bind_fake_object_to_tuple<T>())>()...);
};
#endif
return get(std::make_index_sequence<num_fields<T>>());
}
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} // namespace rfl::internal
#endif

View file

@ -0,0 +1,32 @@
#ifndef RFL_INTERNAL_GETMETAFIELDS_HPP_
#define RFL_INTERNAL_GETMETAFIELDS_HPP_
#include <array>
#include <tuple>
#include <utility>
#include "../MetaField.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 = std::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,57 @@
#ifndef RFL_INTERNAL_GETTYPENAME_HPP_
#define RFL_INTERNAL_GETTYPENAME_HPP_
#include <source_location>
#include <string>
#include <utility>
namespace rfl {
namespace internal {
template <class T>
consteval auto get_type_name_str_view() {
// Unfortunately, we cannot avoid the use of a compiler-specific macro for
// Clang on Windows. For all other compilers, function_name works as intended.
#if defined(__clang__) && defined(_MSC_VER)
const auto func_name = std::string_view{__PRETTY_FUNCTION__};
#else
const auto func_name =
std::string_view{std::source_location::current().function_name()};
#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,71 @@
#ifndef RFL_INTERNAL_HASFIELDS_HPP_
#define RFL_INTERNAL_HASFIELDS_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#include "all_fields.hpp"
#include "is_field.hpp"
#include "is_flatten_field.hpp"
#include "ptr_tuple_t.hpp"
namespace rfl {
namespace internal {
template <class TupleType, int _i = 0>
constexpr bool all_fields_or_flatten() {
if constexpr (_i == std::tuple_size_v<TupleType>) {
return true;
} else {
using T = std::remove_cvref_t<std::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>>() &&
all_fields_or_flatten<TupleType, _i + 1>();
} else {
return is_field_v<T> && all_fields_or_flatten<TupleType, _i + 1>();
}
}
}
template <class TupleType, int _i = 0>
constexpr bool some_fields_or_flatten() {
if constexpr (_i == std::tuple_size_v<TupleType>) {
return false;
} else {
using T = std::remove_cvref_t<std::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>>() ||
some_fields_or_flatten<TupleType, _i + 1>();
} else {
return is_field_v<T> || some_fields_or_flatten<TupleType, _i + 1>();
}
}
}
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,26 @@
#ifndef RFL_INTERNAL_HASFLATTENFIELDS_HPP_
#define RFL_INTERNAL_HASFLATTENFIELDS_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#include "is_flatten_field.hpp"
namespace rfl {
namespace internal {
template <class TupleType, int _i = 0>
constexpr bool has_flatten_fields() {
if constexpr (_i == std::tuple_size_v<TupleType>) {
return false;
} else {
using T = std::remove_cvref_t<std::tuple_element_t<_i, TupleType>>;
return is_flatten_field_v<T> || has_flatten_fields<TupleType, _i + 1>();
}
}
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,29 @@
#ifndef RFL_INTERNAL_HASREFLECTIONMETHODV_HPP_
#define RFL_INTERNAL_HASREFLECTIONMETHODV_HPP_
#include <type_traits>
namespace rfl {
namespace internal {
template <typename Wrapper>
using reflection_method_t =
decltype(std::declval<const Wrapper>().reflection());
template <typename Wrapper, typename = std::void_t<>>
struct has_refl_m : std::false_type {};
template <typename Wrapper>
struct has_refl_m<Wrapper, std::void_t<reflection_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 "reflection".
template <typename Wrapper>
constexpr bool has_reflection_method_v = has_refl_m<Wrapper>::value;
} // namespace internal
} // namespace rfl
#endif

View file

@ -0,0 +1,33 @@
#ifndef RFL_HASREFLECTIONTYPEV_HPP_
#define RFL_HASREFLECTIONTYPEV_HPP_
#include <cstdint>
#include <utility>
namespace rfl {
namespace internal {
template <class Wrapper>
class HasReflectionType {
private:
template <class U>
static std::int64_t foo(...);
template <class U>
static std::int32_t foo(typename U::ReflectionType*);
public:
static constexpr bool value =
sizeof(foo<Wrapper>(nullptr)) == sizeof(std::int32_t);
};
/// Utility parameter for named tuple parsing, can be used by the
/// parsers to determine whether a class or struct defines a type
/// called "ReflectionType".
template <typename Wrapper>
constexpr bool has_reflection_type_v = HasReflectionType<Wrapper>::value;
} // namespace internal
} // namespace rfl
#endif // RFL_HASNAMEDTUPLETYPEV_HPP_

View file

@ -0,0 +1,31 @@
#ifndef RFL_HASTAGV_HPP_
#define RFL_HASTAGV_HPP_
#include <cstdint>
#include <utility>
namespace rfl {
namespace internal {
template <class Wrapper>
class HasTag {
private:
template <class U>
static std::int64_t foo(...);
template <class U>
static std::int32_t foo(typename U::Tag*);
public:
static constexpr bool value =
sizeof(foo<Wrapper>(nullptr)) == sizeof(std::int32_t);
};
/// Used for tagged unions - determines whether a struct as a Tag.
template <typename Wrapper>
constexpr bool has_tag_v = HasTag<Wrapper>::value;
} // namespace internal
} // namespace rfl
#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,27 @@
#ifndef RFL_INTERNAL_ISARRAY_HPP_
#define RFL_INTERNAL_ISARRAY_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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,31 @@
#ifndef RFL_INTERNAL_ISATTRIBUTE_HPP_
#define RFL_INTERNAL_ISATTRIBUTE_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#include "../Attribute.hpp"
#include "../Field.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<std::remove_cvref_t<std::remove_pointer_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,30 @@
#ifndef RFL_INTERNAL_ISDESCRIPTION_HPP_
#define RFL_INTERNAL_ISDESCRIPTION_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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,24 @@
#ifndef RFL_INTERNAL_ISEMPTY_HPP_
#define RFL_INTERNAL_ISEMPTY_HPP_
#include <tuple>
#include <type_traits>
#include "is_named_tuple.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 std::tuple_size_v<TupleType> == 0;
}
}
} // namespace rfl::internal
#endif

View file

@ -0,0 +1,30 @@
#ifndef RFL_INTERNAL_ISFIELD_HPP_
#define RFL_INTERNAL_ISFIELD_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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,29 @@
#ifndef RFL_INTERNAL_ISFLATTENFIELD_HPP_
#define RFL_INTERNAL_ISFLATTENFIELD_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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,29 @@
#ifndef RFL_INTERNAL_ISNOOPTIONALS_HPP_
#define RFL_INTERNAL_ISNOOPTIONALS_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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,30 @@
#ifndef RFL_INTERNAL_ISRENAME_HPP_
#define RFL_INTERNAL_ISRENAME_HPP_
#include <tuple>
#include <type_traits>
#include <utility>
#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

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