Add GoInterface
This commit is contained in:
parent
f96c92fdd6
commit
6e52a6262d
1 changed files with 78 additions and 0 deletions
78
include/utempl/go_interface.hpp
Normal file
78
include/utempl/go_interface.hpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <boost/pfr.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
template <ConstexprString name, typename T>
|
||||
consteval auto FindField() -> std::size_t {
|
||||
constexpr auto names = boost::pfr::names_as_array<std::remove_cvref_t<T>>();
|
||||
return std::ranges::find(names, static_cast<std::string_view>(name)) - names.begin();
|
||||
};
|
||||
|
||||
template <ConstexprString name, typename T>
|
||||
inline constexpr auto Get(T&& arg) {
|
||||
return boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg));
|
||||
};
|
||||
|
||||
template <auto...>
|
||||
struct EmptyField {};
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
template <ConstexprString name, typename T>
|
||||
inline constexpr auto TryGet(T&& arg)
|
||||
-> decltype(boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg)))
|
||||
requires(FindField<name, T>() < boost::pfr::tuple_size_v<std::remove_cvref_t<T>>) {
|
||||
constexpr auto I = FindField<name, T>();
|
||||
return boost::pfr::get<I>(std::forward<T>(arg));
|
||||
};
|
||||
template <ConstexprString name, typename T>
|
||||
inline constexpr auto TryGet(T&& arg) {
|
||||
return EmptyField<name>{};
|
||||
};
|
||||
|
||||
|
||||
template <typename To, typename Transformer, typename From>
|
||||
inline constexpr auto Transform(Transformer&& transformer, From&& from) {
|
||||
return [&]<auto... Is>(std::index_sequence<Is...>){
|
||||
return To{transformer(TryGet<ConstexprString<boost::pfr::get_name<Is, To>().size() + 1>{boost::pfr::get_name<Is, To>().begin()}>(from))...};
|
||||
}(std::make_index_sequence<boost::pfr::tuple_size_v<To>>());
|
||||
};
|
||||
|
||||
} // impl
|
||||
|
||||
struct DefaultFieldTransformer {
|
||||
inline constexpr auto operator()(auto&& arg) -> auto&& {
|
||||
return arg;
|
||||
};
|
||||
inline constexpr auto operator()(auto& arg) -> auto& {
|
||||
return arg;
|
||||
};
|
||||
template <ConstexprString str>
|
||||
inline constexpr auto operator()(EmptyField<str> arg) {
|
||||
static_assert(str == "This Field Not Found");
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Value, typename Transformer = DefaultFieldTransformer>
|
||||
struct GoInterface : Value {
|
||||
inline constexpr GoInterface(Value&& value) :
|
||||
Value(std::move(value)) {};
|
||||
inline constexpr GoInterface(const Value& value) :
|
||||
Value(value) {};
|
||||
template <typename T>
|
||||
inline constexpr GoInterface(T&& value) :
|
||||
Value(impl::Transform<Value>(Transformer{}, std::forward<T>(value))) {};
|
||||
inline constexpr auto operator=(const GoInterface&) -> GoInterface& = default;
|
||||
inline constexpr auto operator=(GoInterface&&) -> GoInterface& = default;
|
||||
inline constexpr auto operator==(const GoInterface& other) const -> bool
|
||||
requires requires {static_cast<const Value&>(*this) == static_cast<const Value&>(other);} {
|
||||
return static_cast<const Value&>(*this) == static_cast<const Value&>(other);
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace utempl
|
||||
|
Loading…
Reference in a new issue