:3
This commit is contained in:
parent
a743cdabe5
commit
bd402f57f5
276 changed files with 37936 additions and 22932 deletions
|
@ -8,26 +8,26 @@
|
|||
#include "to_std_array.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
requires std::is_array_v<T>
|
||||
struct Array {
|
||||
using Type = T;
|
||||
using StdArrayType = to_std_array_t<T>;
|
||||
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;
|
||||
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;
|
||||
~Array() = default;
|
||||
|
||||
StdArrayType arr_;
|
||||
};
|
||||
StdArrayType arr_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
#include "copy_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
|
||||
}
|
||||
} // namespace rfl
|
||||
}
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
#include <unordered_map>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <int N>
|
||||
struct Fields {
|
||||
std::array<std::string, N> names_;
|
||||
template <int N>
|
||||
struct Fields {
|
||||
std::array<std::string, N> names_;
|
||||
|
||||
std::unordered_map<std::string_view, std::int16_t> indices_;
|
||||
};
|
||||
std::unordered_map<std::string_view, std::int16_t> indices_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,148 +9,148 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <class NamedTupleType>
|
||||
struct Getter;
|
||||
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());
|
||||
}
|
||||
/// 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 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);
|
||||
}
|
||||
/// 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());
|
||||
}
|
||||
/// 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 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);
|
||||
}
|
||||
};
|
||||
/// 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);
|
||||
}
|
||||
/// 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 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);
|
||||
}
|
||||
/// 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);
|
||||
}
|
||||
/// 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 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);
|
||||
}
|
||||
};
|
||||
/// 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
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
#include "../Result.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Class, typename T>
|
||||
concept HasValidation = requires(Class obj, T value) {
|
||||
{ Class::validate(value) } -> std::same_as<rfl::Result<T>>;
|
||||
};
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,49 +5,45 @@
|
|||
#include <mutex>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// For a thread-safe memoization pattern.
|
||||
template <class T>
|
||||
class Memoization {
|
||||
public:
|
||||
Memoization() { flag_.clear(); }
|
||||
/// For a thread-safe memoization pattern.
|
||||
template <class T>
|
||||
class Memoization {
|
||||
public:
|
||||
Memoization() { flag_.clear(); }
|
||||
|
||||
~Memoization() = default;
|
||||
~Memoization() = default;
|
||||
|
||||
public:
|
||||
/// Returns the underlying value.
|
||||
template <class F>
|
||||
const T& value(const F& _f) {
|
||||
if (flag_.test()) {
|
||||
return value_;
|
||||
}
|
||||
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_);
|
||||
std::lock_guard<std::mutex> guard(mtx_);
|
||||
|
||||
if (flag_.test()) {
|
||||
return value_;
|
||||
}
|
||||
if (flag_.test()) { return value_; }
|
||||
|
||||
_f(&value_);
|
||||
_f(&value_);
|
||||
|
||||
flag_.test_and_set();
|
||||
flag_.test_and_set();
|
||||
|
||||
return value_;
|
||||
}
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Signifies whether t_ has been set.
|
||||
std::atomic_flag flag_;
|
||||
private:
|
||||
/// Signifies whether t_ has been set.
|
||||
std::atomic_flag flag_;
|
||||
|
||||
/// A mutex, only needed for writing.
|
||||
std::mutex mtx_;
|
||||
/// A mutex, only needed for writing.
|
||||
std::mutex mtx_;
|
||||
|
||||
/// The type to be initialized.
|
||||
T value_;
|
||||
};
|
||||
/// The type to be initialized.
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,142 +5,147 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class T, bool _skip_serialization, bool _skip_deserialization>
|
||||
class Skip {
|
||||
private:
|
||||
using SelfType = Skip<T, _skip_serialization, _skip_deserialization>;
|
||||
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;
|
||||
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>;
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
using ReflectionType = std::optional<T>;
|
||||
|
||||
Skip() : value_(Type()) {}
|
||||
Skip() : value_(Type()) {}
|
||||
|
||||
Skip(const Type& _value) : value_(_value) {}
|
||||
Skip(const Type& _value) : value_(_value) {}
|
||||
|
||||
Skip(ReflectionType&& _value) noexcept
|
||||
: value_(_value ? std::move(*_value) : Type()) {}
|
||||
Skip(ReflectionType&& _value) noexcept
|
||||
: value_(_value ? std::move(*_value) : Type()) {}
|
||||
|
||||
Skip(const ReflectionType& _value) : value_(_value ? *_value : Type()) {}
|
||||
Skip(const ReflectionType& _value) : value_(_value ? *_value : Type()) {}
|
||||
|
||||
Skip(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
Skip(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Skip(SelfType&& _skip) noexcept = default;
|
||||
Skip(SelfType&& _skip) noexcept = default;
|
||||
|
||||
Skip(const SelfType& _skip) = 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(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, 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(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,
|
||||
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()) {}
|
||||
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()) {}
|
||||
/// 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;
|
||||
~Skip() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& get() { return value_; }
|
||||
/// Returns the underlying object.
|
||||
Type& get() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { 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=(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.
|
||||
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.
|
||||
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 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=(const SelfType& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
SelfType& operator=(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=(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;
|
||||
}
|
||||
/// 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_; }
|
||||
/// 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(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_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.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
private:
|
||||
/// The underlying value
|
||||
T value_;
|
||||
};
|
||||
private:
|
||||
/// The underlying value
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,48 +7,46 @@
|
|||
#include <string_view>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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'} {}
|
||||
/// 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 std::array<char, N> _arr) : arr_(_arr) {}
|
||||
|
||||
constexpr StringLiteral(const char (&_str)[N]) {
|
||||
std::copy_n(_str, N, std::data(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.
|
||||
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);
|
||||
}
|
||||
/// 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_{};
|
||||
};
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,28 +2,29 @@
|
|||
#define RFL_INTERNAL_VISITTREE_HPP_
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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) {
|
||||
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...);
|
||||
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...);
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,22 +6,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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 {
|
||||
/// 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_;
|
||||
};
|
||||
/// The underlying visitor.
|
||||
const Visitor* visitor_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_VISIT_HPP_
|
||||
#endif // RFL_VISIT_HPP_
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
#include "is_field.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class TupleType, int _i = 0>
|
||||
constexpr bool all_fields() {
|
||||
if constexpr (_i == std::tuple_size_v<TupleType>) {
|
||||
template <class TupleType, int _i = 0>
|
||||
constexpr bool all_fields() {
|
||||
if constexpr (_i == std::tuple_size_v<TupleType>) {
|
||||
return true;
|
||||
} else {
|
||||
} else {
|
||||
using T = std::tuple_element_t<_i, TupleType>;
|
||||
return is_field_v<T> && all_fields<TupleType, _i + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -6,31 +6,31 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "../Field.hpp"
|
||||
#include "lit_name.hpp"
|
||||
#include "../make_named_tuple.hpp"
|
||||
#include "lit_name.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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));
|
||||
}
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
#include "move_from_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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));
|
||||
}
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
#include "move_from_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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));
|
||||
}
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
#include "move_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
auto copy_to_field_tuple(const T& _t) {
|
||||
auto t = _t;
|
||||
return move_to_field_tuple(std::move(t));
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,26 +4,30 @@
|
|||
#include "../Literal.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several literals.
|
||||
template <class... LiteralTypes>
|
||||
struct define_literal;
|
||||
/// 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;
|
||||
};
|
||||
/// 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...>;
|
||||
};
|
||||
/// Special case - only a single literal is left
|
||||
template <StringLiteral... _content>
|
||||
struct define_literal<Literal<_content...>> {
|
||||
using type = Literal<_content...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,43 +4,45 @@
|
|||
#include "../NamedTuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class... FieldTypes>
|
||||
struct define_named_tuple;
|
||||
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 - 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 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.
|
||||
/// 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...>;
|
||||
};
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,53 +5,64 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several tagged unions.
|
||||
template <StringLiteral _discriminator, class... TaggedUnionTypes>
|
||||
struct define_tagged_union;
|
||||
/// 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<
|
||||
/// 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, NamedTupleTypes1..., NamedTupleTypes2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
||||
using type = TaggedUnion<_discriminator, NamedTupleTypes...>;
|
||||
};
|
||||
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,39 +4,41 @@
|
|||
#include <variant>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several variants.
|
||||
template <class... Vars>
|
||||
struct define_variant;
|
||||
/// 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 - 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 - 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;
|
||||
};
|
||||
/// 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...>;
|
||||
};
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,63 +14,82 @@
|
|||
#include "../StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
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;
|
||||
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;
|
||||
/// 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...};
|
||||
/// 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.");
|
||||
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 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_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>
|
||||
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, 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))...};
|
||||
}
|
||||
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
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,118 +15,121 @@
|
|||
#include "is_flag_enum.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
|
||||
template <class EnumType>
|
||||
class StringConverter {
|
||||
public:
|
||||
static constexpr bool is_flag_enum_ = is_flag_enum<EnumType>;
|
||||
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_>();
|
||||
static constexpr auto names_ =
|
||||
get_enum_names<EnumType, is_flag_enum_>();
|
||||
|
||||
using NamesLiteral = typename decltype(names_)::Literal;
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
/// 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);
|
||||
}
|
||||
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(); };
|
||||
/// 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();
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
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()];
|
||||
}
|
||||
/// 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 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);
|
||||
}
|
||||
};
|
||||
/// 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
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,116 +36,127 @@
|
|||
// defined.
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
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.
|
||||
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__};
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
const auto func_name =
|
||||
std::string_view{std::source_location::current().function_name()};
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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.");
|
||||
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 <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>
|
||||
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>
|
||||
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 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>;
|
||||
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 T j = calc_j<T, _is_flag, _i>();
|
||||
|
||||
constexpr auto name = get_enum_name<static_cast<EnumType>(j)>();
|
||||
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 (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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
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!");
|
||||
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!");
|
||||
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>();
|
||||
constexpr auto max =
|
||||
get_max<std::underlying_type_t<EnumType>, _is_flag>();
|
||||
|
||||
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
|
||||
using EmptyNames = Names<EnumType, rfl::Literal<"">, 0>;
|
||||
|
||||
return get_enum_names_impl<EnumType, EmptyNames, max, _is_flag, 0>();
|
||||
}
|
||||
return get_enum_names_impl<EnumType, EmptyNames, max, _is_flag, 0>();
|
||||
}
|
||||
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
#include "is_scoped_enum.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
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>;
|
||||
};
|
||||
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
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace enums {
|
||||
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>>;
|
||||
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
|
||||
} // namespace enums
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,18 +8,19 @@
|
|||
#include "../field_type.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class TaggedUnionType>
|
||||
struct extract_discriminators;
|
||||
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>>...>;
|
||||
};
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
#include "copy_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
|
||||
}
|
||||
} // namespace rfl
|
||||
}
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,57 +7,62 @@
|
|||
|
||||
#include "../NamedTuple.hpp"
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
#include "find_index.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T, class... Ts>
|
||||
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
|
||||
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;
|
||||
/// 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>;
|
||||
/// 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>();
|
||||
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;
|
||||
};
|
||||
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>...>;
|
||||
/// 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.");
|
||||
static_assert(all_types_match, "All field types must be the same.");
|
||||
|
||||
using Type = typename FieldType<_field_name, FirstAlternativeType>::Type;
|
||||
};
|
||||
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;
|
||||
};
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,33 +7,33 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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>;
|
||||
/// 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);
|
||||
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>;
|
||||
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!");
|
||||
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>();
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
#include "to_flattened_ptr_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using flattened_ptr_tuple_t =
|
||||
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>), T>::type;
|
||||
template <class T>
|
||||
using flattened_ptr_tuple_t =
|
||||
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>),
|
||||
T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "flattened_ptr_tuple_t.hpp"
|
||||
#include "remove_ptrs_tup.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using flattened_tuple_t =
|
||||
typename remove_ptrs_tup<flattened_ptr_tuple_t<T>>::TupleType;
|
||||
template <class T>
|
||||
using flattened_tuple_t =
|
||||
typename remove_ptrs_tup<flattened_ptr_tuple_t<T>>::TupleType;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define RFL_INTERNAL_GETFAKEOBJECT_HPP_
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
#if __GNUC__
|
||||
#ifndef __clang__
|
||||
|
@ -21,16 +21,16 @@ namespace internal {
|
|||
#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>
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
@ -40,7 +40,7 @@ consteval const T& get_fake_object() noexcept {
|
|||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,93 +25,95 @@
|
|||
|
||||
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]...};
|
||||
template <class T>
|
||||
struct Wrapper {
|
||||
using Type = T;
|
||||
T v;
|
||||
};
|
||||
return to_str_lit(std::make_index_sequence<name.size()>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto get_field_names();
|
||||
template <class T>
|
||||
Wrapper(T) -> Wrapper<T>;
|
||||
|
||||
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>>;
|
||||
// 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
|
||||
using Type = std::remove_cvref_t<std::remove_pointer_t<decltype(ptr)>>;
|
||||
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
|
||||
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...));
|
||||
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()> {});
|
||||
}
|
||||
}
|
||||
|
||||
inline auto concat_literals() { return rfl::Literal<>(); }
|
||||
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
|
||||
|
@ -119,38 +121,38 @@ inline auto concat_literals() { return rfl::Literal<>(); }
|
|||
#pragma clang diagnostic ignored "-Wundefined-inline"
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
template <class T>
|
||||
#if __GNUC__
|
||||
#ifndef __clang__
|
||||
[[gnu::no_sanitize_undefined]]
|
||||
[[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 {
|
||||
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>()))>()...);
|
||||
};
|
||||
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>())>()...);
|
||||
};
|
||||
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>>());
|
||||
return get(std::make_index_sequence<num_fields<T>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,24 +9,25 @@
|
|||
#include "../type_name_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,52 +6,51 @@
|
|||
#include <utility>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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.
|
||||
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__};
|
||||
const auto func_name = std::string_view {__PRETTY_FUNCTION__};
|
||||
#else
|
||||
const auto func_name =
|
||||
std::string_view{std::source_location::current().function_name()};
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
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'.");
|
||||
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()>{});
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,61 +11,61 @@
|
|||
#include "ptr_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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 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 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;
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
#include "is_flatten_field.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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>();
|
||||
}
|
||||
}
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,26 +4,26 @@
|
|||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <typename Wrapper>
|
||||
using reflection_method_t =
|
||||
decltype(std::declval<const Wrapper>().reflection());
|
||||
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, 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 {};
|
||||
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;
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,29 +5,29 @@
|
|||
#include <utility>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Wrapper>
|
||||
class HasReflectionType {
|
||||
private:
|
||||
template <class U>
|
||||
static std::int64_t foo(...);
|
||||
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*);
|
||||
template <class U>
|
||||
static std::int32_t foo(typename U::ReflectionType*);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
sizeof(foo<Wrapper>(nullptr)) == sizeof(std::int32_t);
|
||||
};
|
||||
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;
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_HASNAMEDTUPLETYPEV_HPP_
|
||||
#endif // RFL_HASNAMEDTUPLETYPEV_HPP_
|
||||
|
|
|
@ -5,27 +5,27 @@
|
|||
#include <utility>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Wrapper>
|
||||
class HasTag {
|
||||
private:
|
||||
template <class U>
|
||||
static std::int64_t foo(...);
|
||||
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*);
|
||||
template <class U>
|
||||
static std::int32_t foo(typename U::Tag*);
|
||||
|
||||
public:
|
||||
static constexpr bool value =
|
||||
sizeof(foo<Wrapper>(nullptr)) == sizeof(std::int32_t);
|
||||
};
|
||||
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;
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,25 +4,26 @@
|
|||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <typename Wrapper>
|
||||
using to_class_method_t = decltype(std::declval<const Wrapper>().to_class());
|
||||
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, 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 {};
|
||||
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;
|
||||
/// 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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,19 +9,19 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class T>
|
||||
class is_array;
|
||||
template <class T>
|
||||
class is_array;
|
||||
|
||||
template <class T>
|
||||
class is_array : public std::false_type {};
|
||||
template <class T>
|
||||
class is_array : public std::false_type {};
|
||||
|
||||
template <class Type>
|
||||
class is_array<Array<Type>> : public std::true_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;
|
||||
template <class T>
|
||||
constexpr bool is_array_v =
|
||||
is_array<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,22 +10,22 @@
|
|||
|
||||
namespace rfl {
|
||||
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_attribute;
|
||||
template <class T>
|
||||
class is_attribute;
|
||||
|
||||
template <class T>
|
||||
class is_attribute : public std::false_type {};
|
||||
template <class T>
|
||||
class is_attribute : public std::false_type {};
|
||||
|
||||
template <class Type>
|
||||
class is_attribute<Attribute<Type>> : public std::true_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;
|
||||
template <class T>
|
||||
constexpr bool is_attribute_v =
|
||||
is_attribute<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
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>();
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,22 +9,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_description;
|
||||
template <class T>
|
||||
class is_description;
|
||||
|
||||
template <class T>
|
||||
class is_description : public std::false_type {};
|
||||
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 <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;
|
||||
template <class T>
|
||||
constexpr bool is_description_v =
|
||||
is_description<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
|
||||
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;
|
||||
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
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,22 +9,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_field;
|
||||
template <class T>
|
||||
class is_field;
|
||||
|
||||
template <class T>
|
||||
class is_field : public std::false_type {};
|
||||
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 <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;
|
||||
template <class T>
|
||||
constexpr bool is_field_v =
|
||||
is_field<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
#include "../Flatten.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_flatten_field;
|
||||
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 : public std::false_type {};
|
||||
|
||||
template <class T>
|
||||
class is_flatten_field<Flatten<T>> : public std::true_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;
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_literal;
|
||||
template <class T>
|
||||
class is_literal;
|
||||
|
||||
template <class T>
|
||||
class is_literal : public std::false_type {};
|
||||
template <class T>
|
||||
class is_literal : public std::false_type {};
|
||||
|
||||
template <StringLiteral... _s>
|
||||
class is_literal<Literal<_s...>> : public std::true_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;
|
||||
template <class T>
|
||||
constexpr bool is_literal_v =
|
||||
is_literal<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,22 +6,22 @@
|
|||
#include "../NamedTuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_named_tuple;
|
||||
template <class T>
|
||||
class is_named_tuple;
|
||||
|
||||
template <class T>
|
||||
class is_named_tuple : public std::false_type {};
|
||||
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... 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;
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
#include "../NoOptionals.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_no_optionals;
|
||||
template <class T>
|
||||
class is_no_optionals;
|
||||
|
||||
template <class T>
|
||||
class is_no_optionals : public std::false_type {};
|
||||
template <class T>
|
||||
class is_no_optionals : public std::false_type {};
|
||||
|
||||
template <>
|
||||
class is_no_optionals<NoOptionals> : public std::true_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;
|
||||
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
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_pattern;
|
||||
template <class T>
|
||||
class is_pattern;
|
||||
|
||||
template <class T>
|
||||
class is_pattern : public std::false_type {};
|
||||
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 <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;
|
||||
template <class T>
|
||||
constexpr bool is_pattern_v =
|
||||
is_pattern<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,22 +9,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_rename;
|
||||
template <class T>
|
||||
class is_rename;
|
||||
|
||||
template <class T>
|
||||
class is_rename : public std::false_type {};
|
||||
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 <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;
|
||||
template <class T>
|
||||
constexpr bool is_rename_v =
|
||||
is_rename<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,20 +7,20 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class T>
|
||||
class is_skip;
|
||||
template <class T>
|
||||
class is_skip;
|
||||
|
||||
template <class T>
|
||||
class is_skip : public std::false_type {};
|
||||
template <class T>
|
||||
class is_skip : public std::false_type {};
|
||||
|
||||
template <class T, bool _skip_serialization, bool _skip_deserialization>
|
||||
class is_skip<Skip<T, _skip_serialization, _skip_deserialization>>
|
||||
: public std::true_type {};
|
||||
template <class T, bool _skip_serialization, bool _skip_deserialization>
|
||||
class is_skip<Skip<T, _skip_serialization, _skip_deserialization>>
|
||||
: public std::true_type {};
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_skip_v =
|
||||
is_skip<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
template <class T>
|
||||
constexpr bool is_skip_v =
|
||||
is_skip<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_validator;
|
||||
template <class T>
|
||||
class is_validator;
|
||||
|
||||
template <class T>
|
||||
class is_validator : public std::false_type {};
|
||||
template <class T>
|
||||
class is_validator : public std::false_type {};
|
||||
|
||||
template <class T, class V, class... Vs>
|
||||
class is_validator<Validator<T, V, Vs...>> : public std::true_type {};
|
||||
template <class T, class V, class... Vs>
|
||||
class is_validator<Validator<T, V, Vs...>> : public std::true_type {};
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_validator_v =
|
||||
is_validator<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
template <class T>
|
||||
constexpr bool is_validator_v =
|
||||
is_validator<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,22 +5,22 @@
|
|||
#include <variant>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
class is_variant;
|
||||
template <class T>
|
||||
class is_variant;
|
||||
|
||||
template <class T>
|
||||
class is_variant : public std::false_type {};
|
||||
template <class T>
|
||||
class is_variant : public std::false_type {};
|
||||
|
||||
template <class... T>
|
||||
class is_variant<std::variant<T...>> : public std::true_type {};
|
||||
template <class... T>
|
||||
class is_variant<std::variant<T...>> : public std::true_type {};
|
||||
|
||||
template <class T>
|
||||
constexpr bool is_variant_v =
|
||||
is_variant<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
template <class T>
|
||||
constexpr bool is_variant_v =
|
||||
is_variant<std::remove_cvref_t<std::remove_pointer_t<T>>>::value;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
#include "../Literal.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
struct lit_name;
|
||||
template <class T>
|
||||
struct lit_name;
|
||||
|
||||
template <auto _name>
|
||||
struct lit_name<rfl::Literal<_name>> {
|
||||
constexpr static auto name_ = _name;
|
||||
};
|
||||
template <auto _name>
|
||||
struct lit_name<rfl::Literal<_name>> {
|
||||
constexpr static auto name_ = _name;
|
||||
};
|
||||
|
||||
template <class LiteralType>
|
||||
constexpr auto lit_name_v = lit_name<LiteralType>::name_;
|
||||
template <class LiteralType>
|
||||
constexpr auto lit_name_v = lit_name<LiteralType>::name_;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,22 +13,22 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <internal::StringLiteral _discriminator, class T>
|
||||
static inline auto make_tag(const T& _t) noexcept {
|
||||
if constexpr (internal::has_reflection_type_v<T>) {
|
||||
return make_tag<typename T::ReflectionType>();
|
||||
} else if constexpr (named_tuple_t<T>::Names::template contains<
|
||||
_discriminator>()) {
|
||||
return *to_view(_t).template get<_discriminator>();
|
||||
} else if constexpr (internal::has_tag_v<T>) {
|
||||
using LiteralType = typename T::Tag;
|
||||
return LiteralType::template name_of<0>();
|
||||
} else {
|
||||
return rfl::Literal<
|
||||
internal::remove_namespaces<internal::get_type_name<T>()>()>();
|
||||
template <internal::StringLiteral _discriminator, class T>
|
||||
static inline auto make_tag(const T& _t) noexcept {
|
||||
if constexpr (internal::has_reflection_type_v<T>) {
|
||||
return make_tag<typename T::ReflectionType>();
|
||||
} else if constexpr (named_tuple_t<T>::Names::template contains<
|
||||
_discriminator>()) {
|
||||
return *to_view(_t).template get<_discriminator>();
|
||||
} else if constexpr (internal::has_tag_v<T>) {
|
||||
using LiteralType = typename T::Tag;
|
||||
return LiteralType::template name_of<0>();
|
||||
} else {
|
||||
return rfl::Literal<
|
||||
internal::remove_namespaces<internal::get_type_name<T>()>()>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,29 +7,29 @@
|
|||
#include "move_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class FieldTuple, class... Args>
|
||||
auto move_and_flatten_field_tuple(FieldTuple&& _t, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<FieldTuple>>) {
|
||||
return std::tuple_cat(std::move(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<FieldTuple>>;
|
||||
if constexpr (is_flatten_field<T>::value) {
|
||||
return move_and_flatten_field_tuple(
|
||||
std::move(_t), std::move(_args)...,
|
||||
move_and_flatten_field_tuple(
|
||||
move_to_field_tuple(std::move(std::get<i>(_t).value_))));
|
||||
} else {
|
||||
return move_and_flatten_field_tuple(
|
||||
std::move(_t), std::move(_args)...,
|
||||
std::make_tuple(std::move(std::get<i>(_t))));
|
||||
template <class FieldTuple, class... Args>
|
||||
auto move_and_flatten_field_tuple(FieldTuple&& _t, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<FieldTuple>>) {
|
||||
return std::tuple_cat(std::move(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<FieldTuple>>;
|
||||
if constexpr (is_flatten_field<T>::value) {
|
||||
return move_and_flatten_field_tuple(
|
||||
std::move(_t), std::move(_args)...,
|
||||
move_and_flatten_field_tuple(
|
||||
move_to_field_tuple(std::move(std::get<i>(_t).value_))));
|
||||
} else {
|
||||
return move_and_flatten_field_tuple(
|
||||
std::move(_t), std::move(_args)...,
|
||||
std::make_tuple(std::move(std::get<i>(_t))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,24 +9,24 @@
|
|||
#include "move_and_flatten_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class FieldTuple>
|
||||
auto move_field_tuple_to_named_tuple(FieldTuple&& _field_tuple) {
|
||||
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
|
||||
return make_named_tuple(std::move(_fields)...);
|
||||
};
|
||||
template <class FieldTuple>
|
||||
auto move_field_tuple_to_named_tuple(FieldTuple&& _field_tuple) {
|
||||
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
|
||||
return make_named_tuple(std::move(_fields)...);
|
||||
};
|
||||
|
||||
if constexpr (!has_flatten_fields<std::remove_cvref_t<FieldTuple>>()) {
|
||||
return std::apply(ft_to_nt, std::move(_field_tuple));
|
||||
} else {
|
||||
auto flattened_tuple =
|
||||
move_and_flatten_field_tuple(std::move(_field_tuple));
|
||||
return std::apply(ft_to_nt, std::move(flattened_tuple));
|
||||
}
|
||||
}
|
||||
if constexpr (!has_flatten_fields<std::remove_cvref_t<FieldTuple>>()) {
|
||||
return std::apply(ft_to_nt, std::move(_field_tuple));
|
||||
} else {
|
||||
auto flattened_tuple =
|
||||
move_and_flatten_field_tuple(std::move(_field_tuple));
|
||||
return std::apply(ft_to_nt, std::move(flattened_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,102 +4,106 @@
|
|||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../named_tuple_t.hpp"
|
||||
#include "is_field.hpp"
|
||||
#include "is_named_tuple.hpp"
|
||||
#include "nt_to_ptr_named_tuple.hpp"
|
||||
#include "ptr_field_tuple_t.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class PtrFieldTupleType, class PtrNamedTupleType, class... Args>
|
||||
auto make_ptr_fields(PtrNamedTupleType& _n, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
template <class PtrFieldTupleType, class PtrNamedTupleType, class... Args>
|
||||
auto make_ptr_fields(PtrNamedTupleType& _n, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrFieldTupleType>>;
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrFieldTupleType>>;
|
||||
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_args...);
|
||||
} else {
|
||||
using Field =
|
||||
std::remove_cvref_t<std::tuple_element_t<i, PtrFieldTupleType>>;
|
||||
using T = std::remove_cvref_t<std::remove_pointer_t<typename Field::Type>>;
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_args...);
|
||||
} else {
|
||||
using Field =
|
||||
std::remove_cvref_t<std::tuple_element_t<i, PtrFieldTupleType>>;
|
||||
using T =
|
||||
std::remove_cvref_t<std::remove_pointer_t<typename Field::Type>>;
|
||||
|
||||
if constexpr (is_named_tuple_v<T>) {
|
||||
using SubPtrNamedTupleType =
|
||||
typename std::invoke_result<decltype(nt_to_ptr_named_tuple<T>),
|
||||
T>::type;
|
||||
if constexpr (is_named_tuple_v<T>) {
|
||||
using SubPtrNamedTupleType =
|
||||
typename std::invoke_result<decltype(nt_to_ptr_named_tuple<T>),
|
||||
T>::type;
|
||||
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., SubPtrNamedTupleType(_n).fields());
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., SubPtrNamedTupleType(_n).fields());
|
||||
|
||||
} else if constexpr (is_flatten_field<Field>::value) {
|
||||
using SubPtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
} else if constexpr (is_flatten_field<Field>::value) {
|
||||
using SubPtrFieldTupleType =
|
||||
std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., make_ptr_fields<SubPtrFieldTupleType>(_n));
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., make_ptr_fields<SubPtrFieldTupleType>(_n));
|
||||
|
||||
} else {
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., _n.template get_field<Field::name_>());
|
||||
} else {
|
||||
return make_ptr_fields<PtrFieldTupleType>(
|
||||
_n, _args..., _n.template get_field<Field::name_>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Pointers, class... Args>
|
||||
auto move_from_ptr_fields(Pointers& _ptrs, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return T{std::move(_args)...};
|
||||
} else {
|
||||
using FieldType = std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
template <class T, class Pointers, class... Args>
|
||||
auto move_from_ptr_fields(Pointers& _ptrs, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return T {std::move(_args)...};
|
||||
} else {
|
||||
using FieldType =
|
||||
std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
|
||||
if constexpr (is_field_v<FieldType>) {
|
||||
return move_from_ptr_fields<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
rfl::make_field<FieldType::name_>(
|
||||
std::move(*std::get<i>(_ptrs).value())));
|
||||
if constexpr (is_field_v<FieldType>) {
|
||||
return move_from_ptr_fields<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
rfl::make_field<FieldType::name_>(
|
||||
std::move(*std::get<i>(_ptrs).value())));
|
||||
|
||||
} else {
|
||||
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
} else {
|
||||
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
|
||||
using U = std::remove_cvref_t<std::remove_pointer_t<
|
||||
typename std::tuple_element_t<i, PtrFieldTupleType>::Type>>;
|
||||
using U = std::remove_cvref_t<std::remove_pointer_t<
|
||||
typename std::tuple_element_t<i, PtrFieldTupleType>::Type>>;
|
||||
|
||||
return move_from_ptr_fields<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
move_from_ptr_fields<U>(std::get<i>(_ptrs)));
|
||||
return move_from_ptr_fields<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
move_from_ptr_fields<U>(std::get<i>(_ptrs)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a struct of type T from a named tuple by moving the underlying
|
||||
/// fields.
|
||||
template <class T, class NamedTupleType>
|
||||
T move_from_named_tuple(NamedTupleType&& _n) {
|
||||
using RequiredType = std::remove_cvref_t<named_tuple_t<T>>;
|
||||
/// Creates a struct of type T from a named tuple by moving the underlying
|
||||
/// fields.
|
||||
template <class T, class NamedTupleType>
|
||||
T move_from_named_tuple(NamedTupleType&& _n) {
|
||||
using RequiredType = std::remove_cvref_t<named_tuple_t<T>>;
|
||||
|
||||
if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
|
||||
return std::move(_n);
|
||||
if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
|
||||
return std::move(_n);
|
||||
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<NamedTupleType>,
|
||||
RequiredType>()) {
|
||||
auto ptr_named_tuple = nt_to_ptr_named_tuple(_n);
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<NamedTupleType>,
|
||||
RequiredType>()) {
|
||||
auto ptr_named_tuple = nt_to_ptr_named_tuple(_n);
|
||||
|
||||
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
using PtrFieldTupleType = std::remove_cvref_t<ptr_field_tuple_t<T>>;
|
||||
|
||||
auto pointers = make_ptr_fields<PtrFieldTupleType>(ptr_named_tuple);
|
||||
auto pointers = make_ptr_fields<PtrFieldTupleType>(ptr_named_tuple);
|
||||
|
||||
return move_from_ptr_fields<T>(pointers);
|
||||
return move_from_ptr_fields<T>(pointers);
|
||||
|
||||
} else {
|
||||
return move_from_named_tuple<T, RequiredType>(RequiredType(std::move(_n)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return move_from_named_tuple<T, RequiredType>(
|
||||
RequiredType(std::move(_n)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,122 +12,129 @@
|
|||
#include "tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Tuple, int _i = 0>
|
||||
constexpr int calc_flattened_size() {
|
||||
if constexpr (_i == std::tuple_size_v<Tuple>) {
|
||||
return 0;
|
||||
} else {
|
||||
using T = std::remove_pointer_t<std::tuple_element_t<_i, Tuple>>;
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
return calc_flattened_size<ptr_tuple_t<typename T::Type>>() +
|
||||
calc_flattened_size<Tuple, _i + 1>();
|
||||
} else {
|
||||
return 1 + calc_flattened_size<Tuple, _i + 1>();
|
||||
template <class Tuple, int _i = 0>
|
||||
constexpr int calc_flattened_size() {
|
||||
if constexpr (_i == std::tuple_size_v<Tuple>) {
|
||||
return 0;
|
||||
} else {
|
||||
using T = std::remove_pointer_t<std::tuple_element_t<_i, Tuple>>;
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
return calc_flattened_size<ptr_tuple_t<typename T::Type>>() +
|
||||
calc_flattened_size<Tuple, _i + 1>();
|
||||
} else {
|
||||
return 1 + calc_flattened_size<Tuple, _i + 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TargetTupleType, class PtrTupleType, int _j = 0, class... Args>
|
||||
auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
template <class TargetTupleType,
|
||||
class PtrTupleType,
|
||||
int _j = 0,
|
||||
class... Args>
|
||||
auto unflatten_ptr_tuple(PtrTupleType& _t, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
|
||||
constexpr auto size = std::tuple_size_v<std::remove_cvref_t<TargetTupleType>>;
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<TargetTupleType>>;
|
||||
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_args...);
|
||||
} else {
|
||||
using T = std::remove_cvref_t<
|
||||
std::remove_pointer_t<std::tuple_element_t<i, TargetTupleType>>>;
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_args...);
|
||||
} else {
|
||||
using T = std::remove_cvref_t<
|
||||
std::remove_pointer_t<std::tuple_element_t<i, TargetTupleType>>>;
|
||||
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
using SubTargetTupleType =
|
||||
ptr_tuple_t<std::remove_pointer_t<typename T::Type>>;
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
using SubTargetTupleType =
|
||||
ptr_tuple_t<std::remove_pointer_t<typename T::Type>>;
|
||||
|
||||
constexpr int flattened_size = calc_flattened_size<SubTargetTupleType>();
|
||||
constexpr int flattened_size =
|
||||
calc_flattened_size<SubTargetTupleType>();
|
||||
|
||||
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType,
|
||||
_j + flattened_size>(
|
||||
_t, _args...,
|
||||
unflatten_ptr_tuple<SubTargetTupleType, PtrTupleType, _j>(_t));
|
||||
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType,
|
||||
_j + flattened_size>(
|
||||
_t, _args...,
|
||||
unflatten_ptr_tuple<SubTargetTupleType, PtrTupleType, _j>(_t));
|
||||
|
||||
} else {
|
||||
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType, _j + 1>(
|
||||
_t, _args..., std::get<_j>(_t));
|
||||
} else {
|
||||
return unflatten_ptr_tuple<TargetTupleType, PtrTupleType, _j + 1>(
|
||||
_t, _args..., std::get<_j>(_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Pointers, class... Args>
|
||||
auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return std::remove_cvref_t<T>{std::move(_args)...};
|
||||
} else {
|
||||
using FieldType = std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
template <class T, class Pointers, class... Args>
|
||||
auto move_from_pointers(Pointers& _ptrs, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<Pointers>>) {
|
||||
return std::remove_cvref_t<T> {std::move(_args)...};
|
||||
} else {
|
||||
using FieldType =
|
||||
std::tuple_element_t<i, std::remove_cvref_t<Pointers>>;
|
||||
|
||||
if constexpr (std::is_pointer_v<FieldType>) {
|
||||
return move_from_pointers<T>(_ptrs, std::move(_args)...,
|
||||
std::move(*std::get<i>(_ptrs)));
|
||||
if constexpr (std::is_pointer_v<FieldType>) {
|
||||
return move_from_pointers<T>(_ptrs, std::move(_args)...,
|
||||
std::move(*std::get<i>(_ptrs)));
|
||||
|
||||
} else {
|
||||
using PtrTupleType = ptr_tuple_t<std::remove_cvref_t<T>>;
|
||||
} else {
|
||||
using PtrTupleType = ptr_tuple_t<std::remove_cvref_t<T>>;
|
||||
|
||||
using U = std::remove_cvref_t<typename std::remove_pointer_t<
|
||||
typename std::tuple_element_t<i, PtrTupleType>>::Type>;
|
||||
using U = std::remove_cvref_t<typename std::remove_pointer_t<
|
||||
typename std::tuple_element_t<i, PtrTupleType>>::Type>;
|
||||
|
||||
return move_from_pointers<T>(_ptrs, std::move(_args)...,
|
||||
move_from_pointers<U>(std::get<i>(_ptrs)));
|
||||
return move_from_pointers<T>(
|
||||
_ptrs, std::move(_args)...,
|
||||
move_from_pointers<U>(std::get<i>(_ptrs)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto flatten_array(T* _v) {
|
||||
return std::make_tuple(_v);
|
||||
}
|
||||
template <class T>
|
||||
auto flatten_array(T* _v) {
|
||||
return std::make_tuple(_v);
|
||||
}
|
||||
|
||||
template <class T, std::size_t _n>
|
||||
auto flatten_array(std::array<T, _n>* _arr) {
|
||||
const auto fct = [](auto&... _v) {
|
||||
return std::tuple_cat(flatten_array(&_v)...);
|
||||
};
|
||||
return std::apply(fct, *_arr);
|
||||
}
|
||||
template <class T, std::size_t _n>
|
||||
auto flatten_array(std::array<T, _n>* _arr) {
|
||||
const auto fct = [](auto&... _v) {
|
||||
return std::tuple_cat(flatten_array(&_v)...);
|
||||
};
|
||||
return std::apply(fct, *_arr);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_tuple_from_element(T _v) {
|
||||
return std::make_tuple(_v);
|
||||
}
|
||||
template <class T>
|
||||
auto make_tuple_from_element(T _v) {
|
||||
return std::make_tuple(_v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto make_tuple_from_element(Array<T>* _arr) {
|
||||
return flatten_array(&(_arr->arr_));
|
||||
}
|
||||
template <class T>
|
||||
auto make_tuple_from_element(Array<T>* _arr) {
|
||||
return flatten_array(&(_arr->arr_));
|
||||
}
|
||||
|
||||
auto flatten_c_arrays(const auto& _tup) {
|
||||
const auto fct = [](auto... _v) {
|
||||
return std::tuple_cat(make_tuple_from_element(_v)...);
|
||||
};
|
||||
return std::apply(fct, _tup);
|
||||
}
|
||||
auto flatten_c_arrays(const auto& _tup) {
|
||||
const auto fct = [](auto... _v) {
|
||||
return std::tuple_cat(make_tuple_from_element(_v)...);
|
||||
};
|
||||
return std::apply(fct, _tup);
|
||||
}
|
||||
|
||||
/// Creates a struct of type T from a tuple by moving the underlying
|
||||
/// fields.
|
||||
template <class T, class TupleType>
|
||||
auto move_from_tuple(TupleType&& _t) {
|
||||
auto ptr_tuple = tup_to_ptr_tuple(_t);
|
||||
/// Creates a struct of type T from a tuple by moving the underlying
|
||||
/// fields.
|
||||
template <class T, class TupleType>
|
||||
auto move_from_tuple(TupleType&& _t) {
|
||||
auto ptr_tuple = tup_to_ptr_tuple(_t);
|
||||
|
||||
using TargetTupleType = tuple_t<std::remove_cvref_t<T>>;
|
||||
using TargetTupleType = tuple_t<std::remove_cvref_t<T>>;
|
||||
|
||||
auto pointers =
|
||||
flatten_c_arrays(unflatten_ptr_tuple<TargetTupleType>(ptr_tuple));
|
||||
auto pointers =
|
||||
flatten_c_arrays(unflatten_ptr_tuple<TargetTupleType>(ptr_tuple));
|
||||
|
||||
return move_from_pointers<T>(pointers);
|
||||
}
|
||||
return move_from_pointers<T>(pointers);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,33 +13,33 @@
|
|||
#include "wrap_in_fields.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class OriginalStruct>
|
||||
auto move_to_field_tuple(OriginalStruct&& _t) {
|
||||
using T = std::remove_cvref_t<OriginalStruct>;
|
||||
if constexpr (is_named_tuple_v<T>) {
|
||||
return _t.fields();
|
||||
} else if constexpr (has_fields<T>()) {
|
||||
return bind_to_tuple(_t, [](auto& x) { return std::move(x); });
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return std::tuple();
|
||||
} else {
|
||||
using FieldNames = field_names_t<T>;
|
||||
const auto fct = []<class T>(T& _v) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
return Array<Type>(_v);
|
||||
template <class OriginalStruct>
|
||||
auto move_to_field_tuple(OriginalStruct&& _t) {
|
||||
using T = std::remove_cvref_t<OriginalStruct>;
|
||||
if constexpr (is_named_tuple_v<T>) {
|
||||
return _t.fields();
|
||||
} else if constexpr (has_fields<T>()) {
|
||||
return bind_to_tuple(_t, [](auto& x) { return std::move(x); });
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return std::tuple();
|
||||
} else {
|
||||
return std::move(_v);
|
||||
using FieldNames = field_names_t<T>;
|
||||
const auto fct = []<class T>(T& _v) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
return Array<Type>(_v);
|
||||
} else {
|
||||
return std::move(_v);
|
||||
}
|
||||
};
|
||||
auto tup = bind_to_tuple(_t, fct);
|
||||
return wrap_in_fields<FieldNames>(std::move(tup));
|
||||
}
|
||||
};
|
||||
auto tup = bind_to_tuple(_t, fct);
|
||||
return wrap_in_fields<FieldNames>(std::move(tup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,38 +4,38 @@
|
|||
#include <tuple>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Fields, int _i = 1, int _j = 0>
|
||||
constexpr inline bool no_duplicate_field_names() {
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
template <class Fields, int _i = 1, int _j = 0>
|
||||
constexpr inline bool no_duplicate_field_names() {
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
|
||||
if constexpr (num_fields <= 1) {
|
||||
return true;
|
||||
} else {
|
||||
if constexpr (_i == num_fields) {
|
||||
return true;
|
||||
} else if constexpr (_j == -1) {
|
||||
return no_duplicate_field_names<Fields, _i + 1, _i>();
|
||||
} else {
|
||||
using FieldType1 =
|
||||
std::remove_cvref_t<typename std::tuple_element<_i, Fields>::type>;
|
||||
using FieldType2 =
|
||||
std::remove_cvref_t<typename std::tuple_element<_j, Fields>::type>;
|
||||
if constexpr (num_fields <= 1) {
|
||||
return true;
|
||||
} else {
|
||||
if constexpr (_i == num_fields) {
|
||||
return true;
|
||||
} else if constexpr (_j == -1) {
|
||||
return no_duplicate_field_names<Fields, _i + 1, _i>();
|
||||
} else {
|
||||
using FieldType1 = std::remove_cvref_t<
|
||||
typename std::tuple_element<_i, Fields>::type>;
|
||||
using FieldType2 = std::remove_cvref_t<
|
||||
typename std::tuple_element<_j, Fields>::type>;
|
||||
|
||||
constexpr auto field_name_i = FieldType1::name_;
|
||||
constexpr auto field_name_j = FieldType2::name_;
|
||||
constexpr auto field_name_i = FieldType1::name_;
|
||||
constexpr auto field_name_j = FieldType2::name_;
|
||||
|
||||
constexpr bool no_duplicate = (field_name_i != field_name_j);
|
||||
constexpr bool no_duplicate = (field_name_i != field_name_j);
|
||||
|
||||
static_assert(no_duplicate, "Duplicate field names are not allowed");
|
||||
static_assert(no_duplicate, "Duplicate field names are not allowed");
|
||||
|
||||
return no_duplicate && no_duplicate_field_names<Fields, _i, _j - 1>();
|
||||
return no_duplicate && no_duplicate_field_names<Fields, _i, _j - 1>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,48 +7,50 @@
|
|||
#include "../make_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a named tuple.
|
||||
template <class NamedTupleType, class... AlreadyExtracted>
|
||||
auto nt_to_ptr_named_tuple(NamedTupleType& _nt, AlreadyExtracted... _a) {
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a named tuple.
|
||||
template <class NamedTupleType, class... AlreadyExtracted>
|
||||
auto nt_to_ptr_named_tuple(NamedTupleType& _nt, AlreadyExtracted... _a) {
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
|
||||
if constexpr (i == num_fields) {
|
||||
return make_named_tuple(_a...);
|
||||
} else {
|
||||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return nt_to_ptr_named_tuple(
|
||||
_nt, _a..., Field<FieldType::name_, T*>(&std::get<i>(_nt.values())));
|
||||
}
|
||||
}
|
||||
if constexpr (i == num_fields) {
|
||||
return make_named_tuple(_a...);
|
||||
} else {
|
||||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return nt_to_ptr_named_tuple(
|
||||
_nt, _a...,
|
||||
Field<FieldType::name_, T*>(&std::get<i>(_nt.values())));
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a named tuple.
|
||||
template <class NamedTupleType, class... AlreadyExtracted>
|
||||
auto nt_to_ptr_named_tuple(const NamedTupleType& _nt, AlreadyExtracted... _a) {
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a named tuple.
|
||||
template <class NamedTupleType, class... AlreadyExtracted>
|
||||
auto nt_to_ptr_named_tuple(const NamedTupleType& _nt,
|
||||
AlreadyExtracted... _a) {
|
||||
using Fields = typename NamedTupleType::Fields;
|
||||
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto num_fields = std::tuple_size_v<Fields>;
|
||||
|
||||
if constexpr (i == num_fields) {
|
||||
return make_named_tuple(_a...);
|
||||
} else {
|
||||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return nt_to_ptr_named_tuple(
|
||||
_nt, _a...,
|
||||
Field<FieldType::name_, const T*>(&std::get<i>(_nt.values())));
|
||||
}
|
||||
}
|
||||
if constexpr (i == num_fields) {
|
||||
return make_named_tuple(_a...);
|
||||
} else {
|
||||
using FieldType = typename std::tuple_element<i, Fields>::type;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return nt_to_ptr_named_tuple(
|
||||
_nt, _a...,
|
||||
Field<FieldType::name_, const T*>(&std::get<i>(_nt.values())));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -47,165 +47,166 @@ This is the purpose of get_nested_array_size().
|
|||
#endif
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class Derived>
|
||||
struct any_empty_base {
|
||||
any_empty_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(
|
||||
std::is_empty_v<std::remove_cvref_t<Base>> &&
|
||||
std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
struct any_base {
|
||||
any_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(
|
||||
std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>, std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
struct any {
|
||||
any(std::size_t);
|
||||
template <typename T>
|
||||
constexpr operator T() const noexcept;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CountFieldsHelper {
|
||||
template <std::size_t n>
|
||||
static consteval bool constructible() {
|
||||
return []<std::size_t... is>(std::index_sequence<is...>) {
|
||||
return requires { T{any(is)...}; };
|
||||
}
|
||||
(std::make_index_sequence<n>());
|
||||
}
|
||||
|
||||
template <std::size_t l, std::size_t nested, std::size_t r>
|
||||
static consteval bool constructible_with_nested() {
|
||||
return []<std::size_t... i, std::size_t... j, std::size_t... k>(
|
||||
std::index_sequence<i...>, std::index_sequence<j...>,
|
||||
std::index_sequence<k...>) {
|
||||
return requires { T{any(i)..., {any(j)...}, any(k)...}; };
|
||||
}
|
||||
(std::make_index_sequence<l>(), std::make_index_sequence<nested>(),
|
||||
std::make_index_sequence<r>());
|
||||
}
|
||||
|
||||
template <std::size_t n = 0>
|
||||
static consteval std::size_t count_max_args_in_agg_init() {
|
||||
static_assert(n <= static_cast<std::size_t>(sizeof(T)));
|
||||
if constexpr (constructible<n>() && !constructible<n + 1>()) {
|
||||
return n;
|
||||
} else {
|
||||
return count_max_args_in_agg_init<n + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, std::size_t size, std::size_t rest>
|
||||
static consteval std::size_t get_nested_array_size() {
|
||||
if constexpr (size < 1) {
|
||||
return 1;
|
||||
} else if constexpr (constructible_with_nested<index, size, rest>() &&
|
||||
!constructible_with_nested<index, size, rest + 1>()) {
|
||||
return size;
|
||||
} else {
|
||||
return get_nested_array_size<index, size - 1, rest + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t max_args, std::size_t index = 0>
|
||||
static consteval std::size_t find_the_sole_non_empty_base_index() {
|
||||
static_assert(index < max_args);
|
||||
constexpr auto check = []<std::size_t... l, std::size_t... r>(
|
||||
std::index_sequence<l...>,
|
||||
std::index_sequence<r...>) {
|
||||
return requires {
|
||||
T{any_empty_base<T>(l)..., any_base<T>(0), any_empty_base<T>(r)...};
|
||||
};
|
||||
template <class Derived>
|
||||
struct any_empty_base {
|
||||
any_empty_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(std::is_empty_v<std::remove_cvref_t<Base>> &&
|
||||
std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
if constexpr (check(std::make_index_sequence<index>(),
|
||||
std::make_index_sequence<max_args - index - 1>())) {
|
||||
return index;
|
||||
} else {
|
||||
return find_the_sole_non_empty_base_index<max_args, index + 1>();
|
||||
}
|
||||
}
|
||||
template <class Derived>
|
||||
struct any_base {
|
||||
any_base(std::size_t);
|
||||
template <class Base>
|
||||
requires(std::is_base_of_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>> &&
|
||||
!std::is_same_v<std::remove_cvref_t<Base>,
|
||||
std::remove_cv_t<Derived>>)
|
||||
constexpr operator Base&() const noexcept;
|
||||
};
|
||||
|
||||
template <std::size_t arg_index, std::size_t size = 0>
|
||||
static consteval std::size_t get_nested_base_field_count() {
|
||||
static_assert(size <= sizeof(T));
|
||||
if constexpr (constructible_with_nested<arg_index, size, 0>() &&
|
||||
!constructible_with_nested<arg_index, size + 1, 0>()) {
|
||||
return size;
|
||||
} else {
|
||||
return get_nested_base_field_count<arg_index, size + 1>();
|
||||
}
|
||||
}
|
||||
struct any {
|
||||
any(std::size_t);
|
||||
template <typename T>
|
||||
constexpr operator T() const noexcept;
|
||||
};
|
||||
|
||||
template <std::size_t n, std::size_t max_arg_num>
|
||||
static consteval bool has_n_base_param() {
|
||||
constexpr auto right_len = max_arg_num>=n ? max_arg_num-n : 0;
|
||||
return []<std::size_t... l, std::size_t... r>(std::index_sequence<l...>,
|
||||
std::index_sequence<r...>) {
|
||||
return requires { T{any_base<T>(l)..., any(r)...}; };
|
||||
}(std::make_index_sequence<n>(), std::make_index_sequence<right_len>());
|
||||
}
|
||||
template <typename T>
|
||||
struct CountFieldsHelper {
|
||||
template <std::size_t n>
|
||||
static consteval bool constructible() {
|
||||
return []<std::size_t... is>(std::index_sequence<is...>) {
|
||||
return requires { T {any(is)...}; };
|
||||
}(std::make_index_sequence<n>());
|
||||
}
|
||||
|
||||
template <std::size_t max_arg_num, std::size_t index = 0>
|
||||
static consteval std::size_t base_param_num() {
|
||||
if constexpr (!has_n_base_param<index + 1, max_arg_num>()) {
|
||||
return index;
|
||||
} else {
|
||||
return base_param_num<max_arg_num, index + 1>();
|
||||
}
|
||||
}
|
||||
template <std::size_t l, std::size_t nested, std::size_t r>
|
||||
static consteval bool constructible_with_nested() {
|
||||
return []<std::size_t... i, std::size_t... j, std::size_t... k>(
|
||||
std::index_sequence<i...>, std::index_sequence<j...>,
|
||||
std::index_sequence<k...>) {
|
||||
return requires { T {any(i)..., {any(j)...}, any(k)...}; };
|
||||
}(std::make_index_sequence<l>(), std::make_index_sequence<nested>(),
|
||||
std::make_index_sequence<r>());
|
||||
}
|
||||
|
||||
template <std::size_t index, std::size_t max>
|
||||
static consteval std::size_t constructible_no_brace_elision() {
|
||||
static_assert(index <= max);
|
||||
if constexpr (index == max) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1 +
|
||||
constructible_no_brace_elision<
|
||||
index + get_nested_array_size<index, max - index, 0>(), max>();
|
||||
}
|
||||
}
|
||||
template <std::size_t n = 0>
|
||||
static consteval std::size_t count_max_args_in_agg_init() {
|
||||
static_assert(n <= static_cast<std::size_t>(sizeof(T)));
|
||||
if constexpr (constructible<n>() && !constructible<n + 1>()) {
|
||||
return n;
|
||||
} else {
|
||||
return count_max_args_in_agg_init<n + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
static consteval std::size_t count_fields() {
|
||||
constexpr std::size_t max_agg_args = count_max_args_in_agg_init();
|
||||
constexpr std::size_t no_brace_ellison_args =
|
||||
constructible_no_brace_elision<0, max_agg_args>();
|
||||
constexpr std::size_t base_args = base_param_num<no_brace_ellison_args>();
|
||||
if constexpr (no_brace_ellison_args == 0 && base_args == 0) {
|
||||
// Empty struct
|
||||
return 0;
|
||||
} else if constexpr (base_args == no_brace_ellison_args) {
|
||||
// Special case when the derived class is empty.
|
||||
// In such cases the filed number is the fields in base class.
|
||||
// Note that there should be only one base class in this case.
|
||||
return get_nested_base_field_count<
|
||||
find_the_sole_non_empty_base_index<max_agg_args>()>();
|
||||
} else {
|
||||
return no_brace_ellison_args - base_args;
|
||||
}
|
||||
}
|
||||
};
|
||||
template <std::size_t index, std::size_t size, std::size_t rest>
|
||||
static consteval std::size_t get_nested_array_size() {
|
||||
if constexpr (size < 1) {
|
||||
return 1;
|
||||
} else if constexpr (constructible_with_nested<index, size, rest>() &&
|
||||
!constructible_with_nested<index, size,
|
||||
rest + 1>()) {
|
||||
return size;
|
||||
} else {
|
||||
return get_nested_array_size<index, size - 1, rest + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr std::size_t num_fields = CountFieldsHelper<T>::count_fields();
|
||||
template <std::size_t max_args, std::size_t index = 0>
|
||||
static consteval std::size_t find_the_sole_non_empty_base_index() {
|
||||
static_assert(index < max_args);
|
||||
constexpr auto check = []<std::size_t... l, std::size_t... r>(
|
||||
std::index_sequence<l...>,
|
||||
std::index_sequence<r...>) {
|
||||
return requires {
|
||||
T {any_empty_base<T>(l)..., any_base<T>(0),
|
||||
any_empty_base<T>(r)...};
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
if constexpr (check(std::make_index_sequence<index>(),
|
||||
std::make_index_sequence<max_args - index - 1>())) {
|
||||
return index;
|
||||
} else {
|
||||
return find_the_sole_non_empty_base_index<max_args, index + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t arg_index, std::size_t size = 0>
|
||||
static consteval std::size_t get_nested_base_field_count() {
|
||||
static_assert(size <= sizeof(T));
|
||||
if constexpr (constructible_with_nested<arg_index, size, 0>() &&
|
||||
!constructible_with_nested<arg_index, size + 1, 0>()) {
|
||||
return size;
|
||||
} else {
|
||||
return get_nested_base_field_count<arg_index, size + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t n, std::size_t max_arg_num>
|
||||
static consteval bool has_n_base_param() {
|
||||
constexpr auto right_len = max_arg_num >= n ? max_arg_num - n : 0;
|
||||
return []<std::size_t... l, std::size_t... r>(
|
||||
std::index_sequence<l...>, std::index_sequence<r...>) {
|
||||
return requires { T {any_base<T>(l)..., any(r)...}; };
|
||||
}(std::make_index_sequence<n>(), std::make_index_sequence<right_len>());
|
||||
}
|
||||
|
||||
template <std::size_t max_arg_num, std::size_t index = 0>
|
||||
static consteval std::size_t base_param_num() {
|
||||
if constexpr (!has_n_base_param<index + 1, max_arg_num>()) {
|
||||
return index;
|
||||
} else {
|
||||
return base_param_num<max_arg_num, index + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, std::size_t max>
|
||||
static consteval std::size_t constructible_no_brace_elision() {
|
||||
static_assert(index <= max);
|
||||
if constexpr (index == max) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1 + constructible_no_brace_elision<
|
||||
index + get_nested_array_size<index, max - index, 0>(),
|
||||
max>();
|
||||
}
|
||||
}
|
||||
|
||||
static consteval std::size_t count_fields() {
|
||||
constexpr std::size_t max_agg_args = count_max_args_in_agg_init();
|
||||
constexpr std::size_t no_brace_ellison_args =
|
||||
constructible_no_brace_elision<0, max_agg_args>();
|
||||
constexpr std::size_t base_args =
|
||||
base_param_num<no_brace_ellison_args>();
|
||||
if constexpr (no_brace_ellison_args == 0 && base_args == 0) {
|
||||
// Empty struct
|
||||
return 0;
|
||||
} else if constexpr (base_args == no_brace_ellison_args) {
|
||||
// Special case when the derived class is empty.
|
||||
// In such cases the filed number is the fields in base class.
|
||||
// Note that there should be only one base class in this case.
|
||||
return get_nested_base_field_count<
|
||||
find_the_sole_non_empty_base_index<max_agg_args>()>();
|
||||
} else {
|
||||
return no_brace_ellison_args - base_args;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr std::size_t num_fields = CountFieldsHelper<T>::count_fields();
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
|
|
|
@ -8,20 +8,21 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class StructType, class ProcessorsType>
|
||||
struct Processed;
|
||||
template <class StructType, class ProcessorsType>
|
||||
struct Processed;
|
||||
|
||||
template <class StructType, class... Ps>
|
||||
struct Processed<StructType, Processors<Ps...>> {
|
||||
using NamedTupleType = named_tuple_t<StructType>;
|
||||
using type = typename std::invoke_result<
|
||||
decltype(Processors<Ps...>::template process<StructType, NamedTupleType>),
|
||||
NamedTupleType>::type;
|
||||
};
|
||||
template <class StructType, class... Ps>
|
||||
struct Processed<StructType, Processors<Ps...>> {
|
||||
using NamedTupleType = named_tuple_t<StructType>;
|
||||
using type = typename std::invoke_result<
|
||||
decltype(Processors<Ps...>::template process<StructType,
|
||||
NamedTupleType>),
|
||||
NamedTupleType>::type;
|
||||
};
|
||||
|
||||
template <class StructType, class ProcessorsType>
|
||||
using processed_t = typename Processed<StructType, ProcessorsType>::type;
|
||||
template <class StructType, class ProcessorsType>
|
||||
using processed_t = typename Processed<StructType, ProcessorsType>::type;
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
#include "to_ptr_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using ptr_field_tuple_t = decltype(to_ptr_field_tuple(std::declval<T&>()));
|
||||
template <class T>
|
||||
using ptr_field_tuple_t = decltype(to_ptr_field_tuple(std::declval<T&>()));
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
#include "to_ptr_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using ptr_named_tuple_t =
|
||||
typename std::invoke_result<decltype(to_ptr_named_tuple<T>), T>::type;
|
||||
template <class T>
|
||||
using ptr_named_tuple_t =
|
||||
typename std::invoke_result<decltype(to_ptr_named_tuple<T>), T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
#include "to_ptr_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using ptr_tuple_t = decltype(to_ptr_tuple(std::declval<T&>()));
|
||||
template <class T>
|
||||
using ptr_tuple_t = decltype(to_ptr_tuple(std::declval<T&>()));
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,74 +10,93 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Recursively builds a new NamedTuple type from the FieldTypes, leaving out
|
||||
/// the field signified by _name.
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
class _NewNamedTupleType, int _i>
|
||||
struct remove_single_field;
|
||||
/// Recursively builds a new NamedTuple type from the FieldTypes, leaving
|
||||
/// out the field signified by _name.
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType,
|
||||
int _i>
|
||||
struct remove_single_field;
|
||||
|
||||
/// Special case - _i == 0
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
class _NewNamedTupleType>
|
||||
struct remove_single_field<_OldNamedTupleType, _name, _NewNamedTupleType, 0> {
|
||||
using type = _NewNamedTupleType;
|
||||
};
|
||||
/// Special case - _i == 0
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType>
|
||||
struct remove_single_field<_OldNamedTupleType,
|
||||
_name,
|
||||
_NewNamedTupleType,
|
||||
0> {
|
||||
using type = _NewNamedTupleType;
|
||||
};
|
||||
|
||||
/// General case.
|
||||
template <class _OldNamedTupleType, StringLiteral _name,
|
||||
class _NewNamedTupleType, int _i>
|
||||
struct remove_single_field {
|
||||
using OldNamedTupleType = std::remove_cvref_t<_OldNamedTupleType>;
|
||||
/// General case.
|
||||
template <class _OldNamedTupleType,
|
||||
StringLiteral _name,
|
||||
class _NewNamedTupleType,
|
||||
int _i>
|
||||
struct remove_single_field {
|
||||
using OldNamedTupleType = std::remove_cvref_t<_OldNamedTupleType>;
|
||||
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename OldNamedTupleType::Fields>;
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename OldNamedTupleType::Fields>;
|
||||
|
||||
using FieldType = std::remove_cvref_t<typename std::tuple_element<
|
||||
num_fields - _i, typename OldNamedTupleType::Fields>::type>;
|
||||
using FieldType = std::remove_cvref_t<typename std::tuple_element<
|
||||
num_fields - _i,
|
||||
typename OldNamedTupleType::Fields>::type>;
|
||||
|
||||
using NewNamedTupleType =
|
||||
std::conditional_t<_name == FieldType::name_, _NewNamedTupleType,
|
||||
define_named_tuple_t<_NewNamedTupleType, FieldType>>;
|
||||
using NewNamedTupleType = std::conditional_t<
|
||||
_name == FieldType::name_,
|
||||
_NewNamedTupleType,
|
||||
define_named_tuple_t<_NewNamedTupleType, FieldType>>;
|
||||
|
||||
using type = typename remove_single_field<OldNamedTupleType, _name,
|
||||
NewNamedTupleType, _i - 1>::type;
|
||||
};
|
||||
using type = typename remove_single_field<OldNamedTupleType,
|
||||
_name,
|
||||
NewNamedTupleType,
|
||||
_i - 1>::type;
|
||||
};
|
||||
|
||||
/// Recursively removes all of the fields signified by _head and _tail from the
|
||||
/// NamedTupleType.
|
||||
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
|
||||
struct remove_fields;
|
||||
/// Recursively removes all of the fields signified by _head and _tail from
|
||||
/// the NamedTupleType.
|
||||
template <class _NamedTupleType,
|
||||
StringLiteral _head,
|
||||
StringLiteral... _tail>
|
||||
struct remove_fields;
|
||||
|
||||
/// Special case - only head is left.
|
||||
template <class _NamedTupleType, StringLiteral _head>
|
||||
struct remove_fields<_NamedTupleType, _head> {
|
||||
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
|
||||
/// Special case - only head is left.
|
||||
template <class _NamedTupleType, StringLiteral _head>
|
||||
struct remove_fields<_NamedTupleType, _head> {
|
||||
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
|
||||
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
|
||||
using type = typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
|
||||
num_fields>::type;
|
||||
};
|
||||
using type = typename remove_single_field<NamedTupleType,
|
||||
_head,
|
||||
NamedTuple<>,
|
||||
num_fields>::type;
|
||||
};
|
||||
|
||||
/// General case.
|
||||
template <class _NamedTupleType, StringLiteral _head, StringLiteral... _tail>
|
||||
struct remove_fields {
|
||||
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
|
||||
/// General case.
|
||||
template <class _NamedTupleType,
|
||||
StringLiteral _head,
|
||||
StringLiteral... _tail>
|
||||
struct remove_fields {
|
||||
using NamedTupleType = std::remove_cvref_t<_NamedTupleType>;
|
||||
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
constexpr static int num_fields =
|
||||
std::tuple_size_v<typename NamedTupleType::Fields>;
|
||||
|
||||
using NewNamedTupleType =
|
||||
typename remove_single_field<NamedTupleType, _head, NamedTuple<>,
|
||||
num_fields>::type;
|
||||
using NewNamedTupleType = typename remove_single_field<NamedTupleType,
|
||||
_head,
|
||||
NamedTuple<>,
|
||||
num_fields>::type;
|
||||
|
||||
using type = typename remove_fields<NewNamedTupleType, _tail...>::type;
|
||||
};
|
||||
using type = typename remove_fields<NewNamedTupleType, _tail...>::type;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_REMOVEFIELDS_HPP_
|
||||
#endif // RFL_REMOVEFIELDS_HPP_
|
||||
|
|
|
@ -8,23 +8,21 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <StringLiteral _name>
|
||||
consteval auto remove_namespaces() {
|
||||
constexpr auto name = _name.string_view();
|
||||
constexpr size_t pos = name.find_last_of(":");
|
||||
if constexpr (pos == std::string_view::npos) {
|
||||
return _name;
|
||||
}
|
||||
constexpr auto substr = name.substr(pos + 1);
|
||||
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
|
||||
return StringLiteral<sizeof...(Ns) + 1>{substr[Ns]...};
|
||||
};
|
||||
return to_str_lit(std::make_index_sequence<substr.size()>{});
|
||||
}
|
||||
template <StringLiteral _name>
|
||||
consteval auto remove_namespaces() {
|
||||
constexpr auto name = _name.string_view();
|
||||
constexpr size_t pos = name.find_last_of(":");
|
||||
if constexpr (pos == std::string_view::npos) { return _name; }
|
||||
constexpr auto substr = name.substr(pos + 1);
|
||||
const auto to_str_lit = [&]<auto... Ns>(std::index_sequence<Ns...>) {
|
||||
return StringLiteral<sizeof...(Ns) + 1> {substr[Ns]...};
|
||||
};
|
||||
return to_str_lit(std::make_index_sequence<substr.size()> {});
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,22 +5,22 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "ptr_tuple_t.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "ptr_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
struct remove_ptrs_tup;
|
||||
template <class T>
|
||||
struct remove_ptrs_tup;
|
||||
|
||||
template <class... Ts>
|
||||
struct remove_ptrs_tup<std::tuple<Ts...>> {
|
||||
using TupleType =
|
||||
std::tuple<std::remove_cvref_t<std::remove_pointer_t<Ts>>...>;
|
||||
};
|
||||
template <class... Ts>
|
||||
struct remove_ptrs_tup<std::tuple<Ts...>> {
|
||||
using TupleType =
|
||||
std::tuple<std::remove_cvref_t<std::remove_pointer_t<Ts>>...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,24 +5,22 @@
|
|||
#include <vector>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
|
||||
/// Joins a string using the delimiter
|
||||
inline std::string join(const std::string& _delimiter,
|
||||
const std::vector<std::string>& _strings) {
|
||||
if (_strings.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
auto res = _strings[0];
|
||||
for (size_t i = 1; i < _strings.size(); ++i) {
|
||||
res += _delimiter + _strings[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// Joins a string using the delimiter
|
||||
inline std::string join(const std::string& _delimiter,
|
||||
const std::vector<std::string>& _strings) {
|
||||
if (_strings.size() == 0) { return ""; }
|
||||
auto res = _strings[0];
|
||||
for (size_t i = 1; i < _strings.size(); ++i) {
|
||||
res += _delimiter + _strings[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,24 +5,24 @@
|
|||
#include <vector>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
|
||||
inline std::string replace_all(const std::string& _str,
|
||||
const std::string& _from,
|
||||
const std::string& _to) {
|
||||
auto str = _str;
|
||||
inline std::string replace_all(const std::string& _str,
|
||||
const std::string& _from,
|
||||
const std::string& _to) {
|
||||
auto str = _str;
|
||||
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(_from, pos)) != std::string::npos) {
|
||||
str.replace(pos, _from.length(), _to);
|
||||
pos += _to.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(_from, pos)) != std::string::npos) {
|
||||
str.replace(pos, _from.length(), _to);
|
||||
pos += _to.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
#include <vector>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
namespace internal {
|
||||
namespace strings {
|
||||
|
||||
/// Splits a string alongside the delimiter
|
||||
inline std::vector<std::string> split(const std::string& _str,
|
||||
const std::string& _delimiter) {
|
||||
auto str = _str;
|
||||
size_t pos = 0;
|
||||
std::vector<std::string> result;
|
||||
while ((pos = str.find(_delimiter)) != std::string::npos) {
|
||||
result.emplace_back(str.substr(0, pos));
|
||||
str.erase(0, pos + _delimiter.length());
|
||||
}
|
||||
result.emplace_back(std::move(str));
|
||||
return result;
|
||||
}
|
||||
/// Splits a string alongside the delimiter
|
||||
inline std::vector<std::string> split(const std::string& _str,
|
||||
const std::string& _delimiter) {
|
||||
auto str = _str;
|
||||
size_t pos = 0;
|
||||
std::vector<std::string> result;
|
||||
while ((pos = str.find(_delimiter)) != std::string::npos) {
|
||||
result.emplace_back(str.substr(0, pos));
|
||||
str.erase(0, pos + _delimiter.length());
|
||||
}
|
||||
result.emplace_back(std::move(str));
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace strings
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <internal::StringLiteral _discriminator, class T>
|
||||
using tag_t =
|
||||
typename std::invoke_result<decltype(make_tag<_discriminator, T>), T>::type;
|
||||
template <internal::StringLiteral _discriminator, class T>
|
||||
using tag_t =
|
||||
typename std::invoke_result<decltype(make_tag<_discriminator, T>),
|
||||
T>::type;
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,35 +8,36 @@
|
|||
#include "to_ptr_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class PtrTuple, class... Args>
|
||||
auto flatten_ptr_tuple(PtrTuple&& _t, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == 0 && !has_flatten_fields<PtrTuple>()) {
|
||||
return std::forward<PtrTuple>(_t);
|
||||
} else if constexpr (i == std::tuple_size_v<std::remove_cvref_t<PtrTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrTuple>>;
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
return flatten_ptr_tuple(
|
||||
std::forward<PtrTuple>(_t), std::forward<Args>(_args)...,
|
||||
flatten_ptr_tuple(to_ptr_tuple(std::get<i>(_t)->get())));
|
||||
} else {
|
||||
return flatten_ptr_tuple(std::forward<PtrTuple>(_t),
|
||||
std::forward<Args>(_args)...,
|
||||
std::make_tuple(std::get<i>(_t)));
|
||||
template <class PtrTuple, class... Args>
|
||||
auto flatten_ptr_tuple(PtrTuple&& _t, Args... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == 0 && !has_flatten_fields<PtrTuple>()) {
|
||||
return std::forward<PtrTuple>(_t);
|
||||
} else if constexpr (i ==
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrTuple>>;
|
||||
if constexpr (is_flatten_field_v<T>) {
|
||||
return flatten_ptr_tuple(
|
||||
std::forward<PtrTuple>(_t), std::forward<Args>(_args)...,
|
||||
flatten_ptr_tuple(to_ptr_tuple(std::get<i>(_t)->get())));
|
||||
} else {
|
||||
return flatten_ptr_tuple(std::forward<PtrTuple>(_t),
|
||||
std::forward<Args>(_args)...,
|
||||
std::make_tuple(std::get<i>(_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto to_flattened_ptr_tuple(T&& _t) {
|
||||
return flatten_ptr_tuple(to_ptr_tuple(_t));
|
||||
}
|
||||
template <class T>
|
||||
auto to_flattened_ptr_tuple(T&& _t) {
|
||||
return flatten_ptr_tuple(to_ptr_tuple(_t));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,33 +9,33 @@
|
|||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <internal::StringLiteral _name, class Type>
|
||||
inline auto to_ptr_field(Field<_name, Type>& _field) {
|
||||
using T = std::remove_reference_t<Type>;
|
||||
return Field<_name, T*>(&_field.value_);
|
||||
}
|
||||
template <internal::StringLiteral _name, class Type>
|
||||
inline auto to_ptr_field(Field<_name, Type>& _field) {
|
||||
using T = std::remove_reference_t<Type>;
|
||||
return Field<_name, T*>(&_field.value_);
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name, class Type>
|
||||
inline auto to_ptr_field(const Field<_name, Type>& _field) {
|
||||
using T = std::remove_cvref_t<Type>;
|
||||
return Field<_name, const T*>(&_field.value_);
|
||||
}
|
||||
template <internal::StringLiteral _name, class Type>
|
||||
inline auto to_ptr_field(const Field<_name, Type>& _field) {
|
||||
using T = std::remove_cvref_t<Type>;
|
||||
return Field<_name, const T*>(&_field.value_);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline auto to_ptr_field(Flatten<Type>& _field) {
|
||||
using T = std::remove_reference_t<Type>;
|
||||
return Flatten<T*>(&_field.value_);
|
||||
}
|
||||
template <class Type>
|
||||
inline auto to_ptr_field(Flatten<Type>& _field) {
|
||||
using T = std::remove_reference_t<Type>;
|
||||
return Flatten<T*>(&_field.value_);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline auto to_ptr_field(const Flatten<Type>& _field) {
|
||||
using T = std::remove_cvref_t<Type>;
|
||||
return Flatten<const T*>(&_field.value_);
|
||||
}
|
||||
template <class Type>
|
||||
inline auto to_ptr_field(const Flatten<Type>& _field) {
|
||||
using T = std::remove_cvref_t<Type>;
|
||||
return Flatten<const T*>(&_field.value_);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,26 +15,26 @@
|
|||
#include "wrap_in_fields.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
auto to_ptr_field_tuple(T& _t) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_field_tuple(*_t);
|
||||
} else if constexpr (is_named_tuple_v<T>) {
|
||||
return nt_to_ptr_named_tuple(_t).fields();
|
||||
} else if constexpr (has_fields<T>()) {
|
||||
return bind_to_tuple(_t, [](auto& x) { return to_ptr_field(x); });
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return std::tuple();
|
||||
} else {
|
||||
using FieldNames = field_names_t<T>;
|
||||
auto tup = bind_to_tuple(_t, [](auto& x) { return to_ptr_field(x); });
|
||||
return wrap_in_fields<FieldNames>(std::move(tup));
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
auto to_ptr_field_tuple(T& _t) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_field_tuple(*_t);
|
||||
} else if constexpr (is_named_tuple_v<T>) {
|
||||
return nt_to_ptr_named_tuple(_t).fields();
|
||||
} else if constexpr (has_fields<T>()) {
|
||||
return bind_to_tuple(_t, [](auto& x) { return to_ptr_field(x); });
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return std::tuple();
|
||||
} else {
|
||||
using FieldNames = field_names_t<T>;
|
||||
auto tup = bind_to_tuple(_t, [](auto& x) { return to_ptr_field(x); });
|
||||
return wrap_in_fields<FieldNames>(std::move(tup));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,63 +17,65 @@
|
|||
#include "to_ptr_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class PtrFieldTuple, class... Args>
|
||||
auto flatten_ptr_field_tuple(PtrFieldTuple& _t, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i == std::tuple_size_v<std::remove_cvref_t<PtrFieldTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrFieldTuple>>;
|
||||
if constexpr (internal::is_flatten_field<T>::value) {
|
||||
auto subtuple = internal::to_ptr_field_tuple(*std::get<i>(_t).get());
|
||||
return flatten_ptr_field_tuple(_t, std::forward<Args>(_args)...,
|
||||
flatten_ptr_field_tuple(subtuple));
|
||||
} else {
|
||||
return flatten_ptr_field_tuple(_t, std::forward<Args>(_args)...,
|
||||
std::make_tuple(std::get<i>(_t)));
|
||||
template <class PtrFieldTuple, class... Args>
|
||||
auto flatten_ptr_field_tuple(PtrFieldTuple& _t, Args&&... _args) {
|
||||
constexpr auto i = sizeof...(Args);
|
||||
if constexpr (i ==
|
||||
std::tuple_size_v<std::remove_cvref_t<PtrFieldTuple>>) {
|
||||
return std::tuple_cat(std::forward<Args>(_args)...);
|
||||
} else {
|
||||
using T = std::tuple_element_t<i, std::remove_cvref_t<PtrFieldTuple>>;
|
||||
if constexpr (internal::is_flatten_field<T>::value) {
|
||||
auto subtuple = internal::to_ptr_field_tuple(*std::get<i>(_t).get());
|
||||
return flatten_ptr_field_tuple(_t, std::forward<Args>(_args)...,
|
||||
flatten_ptr_field_tuple(subtuple));
|
||||
} else {
|
||||
return flatten_ptr_field_tuple(_t, std::forward<Args>(_args)...,
|
||||
std::make_tuple(std::get<i>(_t)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class PtrFieldTuple>
|
||||
auto field_tuple_to_named_tuple(PtrFieldTuple& _ptr_field_tuple) {
|
||||
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
|
||||
return make_named_tuple(_fields...);
|
||||
};
|
||||
template <class PtrFieldTuple>
|
||||
auto field_tuple_to_named_tuple(PtrFieldTuple& _ptr_field_tuple) {
|
||||
const auto ft_to_nt = []<class... Fields>(Fields&&... _fields) {
|
||||
return make_named_tuple(_fields...);
|
||||
};
|
||||
|
||||
if constexpr (!has_flatten_fields<std::remove_cvref_t<PtrFieldTuple>>()) {
|
||||
return std::apply(ft_to_nt, std::move(_ptr_field_tuple));
|
||||
} else {
|
||||
const auto flattened_tuple = flatten_ptr_field_tuple(_ptr_field_tuple);
|
||||
return std::apply(ft_to_nt, flattened_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct.
|
||||
template <class T>
|
||||
auto to_ptr_named_tuple(T&& _t) {
|
||||
if constexpr (has_fields<std::remove_cvref_t<T>>()) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_named_tuple(*_t);
|
||||
} else if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
|
||||
return nt_to_ptr_named_tuple(_t);
|
||||
} else {
|
||||
auto ptr_field_tuple = to_ptr_field_tuple(_t);
|
||||
return field_tuple_to_named_tuple(ptr_field_tuple);
|
||||
if constexpr (!has_flatten_fields<std::remove_cvref_t<PtrFieldTuple>>()) {
|
||||
return std::apply(ft_to_nt, std::move(_ptr_field_tuple));
|
||||
} else {
|
||||
const auto flattened_tuple = flatten_ptr_field_tuple(_ptr_field_tuple);
|
||||
return std::apply(ft_to_nt, flattened_tuple);
|
||||
}
|
||||
}
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return rfl::NamedTuple<>();
|
||||
} else {
|
||||
using FieldNames = rfl::field_names_t<T>;
|
||||
auto flattened_ptr_tuple = to_flattened_ptr_tuple(_t);
|
||||
return copy_flattened_tuple_to_named_tuple<FieldNames>(flattened_ptr_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct.
|
||||
template <class T>
|
||||
auto to_ptr_named_tuple(T&& _t) {
|
||||
if constexpr (has_fields<std::remove_cvref_t<T>>()) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_named_tuple(*_t);
|
||||
} else if constexpr (is_named_tuple_v<std::remove_cvref_t<T>>) {
|
||||
return nt_to_ptr_named_tuple(_t);
|
||||
} else {
|
||||
auto ptr_field_tuple = to_ptr_field_tuple(_t);
|
||||
return field_tuple_to_named_tuple(ptr_field_tuple);
|
||||
}
|
||||
} else if constexpr (is_empty<T>()) {
|
||||
return rfl::NamedTuple<>();
|
||||
} else {
|
||||
using FieldNames = rfl::field_names_t<T>;
|
||||
auto flattened_ptr_tuple = to_flattened_ptr_tuple(_t);
|
||||
return copy_flattened_tuple_to_named_tuple<FieldNames>(
|
||||
flattened_ptr_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,18 +8,18 @@
|
|||
#include "bind_to_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
constexpr auto to_ptr_tuple(T& _t) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_tuple(*_t);
|
||||
} else {
|
||||
return bind_to_tuple(_t, [](auto& x) { return &x; });
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
constexpr auto to_ptr_tuple(T& _t) {
|
||||
if constexpr (std::is_pointer_v<std::remove_cvref_t<T>>) {
|
||||
return to_ptr_tuple(*_t);
|
||||
} else {
|
||||
return bind_to_tuple(_t, [](auto& x) { return &x; });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,51 +7,51 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class T>
|
||||
struct StdArrayType {
|
||||
using Type = T;
|
||||
};
|
||||
template <class T>
|
||||
struct StdArrayType {
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template <class T, size_t _n>
|
||||
struct StdArrayType<T[_n]> {
|
||||
using Type =
|
||||
std::array<typename StdArrayType<std::remove_cvref_t<T>>::Type, _n>;
|
||||
using ValueType = std::remove_cvref_t<T>;
|
||||
constexpr static size_t size = _n;
|
||||
};
|
||||
template <class T, size_t _n>
|
||||
struct StdArrayType<T[_n]> {
|
||||
using Type =
|
||||
std::array<typename StdArrayType<std::remove_cvref_t<T>>::Type, _n>;
|
||||
using ValueType = std::remove_cvref_t<T>;
|
||||
constexpr static size_t size = _n;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using to_std_array_t = StdArrayType<T>::Type;
|
||||
template <class T>
|
||||
using to_std_array_t = StdArrayType<T>::Type;
|
||||
|
||||
template <class T>
|
||||
auto to_std_array(T&& _t) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
constexpr size_t n = StdArrayType<Type>::size;
|
||||
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
|
||||
return to_std_array_t<Type>({to_std_array(
|
||||
std::forward<typename StdArrayType<Type>::ValueType>(_t[_i]))...});
|
||||
};
|
||||
return fct(std::make_index_sequence<n>());
|
||||
} else {
|
||||
return std::forward<T>(_t);
|
||||
template <class T>
|
||||
auto to_std_array(T&& _t) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
constexpr size_t n = StdArrayType<Type>::size;
|
||||
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
|
||||
return to_std_array_t<Type>({to_std_array(
|
||||
std::forward<typename StdArrayType<Type>::ValueType>(_t[_i]))...});
|
||||
};
|
||||
return fct(std::make_index_sequence<n>());
|
||||
} else {
|
||||
return std::forward<T>(_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto to_std_array(const T& _t) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
constexpr size_t n = StdArrayType<Type>::size;
|
||||
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
|
||||
return to_std_array_t<Type>({to_std_array(_t[_i])...});
|
||||
};
|
||||
return fct(std::make_index_sequence<n>());
|
||||
} else {
|
||||
return _t;
|
||||
template <class T>
|
||||
auto to_std_array(const T& _t) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<Type>) {
|
||||
constexpr size_t n = StdArrayType<Type>::size;
|
||||
const auto fct = [&]<std::size_t... _i>(std::index_sequence<_i...>) {
|
||||
return to_std_array_t<Type>({to_std_array(_t[_i])...});
|
||||
};
|
||||
return fct(std::make_index_sequence<n>());
|
||||
} else {
|
||||
return _t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,34 +5,36 @@
|
|||
|
||||
namespace rfl::internal {
|
||||
|
||||
/// Capitalizes a lower-case character.
|
||||
template <char c>
|
||||
consteval char to_upper() {
|
||||
if constexpr (c >= 'a' && c <= 'z') {
|
||||
return c + ('A' - 'a');
|
||||
} else {
|
||||
return c;
|
||||
/// Capitalizes a lower-case character.
|
||||
template <char c>
|
||||
consteval char to_upper() {
|
||||
if constexpr (c >= 'a' && c <= 'z') {
|
||||
return c + ('A' - 'a');
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the field name from snake case to camel case.
|
||||
template <internal::StringLiteral _name, bool _capitalize, size_t _i = 0,
|
||||
char... chars>
|
||||
consteval auto transform_snake_case() {
|
||||
if constexpr (_i == _name.arr_.size()) {
|
||||
return StringLiteral<sizeof...(chars) + 1>(chars...);
|
||||
} else if constexpr (_name.arr_[_i] == '_') {
|
||||
return transform_snake_case<_name, true, _i + 1, chars...>();
|
||||
} else if constexpr (_name.arr_[_i] == '\0') {
|
||||
return transform_snake_case<_name, false, _name.arr_.size(), chars...>();
|
||||
} else if constexpr (_capitalize) {
|
||||
return transform_snake_case<_name, false, _i + 1, chars...,
|
||||
to_upper<_name.arr_[_i]>()>();
|
||||
} else {
|
||||
return transform_snake_case<_name, false, _i + 1, chars...,
|
||||
_name.arr_[_i]>();
|
||||
/// Transforms the field name from snake case to camel case.
|
||||
template <internal::StringLiteral _name,
|
||||
bool _capitalize,
|
||||
size_t _i = 0,
|
||||
char... chars>
|
||||
consteval auto transform_snake_case() {
|
||||
if constexpr (_i == _name.arr_.size()) {
|
||||
return StringLiteral<sizeof...(chars) + 1>(chars...);
|
||||
} else if constexpr (_name.arr_[_i] == '_') {
|
||||
return transform_snake_case<_name, true, _i + 1, chars...>();
|
||||
} else if constexpr (_name.arr_[_i] == '\0') {
|
||||
return transform_snake_case<_name, false, _name.arr_.size(), chars...>();
|
||||
} else if constexpr (_capitalize) {
|
||||
return transform_snake_case<_name, false, _i + 1, chars...,
|
||||
to_upper<_name.arr_[_i]>()>();
|
||||
} else {
|
||||
return transform_snake_case<_name, false, _i + 1, chars...,
|
||||
_name.arr_[_i]>();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace rfl::internal
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,23 +7,23 @@
|
|||
#include "../make_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a tuple.
|
||||
template <class TupleType, class... AlreadyExtracted>
|
||||
auto tup_to_ptr_tuple(TupleType& _t, AlreadyExtracted... _a) {
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto size = std::tuple_size_v<TupleType>;
|
||||
/// Generates a named tuple that contains pointers to the original values in
|
||||
/// the struct from a tuple.
|
||||
template <class TupleType, class... AlreadyExtracted>
|
||||
auto tup_to_ptr_tuple(TupleType& _t, AlreadyExtracted... _a) {
|
||||
constexpr auto i = sizeof...(AlreadyExtracted);
|
||||
constexpr auto size = std::tuple_size_v<TupleType>;
|
||||
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_a...);
|
||||
} else {
|
||||
return tup_to_ptr_tuple(_t, _a..., &std::get<i>(_t));
|
||||
}
|
||||
}
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(_a...);
|
||||
} else {
|
||||
return tup_to_ptr_tuple(_t, _a..., &std::get<i>(_t));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../to_named_tuple.hpp"
|
||||
#include "ptr_tuple_t.hpp"
|
||||
#include "remove_ptrs_tup.hpp"
|
||||
#include "../to_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using tuple_t = typename remove_ptrs_tup<ptr_tuple_t<T>>::TupleType;
|
||||
template <class T>
|
||||
using tuple_t = typename remove_ptrs_tup<ptr_tuple_t<T>>::TupleType;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,36 +9,37 @@
|
|||
#include "lit_name.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class FieldNames, int j = 0, class... Fields>
|
||||
auto wrap_in_fields(auto&& _tuple, Fields&&... _fields) {
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<decltype(_tuple)>>;
|
||||
constexpr auto i = sizeof...(_fields);
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(std::move(_fields)...);
|
||||
} else {
|
||||
auto value = std::move(std::get<i>(_tuple));
|
||||
using Type = std::remove_cvref_t<std::remove_pointer_t<decltype(value)>>;
|
||||
if constexpr (is_flatten_field_v<Type>) {
|
||||
// The problem here is that the FieldNames are already flattened, but this
|
||||
// is not, so we need to determine how many field names to skip.
|
||||
constexpr auto n_skip = std::tuple_size_v<
|
||||
std::remove_cvref_t<flattened_ptr_tuple_t<typename Type::Type>>>;
|
||||
return wrap_in_fields<FieldNames, j + n_skip>(
|
||||
std::move(_tuple), std::move(_fields)..., std::move(value));
|
||||
} else {
|
||||
const auto name_literal = FieldNames::template name_of<j>();
|
||||
auto new_field = rfl::make_field<
|
||||
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
|
||||
std::move(value));
|
||||
return wrap_in_fields<FieldNames, j + 1>(
|
||||
std::move(_tuple), std::move(_fields)..., std::move(new_field));
|
||||
template <class FieldNames, int j = 0, class... Fields>
|
||||
auto wrap_in_fields(auto&& _tuple, Fields&&... _fields) {
|
||||
constexpr auto size =
|
||||
std::tuple_size_v<std::remove_cvref_t<decltype(_tuple)>>;
|
||||
constexpr auto i = sizeof...(_fields);
|
||||
if constexpr (i == size) {
|
||||
return std::make_tuple(std::move(_fields)...);
|
||||
} else {
|
||||
auto value = std::move(std::get<i>(_tuple));
|
||||
using Type =
|
||||
std::remove_cvref_t<std::remove_pointer_t<decltype(value)>>;
|
||||
if constexpr (is_flatten_field_v<Type>) {
|
||||
// The problem here is that the FieldNames are already flattened, but
|
||||
// this is not, so we need to determine how many field names to skip.
|
||||
constexpr auto n_skip = std::tuple_size_v<
|
||||
std::remove_cvref_t<flattened_ptr_tuple_t<typename Type::Type>>>;
|
||||
return wrap_in_fields<FieldNames, j + n_skip>(
|
||||
std::move(_tuple), std::move(_fields)..., std::move(value));
|
||||
} else {
|
||||
const auto name_literal = FieldNames::template name_of<j>();
|
||||
auto new_field = rfl::make_field<
|
||||
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
|
||||
std::move(value));
|
||||
return wrap_in_fields<FieldNames, j + 1>(
|
||||
std::move(_tuple), std::move(_fields)..., std::move(new_field));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
#endif
|
||||
|
|
|
@ -6,23 +6,23 @@
|
|||
#include "Array.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
struct wrap_in_rfl_array {
|
||||
using type = T;
|
||||
};
|
||||
template <class T>
|
||||
struct wrap_in_rfl_array {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
requires std::is_array_v<T>
|
||||
struct wrap_in_rfl_array<T> {
|
||||
using type = Array<T>;
|
||||
};
|
||||
template <class T>
|
||||
requires std::is_array_v<T>
|
||||
struct wrap_in_rfl_array<T> {
|
||||
using type = Array<T>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using wrap_in_rfl_array_t = typename wrap_in_rfl_array<T>::type;
|
||||
template <class T>
|
||||
using wrap_in_rfl_array_t = typename wrap_in_rfl_array<T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue