feat(reflect-cpp): Switched from glaze -> reflect cpp
A bug was discovered in glaze which prevented valid toml output. We have switched to toml++ and reflect-cpp. The interface has remained the same so this should not break any code
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
glaze_cmake_options = cmake.subproject_options()
|
||||
|
||||
glaze_cmake_options.add_cmake_defines({
|
||||
'BUILD_SHARED_LIBS': 'OFF',
|
||||
'BUILD_STATIC_LIBS': 'ON',
|
||||
'CMAKE_INSTALL_LIBDIR': get_option('libdir'),
|
||||
'CMAKE_INSTALL_INCLUDEDIR': get_option('includedir'),
|
||||
'CMAKE_POSITION_INDEPENDENT_CODE': 'ON',
|
||||
'galze_BUILD_EXAMPLES': 'OFF',
|
||||
'glaze_DEVELOPER_MODE': 'OFF',
|
||||
})
|
||||
|
||||
glaze_sp = cmake.subproject(
|
||||
'glaze',
|
||||
options: glaze_cmake_options,
|
||||
)
|
||||
glaze_dep = glaze_sp.dependency('glaze_glaze')
|
||||
@@ -1,2 +1,2 @@
|
||||
cmake = import('cmake')
|
||||
subdir('glaze')
|
||||
subdir('reflect-cpp')
|
||||
|
||||
21
build-config/reflect-cpp/LICENSE
Normal file
21
build-config/reflect-cpp/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023-2025 Code17 GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
87
build-config/reflect-cpp/include/rfl.hpp
Normal file
87
build-config/reflect-cpp/include/rfl.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef RFL_RFL_HPP_
|
||||
#define RFL_RFL_HPP_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4101)
|
||||
#endif
|
||||
|
||||
#include "rfl/AddStructName.hpp"
|
||||
#include "rfl/AddTagsToVariants.hpp"
|
||||
#include "rfl/AllOf.hpp"
|
||||
#include "rfl/AllowRawPtrs.hpp"
|
||||
#include "rfl/AnyOf.hpp"
|
||||
#include "rfl/Attribute.hpp"
|
||||
#include "rfl/Binary.hpp"
|
||||
#include "rfl/Box.hpp"
|
||||
#include "rfl/Bytestring.hpp"
|
||||
#include "rfl/DefaultIfMissing.hpp"
|
||||
#include "rfl/DefaultVal.hpp"
|
||||
#include "rfl/Description.hpp"
|
||||
#include "rfl/ExtraFields.hpp"
|
||||
#include "rfl/Field.hpp"
|
||||
#include "rfl/Flatten.hpp"
|
||||
#include "rfl/Generic.hpp"
|
||||
#include "rfl/Hex.hpp"
|
||||
#include "rfl/Literal.hpp"
|
||||
#include "rfl/NamedTuple.hpp"
|
||||
#include "rfl/NoExtraFields.hpp"
|
||||
#include "rfl/NoFieldNames.hpp"
|
||||
#include "rfl/NoOptionals.hpp"
|
||||
#include "rfl/Object.hpp"
|
||||
#include "rfl/Oct.hpp"
|
||||
#include "rfl/OneOf.hpp"
|
||||
#include "rfl/Pattern.hpp"
|
||||
#include "rfl/PatternValidator.hpp"
|
||||
#include "rfl/Processors.hpp"
|
||||
#include "rfl/Ref.hpp"
|
||||
#include "rfl/Rename.hpp"
|
||||
#include "rfl/Size.hpp"
|
||||
#include "rfl/Skip.hpp"
|
||||
#include "rfl/SnakeCaseToCamelCase.hpp"
|
||||
#include "rfl/SnakeCaseToPascalCase.hpp"
|
||||
#include "rfl/TaggedUnion.hpp"
|
||||
#include "rfl/Timestamp.hpp"
|
||||
#include "rfl/UnderlyingEnums.hpp"
|
||||
#include "rfl/Validator.hpp"
|
||||
#include "rfl/Variant.hpp"
|
||||
#include "rfl/Vectorstring.hpp"
|
||||
#include "rfl/always_false.hpp"
|
||||
#include "rfl/apply.hpp"
|
||||
#include "rfl/as.hpp"
|
||||
#include "rfl/comparisons.hpp"
|
||||
#include "rfl/concepts.hpp"
|
||||
#include "rfl/default.hpp"
|
||||
#include "rfl/define_literal.hpp"
|
||||
#include "rfl/define_named_tuple.hpp"
|
||||
#include "rfl/define_tagged_union.hpp"
|
||||
#include "rfl/define_variant.hpp"
|
||||
#include "rfl/enums.hpp"
|
||||
#include "rfl/extract_discriminators.hpp"
|
||||
#include "rfl/field_type.hpp"
|
||||
#include "rfl/fields.hpp"
|
||||
#include "rfl/from_generic.hpp"
|
||||
#include "rfl/from_named_tuple.hpp"
|
||||
#include "rfl/get.hpp"
|
||||
#include "rfl/make_from_tuple.hpp"
|
||||
#include "rfl/make_named_tuple.hpp"
|
||||
#include "rfl/name_t.hpp"
|
||||
#include "rfl/named_tuple_t.hpp"
|
||||
#include "rfl/parsing/CustomParser.hpp"
|
||||
#include "rfl/patterns.hpp"
|
||||
#include "rfl/remove_fields.hpp"
|
||||
#include "rfl/replace.hpp"
|
||||
#include "rfl/to_generic.hpp"
|
||||
#include "rfl/to_named_tuple.hpp"
|
||||
#include "rfl/to_view.hpp"
|
||||
#include "rfl/tuple_cat.hpp"
|
||||
#include "rfl/type_name_t.hpp"
|
||||
#include "rfl/view_t.hpp"
|
||||
#include "rfl/visit.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
33
build-config/reflect-cpp/include/rfl/AddStructName.hpp
Normal file
33
build-config/reflect-cpp/include/rfl/AddStructName.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef RFL_ADDSTRUCTNAME_HPP_
|
||||
#define RFL_ADDSTRUCTNAME_HPP_
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "Field.hpp"
|
||||
#include "Literal.hpp"
|
||||
#include "apply.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/get_type_name.hpp"
|
||||
#include "internal/remove_namespaces.hpp"
|
||||
#include "make_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral field_name_>
|
||||
struct AddStructName {
|
||||
/// Adds the name of the struct as a new field.
|
||||
template <class StructType>
|
||||
static auto process(const auto& _view) {
|
||||
using LiteralType = Literal<
|
||||
internal::remove_namespaces<internal::get_type_name<StructType>()>()>;
|
||||
using FieldType = Field<field_name_, LiteralType>;
|
||||
const auto add_new_field = [](const auto&... _fields) {
|
||||
return make_named_tuple(FieldType(LiteralType()), _fields...);
|
||||
};
|
||||
return rfl::apply(add_new_field, _view.fields());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
30
build-config/reflect-cpp/include/rfl/AddTagsToVariants.hpp
Normal file
30
build-config/reflect-cpp/include/rfl/AddTagsToVariants.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef RFL_ADDTAGSTOVARIANTS_HPP_
|
||||
#define RFL_ADDTAGSTOVARIANTS_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to automatically add tags to the variants
|
||||
/// they might encounter.
|
||||
struct AddTagsToVariants {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to automatically add tags to the variants
|
||||
/// they might encounter.
|
||||
struct AddNamespacedTagsToVariants {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
40
build-config/reflect-cpp/include/rfl/AllOf.hpp
Normal file
40
build-config/reflect-cpp/include/rfl/AllOf.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef RFL_ALLOF_HPP_
|
||||
#define RFL_ALLOF_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Requires that all of the contraints C and Cs be true.
|
||||
template <class C, class... Cs>
|
||||
struct AllOf {
|
||||
template <class T>
|
||||
static rfl::Result<T> validate(T _value) noexcept {
|
||||
return validate_impl<T, C, Cs...>(_value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto types = std::vector<ValidationType>(
|
||||
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
|
||||
return ValidationType{ValidationType::AllOf{.types_ = types}};
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T, class Head, class... Tail>
|
||||
static rfl::Result<T> validate_impl(T _value) noexcept {
|
||||
if constexpr (sizeof...(Tail) == 0) {
|
||||
return Head::validate(_value);
|
||||
} else {
|
||||
return Head::validate(_value).and_then(validate_impl<T, Tail...>);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/AllowRawPtrs.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/AllowRawPtrs.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_ALLOWRAWPTRS_HPP_
|
||||
#define RFL_ALLOWRAWPTRS_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to allow raw pointers.
|
||||
struct AllowRawPtrs {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
59
build-config/reflect-cpp/include/rfl/AnyOf.hpp
Normal file
59
build-config/reflect-cpp/include/rfl/AnyOf.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef RFL_ANYOF_HPP_
|
||||
#define RFL_ANYOF_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Requires that all of the contraints C and Cs be true.
|
||||
template <class C, class... Cs>
|
||||
struct AnyOf {
|
||||
template <class T>
|
||||
static rfl::Result<T> validate(const T& _value) noexcept {
|
||||
return validate_impl<T, C, Cs...>(_value, {});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto types = std::vector<ValidationType>(
|
||||
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
|
||||
return ValidationType{ValidationType::AnyOf{.types_ = types}};
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string make_error_message(const std::vector<Error>& _errors) {
|
||||
std::stringstream stream;
|
||||
stream << "Expected at least one of the following validations to pass, but "
|
||||
"none of them did:";
|
||||
for (size_t i = 0; i < _errors.size(); ++i) {
|
||||
stream << "\n" << i + 1 << ") " << _errors.at(i).what();
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <class T, class Head, class... Tail>
|
||||
static rfl::Result<T> validate_impl(const T& _value,
|
||||
std::vector<Error> _errors) {
|
||||
const auto handle_err = [&](Error&& _err) -> rfl::Result<T> {
|
||||
_errors.push_back(std::forward<Error>(_err));
|
||||
if constexpr (sizeof...(Tail) == 0) {
|
||||
return error(make_error_message(_errors));
|
||||
} else {
|
||||
return validate_impl<T, Tail...>(
|
||||
_value, std::forward<std::vector<Error>>(_errors));
|
||||
}
|
||||
};
|
||||
return Head::validate(_value).or_else(handle_err);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
136
build-config/reflect-cpp/include/rfl/Attribute.hpp
Normal file
136
build-config/reflect-cpp/include/rfl/Attribute.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef RFL_ATTRIBUTE_HPP_
|
||||
#define RFL_ATTRIBUTE_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "default.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class T>
|
||||
struct Attribute {
|
||||
using Type = T;
|
||||
using ReflectionType = T;
|
||||
|
||||
Attribute() : value_(Type()) {}
|
||||
|
||||
Attribute(const Type& _value) : value_(_value) {}
|
||||
|
||||
Attribute(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Attribute(Attribute<T>&& _attr) noexcept = default;
|
||||
|
||||
Attribute(const Attribute<Type>& _attr) = default;
|
||||
|
||||
template <class U>
|
||||
Attribute(const Attribute<U>& _attr) : value_(_attr.get()) {}
|
||||
|
||||
template <class U>
|
||||
Attribute(Attribute<U>&& _attr) : value_(_attr.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Attribute(const Attribute<U>& _attr) : value_(_attr.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
Attribute(const Default&) : value_(Type()) {}
|
||||
|
||||
~Attribute() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Attribute<T>& operator=(const Attribute<T>& _attr) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Attribute<T>& operator=(Attribute<T>&& _attr) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Attribute<U>& _attr) {
|
||||
value_ = _attr.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Attribute<U>&& _attr) {
|
||||
value_ = std::forward<T>(_attr.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// We want all parsers other than the XML parser to treat attributes like
|
||||
/// normal fields, so we just implement the reflection interface.
|
||||
const ReflectionType& reflection() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
127
build-config/reflect-cpp/include/rfl/Binary.hpp
Normal file
127
build-config/reflect-cpp/include/rfl/Binary.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef RFL_BINARY_HPP_
|
||||
#define RFL_BINARY_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to define a field in the NamedTuple.
|
||||
template <class T>
|
||||
requires std::is_unsigned_v<T>
|
||||
struct Binary {
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
|
||||
using ReflectionType = std::string;
|
||||
|
||||
using Bitset = std::bitset<sizeof(Type) * 8>;
|
||||
|
||||
Binary() : value_(0) {}
|
||||
|
||||
Binary(const Type& _value) : value_(_value) {}
|
||||
|
||||
Binary(Binary&& _other) noexcept = default;
|
||||
|
||||
Binary(const Binary& _other) = default;
|
||||
|
||||
template <class U>
|
||||
Binary(const Binary<U>& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U>
|
||||
Binary(Binary<U>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Binary(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Binary(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Binary(const Binary<U>& _other) : value_(_other.value()) {}
|
||||
|
||||
Binary(const std::string& _str)
|
||||
: value_(static_cast<T>(Bitset{_str}.to_ullong())) {}
|
||||
|
||||
~Binary() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
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.
|
||||
Binary& operator=(const Binary<T>& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Binary& operator=(Binary<T>&& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Binary<U>& _other) {
|
||||
value_ = _other.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const std::string& _str) {
|
||||
value_ = static_cast<T>(Bitset{_str}.to_ullong());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Binary<U>&& _other) {
|
||||
value_ = std::forward<T>(_other.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Necessary for the automated parsing to work.
|
||||
std::string reflection() const { return Bitset{value_}.to_string(); }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Returns the underlying value as a string, alias for .reflection().
|
||||
std::string str() const { return reflection(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_FIELD_HPP_
|
||||
159
build-config/reflect-cpp/include/rfl/Box.hpp
Normal file
159
build-config/reflect-cpp/include/rfl/Box.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#ifndef RFL_BOX_HPP_
|
||||
#define RFL_BOX_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Result.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
|
||||
enum class Copyability {
|
||||
COPYABLE,
|
||||
NON_COPYABLE
|
||||
};
|
||||
|
||||
/// The Box class behaves very similarly to the unique_ptr, but unlike the
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
|
||||
/// tries to access it after calling std::move does something else that is
|
||||
/// clearly bad practice).
|
||||
///
|
||||
/// By default Box behaves like a unique_ptr in relation to copying, but it can be
|
||||
/// configured to add copy constructor and assignment operators that call the
|
||||
/// same function of the contained type T.
|
||||
|
||||
template <class T, Copyability C = Copyability::NON_COPYABLE>
|
||||
class Box {
|
||||
public:
|
||||
/// The only way of creating new boxes is
|
||||
/// Box<T>::make(...).
|
||||
template <class... Args>
|
||||
static Box make(Args&&... _args) {
|
||||
return Box(std::make_unique<T>(std::forward<Args>(_args)...));
|
||||
}
|
||||
|
||||
/// You can generate them from unique_ptrs as well, in which case it will
|
||||
/// return an Error, if the unique_ptr is not set.
|
||||
static Result<Box> make(std::unique_ptr<T>&& _ptr) {
|
||||
if (!_ptr) {
|
||||
return error("std::unique_ptr was a nullptr.");
|
||||
}
|
||||
return Box(std::move(_ptr));
|
||||
}
|
||||
|
||||
Box() : ptr_(std::make_unique<T>()) {}
|
||||
|
||||
/// Copy constructor if copyable
|
||||
Box(const Box& _other) requires (C == Copyability::COPYABLE)
|
||||
{
|
||||
ptr_ = std::make_unique<T>(*_other);
|
||||
}
|
||||
|
||||
/// Copy constructor if not copyable
|
||||
Box(const Box& _other) requires (C == Copyability::NON_COPYABLE) = delete;
|
||||
|
||||
Box(Box&& _other) = default;
|
||||
|
||||
template <class U, Copyability C2>
|
||||
Box(Box<U, C2>&& _other) noexcept
|
||||
: ptr_(std::forward<std::unique_ptr<U>>(_other.ptr())) {}
|
||||
|
||||
~Box() = default;
|
||||
|
||||
/// Returns a pointer to the underlying object
|
||||
T* get() const { return ptr_.get(); }
|
||||
|
||||
/// Copy assignment operator if copyable
|
||||
Box& operator=(const Box<T>& other) requires (C == Copyability::COPYABLE) {
|
||||
if(this != &other) {
|
||||
ptr_ = std::make_unique<T>(*other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Copy assignment operator if not copyable
|
||||
Box& operator=(const Box& _other) requires (C == Copyability::NON_COPYABLE) = delete;
|
||||
|
||||
/// Move assignment operator
|
||||
Box& operator=(Box&& _other) noexcept = default;
|
||||
|
||||
/// Move assignment operator
|
||||
template <class U>
|
||||
Box& operator=(Box<U>&& _other) noexcept {
|
||||
ptr_ = std::forward<std::unique_ptr<U>>(_other.ptr());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns the underlying object.
|
||||
T& operator*() { return *ptr_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T& operator*() const { return *ptr_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T* operator->() { return ptr_.get(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T* operator->() const { return ptr_.get(); }
|
||||
|
||||
/// Returns the underlying unique_ptr
|
||||
std::unique_ptr<T>& ptr() { return ptr_; }
|
||||
|
||||
/// Returns the underlying unique_ptr
|
||||
const std::unique_ptr<T>& ptr() const { return ptr_; }
|
||||
|
||||
private:
|
||||
/// Only make is allowed to use this constructor.
|
||||
explicit Box(std::unique_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
|
||||
|
||||
private:
|
||||
/// The underlying unique_ptr_
|
||||
std::unique_ptr<T> ptr_;
|
||||
};
|
||||
|
||||
/// Generates a new Ref<T>.
|
||||
template <class T, class... Args>
|
||||
auto make_box(Args&&... _args) {
|
||||
return Box<T>::make(std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
/// Template specialization for a box that is copyable.
|
||||
template<typename T>
|
||||
using CopyableBox = Box<T, Copyability::COPYABLE>;
|
||||
|
||||
template <class T, class... Args>
|
||||
auto make_copyable_box(Args&&... _args) {
|
||||
return CopyableBox<T>::make(std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline auto operator<=>(const Box<T1>& _b1, const Box<T2>& _b2) {
|
||||
return _b1.ptr() <=> _b2.ptr();
|
||||
}
|
||||
|
||||
template <class CharT, class Traits, class T>
|
||||
inline std::basic_ostream<CharT, Traits>& operator<<(
|
||||
std::basic_ostream<CharT, Traits>& _os, const Box<T>& _b) {
|
||||
_os << _b.get();
|
||||
return _os;
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T>
|
||||
struct hash<rfl::Box<T>> {
|
||||
size_t operator()(const rfl::Box<T>& _b) const {
|
||||
return std::hash<std::unique_ptr<T>>{}(_b.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void swap(rfl::Box<T>& _b1, rfl::Box<T>& _b2) {
|
||||
return swap(_b1.ptr(), _b2.ptr());
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
13
build-config/reflect-cpp/include/rfl/Bytestring.hpp
Normal file
13
build-config/reflect-cpp/include/rfl/Bytestring.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef RFL_BYTESTRING_HPP_
|
||||
#define RFL_BYTESTRING_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
using Bytestring = std::vector<std::byte>;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
19
build-config/reflect-cpp/include/rfl/DefaultIfMissing.hpp
Normal file
19
build-config/reflect-cpp/include/rfl/DefaultIfMissing.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef RFL_DEFAULTIFMISSING_HPP_
|
||||
#define RFL_DEFAULTIFMISSING_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to use the default values for missing
|
||||
/// fields.
|
||||
struct DefaultIfMissing {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
129
build-config/reflect-cpp/include/rfl/DefaultVal.hpp
Normal file
129
build-config/reflect-cpp/include/rfl/DefaultVal.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef RFL_DEFAULTVAL_HPP_
|
||||
#define RFL_DEFAULTVAL_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "default.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class T>
|
||||
struct DefaultVal {
|
||||
public:
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
|
||||
DefaultVal() : value_(Type()) {}
|
||||
|
||||
DefaultVal(const Type& _value) : value_(_value) {}
|
||||
|
||||
DefaultVal(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
DefaultVal(DefaultVal&& _field) noexcept = default;
|
||||
|
||||
DefaultVal(const DefaultVal& _field) = default;
|
||||
|
||||
template <class U>
|
||||
DefaultVal(const DefaultVal<U>& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U>
|
||||
DefaultVal(DefaultVal<U>&& _field) noexcept(
|
||||
noexcept(Type(std::move(_field.value()))))
|
||||
: value_(std::move(_field.value())) {}
|
||||
|
||||
template <class U>
|
||||
requires(std::is_convertible_v<U, Type>)
|
||||
DefaultVal(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U>
|
||||
requires(std::is_convertible_v<U, Type>)
|
||||
DefaultVal(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U>
|
||||
requires(std::is_convertible_v<U, Type>)
|
||||
DefaultVal(const DefaultVal<U>& _field) : value_(_field.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type>
|
||||
requires(std::is_default_constructible_v<U>)
|
||||
DefaultVal(const Default&) : value_(Type()) {}
|
||||
|
||||
~DefaultVal() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
DefaultVal& operator=(const DefaultVal& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
DefaultVal& operator=(DefaultVal&& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const DefaultVal<U>& _field) {
|
||||
value_ = _field.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(DefaultVal<U>&& _field) {
|
||||
value_ = std::forward<U>(_field.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
150
build-config/reflect-cpp/include/rfl/Description.hpp
Normal file
150
build-config/reflect-cpp/include/rfl/Description.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifndef RFL_DESCRIPTION_HPP_
|
||||
#define RFL_DESCRIPTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "default.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to add a description to the field - this is only relevant for the JSON
|
||||
/// schema and will be ignored by the normal serialization routines.
|
||||
template <internal::StringLiteral _description, class T>
|
||||
struct Description {
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
|
||||
/// The description of the field.
|
||||
using Content = rfl::Literal<_description>;
|
||||
|
||||
using ReflectionType = Type;
|
||||
|
||||
Description() : value_(Type()) {}
|
||||
|
||||
Description(const Type& _value) : value_(_value) {}
|
||||
|
||||
Description(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Description(Description&& _field) noexcept = default;
|
||||
|
||||
Description(const Description& _field) = default;
|
||||
|
||||
template <class U>
|
||||
Description(const Description<_description, U>& _field)
|
||||
: value_(_field.get()) {}
|
||||
|
||||
template <class U>
|
||||
Description(Description<_description, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Description(const Description<_description, U>& _field)
|
||||
: value_(_field.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
Description(const Default&) : value_(Type()) {}
|
||||
|
||||
~Description() = default;
|
||||
|
||||
/// The description of the field, for internal use.
|
||||
constexpr static const internal::StringLiteral description_ = _description;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Description& operator=(
|
||||
const Description& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Description& operator=(
|
||||
Description&& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Description<_description, U>& _field) {
|
||||
value_ = _field.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Description<_description, U>&& _field) {
|
||||
value_ = std::forward<T>(_field.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns the underlying object - necessary for the reflection to work.
|
||||
const Type& reflection() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
15
build-config/reflect-cpp/include/rfl/ExtraFields.hpp
Normal file
15
build-config/reflect-cpp/include/rfl/ExtraFields.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef RFL_EXTRAFIELDS_HPP_
|
||||
#define RFL_EXTRAFIELDS_HPP_
|
||||
|
||||
#include "Object.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to embed additional fields for which the names cannot be known in
|
||||
/// advance and can therefore not be encoded in the struct.
|
||||
template <class T>
|
||||
class ExtraFields : public Object<T> {};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
151
build-config/reflect-cpp/include/rfl/Field.hpp
Normal file
151
build-config/reflect-cpp/include/rfl/Field.hpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef RFL_FIELD_HPP_
|
||||
#define RFL_FIELD_HPP_
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "default.hpp"
|
||||
#include "internal/Array.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/wrap_in_rfl_array_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to define a field in the NamedTuple.
|
||||
template <internal::StringLiteral _name, class T>
|
||||
struct Field {
|
||||
/// The underlying type.
|
||||
using Type = internal::wrap_in_rfl_array_t<T>;
|
||||
|
||||
/// The name of the field.
|
||||
using Name = rfl::Literal<_name>;
|
||||
|
||||
Field(const Type& _value) : value_(_value) {}
|
||||
|
||||
Field(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Field(Field&& _field) noexcept = default;
|
||||
|
||||
Field(const Field& _field) = default;
|
||||
|
||||
template <class U>
|
||||
Field(const Field<_name, U>& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U>
|
||||
Field(Field<_name, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Field(const Field<_name, U>& _field) : value_(_field.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
Field(const Default&) : value_(Type()) {}
|
||||
|
||||
~Field() = default;
|
||||
|
||||
/// The name of the field, for internal use.
|
||||
constexpr static const internal::StringLiteral name_ = _name;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// The name of the field.
|
||||
constexpr static std::string_view name() { return name_.string_view(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Field& operator=(const Field& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Field& operator=(Field&& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Field<_name, U>& _field) {
|
||||
value_ = _field.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Field<_name, U>&& _field) {
|
||||
value_ = std::forward<T>(_field.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
template <internal::StringLiteral _name, class T>
|
||||
inline auto make_field(T&& _value) {
|
||||
using T0 = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_array_v<T0>) {
|
||||
return Field<_name, T0>(internal::Array<T0>(std::forward<T>(_value)));
|
||||
} else {
|
||||
return Field<_name, T0>(std::forward<T>(_value));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_FIELD_HPP_
|
||||
120
build-config/reflect-cpp/include/rfl/Flatten.hpp
Normal file
120
build-config/reflect-cpp/include/rfl/Flatten.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef RFL_FLATTEN_HPP_
|
||||
#define RFL_FLATTEN_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to embed another struct into the generated output.
|
||||
template <class T>
|
||||
struct Flatten {
|
||||
/// The underlying type.
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
|
||||
Flatten() = default;
|
||||
|
||||
Flatten(const Type& _value) : value_(_value) {}
|
||||
|
||||
Flatten(Type&& _value) noexcept : value_(std::forward<Type>(_value)) {}
|
||||
|
||||
Flatten(const Flatten& _f) = default;
|
||||
|
||||
Flatten(Flatten&& _f) noexcept = default;
|
||||
|
||||
template <class U>
|
||||
Flatten(const Flatten<U>& _f) : value_(_f.get()) {}
|
||||
|
||||
template <class U>
|
||||
Flatten(Flatten<U>&& _f) : value_(_f.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten(U&& _value) : value_(_value) {}
|
||||
|
||||
~Flatten() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& get() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Flatten& operator=(const T& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Flatten& operator=(T&& _value) {
|
||||
value_ = std::forward<Type>(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Flatten& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Flatten& operator=(const Flatten& _f) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Flatten& operator=(Flatten&& _f) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
Flatten& operator=(const Flatten<U>& _f) {
|
||||
value_ = _f.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
Flatten& operator=(Flatten<U>&& _f) {
|
||||
value_ = std::forward<U>(_f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Three-way comparison operator
|
||||
template <class U>
|
||||
auto operator<=>(const Flatten<U>& _f) const {
|
||||
return value_ <=> _f.value_;
|
||||
}
|
||||
|
||||
/// Equality comparison operator.
|
||||
template <class U>
|
||||
bool operator==(const Flatten<U>& _f) const {
|
||||
return value_ == _f.get();
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::forward<Type>(_value); }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
299
build-config/reflect-cpp/include/rfl/Generic.hpp
Normal file
299
build-config/reflect-cpp/include/rfl/Generic.hpp
Normal file
@@ -0,0 +1,299 @@
|
||||
#ifndef RFL_GENERIC_HPP_
|
||||
#define RFL_GENERIC_HPP_
|
||||
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "Object.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "Variant.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
class RFL_API Generic {
|
||||
public:
|
||||
constexpr static std::nullopt_t Null = std::nullopt;
|
||||
|
||||
using Array = std::vector<Generic>;
|
||||
using Object = rfl::Object<Generic>;
|
||||
using VariantType = std::variant<bool, int64_t, double, std::string, Object,
|
||||
Array, std::nullopt_t>;
|
||||
using ReflectionType = std::optional<
|
||||
std::variant<bool, int64_t, double, std::string, Object, Array>>;
|
||||
|
||||
Generic();
|
||||
|
||||
Generic(Generic&& _other) noexcept;
|
||||
|
||||
Generic(const Generic& _other);
|
||||
|
||||
Generic(const VariantType& _value);
|
||||
|
||||
Generic(VariantType&& _value) noexcept;
|
||||
|
||||
Generic(const ReflectionType& _value);
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
Generic(const T& _value) {
|
||||
value_ = _value;
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
Generic(T&& _value) noexcept : value_(std::forward<T>(_value)) {}
|
||||
|
||||
~Generic();
|
||||
|
||||
/// Returns the underlying object.
|
||||
const VariantType& get() const { return value_; }
|
||||
|
||||
/// Whether the object contains the null value.
|
||||
bool is_null() const noexcept;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Generic& operator=(const VariantType& _value);
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Generic& operator=(VariantType&& _value) noexcept;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const T& _value) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::is_same_v<Type, bool>) {
|
||||
value_.emplace<0>(_value);
|
||||
} else if constexpr (std::is_integral_v<Type>) {
|
||||
value_.emplace<1>(static_cast<int64_t>(_value));
|
||||
} else if constexpr (std::is_floating_point_v<Type>) {
|
||||
value_.emplace<2>(static_cast<double>(_value));
|
||||
} else {
|
||||
value_ = _value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Generic& operator=(const Generic& _other);
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Generic& operator=(Generic&& _other);
|
||||
|
||||
/// Returns the underlying object, necessary for the serialization to work.
|
||||
ReflectionType reflection() const noexcept;
|
||||
|
||||
/// Casts the underlying value to an rfl::Generic::Array or returns an
|
||||
/// rfl::Error, if the underlying value is not an rfl::Generic::Array.
|
||||
Result<Array> to_array() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<Array> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, Array>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to an "
|
||||
"rfl::Generic::Array.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a boolean or returns an rfl::Error, if the
|
||||
/// underlying value is not a boolean.
|
||||
Result<bool> to_bool() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<bool> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, bool>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to a "
|
||||
"boolean.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a double or returns an rfl::Error, if the
|
||||
/// underlying value is not a number or the conversion would result in loss of
|
||||
/// precision.
|
||||
Result<double> to_double() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<double> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, double>) {
|
||||
return _v;
|
||||
} else if constexpr (std::is_same_v<V, int64_t>) {
|
||||
auto _d = static_cast<double>(_v);
|
||||
if (static_cast<int64_t>(_d) == _v) {
|
||||
return _d;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to a "
|
||||
"double without loss of precision.");
|
||||
}
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to a "
|
||||
"double.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to an integer or returns an rfl::Error, if the
|
||||
/// underlying value is not an integer.
|
||||
Result<int> to_int() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<int> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, int64_t>) {
|
||||
return static_cast<int>(_v);
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to an "
|
||||
"integer.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to an int64 or returns an rfl::Error, if the
|
||||
/// underlying value is not an integer.
|
||||
Result<int64_t> to_int64() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<int64_t> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, int64_t>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to an "
|
||||
"int64.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to an rfl::Generic::Object or returns an
|
||||
/// rfl::Error, if the underlying value is not an rfl::Generic::Object.
|
||||
Result<Object> to_object() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<Object> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, Object>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to an "
|
||||
"rfl::Generic::Object.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to rfl::Generic::Null or returns an
|
||||
/// rfl::Error, if the underlying value is not rfl::Generic::Null.
|
||||
Result<std::nullopt_t> to_null() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<std::nullopt_t> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, std::nullopt_t>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to "
|
||||
"rfl::Generic::Null.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a string or returns an rfl::Error, if the
|
||||
/// underlying value is not a string.
|
||||
Result<std::string> to_string() const noexcept {
|
||||
return std::visit(
|
||||
[](auto _v) -> Result<std::string> {
|
||||
using V = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same_v<V, std::string>) {
|
||||
return _v;
|
||||
} else {
|
||||
return error(
|
||||
"rfl::Generic: Could not cast the underlying value to a "
|
||||
"string.");
|
||||
}
|
||||
},
|
||||
value_);
|
||||
}
|
||||
|
||||
/// Returns the underlying variant.
|
||||
VariantType& variant() noexcept { return value_; };
|
||||
|
||||
/// Returns the underlying variant.
|
||||
const VariantType& variant() const noexcept { return value_; };
|
||||
|
||||
private:
|
||||
static VariantType from_reflection_type(const ReflectionType& _r) noexcept;
|
||||
|
||||
private:
|
||||
VariantType value_;
|
||||
};
|
||||
|
||||
/// Casts the underlying value to an rfl::Generic::Array or returns an
|
||||
/// rfl::Error, if the underlying value is not an rfl::Generic::Array.
|
||||
inline Result<Generic::Array> to_array(const Generic& _g) noexcept {
|
||||
return _g.to_array();
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a boolean or returns an rfl::Error, if the
|
||||
/// underlying value is not a boolean.
|
||||
inline Result<bool> to_bool(const Generic& _g) noexcept { return _g.to_bool(); }
|
||||
|
||||
/// Casts the underlying value to a double or returns an rfl::Error, if the
|
||||
/// underlying value is not a double.
|
||||
inline Result<double> to_double(const Generic& _g) noexcept {
|
||||
return _g.to_double();
|
||||
}
|
||||
|
||||
/// Casts the underlying value to an integer or returns an rfl::Error, if the
|
||||
/// underlying value is not an integer.
|
||||
inline Result<int> to_int(const Generic& _g) noexcept { return _g.to_int(); }
|
||||
|
||||
/// Casts the underlying value to an int64 or returns an rfl::Error, if the
|
||||
/// underlying value is not an integer.
|
||||
inline Result<long> to_int64(const Generic& _g) noexcept {
|
||||
return _g.to_int64();
|
||||
}
|
||||
|
||||
/// Casts the underlying value to an rfl::Generic::Object or returns an
|
||||
/// rfl::Error, if the underlying value is not an rfl::Generic::Object.
|
||||
inline Result<Generic::Object> to_object(const Generic& _g) noexcept {
|
||||
return _g.to_object();
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a double or returns an rfl::Error, if the
|
||||
/// underlying value is not a double.
|
||||
inline Result<std::nullopt_t> to_null(const Generic& _g) noexcept {
|
||||
return _g.to_null();
|
||||
}
|
||||
|
||||
/// Casts the underlying value to a string or returns an rfl::Error, if the
|
||||
/// underlying value is not a string.
|
||||
inline Result<std::string> to_string(const Generic& _g) noexcept {
|
||||
return _g.to_string();
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
129
build-config/reflect-cpp/include/rfl/Hex.hpp
Normal file
129
build-config/reflect-cpp/include/rfl/Hex.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#ifndef RFL_HEX_HPP_
|
||||
#define RFL_HEX_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to define a field in the NamedTuple.
|
||||
template <class T>
|
||||
requires std::is_integral_v<T>
|
||||
struct Hex {
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
|
||||
using ReflectionType = std::string;
|
||||
|
||||
Hex() : value_(0) {}
|
||||
|
||||
Hex(const Type& _value) : value_(_value) {}
|
||||
|
||||
Hex(Hex<T>&& _other) noexcept = default;
|
||||
|
||||
Hex(const Hex<T>& _other) = default;
|
||||
|
||||
template <class U>
|
||||
Hex(const Hex<U>& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U>
|
||||
Hex(Hex<U>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Hex(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Hex(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Hex(const Hex<U>& _other) : value_(_other.value()) {}
|
||||
|
||||
Hex(const std::string& _str) {
|
||||
std::istringstream(_str) >> std::hex >> value_;
|
||||
}
|
||||
|
||||
~Hex() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
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.
|
||||
Hex<T>& operator=(const Hex<T>& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Hex<T>& operator=(Hex<T>&& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Hex<U>& _other) {
|
||||
value_ = _other.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const std::string& _str) {
|
||||
std::istringstream(_str) >> std::hex >> value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Hex<U>&& _other) {
|
||||
value_ = std::forward<T>(_other.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Necessary for the automated parsing to work.
|
||||
std::string reflection() const {
|
||||
std::stringstream stream;
|
||||
stream << std::hex << value_;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Returns the underlying value as a string, alias for .reflection().
|
||||
std::string str() const { return reflection(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_FIELD_HPP_
|
||||
371
build-config/reflect-cpp/include/rfl/Literal.hpp
Normal file
371
build-config/reflect-cpp/include/rfl/Literal.hpp
Normal file
@@ -0,0 +1,371 @@
|
||||
#ifndef RFL_LITERAL_HPP_
|
||||
#define RFL_LITERAL_HPP_
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "Tuple.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/find_index.hpp"
|
||||
#include "internal/no_duplicate_field_names.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral _name>
|
||||
struct LiteralHelper {
|
||||
constexpr static internal::StringLiteral name_ = _name;
|
||||
};
|
||||
|
||||
template <internal::StringLiteral... fields_>
|
||||
class Literal {
|
||||
using FieldsType = rfl::Tuple<LiteralHelper<fields_>...>;
|
||||
|
||||
public:
|
||||
using ValueType = std::conditional_t<sizeof...(fields_) <= 255, std::uint8_t,
|
||||
std::uint16_t>;
|
||||
|
||||
/// The number of different fields or different options that the literal
|
||||
/// can assume.
|
||||
static constexpr ValueType num_fields_ = sizeof...(fields_);
|
||||
|
||||
using ReflectionType = std::string;
|
||||
|
||||
/// Constructs a Literal from another literal.
|
||||
Literal(const Literal<fields_...>& _other) = default;
|
||||
|
||||
/// Constructs a Literal from another literal.
|
||||
Literal(Literal<fields_...>&& _other) noexcept = default;
|
||||
|
||||
Literal(const std::string& _str) : value_(find_value(_str).value()) {}
|
||||
|
||||
Literal() : value_(0) {}
|
||||
|
||||
~Literal() = default;
|
||||
|
||||
/// Constructs a new Literal.
|
||||
template <internal::StringLiteral _name>
|
||||
static Literal<fields_...> make() {
|
||||
return Literal(Literal<fields_...>::template value_of<_name>());
|
||||
}
|
||||
|
||||
/// Constructs a new Literal, equivalent to make, for reasons of consistency.
|
||||
template <internal::StringLiteral _name>
|
||||
static Literal<fields_...> from_name() {
|
||||
return Literal<fields_...>::template make<_name>();
|
||||
}
|
||||
|
||||
/// Constructs a new Literal.
|
||||
template <ValueType _value>
|
||||
static Literal<fields_...> from_value() {
|
||||
static_assert(_value < num_fields_,
|
||||
"Value cannot exceed number of fields.");
|
||||
return Literal<fields_...>(_value);
|
||||
}
|
||||
|
||||
/// Constructs a new Literal.
|
||||
static Result<Literal<fields_...>> from_value(ValueType _value) {
|
||||
if (_value >= num_fields_) {
|
||||
return error("Value cannot exceed number of fields.");
|
||||
}
|
||||
return Literal<fields_...>(_value);
|
||||
}
|
||||
|
||||
/// Determines whether the literal contains the string.
|
||||
static bool contains(const std::string& _str) {
|
||||
bool found = false;
|
||||
has_value(_str, &found);
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Determines whether the literal contains the string at compile time.
|
||||
template <internal::StringLiteral _name>
|
||||
static constexpr bool contains() {
|
||||
return find_value_of<_name>() != -1;
|
||||
}
|
||||
|
||||
/// Determines whether the literal contains any of the strings in the other
|
||||
/// literal at compile time.
|
||||
template <class OtherLiteralType>
|
||||
static constexpr bool contains_any() {
|
||||
return []<int... _is>(const std::integer_sequence<int, _is...>&) {
|
||||
return (false || ... ||
|
||||
OtherLiteralType::template contains<
|
||||
find_name_within_own_fields<_is>()>());
|
||||
}(std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
/// Determines whether the literal contains all of the strings in the other
|
||||
/// literal at compile time.
|
||||
template <class OtherLiteralType>
|
||||
static constexpr bool contains_all() {
|
||||
return []<int... _is>(const std::integer_sequence<int, _is...>&) {
|
||||
return (true && ... &&
|
||||
OtherLiteralType::template contains<
|
||||
find_name_within_own_fields<_is>()>());
|
||||
}(std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
/// Determines whether the literal has duplicate strings at compile time.
|
||||
/// These is useful for checking collections of strings in other contexts.
|
||||
static constexpr bool has_duplicates() {
|
||||
return !internal::no_duplicate_field_names<FieldsType>();
|
||||
}
|
||||
|
||||
/// Constructs a Literal from a string. Returns an error if the string
|
||||
/// cannot be found.
|
||||
static Result<Literal> from_string(const std::string& _str) {
|
||||
const auto to_literal = [](const auto& _v) {
|
||||
return Literal<fields_...>(_v);
|
||||
};
|
||||
return find_value(_str).transform(to_literal);
|
||||
};
|
||||
|
||||
/// The name defined by the Literal.
|
||||
std::string name() const { return find_name(); }
|
||||
|
||||
/// Returns all possible values of the literal as a std::vector<std::string>.
|
||||
static std::vector<std::string> names() {
|
||||
return allowed_strings_vec(std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
/// Helper function to retrieve a name at compile time.
|
||||
template <int _value>
|
||||
constexpr static auto name_of() {
|
||||
constexpr auto name = find_name_within_own_fields<_value>();
|
||||
return Literal<name>();
|
||||
}
|
||||
|
||||
/// Assigns from another literal.
|
||||
Literal<fields_...>& operator=(const Literal<fields_...>& _other) = default;
|
||||
|
||||
/// Assigns from another literal.
|
||||
Literal<fields_...>& operator=(Literal<fields_...>&& _other) noexcept =
|
||||
default;
|
||||
|
||||
/// Assigns the literal from a string
|
||||
Literal<fields_...>& operator=(const std::string& _str) {
|
||||
value_ = find_value(_str).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <=> for other Literals with the same fields.
|
||||
auto operator<=>(const Literal<fields_...>& _other) const {
|
||||
return value() <=> _other.value();
|
||||
}
|
||||
|
||||
/// <=> for other Literals with different fields.
|
||||
template <internal::StringLiteral... _fields>
|
||||
inline auto operator<=>(const Literal<_fields...>& _l2) const {
|
||||
return name() <=> _l2.name();
|
||||
}
|
||||
|
||||
/// <=> for strings.
|
||||
inline auto operator<=>(const std::string& _str) const {
|
||||
#if __cpp_lib_three_way_comparison >= 201907L
|
||||
return name() <=> _str;
|
||||
#else
|
||||
auto const& const_name = name();
|
||||
if (const_name < _str) {
|
||||
return std::strong_ordering::less;
|
||||
}
|
||||
if (const_name == _str) {
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
return std::strong_ordering::greater;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <=> for const char*.
|
||||
template <internal::StringLiteral... other_fields>
|
||||
inline auto operator<=>(const char* _str) const {
|
||||
#if __cpp_lib_three_way_comparison >= 201907L
|
||||
return name() <=> _str;
|
||||
#else
|
||||
auto const& const_name = name();
|
||||
if (const_name < _str) {
|
||||
return std::strong_ordering::less;
|
||||
}
|
||||
if (const_name == _str) {
|
||||
return std::strong_ordering::equal;
|
||||
}
|
||||
return std::strong_ordering::greater;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
template <class Other>
|
||||
bool operator==(const Other& _other) const {
|
||||
return (*this <=> _other) == 0;
|
||||
}
|
||||
|
||||
/// Alias for .name().
|
||||
std::string reflection() const { return name(); }
|
||||
|
||||
/// Returns the number of fields in the Literal.
|
||||
static constexpr size_t size() { return num_fields_; }
|
||||
|
||||
/// Alias for .name().
|
||||
std::string str() const { return name(); }
|
||||
|
||||
/// Alias for .names().
|
||||
static std::vector<std::string> strings() {
|
||||
return allowed_strings_vec(std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
/// Returns the value actually contained in the Literal.
|
||||
ValueType value() const { return value_; }
|
||||
|
||||
/// Returns the value of the string literal in the template.
|
||||
template <internal::StringLiteral _name>
|
||||
static constexpr ValueType value_of() {
|
||||
constexpr auto value = find_value_of<_name>();
|
||||
static_assert(value >= 0, "String not supported.");
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Only the static methods are allowed to access this.
|
||||
Literal(const ValueType _value) : value_(_value) {}
|
||||
|
||||
/// Returns all of the allowed fields.
|
||||
static std::string allowed_strings() {
|
||||
const auto vec =
|
||||
allowed_strings_vec(std::make_integer_sequence<int, num_fields_>());
|
||||
std::string str;
|
||||
for (size_t i = 0; i < vec.size(); ++i) {
|
||||
const auto head = "'" + vec[i] + "'";
|
||||
str += i == 0 ? head : (", " + head);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/// Returns all of the allowed fields.
|
||||
template <int... _is>
|
||||
static std::vector<std::string> allowed_strings_vec(
|
||||
std::integer_sequence<int, _is...>) {
|
||||
std::vector<std::string> values;
|
||||
(allowed_strings_vec_add_one<_is>(&values), ...);
|
||||
return values;
|
||||
}
|
||||
|
||||
template <int _i>
|
||||
static void allowed_strings_vec_add_one(std::vector<std::string>* _values) {
|
||||
using FieldType = tuple_element_t<_i, FieldsType>;
|
||||
_values->emplace_back(FieldType::name_.str());
|
||||
}
|
||||
|
||||
/// Finds the correct index associated with
|
||||
/// the string at run time.
|
||||
std::string find_name() const {
|
||||
return find_name_set_str(std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
std::string find_name_set_str(std::integer_sequence<int, _is...>) const {
|
||||
std::string name;
|
||||
(find_name_set_if_matches<_is>(&name), ...);
|
||||
return name;
|
||||
}
|
||||
|
||||
template <int _i>
|
||||
void find_name_set_if_matches(std::string* _name) const {
|
||||
if (_i == value_) {
|
||||
using FieldType = tuple_element_t<_i, FieldsType>;
|
||||
*_name = FieldType::name_.str();
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the correct index associated with
|
||||
/// the string at compile time within the Literal's own fields.
|
||||
template <int _i>
|
||||
constexpr static auto find_name_within_own_fields() {
|
||||
return tuple_element_t<_i, FieldsType>::name_;
|
||||
}
|
||||
|
||||
/// Finds the correct value associated with
|
||||
/// the string at run time.
|
||||
static Result<int> find_value(const std::string& _str) {
|
||||
bool found = false;
|
||||
const auto idx = find_value_set_idx(
|
||||
_str, &found, std::make_integer_sequence<int, num_fields_>());
|
||||
if (!found) {
|
||||
return error(
|
||||
"Literal does not support string '" + _str +
|
||||
"'. The following strings are supported: " + allowed_strings() + ".");
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
static int find_value_set_idx(const std::string& _str, bool* _found,
|
||||
std::integer_sequence<int, _is...>) {
|
||||
int idx = 0;
|
||||
(find_value_set_if_matches<_is>(_str, _found, &idx), ...);
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <int _i>
|
||||
static void find_value_set_if_matches(const std::string& _str, bool* _found,
|
||||
int* _idx) {
|
||||
using FieldType = tuple_element_t<_i, FieldsType>;
|
||||
if (!*_found && FieldType::name_.string_view() == _str) {
|
||||
*_idx = _i;
|
||||
*_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the value of a string literal at compile time.
|
||||
template <internal::StringLiteral _name>
|
||||
static constexpr int find_value_of() {
|
||||
return internal::find_index_or_minus_one<_name, FieldsType>();
|
||||
}
|
||||
|
||||
/// Whether the literal contains this string.
|
||||
static void has_value(const std::string& _str, bool* _found) {
|
||||
find_value_set_idx(_str, _found,
|
||||
std::make_integer_sequence<int, num_fields_>());
|
||||
}
|
||||
|
||||
static_assert(sizeof...(fields_) <= std::numeric_limits<ValueType>::max(),
|
||||
"Too many fields.");
|
||||
|
||||
static_assert(sizeof...(fields_) <= 1 || !has_duplicates(),
|
||||
"Duplicate strings are not allowed in a Literal.");
|
||||
|
||||
private:
|
||||
/// The underlying value.
|
||||
ValueType value_;
|
||||
};
|
||||
|
||||
/// Helper function to retrieve a name at compile time.
|
||||
template <class LiteralType, int _value>
|
||||
inline constexpr auto name_of() {
|
||||
return LiteralType::template name_of<_value>();
|
||||
}
|
||||
|
||||
/// Helper function to retrieve a value at compile time.
|
||||
template <class LiteralType, internal::StringLiteral _name>
|
||||
inline constexpr auto value_of() {
|
||||
return LiteralType::template value_of<_name>();
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
template <rfl::internal::StringLiteral... fields>
|
||||
struct hash<rfl::Literal<fields...>> {
|
||||
size_t operator()(const rfl::Literal<fields...>& _l) const {
|
||||
return hash<int>()(static_cast<int>(_l.value()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // RFL_LITERAL_HPP_
|
||||
32
build-config/reflect-cpp/include/rfl/MetaField.hpp
Normal file
32
build-config/reflect-cpp/include/rfl/MetaField.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef RFL_METAFIELD_HPP_
|
||||
#define RFL_METAFIELD_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Contains meta-information about a field in a struct.
|
||||
class MetaField {
|
||||
public:
|
||||
MetaField(const std::string& _name, const std::string& _type)
|
||||
: name_(_name), type_(_type) {}
|
||||
|
||||
~MetaField() = default;
|
||||
|
||||
/// The name of the field we describe.
|
||||
const std::string& name() const { return name_; };
|
||||
|
||||
/// The type of the field we describe.
|
||||
const std::string& type() const { return type_; };
|
||||
|
||||
private:
|
||||
/// The name of the field we describe.
|
||||
std::string name_;
|
||||
|
||||
/// The type of the field we describe.
|
||||
std::string type_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_TAGGEDUNION_HPP_
|
||||
681
build-config/reflect-cpp/include/rfl/NamedTuple.hpp
Normal file
681
build-config/reflect-cpp/include/rfl/NamedTuple.hpp
Normal file
@@ -0,0 +1,681 @@
|
||||
#ifndef RFL_NAMEDTUPLE_HPP_
|
||||
#define RFL_NAMEDTUPLE_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Field.hpp"
|
||||
#include "Literal.hpp"
|
||||
#include "Tuple.hpp"
|
||||
#include "apply.hpp"
|
||||
#include "get.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/find_index.hpp"
|
||||
#include "internal/is_extra_fields.hpp"
|
||||
#include "make_from_tuple.hpp"
|
||||
#include "tuple_cat.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// A named tuple behaves like a tuple,
|
||||
/// but the fields have explicit names, which
|
||||
/// allows for reflection.
|
||||
/// IMPORTANT: We have two template specializations. One with fields, one
|
||||
/// without fields.
|
||||
template <class... FieldTypes>
|
||||
class NamedTuple;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <class... FieldTypes>
|
||||
class NamedTuple {
|
||||
template <int _i>
|
||||
struct Index {};
|
||||
|
||||
static constexpr auto seq_ =
|
||||
std::make_integer_sequence<int, sizeof...(FieldTypes)>();
|
||||
|
||||
public:
|
||||
using Fields = rfl::Tuple<std::remove_cvref_t<FieldTypes>...>;
|
||||
using Names = Literal<std::remove_cvref_t<FieldTypes>::name_...>;
|
||||
using Values = rfl::Tuple<typename std::remove_cvref_t<FieldTypes>::Type...>;
|
||||
|
||||
public:
|
||||
/// Construct from the values.
|
||||
NamedTuple(typename std::remove_cvref<FieldTypes>::type::Type&&... _values)
|
||||
: values_(
|
||||
std::forward<typename std::remove_cvref<FieldTypes>::type::Type>(
|
||||
_values)...) {}
|
||||
|
||||
/// Construct from the values.
|
||||
NamedTuple(
|
||||
const typename std::remove_cvref<FieldTypes>::type::Type&... _values)
|
||||
: values_(rfl::make_tuple(_values...)) {}
|
||||
|
||||
/// Construct from the fields.
|
||||
NamedTuple(FieldTypes&&... _fields)
|
||||
: values_(rfl::make_tuple(std::move(_fields.value_)...)) {}
|
||||
|
||||
/// Construct from the fields.
|
||||
NamedTuple(const FieldTypes&... _fields)
|
||||
: values_(rfl::make_tuple(_fields.value_...)) {}
|
||||
|
||||
/// Construct from a tuple containing fields.
|
||||
NamedTuple(rfl::Tuple<FieldTypes...>&& _tup)
|
||||
: NamedTuple(rfl::make_from_tuple<NamedTuple<FieldTypes...>>(
|
||||
std::forward<rfl::Tuple<FieldTypes...>>(_tup))) {}
|
||||
|
||||
/// Construct from a tuple containing fields.
|
||||
NamedTuple(const rfl::Tuple<FieldTypes...>& _tup)
|
||||
: NamedTuple(rfl::make_from_tuple<NamedTuple<FieldTypes...>>(_tup)) {}
|
||||
|
||||
/// Copy constructor.
|
||||
NamedTuple(const NamedTuple<FieldTypes...>& _other) = default;
|
||||
|
||||
/// Move constructor.
|
||||
NamedTuple(NamedTuple<FieldTypes...>&& _other) = default;
|
||||
|
||||
/// Copy constructor.
|
||||
template <class... OtherFieldTypes>
|
||||
NamedTuple(const NamedTuple<OtherFieldTypes...>& _other)
|
||||
: NamedTuple(retrieve_fields(_other.fields(), seq_)) {}
|
||||
|
||||
/// Move constructor.
|
||||
template <class... OtherFieldTypes>
|
||||
NamedTuple(NamedTuple<OtherFieldTypes...>&& _other)
|
||||
: NamedTuple(retrieve_fields(
|
||||
std::forward<NamedTuple<OtherFieldTypes...>>(_other).fields(),
|
||||
seq_)) {}
|
||||
|
||||
~NamedTuple() = default;
|
||||
|
||||
/// Returns a new named tuple with additional fields.
|
||||
template <internal::StringLiteral _name, class FType, class... Tail>
|
||||
auto add(Field<_name, FType>&& _head, Tail&&... _tail) && {
|
||||
using Head = Field<_name, FType>;
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
|
||||
std::move(*this).make_fields(seq_, std::forward<Head>(_head)))
|
||||
.add(std::forward<Tail>(_tail)...);
|
||||
} else {
|
||||
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
|
||||
std::move(*this).make_fields(seq_, std::forward<Head>(_head)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new named tuple with additional fields.
|
||||
template <internal::StringLiteral _name, class FType, class... Tail>
|
||||
auto add(Field<_name, FType> _head, const Tail&... _tail) const& {
|
||||
using Head = Field<_name, FType>;
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
|
||||
make_fields(seq_, _head))
|
||||
.add(_tail...);
|
||||
} else {
|
||||
return NamedTuple<FieldTypes..., std::remove_cvref_t<Head>>(
|
||||
make_fields(seq_, _head));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for rfl::Tuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(rfl::Tuple<TupContent...>&& _tuple, Tail&&... _tail) && {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return std::move(*this)
|
||||
.add_tuple(std::forward<rfl::Tuple<TupContent...>>(_tuple))
|
||||
.add(std::forward<Tail>(_tail)...);
|
||||
} else {
|
||||
return std::move(*this).add_tuple(
|
||||
std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for rfl::Tuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(rfl::Tuple<TupContent...> _tuple, const Tail&... _tail) const& {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return add_tuple(std::move(_tuple)).add(_tail...);
|
||||
} else {
|
||||
return add_tuple(std::move(_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(NamedTuple<TupContent...>&& _named_tuple, Tail&&... _tail) && {
|
||||
return std::move(*this).add(
|
||||
std::forward<rfl::Tuple<TupContent...>>(
|
||||
std::forward<NamedTuple<TupContent...>>(_named_tuple).fields()),
|
||||
std::forward<Tail>(_tail)...);
|
||||
}
|
||||
|
||||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(NamedTuple<TupContent...> _named_tuple,
|
||||
const Tail&... _tail) const& {
|
||||
return add(_named_tuple.fields(), _tail...);
|
||||
}
|
||||
|
||||
/// Creates a new named tuple by applying the supplied function to
|
||||
/// field. The function is expected to return a named tuple itself.
|
||||
template <typename F>
|
||||
auto and_then(const F& _f) && {
|
||||
const auto transform_field = [&_f](auto... _fields) {
|
||||
return rfl::tuple_cat(_f(std::move(_fields)).fields()...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(rfl::Tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = rfl::apply(transform_field, std::move(*this).fields());
|
||||
return to_nt(std::move(new_fields));
|
||||
}
|
||||
|
||||
/// Creates a new named tuple by applying the supplied function to
|
||||
/// field. The function is expected to return a named tuple itself.
|
||||
template <typename F>
|
||||
auto and_then(const F& _f) const& {
|
||||
const auto transform_field = [&_f](auto... _fields) {
|
||||
return rfl::tuple_cat(_f(std::move(_fields)).fields()...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(rfl::Tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = rfl::apply(transform_field, std::move(fields()));
|
||||
return to_nt(std::move(new_fields));
|
||||
}
|
||||
|
||||
/// Invokes a callable object once for each field in order.
|
||||
template <typename F>
|
||||
void apply(F&& _f) const& {
|
||||
const auto apply_to_field = [&_f](const auto&... fields) {
|
||||
((_f(fields)), ...);
|
||||
};
|
||||
rfl::apply(apply_to_field, fields());
|
||||
}
|
||||
|
||||
/// Returns a tuple containing the fields.
|
||||
Fields fields() && { return std::move(*this).make_fields(seq_); }
|
||||
|
||||
/// Returns a tuple containing the fields.
|
||||
Fields fields() const& { return make_fields(seq_); }
|
||||
|
||||
/// Gets a field by index.
|
||||
template <int _index>
|
||||
auto& get() {
|
||||
return rfl::get<_index>(*this);
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <internal::StringLiteral _field_name>
|
||||
auto& get() {
|
||||
return rfl::get<_field_name>(*this);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field>
|
||||
auto& get() {
|
||||
return rfl::get<Field>(*this);
|
||||
}
|
||||
|
||||
/// Gets a field by index.
|
||||
template <int _index>
|
||||
const auto& get() const {
|
||||
return rfl::get<_index>(*this);
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <internal::StringLiteral _field_name>
|
||||
const auto& get() const {
|
||||
return rfl::get<_field_name>(*this);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field>
|
||||
const auto& get() const {
|
||||
return rfl::get<Field>(*this);
|
||||
}
|
||||
|
||||
/// Returns the results wrapped in a field.
|
||||
template <internal::StringLiteral _field_name>
|
||||
auto get_field() const {
|
||||
return rfl::make_field<_field_name>(rfl::get<_field_name>(*this));
|
||||
}
|
||||
|
||||
/// Copy assignment operator.
|
||||
NamedTuple<FieldTypes...>& operator=(
|
||||
const NamedTuple<FieldTypes...>& _other) = default;
|
||||
|
||||
/// Move assignment operator.
|
||||
NamedTuple<FieldTypes...>& operator=(
|
||||
NamedTuple<FieldTypes...>&& _other) noexcept = default;
|
||||
|
||||
/// Equality operator
|
||||
inline auto operator==(const rfl::NamedTuple<FieldTypes...>& _other) const {
|
||||
return values() == _other.values();
|
||||
}
|
||||
|
||||
/// Three-way comparison operator.
|
||||
inline auto operator<=>(const rfl::NamedTuple<FieldTypes...>& _other) const {
|
||||
return values() <=> _other.values();
|
||||
}
|
||||
|
||||
/// Returns the number of fields. Note that this is not necessary the same
|
||||
/// thing as .size(), because there might be rfl::ExtraFields, which are
|
||||
/// simply counted as one entry by .size(), but are counted by individually by
|
||||
/// .num_fields().
|
||||
size_t num_fields() const {
|
||||
if constexpr (pos_extra_fields() == -1) {
|
||||
return size();
|
||||
} else {
|
||||
return calc_num_fields<pos_extra_fields()>();
|
||||
}
|
||||
}
|
||||
|
||||
/// The position of the extra fields, or -1 if there aren't any.
|
||||
constexpr static int pos_extra_fields() { return pos_extra_fields_; }
|
||||
|
||||
/// Replaces one or several fields, returning a new version
|
||||
/// with the non-replaced fields left unchanged.
|
||||
template <internal::StringLiteral _name, class FType, class... OtherRFields>
|
||||
auto replace(Field<_name, FType>&& _field,
|
||||
OtherRFields&&... _other_fields) && {
|
||||
using RField = Field<_name, FType>;
|
||||
constexpr auto num_other_fields = sizeof...(OtherRFields);
|
||||
if constexpr (num_other_fields == 0) {
|
||||
return std::move(*this).template replace_value<RField>(_field.value_);
|
||||
} else {
|
||||
return std::move(*this)
|
||||
.template replace_value<RField>(_field.value_)
|
||||
.replace(std::forward<OtherRFields>(_other_fields)...);
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces one or several fields, returning a new version
|
||||
/// with the non-replaced fields left unchanged.
|
||||
template <internal::StringLiteral _name, class FType, class... OtherRFields>
|
||||
auto replace(Field<_name, FType> _field,
|
||||
const OtherRFields&... _other_fields) const& {
|
||||
using RField = Field<_name, FType>;
|
||||
constexpr auto num_other_fields = sizeof...(OtherRFields);
|
||||
if constexpr (num_other_fields == 0) {
|
||||
return replace_value<RField>(std::move(_field.value_));
|
||||
} else {
|
||||
return replace_value<RField>(std::move(_field.value_))
|
||||
.replace(_other_fields...);
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for rfl::Tuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto replace(rfl::Tuple<TupContent...>&& _tuple, Tail&&... _tail) && {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return std::move(*this)
|
||||
.replace_tuple(std::forward<rfl::Tuple<TupContent...>>(_tuple))
|
||||
.replace(std::forward<Tail>(_tail)...);
|
||||
} else {
|
||||
return std::move(*this).replace_tuple(
|
||||
std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for rfl::Tuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto replace(rfl::Tuple<TupContent...> _tuple, const Tail&... _tail) const& {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return replace_tuple(std::move(_tuple)).replace(_tail...);
|
||||
} else {
|
||||
return replace_tuple(std::move(_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto replace(NamedTuple<TupContent...>&& _named_tuple, Tail&&... _tail) && {
|
||||
return std::move(*this).replace(
|
||||
std::forward<NamedTuple<TupContent...>>(_named_tuple).fields(),
|
||||
std::forward<Tail>(_tail)...);
|
||||
}
|
||||
|
||||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto replace(NamedTuple<TupContent...> _named_tuple,
|
||||
const Tail&... _tail) const& {
|
||||
return replace(_named_tuple.fields(), _tail...);
|
||||
}
|
||||
|
||||
/// Returns the size of the named tuple
|
||||
static constexpr size_t size() { return rfl::tuple_size_v<Values>; }
|
||||
|
||||
/// Creates a new named tuple by applying the supplied function to every
|
||||
/// field.
|
||||
template <typename F>
|
||||
auto transform(const F& _f) && {
|
||||
const auto transform_field = [&_f](auto... fields) {
|
||||
return rfl::make_tuple(_f(std::move(fields))...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(rfl::Tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = rfl::apply(transform_field, std::move(*this).fields());
|
||||
return to_nt(std::move(new_fields));
|
||||
}
|
||||
|
||||
/// Creates a new named tuple by applying the supplied function to every
|
||||
/// field.
|
||||
template <typename F>
|
||||
auto transform(const F& _f) const& {
|
||||
const auto transform_field = [&_f](auto... fields) {
|
||||
return rfl::make_tuple(_f(std::move(fields))...);
|
||||
};
|
||||
const auto to_nt = []<class... NewFields>(rfl::Tuple<NewFields...>&& _tup) {
|
||||
return NamedTuple<NewFields...>(_tup);
|
||||
};
|
||||
auto new_fields = rfl::apply(transform_field, std::move(fields()));
|
||||
return to_nt(std::move(new_fields));
|
||||
}
|
||||
|
||||
/// Returns the underlying rfl::Tuple.
|
||||
Values& values() { return values_; }
|
||||
|
||||
/// Returns the underlying rfl::Tuple.
|
||||
const Values& values() const { return values_; }
|
||||
|
||||
private:
|
||||
/// Adds the elements of a tuple to a newly created named tuple,
|
||||
/// and other elements to a newly created named tuple.
|
||||
template <class... TupContent>
|
||||
constexpr auto add_tuple(rfl::Tuple<TupContent...>&& _tuple) && {
|
||||
const auto a = [this](auto&&... _fields) {
|
||||
return std::move(*this).add(std::forward<TupContent>(_fields)...);
|
||||
};
|
||||
return rfl::apply(a, std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
|
||||
/// Adds the elements of a tuple to a newly created named tuple,
|
||||
/// and other elements to a newly created named tuple.
|
||||
template <class... TupContent>
|
||||
constexpr auto add_tuple(rfl::Tuple<TupContent...>&& _tuple) const& {
|
||||
const auto a = [this](auto&&... _fields) {
|
||||
return this->add(std::forward<TupContent>(_fields)...);
|
||||
};
|
||||
return rfl::apply(a, std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
|
||||
/// Unfortunately, MSVC forces us to do this...
|
||||
template <int _pos>
|
||||
size_t calc_num_fields() const {
|
||||
const auto& extra_fields = get<_pos>();
|
||||
if constexpr (std::is_pointer_v<
|
||||
std::remove_cvref_t<decltype(extra_fields)>>) {
|
||||
return size() + extra_fields->size() - 1;
|
||||
} else {
|
||||
return size() + extra_fields.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the position of the extra fields, or -1 if there aren't any.
|
||||
template <int _i = 0, int _idx = -1>
|
||||
constexpr static int find_extra_fields() {
|
||||
if constexpr (_i == size()) {
|
||||
return _idx;
|
||||
} else {
|
||||
using FieldType = internal::nth_element_t<_i, FieldTypes...>;
|
||||
constexpr bool is_extra_fields =
|
||||
internal::is_extra_fields_v<typename FieldType::Type>;
|
||||
static_assert(_idx == -1 || !is_extra_fields,
|
||||
"There can only be one rfl::ExtraFields in any struct or "
|
||||
"named tuple.");
|
||||
if constexpr (is_extra_fields) {
|
||||
return find_extra_fields<_i + 1, _i>();
|
||||
} else {
|
||||
return find_extra_fields<_i + 1, _idx>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the fields.
|
||||
template <int... _is, class... AdditionalArgs>
|
||||
auto make_fields(std::integer_sequence<int, _is...>,
|
||||
AdditionalArgs&&... _args) && {
|
||||
const auto wrap = [this]<int _i>(Index<_i>) {
|
||||
using FieldType = internal::nth_element_t<_i, FieldTypes...>;
|
||||
return FieldType(std::move(rfl::get<_i>(values_)));
|
||||
};
|
||||
return rfl::make_tuple(wrap(Index<_is>{})...,
|
||||
std::forward<AdditionalArgs>(_args)...);
|
||||
}
|
||||
|
||||
/// Generates the fields.
|
||||
template <int... _is, class... AdditionalArgs>
|
||||
auto make_fields(std::integer_sequence<int, _is...>,
|
||||
AdditionalArgs... _args) const& {
|
||||
const auto wrap = [this]<int _i>(Index<_i>) {
|
||||
using FieldType = internal::nth_element_t<_i, FieldTypes...>;
|
||||
return FieldType(rfl::get<_i>(values_));
|
||||
};
|
||||
return rfl::make_tuple(wrap(Index<_is>{})..., _args...);
|
||||
}
|
||||
|
||||
/// Generates a new named tuple with one value replaced with a new value.
|
||||
template <int _index, class V, class T, int... _is>
|
||||
auto make_replaced(V&& _values, T&& _val,
|
||||
std::integer_sequence<int, _is...>) const {
|
||||
const auto wrap = [&]<int _i>(Index<_i>) {
|
||||
if constexpr (_i == _index) {
|
||||
return std::forward<T>(_val);
|
||||
} else {
|
||||
using FieldType = internal::nth_element_t<_i, FieldTypes...>;
|
||||
using U = typename FieldType::Type;
|
||||
return FieldType(std::forward<U>(rfl::get<_i>(_values)));
|
||||
}
|
||||
};
|
||||
return NamedTuple<FieldTypes...>(wrap(Index<_is>{})...);
|
||||
}
|
||||
|
||||
/// Replaced the field signified by the field type.
|
||||
template <class Field, class T>
|
||||
NamedTuple<FieldTypes...> replace_value(T&& _val) && {
|
||||
using FieldType = std::remove_cvref_t<Field>;
|
||||
constexpr auto index = internal::find_index<FieldType::name_, Fields>();
|
||||
return make_replaced<index>(std::move(values_), std::forward<T>(_val),
|
||||
seq_);
|
||||
}
|
||||
|
||||
/// Replaced the field signified by the field type.
|
||||
template <class Field, class T>
|
||||
NamedTuple<FieldTypes...> replace_value(T&& _val) const& {
|
||||
using FieldType = std::remove_cvref_t<Field>;
|
||||
constexpr auto index = internal::find_index<FieldType::name_, Fields>();
|
||||
auto values = values_;
|
||||
return make_replaced<index>(std::move(values), std::forward<T>(_val), seq_);
|
||||
}
|
||||
|
||||
/// Adds the elements of a tuple to a newly created named tuple,
|
||||
/// and other elements to a newly created named tuple.
|
||||
template <class... TupContent>
|
||||
auto replace_tuple(rfl::Tuple<TupContent...>&& _tuple) && {
|
||||
const auto r = [this](auto&&... _fields) {
|
||||
return std::move(*this).replace(std::forward<TupContent>(_fields)...);
|
||||
};
|
||||
return rfl::apply(r, std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
|
||||
/// Adds the elements of a tuple to a newly created named tuple,
|
||||
/// and other elements to a newly created named tuple.
|
||||
template <class... TupContent>
|
||||
auto replace_tuple(rfl::Tuple<TupContent...>&& _tuple) const& {
|
||||
const auto r = [this](auto&&... _fields) {
|
||||
return this->replace(std::forward<TupContent>(_fields)...);
|
||||
};
|
||||
return rfl::apply(r, std::forward<rfl::Tuple<TupContent...>>(_tuple));
|
||||
}
|
||||
|
||||
/// Retrieves the fields from another tuple.
|
||||
template <class... OtherFieldTypes, int... _is>
|
||||
constexpr static Fields retrieve_fields(
|
||||
rfl::Tuple<OtherFieldTypes...>&& _other_fields,
|
||||
std::integer_sequence<int, _is...>) {
|
||||
const auto get_field = [&]<int _i>(Index<_i>) {
|
||||
constexpr auto field_name =
|
||||
internal::nth_element_t<_i, FieldTypes...>::name_;
|
||||
constexpr auto index =
|
||||
internal::find_index<field_name, rfl::Tuple<OtherFieldTypes...>>();
|
||||
using FieldType = internal::nth_element_t<_i, FieldTypes...>;
|
||||
using T = std::remove_cvref_t<typename FieldType::Type>;
|
||||
return FieldType(std::forward<T>(rfl::get<index>(_other_fields).value_));
|
||||
};
|
||||
return rfl::make_tuple(get_field(Index<_is>{})...);
|
||||
}
|
||||
|
||||
private:
|
||||
/// The values actually contained in the named tuple.
|
||||
/// As you can see, a NamedTuple is just a normal tuple under-the-hood,
|
||||
/// everything else is resolved at compile time. It should have no
|
||||
/// runtime overhead over a normal rfl::Tuple.
|
||||
Values values_;
|
||||
|
||||
/// The position of rfl::ExtraFields, or -1 if there aren't any.
|
||||
constexpr static int pos_extra_fields_ = find_extra_fields();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// We need a special template instantiation for empty named tuples.
|
||||
template <>
|
||||
class NamedTuple<> {
|
||||
public:
|
||||
using Fields = rfl::Tuple<>;
|
||||
using Names = Literal<>;
|
||||
using Values = rfl::Tuple<>;
|
||||
|
||||
NamedTuple(){};
|
||||
|
||||
~NamedTuple() = default;
|
||||
|
||||
/// Returns a new named tuple with additional fields.
|
||||
template <internal::StringLiteral _name, class FType, class... Tail>
|
||||
auto add(Field<_name, FType> _head, const Tail&... _tail) const {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return NamedTuple<Field<_name, FType>>(std::move(_head)).add(_tail...);
|
||||
} else {
|
||||
return NamedTuple<Field<_name, FType>>(std::move(_head));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for rfl::Tuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(rfl::Tuple<TupContent...> _tuple, const Tail&... _tail) const {
|
||||
if constexpr (sizeof...(Tail) > 0) {
|
||||
return NamedTuple<TupContent...>(std::move(_tuple)).add(_tail...);
|
||||
} else {
|
||||
return NamedTuple<TupContent...>(std::move(_tuple));
|
||||
}
|
||||
}
|
||||
|
||||
/// Template specialization for NamedTuple, so we can pass fields from other
|
||||
/// named tuples.
|
||||
template <class... TupContent, class... Tail>
|
||||
auto add(NamedTuple<TupContent...> _named_tuple, const Tail&... _tail) const {
|
||||
return add(_named_tuple.fields(), _tail...);
|
||||
}
|
||||
|
||||
/// Returns an empty named tuple.
|
||||
template <typename F>
|
||||
auto and_then(const F&) const {
|
||||
return NamedTuple<>();
|
||||
}
|
||||
|
||||
/// Does nothing at all.
|
||||
template <typename F>
|
||||
void apply(F&&) const {}
|
||||
|
||||
/// Returns an empty tuple.
|
||||
auto fields() const { return rfl::Tuple(); }
|
||||
|
||||
/// Must always be 0.
|
||||
size_t num_fields() const { return 0; }
|
||||
|
||||
/// Must always be -1.
|
||||
constexpr static int pos_extra_fields() { return -1; }
|
||||
|
||||
/// Must always be 0.
|
||||
static constexpr size_t size() { return 0; }
|
||||
|
||||
/// Returns an empty named tuple.
|
||||
template <typename F>
|
||||
auto transform(const F&) const {
|
||||
return NamedTuple<>();
|
||||
}
|
||||
|
||||
/// Returns an empty tuple.
|
||||
auto values() const { return rfl::Tuple(); }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <internal::StringLiteral _name1, class Type1,
|
||||
internal::StringLiteral _name2, class Type2>
|
||||
inline auto operator*(const rfl::Field<_name1, Type1>& _f1,
|
||||
const rfl::Field<_name2, Type2>& _f2) {
|
||||
return NamedTuple(_f1, _f2);
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name, class Type, class... FieldTypes>
|
||||
inline auto operator*(const NamedTuple<FieldTypes...>& _tup,
|
||||
const rfl::Field<_name, Type>& _f) {
|
||||
return _tup.add(_f);
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name, class Type, class... FieldTypes>
|
||||
inline auto operator*(const rfl::Field<_name, Type>& _f,
|
||||
const NamedTuple<FieldTypes...>& _tup) {
|
||||
return NamedTuple(_f).add(_tup);
|
||||
}
|
||||
|
||||
template <class... FieldTypes1, class... FieldTypes2>
|
||||
inline auto operator*(const NamedTuple<FieldTypes1...>& _tup1,
|
||||
const NamedTuple<FieldTypes2...>& _tup2) {
|
||||
return _tup1.add(_tup2);
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name1, class Type1,
|
||||
internal::StringLiteral _name2, class Type2>
|
||||
inline auto operator*(rfl::Field<_name1, Type1>&& _f1,
|
||||
rfl::Field<_name2, Type2>&& _f2) {
|
||||
return NamedTuple(std::forward<Field<_name1, Type1>>(_f1),
|
||||
std::forward<Field<_name2, Type2>>(_f2));
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name, class Type, class... FieldTypes>
|
||||
inline auto operator*(NamedTuple<FieldTypes...>&& _tup,
|
||||
rfl::Field<_name, Type>&& _f) {
|
||||
return _tup.add(std::forward<Field<_name, Type>>(_f));
|
||||
}
|
||||
|
||||
template <internal::StringLiteral _name, class Type, class... FieldTypes>
|
||||
inline auto operator*(rfl::Field<_name, Type>&& _f,
|
||||
NamedTuple<FieldTypes...>&& _tup) {
|
||||
return NamedTuple(std::forward<Field<_name, Type>>(_f))
|
||||
.add(std::forward<NamedTuple<FieldTypes...>>(_tup));
|
||||
}
|
||||
|
||||
template <class... FieldTypes1, class... FieldTypes2>
|
||||
inline auto operator*(NamedTuple<FieldTypes1...>&& _tup1,
|
||||
NamedTuple<FieldTypes2...>&& _tup2) {
|
||||
return _tup1.add(std::forward<NamedTuple<FieldTypes2...>>(_tup2));
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_NAMEDTUPLE_HPP_
|
||||
19
build-config/reflect-cpp/include/rfl/NoExtraFields.hpp
Normal file
19
build-config/reflect-cpp/include/rfl/NoExtraFields.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef RFL_NOEXTRAFIELDS_HPP_
|
||||
#define RFL_NOEXTRAFIELDS_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to return an error when there are extra
|
||||
/// fields instead of ignoring them.
|
||||
struct NoExtraFields {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/NoFieldNames.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/NoFieldNames.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_NOFIELDNAMES_HPP_
|
||||
#define RFL_NOFIELDNAMES_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to strip field names.
|
||||
struct NoFieldNames {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/NoOptionals.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/NoOptionals.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_NOOPTIONALS_HPP_
|
||||
#define RFL_NOOPTIONALS_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a "fake" processor - it doesn't do much in itself, but its
|
||||
/// inclusion instructs the parsers to require the inclusion of all fields.
|
||||
struct NoOptionals {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
248
build-config/reflect-cpp/include/rfl/Object.hpp
Normal file
248
build-config/reflect-cpp/include/rfl/Object.hpp
Normal file
@@ -0,0 +1,248 @@
|
||||
#ifndef RFL_OBJECT_HPP_
|
||||
#define RFL_OBJECT_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Result.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to embed additional fields for which the names cannot be known in
|
||||
/// advance and can therefore not be encoded in the struct.
|
||||
template <class T>
|
||||
class Object {
|
||||
public:
|
||||
using DataType = std::vector<std::pair<std::string, T>>;
|
||||
using Type = T;
|
||||
|
||||
/// We want this to behave as similarly to C++ standard containers as
|
||||
/// possible.
|
||||
using key_type = std::string;
|
||||
using mapped_type = T;
|
||||
using value_type = std::pair<std::string, T>;
|
||||
using size_type = typename DataType::size_type;
|
||||
using difference_type = typename DataType::size_type;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = typename DataType::pointer;
|
||||
using const_pointer = typename DataType::const_pointer;
|
||||
using iterator = typename DataType::iterator;
|
||||
using const_iterator = typename DataType::const_iterator;
|
||||
using reverse_iterator = typename DataType::reverse_iterator;
|
||||
using const_reverse_iterator = typename DataType::const_reverse_iterator;
|
||||
|
||||
Object() : data_(), i_(0) {}
|
||||
|
||||
Object(const Object<T>& _f) = default;
|
||||
|
||||
Object(Object<T>&& _f) noexcept = default;
|
||||
|
||||
~Object() = default;
|
||||
|
||||
/// Iterator to the beginning.
|
||||
auto begin() { return data_.begin(); }
|
||||
|
||||
/// Iterator to the beginning.
|
||||
auto begin() const { return data_.begin(); }
|
||||
|
||||
/// Const iterator to the beginning.
|
||||
auto cbegin() const { return data_.cbegin(); }
|
||||
|
||||
/// Iterator to the end.
|
||||
auto end() { return data_.end(); }
|
||||
|
||||
/// Iterator to the end.
|
||||
auto end() const { return data_.end(); }
|
||||
|
||||
/// Const iterator to the end.
|
||||
auto cend() const { return data_.cend(); }
|
||||
|
||||
/// Reverse iterator.
|
||||
auto rbegin() { return data_.rbegin(); }
|
||||
|
||||
/// Reverse iterator.
|
||||
auto rbegin() const { return data_.rbegin(); }
|
||||
|
||||
/// Const reverse iterator.
|
||||
auto crbegin() const { return data_.crbegin(); }
|
||||
|
||||
/// Reverse iterator.
|
||||
auto rend() { return data_.rend(); }
|
||||
|
||||
/// Reverse iterator.
|
||||
auto rend() const { return data_.rend(); }
|
||||
|
||||
/// Const reverse iterator.
|
||||
auto crend() const { return data_.crend(); }
|
||||
|
||||
Object<T>& operator=(const Object<T>& _f) = default;
|
||||
|
||||
Object<T>& operator=(Object<T>&& _f) = default;
|
||||
|
||||
/// Whether the object is empty.
|
||||
auto empty() const { return data_.size() == 0; }
|
||||
|
||||
/// The number of elements currently inside the object.
|
||||
auto size() const { return data_.size(); }
|
||||
|
||||
std::size_t count(const key_type& key) const { return std::count_if(cbegin(), cend(), [&](const auto& p) { return p.first == key; }); }
|
||||
|
||||
/// The maximum possible size.
|
||||
auto max_size() const { return data_.max_size(); }
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
template <class... Args>
|
||||
void insert(const Args&... _values) {
|
||||
(data_.push_back(_values), ...);
|
||||
i_ = 0;
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
template <class... Args>
|
||||
void insert(Args&&... _values) {
|
||||
(data_.emplace_back(std::move(_values)), ...);
|
||||
i_ = 0;
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
void insert(const std::string& _k, const T& _v) {
|
||||
insert(std::make_pair(_k, _v));
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
void insert(const std::string& _k, T&& _v) {
|
||||
insert(std::make_pair(_k, std::move(_v)));
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
void insert(std::string&& _k, T&& _v) {
|
||||
insert(std::make_pair(std::move(_k), std::move(_v)));
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
void insert(const std::string_view& _k, const T& _v) {
|
||||
insert(std::make_pair(std::string(_k), _v));
|
||||
}
|
||||
|
||||
/// Inserts a new element at the end.
|
||||
void insert(const std::string_view& _k, T&& _v) {
|
||||
insert(std::make_pair(std::string(_k), std::move(_v)));
|
||||
}
|
||||
|
||||
/// Alias for insert that primarily exists for compatability with standard
|
||||
/// containers.
|
||||
template <class... Args>
|
||||
void emplace(Args&&... _args) {
|
||||
insert(std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
/// Alias for insert that primarily exists for compatability with standard
|
||||
/// containers.
|
||||
template <class... Args>
|
||||
void emplace(const Args&... _args) {
|
||||
insert(_args...);
|
||||
}
|
||||
|
||||
/// Inserts several new elements at the end.
|
||||
template <class InputIt>
|
||||
void insert_range(InputIt _first, InputIt _last) {
|
||||
for (auto it = _first; it != _last; ++it) {
|
||||
insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts several new elements at the end.
|
||||
template <class RangeType>
|
||||
void insert_range(RangeType _range) {
|
||||
for (const auto& val : _range) {
|
||||
insert(val);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the element signified by the key or creates a new one.
|
||||
T& operator[](const std::string& _key) {
|
||||
const auto i = find(_key);
|
||||
if (i != size()) {
|
||||
return data_[i].second;
|
||||
}
|
||||
data_.emplace_back(std::make_pair(_key, T()));
|
||||
i_ = 0;
|
||||
return data_.back().second;
|
||||
}
|
||||
|
||||
/// Returns the element signified by the key or creates a new one.
|
||||
T& operator[](std::string&& _key) {
|
||||
const auto i = find(_key);
|
||||
if (i != size()) {
|
||||
return data_[i].second;
|
||||
}
|
||||
data_.emplace_back(std::make_pair(std::move(_key), T()));
|
||||
i_ = 0;
|
||||
return data_.back().second;
|
||||
}
|
||||
|
||||
/// Deletes all elements.
|
||||
void clear() {
|
||||
data_.clear();
|
||||
i_ = 0;
|
||||
}
|
||||
|
||||
/// Returns the element signified by the key or throws an exception.
|
||||
T& at(const std::string& _key) {
|
||||
const auto i = find(_key);
|
||||
if (i == size()) {
|
||||
throw std::runtime_error("Key named '" + _key + "' not found.");
|
||||
}
|
||||
return data_[i].second;
|
||||
}
|
||||
|
||||
/// Returns the element signified by the key or throws an exception.
|
||||
const T& at(const std::string& _key) const {
|
||||
const auto i = find(_key);
|
||||
if (i == size()) {
|
||||
throw std::runtime_error("Key named '" + _key + "' not found.");
|
||||
}
|
||||
return data_[i].second;
|
||||
}
|
||||
|
||||
/// Returns a result wrapping the element signified by the key.
|
||||
Result<T> get(const std::string& _key) const noexcept {
|
||||
const auto i = find(_key);
|
||||
if (i == size()) {
|
||||
return error("Key named '" + _key + "' not found.");
|
||||
}
|
||||
return data_[i].second;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t find(const std::string& _key) const {
|
||||
for (size_t i = i_; i < size(); ++i) {
|
||||
if (data_[i].first == _key) {
|
||||
i_ = i + 1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < i_; ++i) {
|
||||
if (data_[i].first == _key) {
|
||||
i_ = i + 1;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return size();
|
||||
}
|
||||
|
||||
private:
|
||||
DataType data_;
|
||||
|
||||
/// Allows faster access
|
||||
mutable size_t i_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
130
build-config/reflect-cpp/include/rfl/Oct.hpp
Normal file
130
build-config/reflect-cpp/include/rfl/Oct.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#ifndef RFL_OCT_HPP_
|
||||
#define RFL_OCT_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to define a field in the NamedTuple.
|
||||
template <class T>
|
||||
requires std::is_integral_v<T>
|
||||
struct Oct {
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
|
||||
using ReflectionType = std::string;
|
||||
|
||||
Oct() : value_(0) {}
|
||||
|
||||
Oct(const Type& _value) : value_(_value) {}
|
||||
|
||||
Oct(Oct<T>&& _other) noexcept = default;
|
||||
|
||||
Oct(const Oct<T>& _other) = default;
|
||||
|
||||
template <class U>
|
||||
Oct(const Oct<U>& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U>
|
||||
Oct(Oct<U>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Oct(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Oct(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Oct(const Oct<U>& _other) : value_(_other.value()) {}
|
||||
|
||||
Oct(const std::string& _str) {
|
||||
std::istringstream(_str) >> std::oct >> value_;
|
||||
}
|
||||
|
||||
~Oct() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
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.
|
||||
Oct<T>& operator=(const Oct<T>& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Oct<T>& operator=(Oct<T>&& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Oct<U>& _other) {
|
||||
value_ = _other.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const std::string& _str) {
|
||||
std::istringstream(_str) >> std::oct >> value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Oct<U>&& _other) {
|
||||
value_ = std::forward<T>(_other.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Necessary for the automated parsing to work.
|
||||
std::string reflection() const {
|
||||
std::stringstream stream;
|
||||
stream << std::oct << value_;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Returns the underlying value as a string, alias for .reflection().
|
||||
std::string str() const { return reflection(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_FIELD_HPP_
|
||||
71
build-config/reflect-cpp/include/rfl/OneOf.hpp
Normal file
71
build-config/reflect-cpp/include/rfl/OneOf.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef RFL_ONEOF_HPP_
|
||||
#define RFL_ONEOF_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Requires that all of the contraints C and Cs be true.
|
||||
template <class C, class... Cs>
|
||||
struct OneOf {
|
||||
template <class T>
|
||||
static rfl::Result<T> validate(const T& _value) noexcept {
|
||||
return validate_impl<T, C, Cs...>(_value, {});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto types = std::vector<ValidationType>(
|
||||
{C::template to_schema<T>(), Cs::template to_schema<T>()...});
|
||||
return ValidationType{ValidationType::OneOf{.types_ = types}};
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string make_error_message(const std::vector<Error>& _errors) {
|
||||
std::stringstream stream;
|
||||
stream << "Expected exactly 1 out of " << sizeof...(Cs) + 1
|
||||
<< " validations to pass, but " << sizeof...(Cs) + 1 - _errors.size()
|
||||
<< " of them did. The following errors were generated: ";
|
||||
for (size_t i = 0; i < _errors.size(); ++i) {
|
||||
stream << "\n" << i + 1 << ") " << _errors.at(i).what();
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <class T, class Head, class... Tail>
|
||||
static rfl::Result<T> validate_impl(const T& _value,
|
||||
std::vector<Error> _errors) {
|
||||
return Head::validate(_value)
|
||||
.and_then([&](auto&& _result) -> rfl::Result<T> {
|
||||
if constexpr (sizeof...(Tail) == 0) {
|
||||
if (_errors.size() == sizeof...(Cs)) {
|
||||
return _value;
|
||||
// The AI suggests return std::forward<decltype(_result)>(_result);
|
||||
// is it correct in this context?
|
||||
}
|
||||
return error(make_error_message(_errors));
|
||||
} else {
|
||||
return validate_impl<T, Tail...>(_value, std::move(_errors));
|
||||
}
|
||||
})
|
||||
.or_else([&](auto&& _err) -> rfl::Result<T> {
|
||||
_errors.emplace_back(std::move(_err));
|
||||
if constexpr (sizeof...(Tail) == 0) {
|
||||
return error(make_error_message(_errors));
|
||||
} else {
|
||||
return validate_impl<T, Tail...>(_value, std::move(_errors));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
14
build-config/reflect-cpp/include/rfl/Pattern.hpp
Normal file
14
build-config/reflect-cpp/include/rfl/Pattern.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef RFL_PATTERN_HPP_
|
||||
#define RFL_PATTERN_HPP_
|
||||
|
||||
#include "PatternValidator.hpp"
|
||||
#include "Validator.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral _regex, internal::StringLiteral _name>
|
||||
using Pattern = Validator<std::string, PatternValidator<_regex, _name>>;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
46
build-config/reflect-cpp/include/rfl/PatternValidator.hpp
Normal file
46
build-config/reflect-cpp/include/rfl/PatternValidator.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef RFL_PATTERNVALIDATOR_HPP_
|
||||
#define RFL_PATTERNVALIDATOR_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#if __has_include(<ctre.hpp>)
|
||||
#include <ctre.hpp>
|
||||
#else
|
||||
#include "thirdparty/ctre.hpp"
|
||||
#endif
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral _regex, internal::StringLiteral _name>
|
||||
struct PatternValidator {
|
||||
using Name = Literal<_name>;
|
||||
using Regex = Literal<_regex>;
|
||||
|
||||
static Result<std::string> validate(const std::string& _str) noexcept {
|
||||
if (ctre::match<ctll::fixed_string<_regex.length>{
|
||||
ctll::construct_from_pointer, _regex.arr_.data()}>(_str)) {
|
||||
return _str;
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
stream << "String '" << _str << "' did not match format '" << _name.str()
|
||||
<< "': '" << _regex.str() << "'.";
|
||||
return error(stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
return ValidationType{ValidationType::Regex{.pattern_ = Regex().str()}};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
83
build-config/reflect-cpp/include/rfl/Processors.hpp
Normal file
83
build-config/reflect-cpp/include/rfl/Processors.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef RFL_INTERNAL_PROCESSORS_HPP_
|
||||
#define RFL_INTERNAL_PROCESSORS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/is_add_tags_to_variants_v.hpp"
|
||||
#include "internal/is_allow_raw_ptrs_v.hpp"
|
||||
#include "internal/is_default_if_missing_v.hpp"
|
||||
#include "internal/is_no_extra_fields_v.hpp"
|
||||
#include "internal/is_no_field_names_v.hpp"
|
||||
#include "internal/is_no_optionals_v.hpp"
|
||||
#include "internal/is_underlying_enums_v.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class... Ps>
|
||||
struct Processors;
|
||||
|
||||
template <>
|
||||
struct Processors<> {
|
||||
static constexpr bool add_tags_to_variants_ = false;
|
||||
static constexpr bool add_namespaced_tags_to_variants_ = false;
|
||||
static constexpr bool allow_raw_ptrs_ = false;
|
||||
static constexpr bool all_required_ = false;
|
||||
static constexpr bool default_if_missing_ = false;
|
||||
static constexpr bool no_extra_fields_ = false;
|
||||
static constexpr bool no_field_names_ = false;
|
||||
static constexpr bool underlying_enums_ = false;
|
||||
|
||||
template <class T, class NamedTupleType>
|
||||
static auto process(NamedTupleType&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Head, class... Tail>
|
||||
struct Processors<Head, Tail...> {
|
||||
static constexpr bool add_tags_to_variants_ =
|
||||
std::disjunction_v<internal::is_add_tags_to_variants<Head>,
|
||||
internal::is_add_tags_to_variants<Tail>...>;
|
||||
|
||||
static constexpr bool add_namespaced_tags_to_variants_ =
|
||||
std::disjunction_v<internal::is_add_namespaced_tags_to_variants<Head>,
|
||||
internal::is_add_namespaced_tags_to_variants<Tail>...>;
|
||||
|
||||
static constexpr bool allow_raw_ptrs_ =
|
||||
std::disjunction_v<internal::is_allow_raw_ptrs<Head>,
|
||||
internal::is_allow_raw_ptrs<Tail>...>;
|
||||
|
||||
static constexpr bool all_required_ =
|
||||
std::disjunction_v<internal::is_no_optionals<Head>,
|
||||
internal::is_no_optionals<Tail>...>;
|
||||
|
||||
static constexpr bool default_if_missing_ =
|
||||
std::disjunction_v<internal::is_default_if_missing<Head>,
|
||||
internal::is_default_if_missing<Tail>...>;
|
||||
|
||||
static constexpr bool no_extra_fields_ =
|
||||
std::disjunction_v<internal::is_no_extra_fields<Head>,
|
||||
internal::is_no_extra_fields<Tail>...>;
|
||||
|
||||
static constexpr bool no_field_names_ =
|
||||
std::disjunction_v<internal::is_no_field_names<Head>,
|
||||
internal::is_no_field_names<Tail>...>;
|
||||
|
||||
static constexpr bool underlying_enums_ =
|
||||
std::disjunction_v<internal::is_underlying_enums<Head>,
|
||||
internal::is_underlying_enums<Tail>...>;
|
||||
|
||||
template <class T, class NamedTupleType>
|
||||
static auto process(NamedTupleType&& _named_tuple) {
|
||||
static_assert(!add_tags_to_variants_ || !add_namespaced_tags_to_variants_,
|
||||
"You cannot add both rfl::AddTagsToVariants and "
|
||||
"rfl::AddNamespacedTagsToVariants.");
|
||||
return Processors<Tail...>::template process<T>(
|
||||
Head::template process<T>(std::move(_named_tuple)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
146
build-config/reflect-cpp/include/rfl/Ref.hpp
Normal file
146
build-config/reflect-cpp/include/rfl/Ref.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#ifndef RFL_REF_HPP_
|
||||
#define RFL_REF_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Result.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// The Ref class behaves very similarly to the shared_ptr, but unlike the
|
||||
/// unique_ptr, it is 100% guaranteed to be filled at all times (unless the user
|
||||
/// tries to access it after calling std::move does something else that is
|
||||
/// clearly bad practice).
|
||||
template <class T>
|
||||
class Ref {
|
||||
public:
|
||||
/// The default way of creating new references is
|
||||
/// Ref<T>::make(...) or make_ref<T>(...).
|
||||
template <class... Args>
|
||||
static Ref<T> make(Args&&... _args) {
|
||||
return Ref<T>(std::make_shared<T>(std::forward<Args>(_args)...));
|
||||
}
|
||||
|
||||
/// You can generate them from shared_ptrs as well, in which case it will
|
||||
/// return an Error, if the shared_ptr is not set.
|
||||
static Result<Ref<T>> make(std::shared_ptr<T>&& _ptr) {
|
||||
if (!_ptr) {
|
||||
return error("std::shared_ptr was a nullptr.");
|
||||
}
|
||||
return Ref<T>(std::move(_ptr));
|
||||
}
|
||||
|
||||
/// You can generate them from shared_ptrs as well, in which case it will
|
||||
/// return an Error, if the shared_ptr is not set.
|
||||
static Result<Ref<T>> make(const std::shared_ptr<T>& _ptr) {
|
||||
if (!_ptr) {
|
||||
return error("std::shared_ptr was a nullptr.");
|
||||
}
|
||||
return Ref<T>(_ptr);
|
||||
}
|
||||
|
||||
Ref() : ptr_(std::make_shared<T>()) {}
|
||||
|
||||
Ref(const Ref<T>& _other) = default;
|
||||
|
||||
Ref(Ref<T>&& _other) = default;
|
||||
|
||||
template <class U>
|
||||
Ref(const Ref<U>& _other) : ptr_(_other.ptr()) {}
|
||||
|
||||
template <class U>
|
||||
Ref(Ref<U>&& _other) noexcept
|
||||
: ptr_(std::forward<std::shared_ptr<U>>(_other.ptr())) {}
|
||||
|
||||
~Ref() = default;
|
||||
|
||||
/// Returns a pointer to the underlying object
|
||||
T* get() const { return ptr_.get(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T& operator*() { return *ptr_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T& operator*() const { return *ptr_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T* operator->() { return ptr_.get(); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
T* operator->() const { return ptr_.get(); }
|
||||
|
||||
/// Returns the underlying shared_ptr
|
||||
std::shared_ptr<T>& ptr() { return ptr_; }
|
||||
|
||||
/// Returns the underlying shared_ptr
|
||||
const std::shared_ptr<T>& ptr() const { return ptr_; }
|
||||
|
||||
/// Copy assignment operator.
|
||||
template <class U>
|
||||
Ref<T>& operator=(const Ref<U>& _other) {
|
||||
ptr_ = _other.ptr();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Move assignment operator
|
||||
template <class U>
|
||||
Ref<T>& operator=(Ref<U>&& _other) noexcept {
|
||||
ptr_ = std::forward<std::shared_ptr<U>>(_other.ptr());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Move assignment operator
|
||||
Ref<T>& operator=(Ref<T>&& _other) noexcept = default;
|
||||
|
||||
/// Copy assignment operator
|
||||
Ref<T>& operator=(const Ref<T>& _other) = default;
|
||||
|
||||
private:
|
||||
/// Only make is allowed to use this constructor.
|
||||
explicit Ref(std::shared_ptr<T>&& _ptr) : ptr_(std::move(_ptr)) {}
|
||||
|
||||
/// Only make is allowed to use this constructor.
|
||||
explicit Ref(const std::shared_ptr<T>& _ptr) : ptr_(_ptr) {}
|
||||
|
||||
private:
|
||||
/// The underlying shared_ptr_
|
||||
std::shared_ptr<T> ptr_;
|
||||
};
|
||||
|
||||
/// Generates a new Ref<T>.
|
||||
template <class T, class... Args>
|
||||
auto make_ref(Args&&... _args) {
|
||||
return Ref<T>::make(std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline auto operator<=>(const Ref<T1>& _t1, const Ref<T2>& _t2) {
|
||||
return _t1.ptr() <=> _t2.ptr();
|
||||
}
|
||||
|
||||
template <class CharT, class Traits, class T>
|
||||
inline std::basic_ostream<CharT, Traits>& operator<<(
|
||||
std::basic_ostream<CharT, Traits>& _os, const Ref<T>& _b) {
|
||||
_os << _b.get();
|
||||
return _os;
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
struct hash<rfl::Ref<T>> {
|
||||
size_t operator()(const rfl::Ref<T>& _r) const {
|
||||
return std::hash<std::shared_ptr<T>>{}(_r.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void swap(rfl::Ref<T>& _r1, rfl::Ref<T>& _r2) {
|
||||
return swap(_r1.ptr(), _r2.ptr());
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // RFL_REF_HPP_
|
||||
141
build-config/reflect-cpp/include/rfl/Rename.hpp
Normal file
141
build-config/reflect-cpp/include/rfl/Rename.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef RFL_RENAME_HPP_
|
||||
#define RFL_RENAME_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "default.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Used to assign a new name to a field, which is different from the name
|
||||
/// inside the struct.
|
||||
template <internal::StringLiteral _name, class T>
|
||||
struct Rename {
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
|
||||
/// The name of the field.
|
||||
using Name = rfl::Literal<_name>;
|
||||
|
||||
Rename() : value_(Type()) {}
|
||||
|
||||
Rename(const Type& _value) : value_(_value) {}
|
||||
|
||||
Rename(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Rename(Rename<_name, T>&& _field) noexcept = default;
|
||||
|
||||
Rename(const Rename<_name, Type>& _field) = default;
|
||||
|
||||
template <class U>
|
||||
Rename(const Rename<_name, U>& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U>
|
||||
Rename(Rename<_name, U>&& _field) : value_(_field.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Rename(const Rename<_name, U>& _field) : value_(_field.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
Rename(const Default&) : value_(Type()) {}
|
||||
|
||||
~Rename() = default;
|
||||
|
||||
/// The name of the field, for internal use.
|
||||
constexpr static const internal::StringLiteral name_ = _name;
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Rename<_name, T>& operator=(const Rename<_name, T>& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Rename<_name, T>& operator=(Rename<_name, T>&& _field) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(const Rename<_name, U>& _field) {
|
||||
value_ = _field.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U>
|
||||
auto& operator=(Rename<_name, U>&& _field) {
|
||||
value_ = std::forward<T>(_field.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
/// The underlying value.
|
||||
Type value_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
447
build-config/reflect-cpp/include/rfl/Result.hpp
Normal file
447
build-config/reflect-cpp/include/rfl/Result.hpp
Normal file
@@ -0,0 +1,447 @@
|
||||
#ifndef RFL_RESULT_HPP_
|
||||
#define RFL_RESULT_HPP_
|
||||
|
||||
#ifdef REFLECTCPP_USE_STD_EXPECTED
|
||||
#include <expected>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Defines the error class to be returned when something went wrong
|
||||
class Error {
|
||||
public:
|
||||
Error(const std::string& _what) : what_(_what) {}
|
||||
Error(std::string&& _what) : what_(std::move(_what)) {}
|
||||
|
||||
Error(const Error& e) = default;
|
||||
Error(Error&& e) = default;
|
||||
|
||||
Error& operator=(const Error&) = default;
|
||||
Error& operator=(Error&&) = default;
|
||||
|
||||
/// Returns the error message, equivalent to .what() in std::exception.
|
||||
const std::string& what() const & { return what_; }
|
||||
/// Moves the error message out of Error object and leaves what_ in a moved from state
|
||||
std::string what() && { return std::move(what_); }
|
||||
|
||||
private:
|
||||
/// Documents what went wrong
|
||||
std::string what_;
|
||||
};
|
||||
|
||||
/// To be returned when there is nothing to return, but there might be an error.
|
||||
struct Nothing {};
|
||||
|
||||
/// This implementation is for cases where std::expected is defined
|
||||
#ifdef REFLECTCPP_USE_STD_EXPECTED
|
||||
|
||||
template <class E>
|
||||
using Unexpected = std::unexpected<E>;
|
||||
|
||||
template <class T>
|
||||
using Result = std::expected<T, rfl::Error>;
|
||||
|
||||
/// This implementation is for cases where std::expected is not defined
|
||||
#else // REFLECTCPP_USE_STD_EXPECTED
|
||||
|
||||
template <class E>
|
||||
struct Unexpected {
|
||||
Unexpected(E&& _err) : err_{std::forward<E>(_err)} {}
|
||||
|
||||
Unexpected(const E& _err) : err_{_err} {}
|
||||
|
||||
Unexpected(Unexpected&&) = default;
|
||||
|
||||
Unexpected(const Unexpected&) = default;
|
||||
|
||||
Unexpected& operator=(Unexpected&&) = default;
|
||||
|
||||
Unexpected& operator=(const Unexpected&) = default;
|
||||
|
||||
const E& error() const& { return err_; }
|
||||
|
||||
E&& error() && { return std::move(err_); }
|
||||
|
||||
E& error() & { return err_; }
|
||||
|
||||
private:
|
||||
E err_;
|
||||
};
|
||||
|
||||
/// The Result class is used for monadic error handling.
|
||||
template <class T>
|
||||
class Result {
|
||||
static_assert(!std::is_same<T, Error>(), "The result type cannot be Error.");
|
||||
|
||||
using TOrErr = std::array<unsigned char, std::max(sizeof(T), sizeof(Error))>;
|
||||
|
||||
public:
|
||||
// using Type = T;
|
||||
using value_type = T;
|
||||
using error_type = rfl::Error;
|
||||
|
||||
Result(const T& _val) : success_(true) { new (&get_t()) T(_val); }
|
||||
|
||||
Result(T&& _val) noexcept : success_(true) {
|
||||
new (&get_t()) T(std::move(_val));
|
||||
}
|
||||
|
||||
Result(const Unexpected<Error>& _err) : success_(false) {
|
||||
new (&get_err()) Error(_err.error());
|
||||
}
|
||||
Result(Unexpected<Error>&& _err) : success_(false) {
|
||||
new (&get_err()) Error(std::move(_err.error()));
|
||||
}
|
||||
|
||||
Result(Result<T>&& _other) noexcept : success_(_other.success_) {
|
||||
move_from_other(_other);
|
||||
}
|
||||
|
||||
Result(const Result<T>& _other) : success_(_other.success_) {
|
||||
copy_from_other(_other);
|
||||
}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
Result(Result<U>&& _other) : success_(_other && true) {
|
||||
auto temp = std::forward<Result<U> >(_other).transform(
|
||||
[](U&& _u) { return T(std::forward<U>(_u)); });
|
||||
move_from_other(temp);
|
||||
}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
Result(const Result<U>& _other) : success_(_other && true) {
|
||||
auto temp = _other.transform([](const U& _u) { return T(_u); });
|
||||
move_from_other(temp);
|
||||
}
|
||||
|
||||
~Result() { destroy(); }
|
||||
|
||||
/// Monadic operation - F must be a function of type T -> Result<U>.
|
||||
template <class F>
|
||||
auto and_then(const F& _f) && {
|
||||
/// Result_U is expected to be of type Result<U>.
|
||||
using Result_U = typename std::invoke_result<F, T>::type;
|
||||
if (success_) {
|
||||
return Result_U(_f(std::move(*this).get_t()));
|
||||
} else {
|
||||
return Result_U(std::move(*this).get_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// Monadic operation - F must be a function of type T -> Result<U>.
|
||||
template <class F>
|
||||
auto and_then(const F& _f) const& {
|
||||
/// Result_U is expected to be of type Result<U>.
|
||||
using Result_U = typename std::invoke_result<F, T>::type;
|
||||
if (success_) {
|
||||
return Result_U(_f(get_t()));
|
||||
} else {
|
||||
return Result_U(get_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the result contains a value, false otherwise.
|
||||
operator bool() const noexcept { return success_; }
|
||||
|
||||
/// Allows access to the underlying value. Careful: Will result in undefined
|
||||
/// behavior, if the result contains an error.
|
||||
T&& operator*() && noexcept { return std::move(*this).get_t(); }
|
||||
|
||||
/// Allows access to the underlying value. Careful: Will result in undefined
|
||||
/// behavior, if the result contains an error.
|
||||
T& operator*() & noexcept { return get_t(); }
|
||||
|
||||
/// Allows read access to the underlying value. Careful: Will result in
|
||||
/// undefined behavior, if the result contains an error.
|
||||
const T& operator*() const& noexcept { return get_t(); }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Result<T>& operator=(const Result<T>& _other) {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
destroy();
|
||||
success_ = _other.success_;
|
||||
copy_from_other(_other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Result<T>& operator=(Result<T>&& _other) noexcept {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
destroy();
|
||||
success_ = _other.success_;
|
||||
move_from_other(_other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Result<T>& operator=(Unexpected<Error>&& _err) noexcept {
|
||||
destroy();
|
||||
success_ = false;
|
||||
new (&get_err()) Error(_err.error());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Result<T>& operator=(const Unexpected<Error>& _err) noexcept {
|
||||
destroy();
|
||||
success_ = false;
|
||||
new (&get_err()) Error(_err.error());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Result<U>& _other) {
|
||||
const auto to_t = [](const U& _u) -> T { return _u; };
|
||||
t_or_err_ = _other.transform(to_t).t_or_err_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Expects a function that takes of type Error -> Result<T> and returns
|
||||
/// Result<T>.
|
||||
template <class F>
|
||||
Result<T> or_else(const F& _f) && {
|
||||
if (success_) {
|
||||
return std::move(*this).get_t();
|
||||
} else {
|
||||
return _f(std::move(*this).get_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// Expects a function that takes of type Error -> Result<T> and returns
|
||||
/// Result<T>.
|
||||
template <class F>
|
||||
Result<T> or_else(const F& _f) const& {
|
||||
if (success_) {
|
||||
return get_t();
|
||||
} else {
|
||||
return _f(get_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// Functor operation - F must be a function of type T -> U.
|
||||
template <class F>
|
||||
auto transform(const F& _f) && {
|
||||
/// Result_U is expected to be of type Result<U>.
|
||||
using U = std::invoke_result_t<F, T>;
|
||||
if (success_) {
|
||||
return rfl::Result<U>(_f(std::move(*this).get_t()));
|
||||
} else {
|
||||
return rfl::Result<U>(rfl::Unexpected(std::move(*this).get_err()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Functor operation - F must be a function of type T -> U.
|
||||
template <class F>
|
||||
auto transform(const F& _f) const& {
|
||||
/// Result_U is expected to be of type Result<U>.
|
||||
using U = typename std::invoke_result<F, T>::type;
|
||||
if (success_) {
|
||||
return rfl::Result<U>(_f(get_t()));
|
||||
} else {
|
||||
return rfl::Result<U>(get_err());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value if the result does not contain an error, throws an
|
||||
/// exceptions if not. Similar to .unwrap() in Rust.
|
||||
T&& value() && {
|
||||
if (success_) {
|
||||
return std::move(*this).get_t();
|
||||
} else {
|
||||
throw std::runtime_error(get_err().what());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value if the result does not contain an error, throws an
|
||||
/// exceptions if not. Similar to .unwrap() in Rust.
|
||||
T& value() & {
|
||||
if (success_) {
|
||||
return get_t();
|
||||
} else {
|
||||
throw std::runtime_error(get_err().what());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value if the result does not contain an error, throws an
|
||||
/// exceptions if not. Similar to .unwrap() in Rust.
|
||||
const T& value() const& {
|
||||
if (success_) {
|
||||
return get_t();
|
||||
} else {
|
||||
throw std::runtime_error(get_err().what());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value or a default.
|
||||
T&& value_or(T&& _default) && noexcept {
|
||||
if (success_) {
|
||||
return std::move(*this).get_t();
|
||||
} else {
|
||||
return std::forward<T>(_default);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value or a default.
|
||||
T value_or(const T& _default) const& noexcept {
|
||||
if (success_) {
|
||||
return get_t();
|
||||
} else {
|
||||
return _default;
|
||||
}
|
||||
}
|
||||
|
||||
template <class G = rfl::Error>
|
||||
rfl::Error error_or(G&& _default) && {
|
||||
if (success_) {
|
||||
return std::forward<G>(_default);
|
||||
} else {
|
||||
return std::move(*this).get_err();
|
||||
}
|
||||
}
|
||||
|
||||
// As specified by the standard :
|
||||
// https://en.cppreference.com/w/cpp/utility/expected
|
||||
// Observers
|
||||
template <class G = rfl::Error>
|
||||
rfl::Error error_or(G&& _default) const& {
|
||||
if (success_) {
|
||||
return std::forward<G>(_default);
|
||||
} else {
|
||||
return get_err();
|
||||
}
|
||||
}
|
||||
|
||||
bool has_value() const noexcept { return success_; }
|
||||
|
||||
Error& error() && {
|
||||
if (success_) throw std::runtime_error("Expected does not contain value");
|
||||
return std::move(*this).get_err();
|
||||
}
|
||||
|
||||
Error& error() & {
|
||||
if (success_) throw std::runtime_error("Expected does not contain value");
|
||||
return get_err();
|
||||
}
|
||||
|
||||
const Error& error() const& {
|
||||
if (success_) throw std::runtime_error("Expected does not contain value");
|
||||
return get_err();
|
||||
}
|
||||
|
||||
T* operator->() noexcept { return &get_t(); }
|
||||
|
||||
const T* operator->() const noexcept { return &get_t(); }
|
||||
|
||||
template <class F>
|
||||
rfl::Result<T> transform_error(F&& f) && {
|
||||
static_assert(
|
||||
std::is_same<std::invoke_result_t<F, rfl::Error>, rfl::Error>(),
|
||||
"A function passed to transform_error must return an error.");
|
||||
if (!has_value()) {
|
||||
return rfl::Result<T>{std::invoke(f, std::move(*this).get_err())};
|
||||
} else {
|
||||
return rfl::Result<T>{std::move(*this).value()};
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
rfl::Result<T> transform_error(F&& f) const& {
|
||||
static_assert(
|
||||
std::is_same<std::invoke_result_t<F, rfl::Error>, rfl::Error>(),
|
||||
"A function passed to transform_error must return an error.");
|
||||
if (!has_value()) {
|
||||
return rfl::Result<T>{std::invoke(f, get_err())};
|
||||
} else {
|
||||
return rfl::Result<T>{value()};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void copy_from_other(const Result<T>& _other) {
|
||||
if (success_) {
|
||||
new (&get_t()) T(_other.get_t());
|
||||
} else {
|
||||
new (&get_err()) Error(_other.get_err());
|
||||
}
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (success_) {
|
||||
if constexpr (std::is_destructible_v<std::remove_cv_t<T> >) {
|
||||
get_t().~T();
|
||||
}
|
||||
} else {
|
||||
get_err().~Error();
|
||||
}
|
||||
}
|
||||
|
||||
T&& get_t() && noexcept {
|
||||
return std::move(*std::launder(reinterpret_cast<T*>(t_or_err_.data())));
|
||||
}
|
||||
|
||||
T& get_t() & noexcept {
|
||||
return *std::launder(reinterpret_cast<T*>(t_or_err_.data()));
|
||||
}
|
||||
|
||||
const T& get_t() const& noexcept {
|
||||
return *std::launder(reinterpret_cast<const T*>(t_or_err_.data()));
|
||||
}
|
||||
|
||||
Error&& get_err() && noexcept {
|
||||
return std::move(*std::launder(reinterpret_cast<Error*>(t_or_err_.data())));
|
||||
}
|
||||
|
||||
Error& get_err() & noexcept {
|
||||
return *std::launder(reinterpret_cast<Error*>(t_or_err_.data()));
|
||||
}
|
||||
|
||||
const Error& get_err() const& noexcept {
|
||||
return *std::launder(reinterpret_cast<const Error*>(t_or_err_.data()));
|
||||
}
|
||||
|
||||
void move_from_other(Result<T>& _other) noexcept {
|
||||
if (success_) {
|
||||
new (&get_t()) T(std::move(_other.get_t()));
|
||||
} else {
|
||||
new (&get_err()) Error(std::move(_other.get_err()));
|
||||
}
|
||||
}
|
||||
/// Signifies whether this was a success.
|
||||
bool success_;
|
||||
|
||||
/// The underlying data, can either be T or Error.
|
||||
alignas(std::max(alignof(T), alignof(Error))) TOrErr t_or_err_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/// Shorthand for unexpected error.
|
||||
inline Unexpected<Error> error(const std::string& _what) {
|
||||
return Unexpected<Error>(Error(_what));
|
||||
}
|
||||
|
||||
inline Unexpected<Error> error(std::string&& _what) {
|
||||
return Unexpected<Error>(Error(std::move(_what)));
|
||||
}
|
||||
|
||||
/// Shorthand for unexpected error.
|
||||
inline Unexpected<Error> error(const Error& _err) {
|
||||
return Unexpected<Error>(_err);
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
35
build-config/reflect-cpp/include/rfl/Size.hpp
Normal file
35
build-config/reflect-cpp/include/rfl/Size.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef RFL_SIZE_HPP_
|
||||
#define RFL_SIZE_HPP_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Ref.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class V>
|
||||
struct Size {
|
||||
template <class T>
|
||||
static rfl::Result<T> validate(const T& _t) {
|
||||
const auto to_t = [&](const auto&) { return _t; };
|
||||
const auto embellish_error = [](const auto& _err) -> Error {
|
||||
return Error("Size validation failed: " + _err.what());
|
||||
};
|
||||
return V::validate(_t.size()).transform(to_t).transform_error(
|
||||
embellish_error);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
return ValidationType{ValidationType::Size{
|
||||
.size_limit_ =
|
||||
rfl::Ref<ValidationType>::make(V::template to_schema<size_t>())}};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
20
build-config/reflect-cpp/include/rfl/Skip.hpp
Normal file
20
build-config/reflect-cpp/include/rfl/Skip.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef RFL_SKIP_HPP_
|
||||
#define RFL_SKIP_HPP_
|
||||
|
||||
#include "internal/Skip.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class T>
|
||||
using Skip = internal::Skip<T, true, true>;
|
||||
|
||||
template <class T>
|
||||
using SkipSerialization = internal::Skip<T, true, false>;
|
||||
|
||||
template <class T>
|
||||
using SkipDeserialization = internal::Skip<T, false, true>;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef RFL_SNAKECASETOCAMELCASE_HPP_
|
||||
#define RFL_SNAKECASETOCAMELCASE_HPP_
|
||||
|
||||
#include "Field.hpp"
|
||||
#include "internal/is_rename.hpp"
|
||||
#include "internal/transform_snake_case.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
struct SnakeCaseToCamelCase {
|
||||
public:
|
||||
/// Replaces all instances of snake_case field names with camelCase.
|
||||
template <class StructType>
|
||||
static auto process(const auto& _named_tuple) {
|
||||
return _named_tuple.transform([]<class FieldType>(const FieldType& _f) {
|
||||
if constexpr (FieldType::name() != "xml_content" &&
|
||||
!internal::is_rename_v<typename FieldType::Type>) {
|
||||
return handle_one_field(_f);
|
||||
} else {
|
||||
return _f;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
/// Applies the logic to a single field.
|
||||
template <class FieldType>
|
||||
static auto handle_one_field(const FieldType& _f) {
|
||||
using NewFieldType =
|
||||
Field<internal::transform_snake_case<FieldType::name_,
|
||||
/*capitalize=*/false>(),
|
||||
typename FieldType::Type>;
|
||||
return NewFieldType(_f.value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef RFL_SNAKECASETOPASCALCASE_HPP_
|
||||
#define RFL_SNAKECASETOPASCALCASE_HPP_
|
||||
|
||||
#include "Field.hpp"
|
||||
#include "internal/is_rename.hpp"
|
||||
#include "internal/transform_snake_case.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
struct SnakeCaseToPascalCase {
|
||||
public:
|
||||
/// Replaces all instances of snake_case field names with PascalCase.
|
||||
template <class StructType>
|
||||
static auto process(const auto& _named_tuple) {
|
||||
const auto handle_one = []<class FieldType>(const FieldType& _f) {
|
||||
if constexpr (FieldType::name() != "xml_content" &&
|
||||
!internal::is_rename_v<typename FieldType::Type>) {
|
||||
return handle_one_field(_f);
|
||||
} else {
|
||||
return _f;
|
||||
}
|
||||
};
|
||||
return _named_tuple.transform(handle_one);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Applies the logic to a single field.
|
||||
template <class FieldType>
|
||||
static auto handle_one_field(const FieldType& _f) {
|
||||
using NewFieldType =
|
||||
Field<internal::transform_snake_case<FieldType::name_,
|
||||
/*capitalize=*/true>(),
|
||||
typename FieldType::Type>;
|
||||
return NewFieldType(_f.value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
146
build-config/reflect-cpp/include/rfl/TaggedUnion.hpp
Normal file
146
build-config/reflect-cpp/include/rfl/TaggedUnion.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#ifndef RFL_TAGGEDUNION_HPP_
|
||||
#define RFL_TAGGEDUNION_HPP_
|
||||
|
||||
#include "Variant.hpp"
|
||||
#include "define_literal.hpp"
|
||||
#include "internal/Getter.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/tag_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
// https://serde.rs/enum-representations.html
|
||||
template <internal::StringLiteral _discriminator, class... Ts>
|
||||
struct TaggedUnion {
|
||||
static constexpr internal::StringLiteral discrimininator_ = _discriminator;
|
||||
|
||||
/// The type of the underlying variant.
|
||||
using VariantType = rfl::Variant<Ts...>;
|
||||
|
||||
TaggedUnion(const VariantType& _variant) : variant_(_variant) {}
|
||||
|
||||
TaggedUnion(VariantType&& _variant) noexcept
|
||||
: variant_(std::move(_variant)) {}
|
||||
|
||||
TaggedUnion(const TaggedUnion<_discriminator, Ts...>& _tagged_union) =
|
||||
default;
|
||||
|
||||
TaggedUnion(TaggedUnion<_discriminator, Ts...>&& _tagged_union) noexcept =
|
||||
default;
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
TaggedUnion(const T& _t) : variant_(_t) {}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
TaggedUnion(T&& _t) noexcept : variant_(std::forward<T>(_t)) {}
|
||||
|
||||
~TaggedUnion() = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(const VariantType& _variant) {
|
||||
variant_ = _variant;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(VariantType&& _variant) {
|
||||
variant_ = std::move(_variant);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(T&& _variant) {
|
||||
variant_ = std::forward<T>(_variant);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class T,
|
||||
typename std::enable_if<std::is_convertible_v<T, VariantType>,
|
||||
bool>::type = true>
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(const T& _variant) {
|
||||
variant_ = _variant;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(
|
||||
const TaggedUnion<_discriminator, Ts...>& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
TaggedUnion<_discriminator, Ts...>& operator=(
|
||||
TaggedUnion<_discriminator, Ts...>&& _other) = default;
|
||||
|
||||
/// Returns the underlying variant.
|
||||
VariantType& variant() { return variant_; }
|
||||
|
||||
/// Returns the underlying variant.
|
||||
const VariantType& variant() const { return variant_; }
|
||||
|
||||
/// Applies function _f to all underlying alternatives.
|
||||
template <class F>
|
||||
auto visit(F&& _f)
|
||||
-> decltype(std::declval<VariantType>().visit(std::declval<F&&>())) {
|
||||
return variant_.visit(std::forward<F>(_f));
|
||||
}
|
||||
|
||||
/// Applies function _f to all underlying alternatives.
|
||||
template <class F>
|
||||
auto visit(F&& _f) const
|
||||
-> decltype(std::declval<VariantType>().visit(std::declval<F&&>())) {
|
||||
return variant_.visit(std::forward<F>(_f));
|
||||
}
|
||||
|
||||
/// The underlying variant - a TaggedUnion is a thin wrapper
|
||||
/// around a variant that is mainly used for parsing.
|
||||
VariantType variant_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept TaggedUnionBased = requires(T t) {
|
||||
[]<internal::StringLiteral _discriminator, typename... Args>(
|
||||
TaggedUnion<_discriminator, Args...> const&) {}(t);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct PossibleTags;
|
||||
|
||||
template <internal::StringLiteral _discriminator, class... Ts>
|
||||
struct PossibleTags<TaggedUnion<_discriminator, Ts...>> {
|
||||
using Type = define_literal_t<internal::tag_t<_discriminator, Ts>...>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using possible_tags_t = typename PossibleTags<T>::Type;
|
||||
|
||||
template <internal::StringLiteral _discriminator, class... Ts>
|
||||
bool operator==(
|
||||
const TaggedUnion<_discriminator, Ts...>& lhs,
|
||||
const TaggedUnion<_discriminator, Ts...>& rhs
|
||||
) {
|
||||
|
||||
return (lhs.variant().index() == rhs.variant().index()) &&
|
||||
lhs.variant().visit(
|
||||
[&rhs](const auto& l) {
|
||||
return rhs.variant().visit(
|
||||
[&l](const auto& r) -> bool {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(l)>, std::decay_t<decltype(r)>>)
|
||||
return l == r;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_TAGGEDUNION_HPP_
|
||||
121
build-config/reflect-cpp/include/rfl/Timestamp.hpp
Normal file
121
build-config/reflect-cpp/include/rfl/Timestamp.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#ifndef RFL_TIMESTAMP_HPP_
|
||||
#define RFL_TIMESTAMP_HPP_
|
||||
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// For serializing and deserializing time stamps.
|
||||
template <internal::StringLiteral _format>
|
||||
class Timestamp {
|
||||
constexpr static const internal::StringLiteral format_ = _format;
|
||||
|
||||
public:
|
||||
using Format = rfl::Literal<_format>;
|
||||
|
||||
using ReflectionType = std::string;
|
||||
|
||||
Timestamp() : tm_(std::tm{}) {}
|
||||
|
||||
Timestamp(const char* _str) : tm_(std::tm{}) {
|
||||
const auto r = strptime(_str, _format.str().c_str(), &tm_);
|
||||
if (r == NULL) {
|
||||
throw std::runtime_error("String '" + std::string(_str) +
|
||||
"' did not match format '" + Format().str() +
|
||||
"'.");
|
||||
}
|
||||
}
|
||||
|
||||
Timestamp(const std::string& _str) : Timestamp(_str.c_str()) {}
|
||||
|
||||
Timestamp(const std::tm& _tm) : tm_(_tm) {}
|
||||
|
||||
Timestamp(const time_t _t) : tm_(std::tm{}) {
|
||||
auto t = _t;
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
gmtime_s(&tm_, &t);
|
||||
#else
|
||||
gmtime_r(&t, &tm_);
|
||||
#endif
|
||||
}
|
||||
|
||||
~Timestamp() = default;
|
||||
|
||||
/// Returns a result containing the timestamp when successful or an Error
|
||||
/// otherwise.
|
||||
static Result<Timestamp> from_string(const char* _str) noexcept {
|
||||
try {
|
||||
return Timestamp(_str);
|
||||
} catch (std::exception& e) {
|
||||
return error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a result containing the timestamp when successful or an Error
|
||||
/// otherwise.
|
||||
static Result<Timestamp> from_string(const std::string& _str) {
|
||||
return from_string(_str.c_str());
|
||||
}
|
||||
|
||||
/// Returns a result containing the timestamp when successful or an Error
|
||||
/// otherwise.
|
||||
static Result<Timestamp> make(const auto& _str) noexcept {
|
||||
return from_string(_str);
|
||||
}
|
||||
|
||||
/// Necessary for the serialization to work.
|
||||
ReflectionType reflection() const {
|
||||
char outstr[200];
|
||||
strftime(outstr, 200, format_.str().c_str(), &tm_);
|
||||
return std::string(outstr);
|
||||
}
|
||||
|
||||
/// Expresses the underlying timestamp as a string.
|
||||
std::string str() const { return reflection(); }
|
||||
|
||||
/// Trivial accessor to the underlying time stamp.
|
||||
std::tm& tm() { return tm_; }
|
||||
|
||||
/// Trivial (const) accessor to the underlying time stamp.
|
||||
const std::tm& tm() const { return tm_; }
|
||||
|
||||
/// Returns a UTC time represented by a time_t type.
|
||||
time_t to_time_t() const {
|
||||
auto tm = tm_;
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
return _mkgmtime(&tm);
|
||||
#else
|
||||
return static_cast<time_t>(timegm(&tm) - tm_.tm_gmtoff);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
// This workaround is necessary, because strptime is not available on Windows.
|
||||
char* strptime(const char* _s, const char* _f, std::tm* _tm) {
|
||||
std::istringstream input(_s);
|
||||
input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||
input >> std::get_time(_tm, _f);
|
||||
if (input.fail()) {
|
||||
return NULL;
|
||||
}
|
||||
return (char*)(_s + input.tellg());
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
/// The underlying time stamp.
|
||||
std::tm tm_;
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
267
build-config/reflect-cpp/include/rfl/Tuple.hpp
Normal file
267
build-config/reflect-cpp/include/rfl/Tuple.hpp
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef RFL_TUPLE_HPP_
|
||||
#define RFL_TUPLE_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/nth_element_t.hpp"
|
||||
#include "internal/ptr_cast.hpp"
|
||||
#include "internal/tuple/calculate_positions.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class... FieldTypes>
|
||||
class Tuple;
|
||||
|
||||
template <>
|
||||
class Tuple<> {
|
||||
public:
|
||||
Tuple() {}
|
||||
};
|
||||
|
||||
template <class... Types>
|
||||
class Tuple {
|
||||
static constexpr size_t size_ = sizeof...(Types);
|
||||
|
||||
static constexpr auto positions_ =
|
||||
internal::tuple::calculate_positions<Types...>();
|
||||
|
||||
static constexpr auto seq_ = std::make_integer_sequence<int, size_>{};
|
||||
|
||||
static constexpr unsigned int num_bytes_ = std::get<size_>(positions_);
|
||||
|
||||
using DataType = std::array<unsigned char, num_bytes_>;
|
||||
|
||||
public:
|
||||
Tuple(const Types&... _t) { copy_from_types(_t..., seq_); }
|
||||
|
||||
Tuple(Types&&... _t) noexcept { move_from_types(std::move(_t)..., seq_); }
|
||||
|
||||
Tuple() : Tuple(Types()...) {}
|
||||
|
||||
Tuple(const Tuple& _other) { copy_from_other(_other, seq_); }
|
||||
|
||||
Tuple(Tuple&& _other) noexcept { move_from_other(std::move(_other), seq_); }
|
||||
|
||||
~Tuple() { destroy_if_necessary(seq_); }
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index>
|
||||
constexpr auto& get() {
|
||||
using Type = internal::nth_element_t<_index, Types...>;
|
||||
return *internal::ptr_cast<Type*>(data_.data() + pos<_index>());
|
||||
}
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index>
|
||||
constexpr const auto& get() const {
|
||||
using Type = internal::nth_element_t<_index, Types...>;
|
||||
return *internal::ptr_cast<const Type*>(data_.data() + pos<_index>());
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Tuple& operator=(const Tuple& _other) {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
auto temp = Tuple(_other);
|
||||
destroy_if_necessary(seq_);
|
||||
move_from_other(std::move(temp), seq_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Tuple& operator=(Tuple&& _other) noexcept {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
destroy_if_necessary(seq_);
|
||||
move_from_other(std::move(_other), seq_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Equality operator.
|
||||
template <class... OtherTypes>
|
||||
bool operator==(const Tuple<OtherTypes...>& _other) const noexcept {
|
||||
static_assert(sizeof...(Types) == sizeof...(OtherTypes),
|
||||
"The size of the two tuples must be the same.");
|
||||
const auto is_same = [&]<int _i>(std::integral_constant<int, _i>) -> bool {
|
||||
return this->get<_i>() == _other.template get<_i>();
|
||||
};
|
||||
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
|
||||
return (true && ... && is_same(std::integral_constant<int, _is>{}));
|
||||
}(std::make_integer_sequence<int, sizeof...(Types)>());
|
||||
}
|
||||
|
||||
/// Three-way comparison operator.
|
||||
template <class... OtherTypes>
|
||||
auto operator<=>(const Tuple<OtherTypes...>& _other) const noexcept {
|
||||
static_assert(sizeof...(Types) == sizeof...(OtherTypes),
|
||||
"The size of the two tuples must be the same.");
|
||||
|
||||
const auto compare = [&]<int _i>(std::strong_ordering* _ordering,
|
||||
std::integral_constant<int, _i>) {
|
||||
if (*_ordering != std::strong_ordering::equivalent &&
|
||||
this->get<_i>() != _other.template get<_i>()) {
|
||||
*_ordering = (this->get<_i>() <=> _other.template get<_i>());
|
||||
}
|
||||
};
|
||||
|
||||
return [&]<int... _is>(std::integer_sequence<int, _is...>) {
|
||||
auto ordering = std::strong_ordering::equivalent;
|
||||
(compare(&ordering, std::integral_constant<int, _is>{}), ...);
|
||||
return ordering;
|
||||
}(std::make_integer_sequence<int, sizeof...(Types)>());
|
||||
}
|
||||
|
||||
private:
|
||||
template <int... _is>
|
||||
void copy_from_other(const Tuple& _other,
|
||||
std::integer_sequence<int, _is...>) {
|
||||
const auto copy_one = [this]<int _i>(const auto& _other,
|
||||
std::integral_constant<int, _i>) {
|
||||
using Type = internal::nth_element_t<_i, Types...>;
|
||||
::new (static_cast<void*>(data_.data() + pos<_i>()))
|
||||
Type(_other.template get<_i>());
|
||||
};
|
||||
(copy_one(_other, std::integral_constant<int, _is>{}), ...);
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
void copy_from_types(const Types&... _types,
|
||||
std::integer_sequence<int, _is...>) {
|
||||
const auto copy_one = [this]<int _i>(const auto& _t,
|
||||
std::integral_constant<int, _i>) {
|
||||
using Type = internal::nth_element_t<_i, Types...>;
|
||||
::new (static_cast<void*>(data_.data() + pos<_i>())) Type(_t);
|
||||
};
|
||||
(copy_one(_types, std::integral_constant<int, _is>{}), ...);
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
void destroy_if_necessary(std::integer_sequence<int, _is...>) {
|
||||
const auto destroy_one = [](auto& _t) {
|
||||
using Type = std::remove_cvref_t<decltype(_t)>;
|
||||
if constexpr (std::is_destructible_v<Type>) {
|
||||
_t.~Type();
|
||||
}
|
||||
};
|
||||
(destroy_one(get<_is>()), ...);
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
void move_from_other(Tuple&& _other, std::integer_sequence<int, _is...>) {
|
||||
const auto move_one = [this]<int _i>(auto&& _other,
|
||||
std::integral_constant<int, _i>) {
|
||||
using Type = internal::nth_element_t<_i, Types...>;
|
||||
::new (static_cast<void*>(data_.data() + pos<_i>()))
|
||||
Type(std::move(_other.template get<_i>()));
|
||||
};
|
||||
(move_one(_other, std::integral_constant<int, _is>{}), ...);
|
||||
}
|
||||
|
||||
template <int... _is>
|
||||
void move_from_types(Types&&... _types, std::integer_sequence<int, _is...>) {
|
||||
const auto move_one = [this]<int _i>(auto&& _t,
|
||||
std::integral_constant<int, _i>) {
|
||||
using Type = internal::nth_element_t<_i, Types...>;
|
||||
::new (static_cast<void*>(data_.data() + pos<_i>())) Type(std::move(_t));
|
||||
};
|
||||
(move_one(std::move(_types), std::integral_constant<int, _is>{}), ...);
|
||||
}
|
||||
|
||||
template <int _i>
|
||||
static consteval unsigned int pos() {
|
||||
return std::get<_i>(positions_);
|
||||
}
|
||||
|
||||
private:
|
||||
/// The underlying data, can be any of the underlying types.
|
||||
alignas(Types...) DataType data_;
|
||||
};
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr auto& get(rfl::Tuple<Types...>& _tup) {
|
||||
return _tup.template get<_index>();
|
||||
}
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr const auto& get(const rfl::Tuple<Types...>& _tup) {
|
||||
return _tup.template get<_index>();
|
||||
}
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr auto& get(std::tuple<Types...>& _tup) {
|
||||
return std::get<_index>(_tup);
|
||||
}
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr const auto& get(const std::tuple<Types...>& _tup) {
|
||||
return std::get<_index>(_tup);
|
||||
}
|
||||
|
||||
template <class... Types>
|
||||
auto make_tuple(Types&&... _args) {
|
||||
return rfl::Tuple<std::decay_t<Types>...>(std::forward<Types>(_args)...);
|
||||
}
|
||||
|
||||
template <int N, class T>
|
||||
struct tuple_element;
|
||||
|
||||
template <int N, class... Ts>
|
||||
struct tuple_element<N, rfl::Tuple<Ts...>> {
|
||||
using type = internal::nth_element_t<N, Ts...>;
|
||||
};
|
||||
|
||||
template <int N, class... Ts>
|
||||
struct tuple_element<N, std::tuple<Ts...>> {
|
||||
using type = internal::nth_element_t<N, Ts...>;
|
||||
};
|
||||
|
||||
template <int N, class T>
|
||||
using tuple_element_t =
|
||||
typename rfl::tuple_element<N, std::remove_cvref_t<T>>::type;
|
||||
|
||||
template <class T>
|
||||
struct tuple_size;
|
||||
|
||||
template <class... Ts>
|
||||
struct tuple_size<rfl::Tuple<Ts...>> {
|
||||
static constexpr auto value = sizeof...(Ts);
|
||||
};
|
||||
|
||||
template <class... Ts>
|
||||
struct tuple_size<std::tuple<Ts...>> {
|
||||
static constexpr auto value = sizeof...(Ts);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline constexpr auto tuple_size_v =
|
||||
rfl::tuple_size<std::remove_cvref_t<T>>::value;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr auto& get(rfl::Tuple<Types...>& _tup) {
|
||||
return _tup.template get<_index>();
|
||||
}
|
||||
|
||||
/// Gets an element by index.
|
||||
template <int _index, class... Types>
|
||||
constexpr const auto& get(const rfl::Tuple<Types...>& _tup) {
|
||||
return _tup.template get<_index>();
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/UnderlyingEnums.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/UnderlyingEnums.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_UNDERLYINGENUMS_HPP_
|
||||
#define RFL_UNDERLYINGENUMS_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// This is a 'fake' processor - it doesn't do much by itself, but its
|
||||
/// its inclusion instructs parsers not to convert enum types to strings, but to integers
|
||||
struct UnderlyingEnums {
|
||||
public:
|
||||
template <class StructType>
|
||||
static auto process(auto&& _named_tuple) {
|
||||
return _named_tuple;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
135
build-config/reflect-cpp/include/rfl/Validator.hpp
Normal file
135
build-config/reflect-cpp/include/rfl/Validator.hpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#ifndef RFL_VALIDATOR_HPP_
|
||||
#define RFL_VALIDATOR_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "AllOf.hpp"
|
||||
#include "Result.hpp"
|
||||
#include "internal/HasValidation.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class T, class V, class... Vs>
|
||||
requires internal::HasValidation<AllOf<V, Vs...>, T>
|
||||
struct Validator {
|
||||
public:
|
||||
using ReflectionType = T;
|
||||
using ValidationType =
|
||||
std::conditional_t<sizeof...(Vs) == 0, V, AllOf<V, Vs...>>;
|
||||
|
||||
/// Exception-free validation.
|
||||
static Result<Validator> from_value(const T& _value) noexcept {
|
||||
try {
|
||||
return Validator(_value);
|
||||
} catch (std::exception& e) {
|
||||
return error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
Validator() : value_(ValidationType::validate(T()).value()) {}
|
||||
|
||||
Validator(Validator&& _other) noexcept = default;
|
||||
|
||||
Validator(const Validator& _other) = default;
|
||||
|
||||
Validator(T&& _value) : value_(ValidationType::validate(_value).value()) {}
|
||||
|
||||
Validator(const T& _value)
|
||||
: value_(ValidationType::validate(_value).value()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
Validator(U&& _value)
|
||||
: value_(ValidationType::validate(T(std::forward<U>(_value))).value()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
Validator(const U& _value)
|
||||
: value_(ValidationType::validate(T(_value)).value()) {}
|
||||
|
||||
~Validator() = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const T& _value) {
|
||||
value_ = ValidationType::validate(_value).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(T&& _value) {
|
||||
value_ = ValidationType::validate(std::forward<T>(_value)).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Validator& operator=(const Validator& _other) =
|
||||
default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Validator& operator=(Validator&& _other) noexcept =
|
||||
default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
auto& operator=(U&& _value) noexcept {
|
||||
value_ = ValidationType::validate(T(std::forward<U>(_value))).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, T>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = ValidationType::validate(T(_value)).value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Equality operator other Validators.
|
||||
bool operator==(const Validator& _other) const {
|
||||
return value() == _other.value();
|
||||
}
|
||||
|
||||
/// Exposes the underlying value.
|
||||
T& value() { return value_; }
|
||||
|
||||
/// Exposes the underlying value.
|
||||
const T& value() const { return value_; }
|
||||
|
||||
/// Necessary for the serialization to work.
|
||||
const T& reflection() const { return value_; }
|
||||
|
||||
private:
|
||||
/// The underlying value.
|
||||
T value_;
|
||||
};
|
||||
|
||||
template <class T, class V, class... Vs>
|
||||
inline auto operator<=>(const Validator<T, V, Vs...>& _v1,
|
||||
const Validator<T, V, Vs...>& _v2) {
|
||||
return _v1.value() <=> _v2.value();
|
||||
}
|
||||
|
||||
template <class T, class V, class... Vs>
|
||||
inline auto operator<=>(const Validator<T, V, Vs...>& _v, const T& _t) {
|
||||
return _v.value() <=> _t;
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T, class V, class... Vs>
|
||||
struct hash<rfl::Validator<T, V, Vs...>> {
|
||||
size_t operator()(const rfl::Validator<T, V, Vs...>& _v) const {
|
||||
return hash<T>()(_v.value());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
559
build-config/reflect-cpp/include/rfl/Variant.hpp
Normal file
559
build-config/reflect-cpp/include/rfl/Variant.hpp
Normal file
@@ -0,0 +1,559 @@
|
||||
#ifndef RFL_VARIANT_HPP_
|
||||
#define RFL_VARIANT_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "internal/element_index.hpp"
|
||||
#include "internal/nth_element_t.hpp"
|
||||
#include "internal/ptr_cast.hpp"
|
||||
#include "internal/variant/find_max_size.hpp"
|
||||
#include "internal/variant/is_alternative_type.hpp"
|
||||
#include "internal/variant/result_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class... AlternativeTypes>
|
||||
class Variant {
|
||||
static constexpr auto max_size_wrapper_ =
|
||||
internal::variant::find_max_size<AlternativeTypes...>();
|
||||
|
||||
static constexpr unsigned long num_bytes_ = max_size_wrapper_.size_;
|
||||
|
||||
using DataType = std::array<unsigned char, num_bytes_>;
|
||||
|
||||
using IndexType =
|
||||
std::conditional_t<sizeof...(AlternativeTypes) <=
|
||||
std::numeric_limits<std::uint8_t>::max(),
|
||||
std::uint8_t, std::uint16_t>;
|
||||
|
||||
static constexpr IndexType size_ = sizeof...(AlternativeTypes);
|
||||
|
||||
template <class F>
|
||||
using result_t = internal::variant::result_t<F, AlternativeTypes...>;
|
||||
|
||||
template <IndexType _i>
|
||||
using Index = std::integral_constant<IndexType, _i>;
|
||||
|
||||
template <class T>
|
||||
struct TypeWrapper {};
|
||||
|
||||
public:
|
||||
Variant() : index_(IndexType()), data_(DataType()) {
|
||||
using FirstAlternative = internal::nth_element_t<0, AlternativeTypes...>;
|
||||
move_from_type(FirstAlternative());
|
||||
}
|
||||
|
||||
Variant(const Variant& _other)
|
||||
: index_(IndexType()), data_(DataType()) {
|
||||
copy_from_other(_other);
|
||||
}
|
||||
|
||||
Variant(Variant&& _other) noexcept
|
||||
: index_(IndexType()), data_(DataType()) {
|
||||
move_from_other(std::move(_other));
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<internal::variant::is_alternative_type<
|
||||
T, AlternativeTypes...>(),
|
||||
bool>::type = true>
|
||||
Variant(const T& _t) : index_(IndexType()), data_(DataType()) {
|
||||
copy_from_type(_t);
|
||||
}
|
||||
|
||||
template <class T,
|
||||
typename std::enable_if<internal::variant::is_alternative_type<
|
||||
T, AlternativeTypes...>(),
|
||||
bool>::type = true>
|
||||
Variant(T&& _t) noexcept : index_(IndexType()), data_(DataType()) {
|
||||
move_from_type(std::forward<T>(_t));
|
||||
}
|
||||
|
||||
~Variant() { destroy_if_necessary(); }
|
||||
|
||||
/// Emplaces a new element into the variant.
|
||||
template <class T, class... Args>
|
||||
constexpr T& emplace(Args&&... _args) {
|
||||
auto t = T{std::forward<Args>(_args)...};
|
||||
destroy_if_necessary();
|
||||
move_from_type(std::move(t));
|
||||
return *internal::ptr_cast<T*>(data_.data());
|
||||
}
|
||||
|
||||
/// Emplaces a new element into the variant.
|
||||
template <int _i, class... Args>
|
||||
constexpr auto& emplace(Args&&... _args) {
|
||||
using T = internal::nth_element_t<_i, AlternativeTypes...>;
|
||||
return emplace<T>(std::move(_args)...);
|
||||
}
|
||||
|
||||
/// Returns the index of the element currently held.
|
||||
constexpr int index() const noexcept { return index_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class T,
|
||||
typename std::enable_if<internal::variant::is_alternative_type<
|
||||
T, AlternativeTypes...>(),
|
||||
bool>::type = true>
|
||||
Variant& operator=(const T& _t) {
|
||||
auto temp = Variant(_t);
|
||||
destroy_if_necessary();
|
||||
move_from_other(std::move(temp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class T,
|
||||
typename std::enable_if<internal::variant::is_alternative_type<
|
||||
T, AlternativeTypes...>(),
|
||||
bool>::type = true>
|
||||
Variant& operator=(T&& _t) noexcept {
|
||||
destroy_if_necessary();
|
||||
move_from_type(std::forward<T>(_t));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Variant& operator=(const Variant& _other) {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
auto temp = Variant(_other);
|
||||
destroy_if_necessary();
|
||||
move_from_other(std::move(temp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
Variant& operator=(Variant&& _other) noexcept {
|
||||
if (this == &_other) {
|
||||
return *this;
|
||||
}
|
||||
destroy_if_necessary();
|
||||
move_from_other(std::move(_other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Swaps the content with the other variant.
|
||||
void swap(Variant& _other) noexcept {
|
||||
if (this == &_other) {
|
||||
return;
|
||||
}
|
||||
auto temp = Variant(std::move(*this));
|
||||
move_from_other(std::move(_other));
|
||||
_other = std::move(temp);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
result_t<F> visit(F&& _f) {
|
||||
using ResultType = result_t<F>;
|
||||
if constexpr (std::is_same_v<ResultType, void>) {
|
||||
bool visited = false;
|
||||
do_visit_no_result(std::forward<F>(_f), &visited,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
} else if constexpr (std::is_reference_v<ResultType>) {
|
||||
std::remove_reference_t<ResultType>* res = nullptr;
|
||||
do_visit_with_reference(std::forward<F>(_f), &res,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
return *res;
|
||||
} else {
|
||||
auto res = std::optional<ResultType>();
|
||||
do_visit_with_result(std::forward<F>(_f), &res,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
return std::move(*res);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
result_t<F> visit(F&& _f) const {
|
||||
using ResultType = result_t<F>;
|
||||
if constexpr (std::is_same_v<ResultType, void>) {
|
||||
bool visited = false;
|
||||
do_visit_no_result(std::forward<F>(_f), &visited,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
} else if constexpr (std::is_reference_v<ResultType>) {
|
||||
std::remove_reference_t<ResultType>* res = nullptr;
|
||||
do_visit_with_reference(std::forward<F>(_f), &res,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
return *res;
|
||||
} else {
|
||||
auto res = std::optional<ResultType>();
|
||||
do_visit_with_result(std::forward<F>(_f), &res,
|
||||
std::make_integer_sequence<IndexType, size_>());
|
||||
return std::move(*res);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void copy_from_other(const Variant& _other) {
|
||||
const auto copy_one = [this](const auto& _t) { this->copy_from_type(_t); };
|
||||
_other.visit(copy_one);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_from_other_type(const T& _t) {
|
||||
bool set = false;
|
||||
const auto copy_one = [&, this]<class AltType>(const T& _t,
|
||||
const TypeWrapper<AltType>) {
|
||||
if constexpr (std::is_convertible_v<T, AltType>) {
|
||||
if (!set) {
|
||||
move_from_type(AltType(_t));
|
||||
set = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
(copy_one(_t, TypeWrapper<AlternativeTypes>{}), ...);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_from_type(const T& _t) noexcept {
|
||||
using CurrentType = std::remove_cvref_t<decltype(_t)>;
|
||||
index_ =
|
||||
internal::element_index<CurrentType,
|
||||
std::remove_cvref_t<AlternativeTypes>...>();
|
||||
new (data_.data()) CurrentType(_t);
|
||||
}
|
||||
|
||||
void destroy_if_necessary() {
|
||||
const auto destroy_one = [](auto& _t) {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
if constexpr (std::is_destructible_v<T>) {
|
||||
_t.~T();
|
||||
}
|
||||
};
|
||||
visit(destroy_one);
|
||||
}
|
||||
|
||||
template <class F, IndexType... _is>
|
||||
void do_visit_no_result(F& _f, bool* _visited,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
auto visit_one = [this]<IndexType _i>(const F& _f, bool* _visited,
|
||||
Index<_i>) {
|
||||
if (!*_visited && index_ == _i) {
|
||||
_f(get_alternative<_i>());
|
||||
*_visited = true;
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _visited, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, IndexType... _is>
|
||||
void do_visit_no_result(F& _f, bool* _visited,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
auto visit_one = [this]<IndexType _i>(const F& _f, bool* _visited,
|
||||
Index<_i>) {
|
||||
if (!*_visited && index_ == _i) {
|
||||
_f(get_alternative<_i>());
|
||||
*_visited = true;
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _visited, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, IndexType... _is>
|
||||
void do_visit_no_result(const F& _f, bool* _visited,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, bool* _visited,
|
||||
Index<_i>) {
|
||||
if (!*_visited && index_ == _i) {
|
||||
_f(get_alternative<_i>());
|
||||
*_visited = true;
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _visited, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, IndexType... _is>
|
||||
void do_visit_no_result(const F& _f, bool* _visited,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, bool* _visited,
|
||||
Index<_i>) {
|
||||
if (!*_visited && index_ == _i) {
|
||||
_f(get_alternative<_i>());
|
||||
*_visited = true;
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _visited, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_result(F& _f, std::optional<ResultType>* _result,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
auto visit_one = [this]<IndexType _i>(const F& _f,
|
||||
std::optional<ResultType>* _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
_result->emplace(_f(get_alternative<_i>()));
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_result(F& _f, std::optional<ResultType>* _result,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
auto visit_one = [this]<IndexType _i>(const F& _f,
|
||||
std::optional<ResultType>* _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
_result->emplace(_f(get_alternative<_i>()));
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_result(const F& _f, std::optional<ResultType>* _result,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f,
|
||||
std::optional<ResultType>* _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
_result->emplace(_f(get_alternative<_i>()));
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_result(const F& _f, std::optional<ResultType>* _result,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f,
|
||||
std::optional<ResultType>* _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
_result->emplace(_f(get_alternative<_i>()));
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_reference(F& _f, ResultType** _result,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
*_result = &_f(get_alternative<_i>());
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_reference(F& _f, ResultType** _result,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
*_result = &_f(get_alternative<_i>());
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_reference(const F& _f, ResultType** _result,
|
||||
std::integer_sequence<IndexType, _is...>) {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
*_result = &_f(get_alternative<_i>());
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <class F, class ResultType, IndexType... _is>
|
||||
void do_visit_with_reference(const F& _f, ResultType** _result,
|
||||
std::integer_sequence<IndexType, _is...>) const {
|
||||
const auto visit_one = [this]<IndexType _i>(const F& _f, ResultType** _result,
|
||||
Index<_i>) {
|
||||
if (!*_result && index_ == _i) {
|
||||
*_result = &_f(get_alternative<_i>());
|
||||
}
|
||||
};
|
||||
(visit_one(_f, _result, Index<_is>{}), ...);
|
||||
}
|
||||
|
||||
template <IndexType _i>
|
||||
auto& get_alternative() noexcept {
|
||||
using CurrentType = internal::nth_element_t<_i, AlternativeTypes...>;
|
||||
return *internal::ptr_cast<CurrentType*>(data_.data());
|
||||
}
|
||||
|
||||
template <IndexType _i>
|
||||
const auto& get_alternative() const noexcept {
|
||||
using CurrentType = internal::nth_element_t<_i, AlternativeTypes...>;
|
||||
return *internal::ptr_cast<const CurrentType*>(data_.data());
|
||||
}
|
||||
|
||||
void move_from_other(Variant&& _other) noexcept {
|
||||
const auto move_one = [this](auto&& _t) {
|
||||
this->move_from_type(std::forward<std::remove_cvref_t<decltype(_t)>>(_t));
|
||||
};
|
||||
std::move(_other).visit(move_one);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_from_type(T&& _t) noexcept {
|
||||
using CurrentType = std::remove_cvref_t<decltype(_t)>;
|
||||
index_ =
|
||||
internal::element_index<CurrentType,
|
||||
std::remove_cvref_t<AlternativeTypes>...>();
|
||||
new (data_.data()) CurrentType(std::forward<T>(_t));
|
||||
}
|
||||
|
||||
private:
|
||||
/// Index indicating which of the alternatives is currently contained in the
|
||||
/// variant.
|
||||
IndexType index_;
|
||||
|
||||
/// The underlying data, can be any of the underlying types.
|
||||
alignas(AlternativeTypes...) DataType data_;
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
concept VariantBased = requires(std::decay_t<V> v) {
|
||||
[]<typename... Args>(Variant<Args...> const&) {}(v);
|
||||
};
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr T* get_if(Variant<Types...>* _v) noexcept {
|
||||
const auto get = [](auto& _v) -> T* {
|
||||
using Type = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same<Type, std::remove_cvref_t<T>>()) {
|
||||
return &_v;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
return _v->visit(get);
|
||||
}
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr const T* get_if(const Variant<Types...>* _v) noexcept {
|
||||
const auto get = [](const auto& _v) -> const T* {
|
||||
using Type = std::remove_cvref_t<decltype(_v)>;
|
||||
if constexpr (std::is_same<Type, std::remove_cvref_t<T>>()) {
|
||||
return &_v;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
return _v->visit(get);
|
||||
}
|
||||
|
||||
template <int _i, class... Types>
|
||||
constexpr auto* get_if(Variant<Types...>* _v) noexcept {
|
||||
using T = internal::nth_element_t<_i, Types...>;
|
||||
return get_if<T>(_v);
|
||||
}
|
||||
|
||||
template <int _i, class... Types>
|
||||
constexpr auto* get_if(const Variant<Types...>* _v) noexcept {
|
||||
using T = internal::nth_element_t<_i, Types...>;
|
||||
return get_if<T>(_v);
|
||||
}
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr T& get(Variant<Types...>& _v) {
|
||||
auto ptr = get_if<T>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr T&& get(Variant<Types...>&& _v) {
|
||||
auto ptr = get_if<T>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return std::move(*ptr);
|
||||
}
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr const T& get(const Variant<Types...>& _v) {
|
||||
auto ptr = get_if<T>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <int _i, class... Types>
|
||||
constexpr auto& get(Variant<Types...>& _v) {
|
||||
auto ptr = get_if<_i>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <int _i, class... Types>
|
||||
constexpr auto&& get(Variant<Types...>&& _v) {
|
||||
auto ptr = get_if<_i>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return std::move(*ptr);
|
||||
}
|
||||
|
||||
template <int _i, class... Types>
|
||||
constexpr const auto& get(const Variant<Types...>& _v) {
|
||||
auto ptr = get_if<_i>(&_v);
|
||||
if (!ptr) {
|
||||
throw std::runtime_error("Variant does not contain signified type.");
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <class T, class... Types>
|
||||
constexpr bool holds_alternative(const Variant<Types...>& _v) noexcept {
|
||||
constexpr auto ix = internal::element_index<std::remove_cvref_t<T>,
|
||||
std::remove_cvref_t<Types>...>();
|
||||
static_assert(ix != -1, "Type not supported.");
|
||||
return ix == _v.index();
|
||||
}
|
||||
|
||||
template <int N, class T>
|
||||
struct variant_alternative;
|
||||
|
||||
template <int N, class... Types>
|
||||
struct variant_alternative<N, Variant<Types...>> {
|
||||
using type = internal::nth_element_t<N, Types...>;
|
||||
};
|
||||
|
||||
template <int N, class VariantType>
|
||||
using variant_alternative_t =
|
||||
typename variant_alternative<N, std::remove_cvref_t<VariantType>>::type;
|
||||
|
||||
template <class T>
|
||||
struct variant_size;
|
||||
|
||||
template <class... Types>
|
||||
struct variant_size<Variant<Types...>>
|
||||
: std::integral_constant<size_t, sizeof...(Types)> {};
|
||||
|
||||
template <class VariantType>
|
||||
constexpr size_t variant_size_v =
|
||||
variant_size<std::remove_cvref_t<VariantType>>();
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
namespace std {
|
||||
template <class... Types>
|
||||
void swap(rfl::Variant<Types...>& _lhs, rfl::Variant<Types...>& _rhs) noexcept {
|
||||
_lhs.swap(_rhs);
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
13
build-config/reflect-cpp/include/rfl/Vectorstring.hpp
Normal file
13
build-config/reflect-cpp/include/rfl/Vectorstring.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef RFL_VECTORSTRING_HPP_
|
||||
#define RFL_VECTORSTRING_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace rfl {
|
||||
|
||||
using Vectorstring = std::vector<char>;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
12
build-config/reflect-cpp/include/rfl/always_false.hpp
Normal file
12
build-config/reflect-cpp/include/rfl/always_false.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef RFL_ALWAYSFALSE_HPP_
|
||||
#define RFL_ALWAYSFALSE_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// To be used inside visitor patterns
|
||||
template <class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_ALWAYSFALSE_HPP_
|
||||
31
build-config/reflect-cpp/include/rfl/apply.hpp
Normal file
31
build-config/reflect-cpp/include/rfl/apply.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef RFL_APPLY_HPP_
|
||||
#define RFL_APPLY_HPP_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "Tuple.hpp"
|
||||
#include "internal/tuple/apply.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class F, class... Types>
|
||||
auto apply(F&& _f, const rfl::Tuple<Types...>& _tup) {
|
||||
return internal::tuple::apply(
|
||||
_f, _tup, std::make_integer_sequence<int, sizeof...(Types)>());
|
||||
}
|
||||
|
||||
template <class F, class... Types>
|
||||
auto apply(F&& _f, rfl::Tuple<Types...>& _tup) {
|
||||
return internal::tuple::apply(
|
||||
_f, _tup, std::make_integer_sequence<int, sizeof...(Types)>());
|
||||
}
|
||||
|
||||
template <class F, class... Types>
|
||||
auto apply(F&& _f, rfl::Tuple<Types...>&& _tup) {
|
||||
return internal::tuple::apply(
|
||||
_f, std::move(_tup), std::make_integer_sequence<int, sizeof...(Types)>());
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
35
build-config/reflect-cpp/include/rfl/as.hpp
Normal file
35
build-config/reflect-cpp/include/rfl/as.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef RFL_AS_HPP_
|
||||
#define RFL_AS_HPP_
|
||||
|
||||
#include "from_named_tuple.hpp"
|
||||
#include "make_named_tuple.hpp"
|
||||
#include "to_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Generates a type T from the input values.
|
||||
template <class T, class Head, class... Tail>
|
||||
T as(Head&& _head, Tail&&... _tail) {
|
||||
if constexpr (sizeof...(_tail) == 0) {
|
||||
return from_named_tuple<T>(to_named_tuple(std::forward<Head>(_head)));
|
||||
} else {
|
||||
return from_named_tuple<T>(
|
||||
to_named_tuple(std::forward<Head>(_head))
|
||||
.add(to_named_tuple(std::forward<Tail>(_tail))...));
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a type T from the input values.
|
||||
template <class T, class Head, class... Tail>
|
||||
T as(const Head& _head, const Tail&... _tail) {
|
||||
if constexpr (sizeof...(_tail) == 0) {
|
||||
return from_named_tuple<T>(to_named_tuple(_head));
|
||||
} else {
|
||||
return from_named_tuple<T>(
|
||||
to_named_tuple(_head).add(to_named_tuple(_tail)...));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
19
build-config/reflect-cpp/include/rfl/common.hpp
Normal file
19
build-config/reflect-cpp/include/rfl/common.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef RFL_COMMON_HPP_
|
||||
#define RFL_COMMON_HPP_
|
||||
|
||||
|
||||
#ifdef RFL_BUILD_SHARED
|
||||
#ifdef _WIN32
|
||||
#ifdef reflectcpp_EXPORTS
|
||||
#define RFL_API __declspec(dllexport)
|
||||
#else
|
||||
#define RFL_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define RFL_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
#else
|
||||
#define RFL_API
|
||||
#endif
|
||||
|
||||
#endif
|
||||
164
build-config/reflect-cpp/include/rfl/comparisons.hpp
Normal file
164
build-config/reflect-cpp/include/rfl/comparisons.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef RFL_COMPARISONS_HPP_
|
||||
#define RFL_COMPARISONS_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "parsing/schema/ValidationType.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <auto _threshold>
|
||||
struct EqualTo {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value != threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected to be equal to " << threshold << ", but got "
|
||||
<< _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::EqualTo{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto _threshold>
|
||||
struct Minimum {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value < threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected to be greater than or equal to " << threshold
|
||||
<< ", but got " << _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::Minimum{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto _threshold>
|
||||
struct ExclusiveMinimum {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value <= threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected to be greater than " << threshold
|
||||
<< ", but got " << _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::ExclusiveMinimum{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto _threshold>
|
||||
struct Maximum {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value > threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected to be less than or equal to " << threshold
|
||||
<< ", but got " << _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::Maximum{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto _threshold>
|
||||
struct ExclusiveMaximum {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value >= threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected to be less than " << threshold << ", but got "
|
||||
<< _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::ExclusiveMaximum{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
template <auto _threshold>
|
||||
struct NotEqualTo {
|
||||
template <class T>
|
||||
static Result<T> validate(T _value) noexcept {
|
||||
constexpr auto threshold = static_cast<T>(_threshold);
|
||||
if (_value == threshold) {
|
||||
std::stringstream stream;
|
||||
stream << "Value expected not to be equal to " << threshold
|
||||
<< ", but got " << _value << ".";
|
||||
return error(stream.str());
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static parsing::schema::ValidationType to_schema() {
|
||||
using ValidationType = parsing::schema::ValidationType;
|
||||
const auto value =
|
||||
std::is_floating_point_v<T>
|
||||
? rfl::Variant<double, int>(static_cast<double>(_threshold))
|
||||
: rfl::Variant<double, int>(static_cast<int>(_threshold));
|
||||
return ValidationType{ValidationType::NotEqualTo{.value_ = value}};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
67
build-config/reflect-cpp/include/rfl/concepts.hpp
Normal file
67
build-config/reflect-cpp/include/rfl/concepts.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef RFL_CONCEPTS_HPP_
|
||||
#define RFL_CONCEPTS_HPP_
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl::concepts {
|
||||
|
||||
/// Concept for byte-like types that can be used in contiguous containers
|
||||
/// Includes char, signed char, unsigned char, std::byte, and uint8_t
|
||||
template <typename T>
|
||||
concept ByteLike = std::same_as<T, char> || std::same_as<T, signed char> ||
|
||||
std::same_as<T, unsigned char> ||
|
||||
std::same_as<T, std::uint8_t> || std::same_as<T, std::byte>;
|
||||
|
||||
/// Concept for containers with a contiguous sequence of byte-like types
|
||||
/// Requires:
|
||||
/// - Container has a value_type that is byte-like
|
||||
/// - Container provides data() method returning a pointer to contiguous memory
|
||||
/// - Container provides size() method returning the number of elements
|
||||
/// - Container supports range-based for loops (begin/end)
|
||||
template <typename Container>
|
||||
concept ContiguousByteContainer = requires(const Container& c) {
|
||||
typename Container::value_type;
|
||||
{ c.data() } -> std::convertible_to<const typename Container::value_type*>;
|
||||
{ c.size() } -> std::convertible_to<std::size_t>;
|
||||
{ c.begin() } -> std::input_iterator;
|
||||
{ c.end() } -> std::input_iterator;
|
||||
requires ByteLike<typename Container::value_type>;
|
||||
requires std::contiguous_iterator<decltype(c.begin())>;
|
||||
};
|
||||
|
||||
/// Concept for mutable containers with a contiguous sequence of byte-like types
|
||||
/// Extends ContiguousByteContainer with mutable access requirements
|
||||
template <typename Container>
|
||||
concept MutableContiguousByteContainer =
|
||||
ContiguousByteContainer<Container> && requires(Container& c) {
|
||||
{ c.data() } -> std::convertible_to<typename Container::value_type*>;
|
||||
{ c.begin() } -> std::output_iterator<typename Container::value_type>;
|
||||
{ c.end() } -> std::output_iterator<typename Container::value_type>;
|
||||
};
|
||||
|
||||
/// Concept for back-insertable byte containers (like std::vector<uint8_t>)
|
||||
/// Useful for containers that can grow dynamically during serialization
|
||||
template <typename Container>
|
||||
concept BackInsertableByteContainer =
|
||||
ContiguousByteContainer<Container> &&
|
||||
requires(Container& c, typename Container::value_type v) {
|
||||
c.push_back(v);
|
||||
c.reserve(std::size_t{});
|
||||
{ c.capacity() } -> std::convertible_to<std::size_t>;
|
||||
};
|
||||
|
||||
/// Concept for byte spans or views (read-only, non-owning containers)
|
||||
/// Includes std::span<const uint8_t>, std::string_view when used with char
|
||||
/// data, etc.
|
||||
template <typename Container>
|
||||
concept ByteSpanLike = ContiguousByteContainer<Container> &&
|
||||
std::is_trivially_copyable_v<Container> &&
|
||||
std::is_trivially_destructible_v<Container>;
|
||||
|
||||
} // namespace rfl::concepts
|
||||
|
||||
#endif // RFL_CONCEPTS_HPP_
|
||||
19
build-config/reflect-cpp/include/rfl/config.hpp
Normal file
19
build-config/reflect-cpp/include/rfl/config.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef RFL_CONFIG_HPP_
|
||||
#define RFL_CONFIG_HPP_
|
||||
|
||||
namespace rfl::config {
|
||||
|
||||
// To specify a different range for a particular enum type, specialize the
|
||||
// enum_range template for that enum type.
|
||||
template <typename T>
|
||||
struct enum_range {
|
||||
// In your template specialization, uncomment these two lines and replace them
|
||||
// with the values of your choice.
|
||||
// static constexpr int min = ...;
|
||||
// static constexpr int max = ...;
|
||||
};
|
||||
|
||||
} // namespace rfl::config
|
||||
|
||||
#endif
|
||||
|
||||
14
build-config/reflect-cpp/include/rfl/default.hpp
Normal file
14
build-config/reflect-cpp/include/rfl/default.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef RFL_DEFAULT_HPP_
|
||||
#define RFL_DEFAULT_HPP_
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Helper class that can be passed to a field
|
||||
/// to trigger the default value of the type.
|
||||
struct Default {};
|
||||
|
||||
inline static const auto default_value = Default{};
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
16
build-config/reflect-cpp/include/rfl/define_literal.hpp
Normal file
16
build-config/reflect-cpp/include/rfl/define_literal.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef RFL_DEFINELITERAL_HPP_
|
||||
#define RFL_DEFINELITERAL_HPP_
|
||||
|
||||
#include "Literal.hpp"
|
||||
#include "internal/define_literal.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Allows you to combine several literal types.
|
||||
template <class... LiteralTypes>
|
||||
using define_literal_t =
|
||||
typename internal::define_literal<LiteralTypes...>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_DEFINELITERAL_HPP_
|
||||
15
build-config/reflect-cpp/include/rfl/define_named_tuple.hpp
Normal file
15
build-config/reflect-cpp/include/rfl/define_named_tuple.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef RFL_DEFINENAMEDTUPLE_HPP_
|
||||
#define RFL_DEFINENAMEDTUPLE_HPP_
|
||||
|
||||
#include "NamedTuple.hpp"
|
||||
#include "internal/define_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class... FieldTypes>
|
||||
using define_named_tuple_t =
|
||||
typename internal::define_named_tuple<FieldTypes...>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_DEFINENAMEDTUPLE_HPP_
|
||||
17
build-config/reflect-cpp/include/rfl/define_tagged_union.hpp
Normal file
17
build-config/reflect-cpp/include/rfl/define_tagged_union.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef RFL_DEFINETAGGEDUNION_HPP_
|
||||
#define RFL_DEFINETAGGEDUNION_HPP_
|
||||
|
||||
#include "TaggedUnion.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/define_tagged_union.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral _discriminator, class... TaggedUnionTypes>
|
||||
using define_tagged_union_t =
|
||||
typename internal::define_tagged_union<_discriminator,
|
||||
TaggedUnionTypes...>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
15
build-config/reflect-cpp/include/rfl/define_variant.hpp
Normal file
15
build-config/reflect-cpp/include/rfl/define_variant.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef RFL_DEFINEVARIANT_HPP_
|
||||
#define RFL_DEFINEVARIANT_HPP_
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "internal/define_variant.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <class... Vars>
|
||||
using define_variant_t = typename internal::define_variant<Vars...>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_DEFINEVARIANT_HPP_
|
||||
118
build-config/reflect-cpp/include/rfl/enums.hpp
Normal file
118
build-config/reflect-cpp/include/rfl/enums.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#ifndef RFL_ENUMS_HPP_
|
||||
#define RFL_ENUMS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Result.hpp"
|
||||
#include "internal/enums/get_enum_names.hpp"
|
||||
#include "internal/strings/strings.hpp"
|
||||
#include "thirdparty/enchantum/enchantum.hpp"
|
||||
#include "thirdparty/enchantum/bitflags.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <enchantum::Enum EnumType>
|
||||
std::string enum_to_string(const EnumType _enum) {
|
||||
const auto to_string_or_number = [](const EnumType e) {
|
||||
const auto s = enchantum::to_string(e);
|
||||
return s.empty() ? std::to_string(
|
||||
static_cast<std::underlying_type_t<EnumType>>(e))
|
||||
: std::string(s);
|
||||
};
|
||||
|
||||
if constexpr (enchantum::is_bitflag<EnumType>) {
|
||||
// Iterates through the enum bit by bit and matches it against the flags.
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
auto val = static_cast<T>(_enum);
|
||||
int i = 0;
|
||||
std::vector<std::string> flags;
|
||||
while (val != 0) {
|
||||
const auto bit = val & static_cast<T>(1);
|
||||
if (bit == 1) {
|
||||
auto str =
|
||||
to_string_or_number(static_cast<EnumType>(static_cast<T>(1) << i));
|
||||
flags.emplace_back(std::move(str));
|
||||
}
|
||||
++i;
|
||||
val >>= 1;
|
||||
}
|
||||
return internal::strings::join("|", flags);
|
||||
} else {
|
||||
return to_string_or_number(_enum);
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a string to a value of the given enum type.
|
||||
template <enchantum::Enum EnumType>
|
||||
Result<EnumType> string_to_enum(const std::string& _str) {
|
||||
const auto cast_numbers_or_names =
|
||||
[](const std::string& name) -> Result<EnumType> {
|
||||
const auto r = enchantum::cast<EnumType>(name);
|
||||
if (r) return *r;
|
||||
try {
|
||||
return static_cast<EnumType>(std::stoi(name));
|
||||
} catch (std::exception& exp) {
|
||||
return error(exp.what());
|
||||
}
|
||||
};
|
||||
|
||||
if constexpr (enchantum::is_bitflag<EnumType>) {
|
||||
using T = std::underlying_type_t<EnumType>;
|
||||
const auto split = internal::strings::split(_str, "|");
|
||||
auto res = static_cast<T>(0);
|
||||
for (const auto& s : split) {
|
||||
const auto r = cast_numbers_or_names(s);
|
||||
if (r) {
|
||||
res |= static_cast<T>(*r);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return static_cast<EnumType>(res);
|
||||
} else {
|
||||
return cast_numbers_or_names(_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type to
|
||||
// their values.
|
||||
template <enchantum::Enum EnumType>
|
||||
auto get_enumerators() {
|
||||
return internal::enums::names_to_enumerator_named_tuple(
|
||||
internal::enums::get_enum_names<EnumType>());
|
||||
}
|
||||
|
||||
// Returns a named tuple mapping names of enumerators of the given enum type to
|
||||
// their underlying values.
|
||||
template <enchantum::Enum EnumType>
|
||||
auto get_underlying_enumerators() {
|
||||
return internal::enums::names_to_underlying_enumerator_named_tuple(
|
||||
internal::enums::get_enum_names<EnumType>());
|
||||
}
|
||||
|
||||
// Returns an std::array containing pairs of enumerator names (as
|
||||
// std::string_view) and values.
|
||||
template <enchantum::Enum EnumType>
|
||||
constexpr auto get_enumerator_array() {
|
||||
return internal::enums::names_to_enumerator_array(
|
||||
internal::enums::get_enum_names<EnumType>());
|
||||
}
|
||||
|
||||
// Returns an std::array containing pairs of enumerator names (as
|
||||
// std::string_view) and underlying values.
|
||||
template <enchantum::Enum EnumType>
|
||||
constexpr auto get_underlying_enumerator_array() {
|
||||
return internal::enums::names_to_underlying_enumerator_array(
|
||||
internal::enums::get_enum_names<EnumType>());
|
||||
}
|
||||
|
||||
// Returns the range of the given enum type as a pair of the minimum and maximum
|
||||
template <enchantum::Enum EnumType>
|
||||
constexpr auto get_enum_range() {
|
||||
return std::make_pair(enchantum::enum_traits<EnumType>::min,
|
||||
enchantum::enum_traits<EnumType>::max);
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_ENUMS_HPP_
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef RFL_EXTRACTDISTRIMINATORS_HPP_
|
||||
#define RFL_EXTRACTDISTRIMINATORS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "TaggedUnion.hpp"
|
||||
#include "define_literal.hpp"
|
||||
#include "field_type.hpp"
|
||||
#include "internal/extract_discriminators.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Extracts a Literal containing all of the discriminators from a TaggedUnion.
|
||||
template <class TaggedUnionType>
|
||||
using extract_discriminators_t =
|
||||
typename internal::extract_discriminators<TaggedUnionType>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_EXTRACTDISTRIMINATORS_HPP_
|
||||
18
build-config/reflect-cpp/include/rfl/field_names_t.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/field_names_t.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_FIELD_NAMES_T_HPP_
|
||||
#define RFL_FIELD_NAMES_T_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "internal/get_field_names.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Returns a rfl::Literal containing the field names of struct T.
|
||||
template <class T>
|
||||
using field_names_t = typename std::invoke_result<
|
||||
decltype(internal::get_field_names<std::remove_cvref_t<T>>)>::type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/field_type.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/field_type.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_FIELD_TYPE_HPP_
|
||||
#define RFL_FIELD_TYPE_HPP_
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include "internal/StringLiteral.hpp"
|
||||
#include "internal/field_type.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
template <internal::StringLiteral _field_name, class T>
|
||||
using field_type_t = typename internal::FieldType<_field_name, T>::Type;
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
17
build-config/reflect-cpp/include/rfl/fields.hpp
Normal file
17
build-config/reflect-cpp/include/rfl/fields.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef RFL_FIELDS_HPP_
|
||||
#define RFL_FIELDS_HPP_
|
||||
|
||||
#include "internal/get_meta_fields.hpp"
|
||||
#include "named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Returns meta-information about the fields.
|
||||
template <class T>
|
||||
auto fields() {
|
||||
return internal::get_meta_fields<named_tuple_t<T>>();
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
17
build-config/reflect-cpp/include/rfl/from_generic.hpp
Normal file
17
build-config/reflect-cpp/include/rfl/from_generic.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef RFL_FROM_GENERIC_HPP_
|
||||
#define RFL_FROM_GENERIC_HPP_
|
||||
|
||||
#include "Generic.hpp"
|
||||
#include "generic/read.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Generates the struct T from a named tuple.
|
||||
template <class T, class... Ps>
|
||||
auto from_generic(const Generic& _g) {
|
||||
return rfl::generic::read<T, Ps...>(_g);
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
53
build-config/reflect-cpp/include/rfl/from_named_tuple.hpp
Normal file
53
build-config/reflect-cpp/include/rfl/from_named_tuple.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef RFL_FROM_NAMED_TUPLE_HPP_
|
||||
#define RFL_FROM_NAMED_TUPLE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "internal/copy_from_named_tuple.hpp"
|
||||
#include "internal/copy_from_tuple.hpp"
|
||||
#include "internal/has_fields.hpp"
|
||||
#include "internal/move_from_named_tuple.hpp"
|
||||
#include "internal/move_from_tuple.hpp"
|
||||
#include "named_tuple_t.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Generates the struct T from a named tuple.
|
||||
template <class T, class NamedTupleType>
|
||||
auto from_named_tuple(NamedTupleType&& _n) {
|
||||
using RequiredType = std::remove_cvref_t<rfl::named_tuple_t<T>>;
|
||||
if constexpr (!std::is_same<std::remove_cvref_t<NamedTupleType>,
|
||||
RequiredType>()) {
|
||||
return from_named_tuple<T>(RequiredType(std::forward<NamedTupleType>(_n)));
|
||||
} else if constexpr (internal::has_fields<T>()) {
|
||||
if constexpr (std::is_lvalue_reference<NamedTupleType>{}) {
|
||||
return internal::copy_from_named_tuple<T>(_n);
|
||||
} else {
|
||||
return internal::move_from_named_tuple<T>(_n);
|
||||
}
|
||||
} else {
|
||||
if constexpr (std::is_lvalue_reference<NamedTupleType>{}) {
|
||||
return internal::copy_from_tuple<T>(_n.values());
|
||||
} else {
|
||||
return internal::move_from_tuple<T>(std::move(_n.values()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the struct T from a named tuple.
|
||||
template <class T, class NamedTupleType>
|
||||
auto from_named_tuple(const NamedTupleType& _n) {
|
||||
using RequiredType = std::remove_cvref_t<rfl::named_tuple_t<T>>;
|
||||
if constexpr (!std::is_same<std::remove_cvref_t<NamedTupleType>,
|
||||
RequiredType>()) {
|
||||
return from_named_tuple<T>(RequiredType(_n));
|
||||
} else if constexpr (internal::has_fields<T>()) {
|
||||
return internal::copy_from_named_tuple<T>(_n);
|
||||
} else {
|
||||
return internal::copy_from_tuple<T>(_n.values());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
17
build-config/reflect-cpp/include/rfl/generic/Parser.hpp
Normal file
17
build-config/reflect-cpp/include/rfl/generic/Parser.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef GENERIC_PARSER_HPP_
|
||||
#define GENERIC_PARSER_HPP_
|
||||
|
||||
#include "../parsing/Parser.hpp"
|
||||
#include "Reader.hpp"
|
||||
#include "Writer.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace generic {
|
||||
|
||||
template <class T, class ProcessorsType>
|
||||
using Parser = parsing::Parser<Reader, Writer, T, ProcessorsType>;
|
||||
|
||||
}
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
102
build-config/reflect-cpp/include/rfl/generic/Reader.hpp
Normal file
102
build-config/reflect-cpp/include/rfl/generic/Reader.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef GENERIC_READER_HPP_
|
||||
#define GENERIC_READER_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../Generic.hpp"
|
||||
#include "../Result.hpp"
|
||||
#include "../always_false.hpp"
|
||||
|
||||
namespace rfl::generic {
|
||||
|
||||
struct Reader {
|
||||
using InputArrayType = Generic::Array;
|
||||
using InputObjectType = Generic::Object;
|
||||
using InputVarType = Generic;
|
||||
|
||||
template <class T>
|
||||
static constexpr bool has_custom_constructor = false;
|
||||
|
||||
rfl::Result<InputVarType> get_field_from_array(
|
||||
const size_t _idx, const InputArrayType& _arr) const noexcept {
|
||||
if (_idx >= _arr.size()) {
|
||||
return error("Index " + std::to_string(_idx) + " of of bounds.");
|
||||
}
|
||||
return _arr[_idx];
|
||||
}
|
||||
|
||||
rfl::Result<InputVarType> get_field_from_object(
|
||||
const std::string& _name, const InputObjectType& _obj) const noexcept {
|
||||
return _obj.get(_name);
|
||||
}
|
||||
|
||||
bool is_empty(const InputVarType& _var) const noexcept {
|
||||
return _var.is_null();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
rfl::Result<T> to_basic_type(const InputVarType& _var) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
return _var.to_string();
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
return _var.to_bool();
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
|
||||
return _var.to_double().transform(
|
||||
[](const auto& _v) { return static_cast<T>(_v); });
|
||||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
if constexpr (sizeof(T) > sizeof(int)) {
|
||||
return _var.to_int64().transform(
|
||||
[](const auto& _v) { return static_cast<T>(_v); });
|
||||
} else {
|
||||
return _var.to_int().transform(
|
||||
[](const auto& _v) { return static_cast<T>(_v); });
|
||||
}
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<T>, "Unsupported type.");
|
||||
}
|
||||
}
|
||||
|
||||
template <class ArrayReader>
|
||||
std::optional<Error> read_array(const ArrayReader& _array_reader,
|
||||
const InputArrayType& _arr) const noexcept {
|
||||
for (const auto& v : _arr) {
|
||||
const auto err = _array_reader.read(InputVarType(v));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <class ObjectReader>
|
||||
std::optional<Error> read_object(const ObjectReader& _object_reader,
|
||||
const InputObjectType& _obj) const noexcept {
|
||||
for (const auto& [k, v] : _obj) {
|
||||
_object_reader.read(std::string_view(k), v);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
rfl::Result<InputArrayType> to_array(
|
||||
const InputVarType& _var) const noexcept {
|
||||
return _var.to_array();
|
||||
}
|
||||
|
||||
rfl::Result<InputObjectType> to_object(
|
||||
const InputVarType& _var) const noexcept {
|
||||
return _var.to_object();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
rfl::Result<T> use_custom_constructor(
|
||||
const InputVarType /*_var*/) const noexcept {
|
||||
return error("Not supported for generic types");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rfl::generic
|
||||
|
||||
#endif
|
||||
110
build-config/reflect-cpp/include/rfl/generic/Writer.hpp
Normal file
110
build-config/reflect-cpp/include/rfl/generic/Writer.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#ifndef GENERIC_WRITER_HPP_
|
||||
#define GENERIC_WRITER_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../Generic.hpp"
|
||||
#include "../always_false.hpp"
|
||||
#include "../common.hpp"
|
||||
|
||||
namespace rfl::generic {
|
||||
|
||||
struct RFL_API Writer {
|
||||
struct OutputArray {
|
||||
Generic::Array* val_;
|
||||
};
|
||||
|
||||
struct OutputObject {
|
||||
Generic::Object* val_;
|
||||
};
|
||||
|
||||
using OutputArrayType = OutputArray;
|
||||
using OutputObjectType = OutputObject;
|
||||
using OutputVarType = Generic;
|
||||
|
||||
Writer() {}
|
||||
|
||||
~Writer() = default;
|
||||
|
||||
OutputArrayType array_as_root(const size_t _size) const noexcept;
|
||||
|
||||
OutputObjectType object_as_root(const size_t _size) const noexcept;
|
||||
|
||||
OutputVarType null_as_root() const noexcept;
|
||||
|
||||
template <class T>
|
||||
OutputVarType value_as_root(const T& _var) const noexcept {
|
||||
root_ = to_generic(_var);
|
||||
return root_;
|
||||
}
|
||||
|
||||
OutputArrayType add_array_to_array(const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept;
|
||||
|
||||
OutputArrayType add_array_to_object(const std::string_view& _name,
|
||||
const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept;
|
||||
|
||||
OutputObjectType add_object_to_array(const size_t _size,
|
||||
OutputArrayType* _parent) const noexcept;
|
||||
|
||||
OutputObjectType add_object_to_object(
|
||||
const std::string_view& _name, const size_t _size,
|
||||
OutputObjectType* _parent) const noexcept;
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_array(const T& _var,
|
||||
OutputArrayType* _parent) const noexcept {
|
||||
const auto g = to_generic(_var);
|
||||
_parent->val_->push_back(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OutputVarType add_value_to_object(const std::string_view& _name,
|
||||
const T& _var,
|
||||
OutputObjectType* _parent) const noexcept {
|
||||
const auto g = to_generic(_var);
|
||||
_parent->val_->insert(_name, g);
|
||||
return g;
|
||||
}
|
||||
|
||||
OutputVarType add_null_to_array(OutputArrayType* _parent) const noexcept;
|
||||
|
||||
OutputVarType add_null_to_object(const std::string_view& _name,
|
||||
OutputObjectType* _parent) const noexcept;
|
||||
|
||||
void end_array(OutputArrayType*) const noexcept {}
|
||||
|
||||
void end_object(OutputObjectType*) const noexcept {}
|
||||
|
||||
OutputVarType& root() { return root_; }
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
OutputVarType to_generic(const T& _var) const noexcept {
|
||||
if constexpr (std::is_same<std::remove_cvref_t<T>, std::string>()) {
|
||||
return OutputVarType(_var);
|
||||
} else if constexpr (std::is_same<std::remove_cvref_t<T>, bool>()) {
|
||||
return OutputVarType(_var);
|
||||
} else if constexpr (std::is_floating_point<std::remove_cvref_t<T>>()) {
|
||||
return OutputVarType(static_cast<double>(_var));
|
||||
} else if constexpr (std::is_integral<std::remove_cvref_t<T>>()) {
|
||||
return OutputVarType(static_cast<int64_t>(_var));
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "Unsupported type");
|
||||
}
|
||||
return OutputVarType{};
|
||||
}
|
||||
|
||||
private:
|
||||
mutable OutputVarType root_;
|
||||
};
|
||||
|
||||
} // namespace rfl::generic
|
||||
|
||||
#endif
|
||||
22
build-config/reflect-cpp/include/rfl/generic/read.hpp
Normal file
22
build-config/reflect-cpp/include/rfl/generic/read.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef GENERIC_READ_HPP_
|
||||
#define GENERIC_READ_HPP_
|
||||
|
||||
|
||||
#include "../Generic.hpp"
|
||||
#include "../Processors.hpp"
|
||||
#include "Parser.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace generic {
|
||||
|
||||
/// Parses an object from a generic type.
|
||||
template <class T, class... Ps>
|
||||
auto read(const Generic& _g) {
|
||||
const auto r = Reader();
|
||||
return Parser<T, Processors<Ps...>>::read(r, _g);
|
||||
}
|
||||
|
||||
} // namespace generic
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
24
build-config/reflect-cpp/include/rfl/generic/write.hpp
Normal file
24
build-config/reflect-cpp/include/rfl/generic/write.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef GENERIC_WRITE_HPP_
|
||||
#define GENERIC_WRITE_HPP_
|
||||
|
||||
#include "../Generic.hpp"
|
||||
#include "../parsing/Parent.hpp"
|
||||
#include "Parser.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace generic {
|
||||
|
||||
/// Writes an object to a generic.
|
||||
template <class... Ps>
|
||||
Generic write(const auto& _t) {
|
||||
using T = std::remove_cvref_t<decltype(_t)>;
|
||||
using ParentType = parsing::Parent<Writer>;
|
||||
auto w = Writer();
|
||||
Parser<T, Processors<Ps...>>::write(w, _t, typename ParentType::Root{});
|
||||
return w.root();
|
||||
}
|
||||
|
||||
} // namespace generic
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
48
build-config/reflect-cpp/include/rfl/get.hpp
Normal file
48
build-config/reflect-cpp/include/rfl/get.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef RFL_GET_HPP_
|
||||
#define RFL_GET_HPP_
|
||||
|
||||
#include "internal/Getter.hpp"
|
||||
#include "internal/StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
|
||||
/// Gets a field by index.
|
||||
template <int _index, class NamedTupleType>
|
||||
inline auto& get(NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get<_index>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <internal::StringLiteral _field_name, class NamedTupleType>
|
||||
inline auto& get(NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get<_field_name>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field, class NamedTupleType>
|
||||
inline auto& get(NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get<Field>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by index.
|
||||
template <int _index, class NamedTupleType>
|
||||
inline const auto& get(const NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get_const<_index>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <internal::StringLiteral _field_name, class NamedTupleType>
|
||||
inline const auto& get(const NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get_const<_field_name>(
|
||||
_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field, class NamedTupleType>
|
||||
inline const auto& get(const NamedTupleType& _tup) {
|
||||
return internal::Getter<NamedTupleType>::template get_const<Field>(_tup);
|
||||
}
|
||||
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
32
build-config/reflect-cpp/include/rfl/internal/Array.hpp
Normal file
32
build-config/reflect-cpp/include/rfl/internal/Array.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef RFL_INTERNAL_ARRAY_HPP_
|
||||
#define RFL_INTERNAL_ARRAY_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "to_std_array.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
requires std::is_array_v<T>
|
||||
struct Array {
|
||||
using Type = T;
|
||||
using StdArrayType = to_std_array_t<T>;
|
||||
|
||||
Array() = default;
|
||||
Array(const StdArrayType &_arr) : arr_(_arr) {}
|
||||
Array(StdArrayType &&_arr) : arr_(std::move(_arr)) {}
|
||||
Array(const T &_arr) : arr_(to_std_array(_arr)) {}
|
||||
Array(T &&_arr) : arr_(to_std_array(_arr)) {}
|
||||
|
||||
~Array() = default;
|
||||
|
||||
StdArrayType arr_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
18
build-config/reflect-cpp/include/rfl/internal/Field.hpp
Normal file
18
build-config/reflect-cpp/include/rfl/internal/Field.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
|
||||
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "copy_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
|
||||
}
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
23
build-config/reflect-cpp/include/rfl/internal/Fields.hpp
Normal file
23
build-config/reflect-cpp/include/rfl/internal/Fields.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef RFL_INTERNAL_FIELDS_HPP_
|
||||
#define RFL_INTERNAL_FIELDS_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <int N>
|
||||
struct Fields {
|
||||
std::array<std::string, N> names_;
|
||||
|
||||
std::unordered_map<std::string_view, std::int16_t> indices_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
84
build-config/reflect-cpp/include/rfl/internal/Getter.hpp
Normal file
84
build-config/reflect-cpp/include/rfl/internal/Getter.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef RFL_INTERNAL_GETTER_HPP_
|
||||
#define RFL_INTERNAL_GETTER_HPP_
|
||||
|
||||
#include "../Tuple.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
#include "find_index.hpp"
|
||||
|
||||
namespace rfl::internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <class NamedTupleType>
|
||||
struct Getter;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Default case - anything that cannot be explicitly matched.
|
||||
template <class NamedTupleType>
|
||||
struct Getter {
|
||||
public:
|
||||
/// Retrieves the indicated value from the tuple.
|
||||
template <int _index>
|
||||
static inline auto& get(NamedTupleType& _tup) {
|
||||
return rfl::get<_index>(_tup.values());
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <StringLiteral _field_name>
|
||||
static inline auto& get(NamedTupleType& _tup) {
|
||||
constexpr auto index =
|
||||
find_index<_field_name, typename NamedTupleType::Fields>();
|
||||
return Getter<NamedTupleType>::template get<index>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field>
|
||||
static inline auto& get(NamedTupleType& _tup) {
|
||||
constexpr auto index =
|
||||
find_index<Field::name_, typename NamedTupleType::Fields>();
|
||||
static_assert(
|
||||
std::is_same<typename tuple_element_t<
|
||||
index, typename NamedTupleType::Fields>::Type,
|
||||
typename Field::Type>(),
|
||||
"If two fields have the same name, "
|
||||
"their type must be the same as "
|
||||
"well.");
|
||||
return Getter<NamedTupleType>::template get<index>(_tup);
|
||||
}
|
||||
|
||||
/// Retrieves the indicated value from the tuple.
|
||||
template <int _index>
|
||||
static inline const auto& get_const(const NamedTupleType& _tup) {
|
||||
return rfl::get<_index>(_tup.values());
|
||||
}
|
||||
|
||||
/// Gets a field by name.
|
||||
template <StringLiteral _field_name>
|
||||
static inline const auto& get_const(const NamedTupleType& _tup) {
|
||||
constexpr auto index =
|
||||
find_index<_field_name, typename NamedTupleType::Fields>();
|
||||
return Getter<NamedTupleType>::template get_const<index>(_tup);
|
||||
}
|
||||
|
||||
/// Gets a field by the field type.
|
||||
template <class Field>
|
||||
static inline const auto& get_const(const NamedTupleType& _tup) {
|
||||
constexpr auto index =
|
||||
find_index<Field::name_, typename NamedTupleType::Fields>();
|
||||
static_assert(
|
||||
std::is_same<typename tuple_element_t<
|
||||
index, typename NamedTupleType::Fields>::Type,
|
||||
typename Field::Type>(),
|
||||
"If two fields have the same name, "
|
||||
"their type must be the same as "
|
||||
"well.");
|
||||
return Getter<NamedTupleType>::template get_const<index>(_tup);
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef RFL_INTERNAL_HASVALIDATION_HPP_
|
||||
#define RFL_INTERNAL_HASVALIDATION_HPP_
|
||||
|
||||
#include "../Result.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class Class, typename T>
|
||||
concept HasValidation = requires(Class obj, T value) {
|
||||
{ Class::validate(value) } -> std::same_as<rfl::Result<T>>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
149
build-config/reflect-cpp/include/rfl/internal/Skip.hpp
Normal file
149
build-config/reflect-cpp/include/rfl/internal/Skip.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#ifndef RFL_INTERNAL_SKIP_HPP_
|
||||
#define RFL_INTERNAL_SKIP_HPP_
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../default.hpp"
|
||||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <class T, bool _skip_serialization, bool _skip_deserialization>
|
||||
class Skip {
|
||||
private:
|
||||
using SelfType = Skip<T, _skip_serialization, _skip_deserialization>;
|
||||
|
||||
public:
|
||||
static constexpr bool skip_serialization_ = _skip_serialization;
|
||||
static constexpr bool skip_deserialization_ = _skip_deserialization;
|
||||
|
||||
/// The underlying type.
|
||||
using Type = T;
|
||||
using ReflectionType = std::optional<T>;
|
||||
|
||||
Skip() : value_(Type()) {}
|
||||
|
||||
Skip(const Type& _value) : value_(_value) {}
|
||||
|
||||
Skip(ReflectionType&& _value) noexcept
|
||||
: value_(_value ? std::move(*_value) : Type()) {}
|
||||
|
||||
Skip(const ReflectionType& _value) : value_(_value ? *_value : Type()) {}
|
||||
|
||||
Skip(Type&& _value) noexcept : value_(std::move(_value)) {}
|
||||
|
||||
Skip(SelfType&& _skip) noexcept = default;
|
||||
|
||||
Skip(const SelfType& _skip) = default;
|
||||
|
||||
template <class U, bool _skip_s, bool _skip_d>
|
||||
Skip(const Skip<U, _skip_s, _skip_d>& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, bool _skip_s, bool _skip_d>
|
||||
Skip(Skip<U, _skip_s, _skip_d>&& _other) : value_(_other.get()) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(const U& _value) : value_(_value) {}
|
||||
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(U&& _value) noexcept : value_(std::forward<U>(_value)) {}
|
||||
|
||||
template <class U, bool _skip_s, bool _skip_d,
|
||||
typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
Skip(const Skip<U, _skip_s, _skip_d>& _skip) : value_(_skip.value()) {}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
Skip(const Default&) : value_(Type()) {}
|
||||
|
||||
~Skip() = default;
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& get() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& get() const { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& operator()() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& operator()() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(const Type& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
auto& operator=(Type&& _value) noexcept {
|
||||
value_ = std::move(_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, typename std::enable_if<std::is_convertible_v<U, Type>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const U& _value) {
|
||||
value_ = _value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object to its default value.
|
||||
template <class U = Type,
|
||||
typename std::enable_if<std::is_default_constructible_v<U>,
|
||||
bool>::type = true>
|
||||
auto& operator=(const Default&) {
|
||||
value_ = Type();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
SelfType& operator=(const SelfType& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
SelfType& operator=(SelfType&& _other) = default;
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, bool _skip_s, bool _skip_d>
|
||||
auto& operator=(const Skip<U, _skip_s, _skip_d>& _skip) {
|
||||
value_ = _skip.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Assigns the underlying object.
|
||||
template <class U, bool _skip_s, bool _skip_d>
|
||||
auto& operator=(Skip<U, _skip_s, _skip_d>&& _skip) {
|
||||
value_ = std::forward<T>(_skip.value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns the ReflectionType - necessary for the serialization to work.
|
||||
ReflectionType reflection() const { return value_; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(const Type& _value) { value_ = _value; }
|
||||
|
||||
/// Assigns the underlying object.
|
||||
void set(Type&& _value) { value_ = std::move(_value); }
|
||||
|
||||
/// Returns the underlying object.
|
||||
Type& value() { return value_; }
|
||||
|
||||
/// Returns the underlying object.
|
||||
const Type& value() const { return value_; }
|
||||
|
||||
private:
|
||||
/// The underlying value
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef RFL_INTERNAL_STRINGLITERAL_HPP_
|
||||
#define RFL_INTERNAL_STRINGLITERAL_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Normal strings cannot be used as template
|
||||
/// parameters, but this can. This is needed
|
||||
/// for the parameters names in the NamedTuples.
|
||||
template <size_t N>
|
||||
struct StringLiteral {
|
||||
constexpr StringLiteral(const auto... _chars) : arr_{_chars..., '\0'} {}
|
||||
|
||||
constexpr StringLiteral(const std::array<char, N> _arr) : arr_(_arr) {}
|
||||
|
||||
constexpr StringLiteral(const char (&_str)[N]) {
|
||||
std::copy_n(_str, N, std::data(arr_));
|
||||
}
|
||||
|
||||
/// Returns the value as a string.
|
||||
std::string str() const { return std::string(string_view()); }
|
||||
|
||||
/// Returns the value as a string.
|
||||
constexpr std::string_view string_view() const {
|
||||
return std::string_view(std::data(arr_), N - 1);
|
||||
}
|
||||
|
||||
static constexpr size_t length = N - 1;
|
||||
|
||||
std::array<char, N> arr_{};
|
||||
};
|
||||
|
||||
template <size_t N1, size_t N2>
|
||||
constexpr inline bool operator==(const StringLiteral<N1>& _first,
|
||||
const StringLiteral<N2>& _second) {
|
||||
if constexpr (N1 != N2) {
|
||||
return false;
|
||||
}
|
||||
return _first.string_view() == _second.string_view();
|
||||
}
|
||||
|
||||
template <size_t N1, size_t N2>
|
||||
constexpr inline bool operator!=(const StringLiteral<N1>& _first,
|
||||
const StringLiteral<N2>& _second) {
|
||||
return !(_first == _second);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
29
build-config/reflect-cpp/include/rfl/internal/VisitTree.hpp
Normal file
29
build-config/reflect-cpp/include/rfl/internal/VisitTree.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef RFL_INTERNAL_VISITTREE_HPP_
|
||||
#define RFL_INTERNAL_VISITTREE_HPP_
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
struct VisitTree {
|
||||
/// Evaluates a visitor pattern using a tree-like structure.
|
||||
template <int _begin, int _end, class Visitor, class... Args>
|
||||
static inline auto visit(const auto& _v, const int _i,
|
||||
const Args&... _args) {
|
||||
static_assert(_end > _begin, "_end needs to be greater than _begin.");
|
||||
if constexpr (_end - _begin == 1) {
|
||||
return _v.template visit<_begin>(_args...);
|
||||
} else {
|
||||
constexpr int middle = (_begin + _end) / 2;
|
||||
if (_i < middle) {
|
||||
return visit<_begin, middle, Visitor>(_v, _i, _args...);
|
||||
} else {
|
||||
return visit<middle, _end, Visitor>(_v, _i, _args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef RFL_INTERNAL_VISITORWRAPPER_HPP_
|
||||
#define RFL_INTERNAL_VISITORWRAPPER_HPP_
|
||||
|
||||
#include "../Literal.hpp"
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Necessary for the VisitTree structure.
|
||||
template <class Visitor, internal::StringLiteral... _fields>
|
||||
struct VisitorWrapper {
|
||||
/// Calls the underlying visitor when required to do so.
|
||||
template <int _i, class... Args>
|
||||
inline auto visit(const Args&... _args) const {
|
||||
return (*visitor_)(name_of<Literal<_fields...>, _i>(), _args...);
|
||||
}
|
||||
|
||||
/// The underlying visitor.
|
||||
const Visitor* visitor_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif // RFL_VISIT_HPP_
|
||||
23
build-config/reflect-cpp/include/rfl/internal/all_fields.hpp
Normal file
23
build-config/reflect-cpp/include/rfl/internal/all_fields.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef RFL_INTERNAL_ALLFIELDS_HPP_
|
||||
#define RFL_INTERNAL_ALLFIELDS_HPP_
|
||||
|
||||
#include "../Tuple.hpp"
|
||||
#include "is_field.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class TupleType, int _i = 0>
|
||||
constexpr bool all_fields() {
|
||||
if constexpr (_i == rfl::tuple_size_v<TupleType>) {
|
||||
return true;
|
||||
} else {
|
||||
using T = tuple_element_t<_i, TupleType>;
|
||||
return is_field_v<T> && all_fields<TupleType, _i + 1>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
4401
build-config/reflect-cpp/include/rfl/internal/bind_to_tuple.hpp
Normal file
4401
build-config/reflect-cpp/include/rfl/internal/bind_to_tuple.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
#ifndef RFL_INTERNAL_COPY_FLATTENED_TUPLE_TO_NAMED_TUPLE_HPP_
|
||||
#define RFL_INTERNAL_COPY_FLATTENED_TUPLE_TO_NAMED_TUPLE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../Field.hpp"
|
||||
#include "../make_named_tuple.hpp"
|
||||
#include "lit_name.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class FieldNames, int _i>
|
||||
auto copy_one_element(const auto& _flattened_tuple) {
|
||||
const auto name_literal = FieldNames::template name_of<_i>();
|
||||
return rfl::make_field<
|
||||
lit_name_v<std::remove_cvref_t<decltype(name_literal)>>>(
|
||||
std::get<_i>(_flattened_tuple));
|
||||
}
|
||||
|
||||
template <class FieldNames, class... Fields>
|
||||
auto copy_flattened_tuple_to_named_tuple(const auto& _flattened_tuple) {
|
||||
constexpr auto size =
|
||||
rfl::tuple_size_v<std::remove_cvref_t<decltype(_flattened_tuple)>>;
|
||||
return [&]<int... _i>(std::integer_sequence<int, _i...>) {
|
||||
return make_named_tuple(
|
||||
copy_one_element<FieldNames, _i>(_flattened_tuple)...);
|
||||
}
|
||||
(std::make_integer_sequence<int, size>());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef RFL_INTERNAL_COPY_FROM_NAMED_TUPLE_HPP_
|
||||
#define RFL_INTERNAL_COPY_FROM_NAMED_TUPLE_HPP_
|
||||
|
||||
#include "move_from_named_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Creates a struct of type T from a named tuple.
|
||||
/// All fields of the struct must be an rfl::Field.
|
||||
template <class T, class NamedTupleType>
|
||||
T copy_from_named_tuple(const NamedTupleType& _n) {
|
||||
auto n = _n;
|
||||
return move_from_named_tuple<T>(std::move(n));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef RFL_COPY_FROM_TUPLE_HPP_
|
||||
#define RFL_COPY_FROM_TUPLE_HPP_
|
||||
|
||||
#include "move_from_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Creates a struct of type T from a tuple by copying the underlying
|
||||
/// fields.
|
||||
template <class T, class TupleType>
|
||||
T copy_from_tuple(const TupleType& _t) {
|
||||
auto t = _t;
|
||||
return move_from_tuple<T, TupleType>(std::move(t));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_INTERNAL_COPY_TO_FIELD_TUPLE_HPP_
|
||||
#define RFL_INTERNAL_COPY_TO_FIELD_TUPLE_HPP_
|
||||
|
||||
#include "move_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
auto copy_to_field_tuple(const T& _t) {
|
||||
auto t = _t;
|
||||
return move_to_field_tuple(std::move(t));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef RFL_INTERNAL_DEFINELITERAL_HPP_
|
||||
#define RFL_INTERNAL_DEFINELITERAL_HPP_
|
||||
|
||||
#include "../Literal.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several literals.
|
||||
template <class... LiteralTypes>
|
||||
struct define_literal;
|
||||
|
||||
/// General case
|
||||
template <StringLiteral... _content1, StringLiteral... _content2, class... Tail>
|
||||
struct define_literal<Literal<_content1...>, Literal<_content2...>, Tail...> {
|
||||
using type = typename define_literal<Literal<_content1..., _content2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Special case - only a single literal is left
|
||||
template <StringLiteral... _content>
|
||||
struct define_literal<Literal<_content...>> {
|
||||
using type = Literal<_content...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef RFL_INTERNAL_DEFINENAMEDTUPLE_HPP_
|
||||
#define RFL_INTERNAL_DEFINENAMEDTUPLE_HPP_
|
||||
|
||||
#include "../NamedTuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class... FieldTypes>
|
||||
struct define_named_tuple;
|
||||
|
||||
/// Allows you to combine several named tuples and/or additional fields.
|
||||
/// Recursive case - all types are fields.
|
||||
template <class Head, class... Tail>
|
||||
struct define_named_tuple<Head, Tail...> {
|
||||
using type = typename define_named_tuple<NamedTuple<Head>, Tail...>::type;
|
||||
};
|
||||
|
||||
/// Allows you to combine several named tuples and/or additional fields.
|
||||
/// Recursive case - first type is NamedTuple, second type is field.
|
||||
template <class Head, class... TupContent, class... Tail>
|
||||
struct define_named_tuple<NamedTuple<TupContent...>, Head, Tail...> {
|
||||
using type = typename define_named_tuple<NamedTuple<TupContent..., Head>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Allows you to combine several named tuples and/or additional fields.
|
||||
/// Recursive case - first type is NamedTuple, second type is also NamedTuple.
|
||||
template <class... TupContent, class... TupContent2, class... Tail>
|
||||
struct define_named_tuple<NamedTuple<TupContent...>, NamedTuple<TupContent2...>,
|
||||
Tail...> {
|
||||
using type =
|
||||
typename define_named_tuple<NamedTuple<TupContent..., TupContent2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Allows you to combine several named tuples and/or additional fields.
|
||||
template <class... TupContent>
|
||||
struct define_named_tuple<NamedTuple<TupContent...>> {
|
||||
using type = NamedTuple<TupContent...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef RFL_INTERNAL_DEFINETAGGEDUNION_HPP_
|
||||
#define RFL_INTERNAL_DEFINETAGGEDUNION_HPP_
|
||||
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several tagged unions.
|
||||
template <StringLiteral _discriminator, class... TaggedUnionTypes>
|
||||
struct define_tagged_union;
|
||||
|
||||
/// Recursive case - both tagged union.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes1,
|
||||
class... NamedTupleTypes2, class... Tail>
|
||||
struct define_tagged_union<
|
||||
_discriminator, TaggedUnion<_discriminator, NamedTupleTypes1...>,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes2...>, Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes1..., NamedTupleTypes2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Recursive case - tagged union plus named tuple.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes,
|
||||
class... FieldTypes, class... Tail>
|
||||
struct define_tagged_union<_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>,
|
||||
NamedTuple<FieldTypes...>, Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...,
|
||||
NamedTuple<FieldTypes...>>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Recursive case - named tuple.
|
||||
template <StringLiteral _discriminator, class... FieldTypes, class... Tail>
|
||||
struct define_tagged_union<_discriminator, NamedTuple<FieldTypes...>, Tail...> {
|
||||
using type = typename define_tagged_union<
|
||||
_discriminator, TaggedUnion<_discriminator, NamedTuple<FieldTypes...>>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Special case - only a single TaggedUnion is left.
|
||||
template <StringLiteral _discriminator, class... NamedTupleTypes>
|
||||
struct define_tagged_union<_discriminator,
|
||||
TaggedUnion<_discriminator, NamedTupleTypes...>> {
|
||||
using type = TaggedUnion<_discriminator, NamedTupleTypes...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef RFL_INTERNAL_DEFINEVARIANT_HPP_
|
||||
#define RFL_INTERNAL_DEFINEVARIANT_HPP_
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
/// Allows you to combine several variants.
|
||||
template <class... Vars>
|
||||
struct define_variant;
|
||||
|
||||
/// Recursive case - both variants.
|
||||
template <class... Vars1, class... Vars2, class... Tail>
|
||||
struct define_variant<std::variant<Vars1...>, std::variant<Vars2...>, Tail...> {
|
||||
using type = typename define_variant<std::variant<Vars1..., Vars2...>,
|
||||
Tail...>::type;
|
||||
};
|
||||
|
||||
/// Recursive case - variant plus other type.
|
||||
template <class... Vars, class Head, class... Tail>
|
||||
struct define_variant<std::variant<Vars...>, Head, Tail...> {
|
||||
using type =
|
||||
typename define_variant<std::variant<Vars..., Head>, Tail...>::type;
|
||||
};
|
||||
|
||||
/// Recursive case - other type.
|
||||
template <class Head, class... Tail>
|
||||
struct define_variant<Head, Tail...> {
|
||||
using type = typename define_variant<std::variant<Head>, Tail...>::type;
|
||||
};
|
||||
|
||||
/// Special case - only a single variant is left.
|
||||
template <class... Vars>
|
||||
struct define_variant<std::variant<Vars...>> {
|
||||
using type = std::variant<Vars...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef RFL_INTERNAL_ELEMENT_INDEX_HPP_
|
||||
#define RFL_INTERNAL_ELEMENT_INDEX_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace rfl::internal {
|
||||
|
||||
template <int _i, class T>
|
||||
consteval int find_element_index() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <int _i, class T, class Head, class... Tail>
|
||||
consteval int find_element_index() {
|
||||
if constexpr (std::is_same_v<T, Head>) {
|
||||
return _i;
|
||||
} else {
|
||||
return find_element_index<_i + 1, T, Tail...>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class... AlternativeTypes>
|
||||
consteval int element_index() {
|
||||
return find_element_index<0, T, AlternativeTypes...>();
|
||||
}
|
||||
|
||||
} // namespace rfl::internal
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef RFL_INTERNAL_ENUMS_NAMES_HPP_
|
||||
#define RFL_INTERNAL_ENUMS_NAMES_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../../Literal.hpp"
|
||||
//#include "../../config.hpp"
|
||||
//#include "../../define_literal.hpp"
|
||||
#include "../../make_named_tuple.hpp"
|
||||
//#include "../../thirdparty/enchantum/enchantum.hpp"
|
||||
#include "../StringLiteral.hpp"
|
||||
|
||||
namespace rfl::internal::enums {
|
||||
|
||||
template <class EnumType, class LiteralType, size_t N, bool _is_flag,
|
||||
auto... _enums>
|
||||
struct Names {
|
||||
/// Contains a collection of enums as compile-time strings.
|
||||
using Literal = LiteralType;
|
||||
|
||||
/// The number of possible values
|
||||
constexpr static size_t size = N;
|
||||
|
||||
/// A list of all the possible enums
|
||||
constexpr static auto enums_ = std::array<EnumType, N>{_enums...};
|
||||
};
|
||||
|
||||
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
|
||||
return make_named_tuple(Field<_names, EnumType>{_enums}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
|
||||
auto... _enums>
|
||||
auto names_to_underlying_enumerator_named_tuple(
|
||||
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
|
||||
return make_named_tuple(Field<_names, std::underlying_type_t<EnumType>>{
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums)}...);
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<std::pair<std::string_view, EnumType>, N>
|
||||
names_to_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::name_.string_view(), _enums)...};
|
||||
}
|
||||
|
||||
template <class EnumType, size_t N, bool _is_flag, StringLiteral... _names,
|
||||
auto... _enums>
|
||||
constexpr std::array<
|
||||
std::pair<std::string_view, std::underlying_type_t<EnumType>>, N>
|
||||
names_to_underlying_enumerator_array(
|
||||
Names<EnumType, Literal<_names...>, N, _is_flag, _enums...>) {
|
||||
return {
|
||||
std::make_pair(LiteralHelper<_names>::name_.string_view(),
|
||||
static_cast<std::underlying_type_t<EnumType>>(_enums))...};
|
||||
}
|
||||
|
||||
} // namespace rfl::internal::enums
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifndef RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
|
||||
#define RFL_INTERNAL_ENUMS_GET_ENUM_NAMES_HPP_
|
||||
|
||||
// Enum values must be greater than or equal to RFL_ENUM_RANGE_MIN.
|
||||
// By default, RFL_ENUM_RANGE_MIN is set to -256.
|
||||
// To change the default minimum range for all enum types, redefine the macro
|
||||
// RFL_ENUM_RANGE_MIN.
|
||||
#if !defined(RFL_ENUM_RANGE_MIN)
|
||||
#define RFL_ENUM_RANGE_MIN -256
|
||||
#endif
|
||||
|
||||
// Enum values must be less than or equal to RFL_ENUM_RANGE_MAX.
|
||||
// By default, RFL_ENUM_RANGE_MAX is set to 256.
|
||||
// To change the default maximum range for all enum types, redefine the macro
|
||||
// RFL_ENUM_RANGE_MAX.
|
||||
#if !defined(RFL_ENUM_RANGE_MAX)
|
||||
#define RFL_ENUM_RANGE_MAX 256
|
||||
#endif
|
||||
|
||||
#ifdef ENCHANTUM_MIN_RANGE
|
||||
#undef ENCHANTUM_MIN_RANGE
|
||||
#endif
|
||||
#define ENCHANTUM_MIN_RANGE RFL_ENUM_RANGE_MIN
|
||||
|
||||
#ifdef ENCHANTUM_MAX_RANGE
|
||||
#undef ENCHANTUM_MAX_RANGE
|
||||
#endif
|
||||
#define ENCHANTUM_MAX_RANGE RFL_ENUM_RANGE_MAX
|
||||
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
|
||||
#include "../../thirdparty/enchantum/enchantum.hpp"// NOLINT(unused-includes)
|
||||
|
||||
#include "../../Literal.hpp"
|
||||
#include "Names.hpp"
|
||||
#include "range_defined.hpp"
|
||||
|
||||
// https://en.cppreference.com/w/cpp/language/static_cast:
|
||||
|
||||
// 8) A value of integer or enumeration type can be converted to any complete
|
||||
// enumeration type.
|
||||
|
||||
// If the underlying type is not fixed, the behavior is undefined if the value
|
||||
// of expression is out of range (the range is all values possible for the
|
||||
// smallest bit-field large enough to hold all enumerators of the target
|
||||
// enumeration). If the underlying type is fixed, the result is the same as
|
||||
// converting the original value first to the underlying type of the enumeration
|
||||
// and then to the enumeration type.
|
||||
|
||||
// https://en.cppreference.com/w/cpp/language/enum
|
||||
|
||||
// enum struct|class name { enumerator = constexpr , enumerator = constexpr ,
|
||||
// ... } (1)
|
||||
// ...
|
||||
// 1) declares a scoped enumeration type whose underlying type is int (the
|
||||
// keywords class and struct are exactly equivalent)
|
||||
//
|
||||
// --> These rules taken together imply that if you EITHER fix the type OR you
|
||||
// use a scoped integer, static_cast<MyEnum>(some_integer_value) will always be
|
||||
// defined.
|
||||
|
||||
template <enchantum::Enum E>
|
||||
requires requires(E e) {
|
||||
{ e | e } -> std::same_as<E>;
|
||||
}
|
||||
constexpr inline bool enchantum::is_bitflag<E> = true;
|
||||
|
||||
// Specialize the enchantum EnumTraits further, so rfl::config::enum_range
|
||||
// works.
|
||||
namespace enchantum {
|
||||
|
||||
template <SignedEnum E>
|
||||
requires rfl::internal::enums::range_defined<E>
|
||||
struct enum_traits<E> {
|
||||
static constexpr std::size_t prefix_length = 0;
|
||||
|
||||
static constexpr auto min = rfl::config::enum_range<E>::min;
|
||||
static constexpr auto max = rfl::config::enum_range<E>::max;
|
||||
};
|
||||
|
||||
template <UnsignedEnum E>
|
||||
requires rfl::internal::enums::range_defined<E>
|
||||
struct enum_traits<E> {
|
||||
static constexpr std::size_t prefix_length = 0;
|
||||
|
||||
static constexpr auto min = rfl::config::enum_range<E>::min;
|
||||
static constexpr auto max = rfl::config::enum_range<E>::max;
|
||||
};
|
||||
|
||||
template <UnscopedEnum E>
|
||||
requires SignedEnum<E> &&
|
||||
(!EnumFixedUnderlying<E>) && rfl::internal::enums::range_defined<E>
|
||||
struct enum_traits<E> {
|
||||
static constexpr auto min = rfl::config::enum_range<E>::min;
|
||||
static constexpr auto max = rfl::config::enum_range<E>::max;
|
||||
};
|
||||
|
||||
template <UnscopedEnum E>
|
||||
requires UnsignedEnum<E> &&
|
||||
(!EnumFixedUnderlying<E>) && rfl::internal::enums::range_defined<E>
|
||||
struct enum_traits<E> {
|
||||
static constexpr auto min = rfl::config::enum_range<E>::min;
|
||||
static constexpr auto max = rfl::config::enum_range<E>::max;
|
||||
};
|
||||
|
||||
} // namespace enchantum
|
||||
|
||||
namespace rfl::internal::enums {
|
||||
|
||||
template <enchantum::Enum EnumType>
|
||||
consteval auto get_enum_names() {
|
||||
return []<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
constexpr auto& entries = enchantum::entries<EnumType>;
|
||||
constexpr auto to_str_lit =
|
||||
[]<std::size_t... Js>(const char* name, std::index_sequence<Js...>) {
|
||||
return StringLiteral<sizeof...(Js) + 1>{name[Js]...};
|
||||
};
|
||||
return Names<EnumType,
|
||||
Literal<to_str_lit(
|
||||
entries[Is].second.data(),
|
||||
std::make_index_sequence<entries[Is].second.size()>{})...>,
|
||||
entries.size(), enchantum::is_bitflag<EnumType>,
|
||||
entries[Is].first...>{};
|
||||
}(std::make_index_sequence<enchantum::count<EnumType>>{});
|
||||
}
|
||||
} // namespace rfl::internal::enums
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef RFL_INTERNAL_ENUMS_RANGE_DEFINED_HPP_
|
||||
#define RFL_INTERNAL_ENUMS_RANGE_DEFINED_HPP_
|
||||
|
||||
#include "../../config.hpp"
|
||||
|
||||
namespace rfl::internal::enums {
|
||||
|
||||
template <class E>
|
||||
concept range_defined = requires {
|
||||
{ config::enum_range<E>::min };
|
||||
|
||||
{ config::enum_range<E>::max };
|
||||
};
|
||||
|
||||
} // namespace rfl::internal::enums
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef RFL_INTERNAL_EXTRACTDISTRIMINATORS_HPP_
|
||||
#define RFL_INTERNAL_EXTRACTDISTRIMINATORS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "../define_literal.hpp"
|
||||
#include "../field_type.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class TaggedUnionType>
|
||||
struct extract_discriminators;
|
||||
|
||||
template <StringLiteral _discriminator, class... NamedTupleType>
|
||||
struct extract_discriminators<TaggedUnion<_discriminator, NamedTupleType...>> {
|
||||
using type = define_literal_t<
|
||||
std::remove_cvref_t<field_type_t<_discriminator, NamedTupleType>>...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_INTERNAL_FIELD_TUPLE_T_HPP_
|
||||
#define RFL_INTERNAL_FIELD_TUPLE_T_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "copy_to_field_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using field_tuple_t =
|
||||
typename std::invoke_result<decltype(copy_to_field_tuple<T>), T>::type;
|
||||
|
||||
}
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
64
build-config/reflect-cpp/include/rfl/internal/field_type.hpp
Normal file
64
build-config/reflect-cpp/include/rfl/internal/field_type.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef RFL_INTERNAL_FIELD_TYPE_HPP_
|
||||
#define RFL_INTERNAL_FIELD_TYPE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
//#include "../NamedTuple.hpp"
|
||||
#include "../TaggedUnion.hpp"
|
||||
#include "../Tuple.hpp"
|
||||
#include "../named_tuple_t.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
#include "find_index.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T, class... Ts>
|
||||
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
|
||||
|
||||
/// Finds the type of the field signified by _field_name
|
||||
template <StringLiteral _field_name, class T>
|
||||
struct FieldType;
|
||||
|
||||
/// Default option - for named tuples.
|
||||
template <StringLiteral _field_name, class T>
|
||||
struct FieldType {
|
||||
using NamedTupleType = named_tuple_t<T>;
|
||||
|
||||
static constexpr int field_ix_ =
|
||||
internal::find_index<_field_name, typename NamedTupleType::Fields>();
|
||||
|
||||
using Type = typename tuple_element_t<field_ix_,
|
||||
typename NamedTupleType::Fields>::Type;
|
||||
};
|
||||
|
||||
/// For variants - in this case the FieldType returned by all options must be
|
||||
/// the same.
|
||||
template <StringLiteral _field_name, class FirstAlternativeType,
|
||||
class... OtherAlternativeTypes>
|
||||
struct FieldType<_field_name,
|
||||
std::variant<FirstAlternativeType, OtherAlternativeTypes...>> {
|
||||
constexpr static bool all_types_match = std::conjunction_v<std::is_same<
|
||||
typename FieldType<_field_name, FirstAlternativeType>::Type,
|
||||
typename FieldType<_field_name, OtherAlternativeTypes>::Type>...>;
|
||||
|
||||
static_assert(all_types_match, "All field types must be the same.");
|
||||
|
||||
using Type = typename FieldType<_field_name, FirstAlternativeType>::Type;
|
||||
};
|
||||
|
||||
/// For tagged union - just defers to the variant.
|
||||
template <StringLiteral _field_name, StringLiteral _discriminator_name,
|
||||
class... VarTypes>
|
||||
struct FieldType<_field_name, TaggedUnion<_discriminator_name, VarTypes...>> {
|
||||
using Type =
|
||||
typename FieldType<_field_name,
|
||||
typename TaggedUnion<_discriminator_name,
|
||||
VarTypes...>::VariantType>::Type;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
66
build-config/reflect-cpp/include/rfl/internal/find_index.hpp
Normal file
66
build-config/reflect-cpp/include/rfl/internal/find_index.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef RFL_FIND_INDEX_HPP_
|
||||
#define RFL_FIND_INDEX_HPP_
|
||||
|
||||
#include "../Tuple.hpp"
|
||||
#include "StringLiteral.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class FieldType, StringLiteral _field_name, int _i>
|
||||
struct FieldWrapper {
|
||||
constexpr static int i_ = _i;
|
||||
};
|
||||
|
||||
template <StringLiteral _field_name, class F1, int _i1, class F2, int _i2>
|
||||
constexpr auto operator|(const FieldWrapper<F1, _field_name, _i1>& _f1,
|
||||
const FieldWrapper<F2, _field_name, _i2>& _f2) {
|
||||
if constexpr (F1::name_ == _field_name) {
|
||||
return _f1;
|
||||
} else {
|
||||
return _f2;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Head, class... Tail>
|
||||
constexpr auto find_matching_field(const Head& _head, const Tail&... _tail) {
|
||||
return (_head | ... | _tail);
|
||||
};
|
||||
|
||||
template <StringLiteral _field_name, class Fields, int... _is>
|
||||
constexpr auto wrap_fields(std::integer_sequence<int, _is...>) {
|
||||
return find_matching_field(FieldWrapper<rfl::tuple_element_t<_is, Fields>,
|
||||
_field_name, _is>{}...)
|
||||
.i_;
|
||||
}
|
||||
|
||||
/// Finds the index of the field signified by _field_name
|
||||
template <StringLiteral _field_name, class Fields>
|
||||
constexpr static int find_index() {
|
||||
constexpr int ix = wrap_fields<_field_name, Fields>(
|
||||
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>());
|
||||
static_assert(rfl::tuple_element_t<ix, Fields>::name_ == _field_name,
|
||||
"No matching field found.");
|
||||
return ix;
|
||||
}
|
||||
|
||||
/// Finds the index of the field signified by _field_name or -1.
|
||||
template <StringLiteral _field_name, class Fields>
|
||||
constexpr static int find_index_or_minus_one() {
|
||||
if constexpr (rfl::tuple_size_v<Fields> == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
constexpr int ix = wrap_fields<_field_name, Fields>(
|
||||
std::make_integer_sequence<int, rfl::tuple_size_v<Fields>>());
|
||||
if constexpr (rfl::tuple_element_t<ix, Fields>::name_ == _field_name) {
|
||||
return ix;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
|
||||
#define RFL_INTERNAL_FLATTENED_PTR_TUPLE_T_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "to_flattened_ptr_tuple.hpp"
|
||||
|
||||
namespace rfl {
|
||||
namespace internal {
|
||||
|
||||
template <class T>
|
||||
using flattened_ptr_tuple_t =
|
||||
typename std::invoke_result<decltype(to_flattened_ptr_tuple<T>), T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rfl
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user