Compare commits

...

6 Commits

Author SHA1 Message Date
8bb1783209 Merge pull request #95 from BlackMATov/dev
Dev
2024-08-08 03:31:30 +07:00
BlackMATov
f90e8af84b refactor enum_type api for working with dynamic values 2024-08-08 03:08:23 +07:00
BlackMATov
11bc1c23b7 fix gcc warnings 2024-08-08 00:50:58 +07:00
BlackMATov
e04f8a1fec uvalue's ops can throw exceptions now (when operations are not defined) 2024-08-08 00:27:20 +07:00
BlackMATov
1336ade8b3 new uvalue ops (less, equals) 2024-08-07 08:39:17 +07:00
BlackMATov
1390279b63 fix some tidy warnings 2024-08-02 10:24:45 +07:00
19 changed files with 1127 additions and 123 deletions

View File

@@ -60,8 +60,8 @@ TEST_CASE("meta/meta_examples/enum/usage") {
const meta::enum_type align_type = meta::resolve_type(e);
// converts the enumerator to its name
CHECK(align_type.value_to_name(e) == "center");
CHECK(align_type.value_to_evalue(e).get_name() == "center");
// ... and back again
CHECK(align_type.name_to_value("center").as<align>() == e);
CHECK(align_type.name_to_evalue("center").get_value().as<align>() == e);
}

View File

@@ -188,6 +188,18 @@
#define META_HPP_DETAIL_IGNORE_OVERRIDE_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP()
//
//
//
#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() \
META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_PUSH() \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wunknown-warning-option") \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wfloat-equal") \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wordered-compare-function-pointers")
#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP()
namespace meta_hpp::detail
{
template < typename Enum >
@@ -444,6 +456,7 @@ namespace meta_hpp::detail
bad_const_access,
bad_uvalue_access,
bad_uvalue_operation,
bad_argument_cast,
bad_instance_cast,
@@ -463,6 +476,8 @@ namespace meta_hpp::detail
return "bad const access";
case error_code::bad_uvalue_access:
return "bad uvalue access";
case error_code::bad_uvalue_operation:
return "bad uvalue operation";
case error_code::bad_argument_cast:
return "bad argument cast";
case error_code::bad_instance_cast:
@@ -2755,6 +2770,12 @@ namespace meta_hpp
[[nodiscard]] uvalue unmap() const;
[[nodiscard]] bool has_unmap_op() const noexcept;
[[nodiscard]] bool less(const uvalue& other) const;
[[nodiscard]] bool has_less_op() const noexcept;
[[nodiscard]] bool equals(const uvalue& other) const;
[[nodiscard]] bool has_equals_op() const noexcept;
template < typename T >
[[nodiscard]] bool is() const noexcept;
@@ -3116,11 +3137,10 @@ namespace meta_hpp
[[nodiscard]] const evalue_list& get_evalues() const noexcept;
[[nodiscard]] evalue get_evalue(std::string_view name) const noexcept;
template < enum_kind Enum >
[[nodiscard]] std::string_view value_to_name(Enum value) const;
[[nodiscard]] const uvalue& name_to_value(std::string_view name) const noexcept;
[[nodiscard]] evalue value_to_evalue(Enum value) const;
[[nodiscard]] evalue value_to_evalue(const uvalue& value) const;
[[nodiscard]] evalue name_to_evalue(std::string_view name) const noexcept;
};
class function_type final : public type_base<function_type> {
@@ -9127,7 +9147,36 @@ namespace meta_hpp
return data_->evalues;
}
inline evalue enum_type::get_evalue(std::string_view name) const noexcept {
template < enum_kind Enum >
evalue enum_type::value_to_evalue(Enum value) const {
if ( *this != resolve_type<Enum>() ) {
return evalue{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().as<Enum>() == value ) {
return evalue;
}
}
return evalue{};
}
inline evalue enum_type::value_to_evalue(const uvalue& value) const {
if ( *this != value.get_type() ) {
return evalue{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().equals(value) ) {
return evalue;
}
}
return evalue{};
}
inline evalue enum_type::name_to_evalue(std::string_view name) const noexcept {
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_name() == name ) {
return evalue;
@@ -9135,29 +9184,6 @@ namespace meta_hpp
}
return evalue{};
}
template < enum_kind Enum >
std::string_view enum_type::value_to_name(Enum value) const {
if ( resolve_type<Enum>() != *this ) {
return std::string_view{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().as<Enum>() == value ) {
return evalue.get_name();
}
}
return std::string_view{};
}
inline const uvalue& enum_type::name_to_value(std::string_view name) const noexcept {
if ( const evalue& value = get_evalue(name) ) {
return value.get_value();
}
static const uvalue empty_value;
return empty_value;
}
}
namespace meta_hpp::detail
@@ -10474,6 +10500,120 @@ namespace meta_hpp::detail
};
}
namespace meta_hpp::detail
{
template < typename T >
struct equals_traits;
template < typename T >
concept has_equals_traits //
= requires(const T& v) { equals_traits<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v == v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct equals_traits<T> {
bool operator()(const T& l, const T& r) const {
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH()
return l == r;
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP()
}
};
template < typename T, std::size_t Size >
requires has_equals_traits<T>
struct equals_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits >
requires has_equals_traits<T>
struct equals_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
struct equals_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Deleter >
struct equals_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
requires has_equals_traits<T>
struct equals_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() == r.get();
}
};
template < typename... Ts >
requires(... && has_equals_traits<Ts>)
struct equals_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
}
#define META_HPP_DECLARE_EQUALS_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct equals_traits<T> { \
bool operator()(const T& l, const T& r) const { \
return l == r; \
} \
}; \
}
namespace meta_hpp::detail
{
template < typename T >
@@ -10536,6 +10676,120 @@ namespace meta_hpp::detail
};
}
namespace meta_hpp::detail
{
template < typename T >
struct less_traits;
template < typename T >
concept has_less_traits //
= requires(const T& v) { less_traits<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v < v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct less_traits<T> {
bool operator()(const T& l, const T& r) const {
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH()
return l < r;
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP()
}
};
template < typename T, std::size_t Size >
requires has_less_traits<T>
struct less_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits >
requires has_less_traits<T>
struct less_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
struct less_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Deleter >
struct less_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
requires has_less_traits<T>
struct less_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() < r.get();
}
};
template < typename... Ts >
requires(... && has_less_traits<Ts>)
struct less_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
}
#define META_HPP_DECLARE_LESS_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct less_traits<T> { \
bool operator()(const T& l, const T& r) const { \
return l < r; \
} \
}; \
}
namespace meta_hpp::detail
{
template < typename T >
@@ -10583,6 +10837,9 @@ namespace meta_hpp
uvalue (*const deref)(const storage_u& self);
uvalue (*const index)(const storage_u& self, std::size_t i);
uvalue (*const unmap)(const storage_u& self);
bool (*const less)(const storage_u& l, const storage_u& r);
bool (*const equals)(const storage_u& l, const storage_u& r);
// NOLINTEND(*-avoid-const-or-ref-data-members)
template < typename T >
@@ -10785,6 +11042,26 @@ namespace meta_hpp
return nullptr;
}
}()},
.less{[]() {
if constexpr ( detail::has_less_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::less_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
.equals{[]() {
if constexpr ( detail::has_equals_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::equals_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
};
return &table;
@@ -10920,9 +11197,12 @@ namespace meta_hpp
inline uvalue uvalue::operator*() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->deref != nullptr //
? vtable->deref(storage_)
: uvalue{};
if ( tag != storage_e::nothing && vtable->deref != nullptr ) {
return vtable->deref(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_deref_op() const noexcept {
@@ -10932,9 +11212,12 @@ namespace meta_hpp
inline uvalue uvalue::operator[](std::size_t index) const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->index != nullptr //
? vtable->index(storage_, index)
: uvalue{};
if ( tag != storage_e::nothing && vtable->index != nullptr ) {
return vtable->index(storage_, index);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_index_op() const noexcept {
@@ -10944,21 +11227,31 @@ namespace meta_hpp
inline uvalue uvalue::copy() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->copy != nullptr //
? vtable->copy(storage_)
: uvalue{};
if ( tag == storage_e::nothing ) {
return uvalue{};
}
if ( vtable->copy != nullptr ) {
return vtable->copy(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_copy_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->copy != nullptr;
return tag == storage_e::nothing || vtable->copy != nullptr;
}
inline uvalue uvalue::unmap() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->unmap != nullptr //
? vtable->unmap(storage_)
: uvalue{};
if ( tag != storage_e::nothing && vtable->unmap != nullptr ) {
return vtable->unmap(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_unmap_op() const noexcept {
@@ -10966,6 +11259,62 @@ namespace meta_hpp
return tag != storage_e::nothing && vtable->unmap != nullptr;
}
inline bool uvalue::less(const uvalue& other) const {
if ( this == &other ) {
return false;
}
auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this);
auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other);
if ( l_tag != r_tag || l_tag == storage_e::nothing ) {
return l_tag < r_tag;
}
if ( l_vtable != r_vtable ) {
return l_vtable->type < r_vtable->type;
}
if ( l_vtable->less != nullptr ) {
return l_vtable->less(storage_, other.storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_less_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag == storage_e::nothing || vtable->less != nullptr;
}
inline bool uvalue::equals(const uvalue& other) const {
if ( this == &other ) {
return true;
}
auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this);
auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other);
if ( l_tag != r_tag || l_tag == storage_e::nothing ) {
return l_tag == r_tag;
}
if ( l_vtable != r_vtable ) {
return l_vtable->type == r_vtable->type;
}
if ( l_vtable->equals != nullptr ) {
return l_vtable->equals(storage_, other.storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_equals_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag == storage_e::nothing || vtable->equals != nullptr;
}
template < typename T >
bool uvalue::is() const noexcept {
static_assert(std::is_same_v<T, std::decay_t<T>>);

View File

@@ -0,0 +1,80 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021-2024, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include <meta.hpp/meta_all.hpp>
#include <doctest/doctest.h>
namespace
{
enum class align {
left,
right,
center,
};
enum class color {
red,
green,
blue,
};
}
TEST_CASE("meta/meta_discussion/93") {
namespace meta = meta_hpp;
meta::enum_<align>()
.evalue_("left", align::left)
.evalue_("right", align::right)
.evalue_("center", align::center);
const meta::enum_type align_type = meta::resolve_type<align>();
{
CHECK(align_type.name_to_evalue("left").get_name() == "left");
CHECK(align_type.name_to_evalue("right").get_name() == "right");
CHECK(align_type.name_to_evalue("center").get_name() == "center");
}
{
align v = align::right;
CHECK(align_type.value_to_evalue(v).get_name() == "right");
CHECK(align_type.value_to_evalue(std::as_const(v)).get_name() == "right");
CHECK(align_type.value_to_evalue(std::move(std::as_const(v))).get_name() == "right");
CHECK(align_type.value_to_evalue(std::move(v)).get_name() == "right");
v = align::center;
CHECK(align_type.value_to_evalue(v).get_name() == "center");
CHECK(align_type.value_to_evalue(std::as_const(v)).get_name() == "center");
CHECK(align_type.value_to_evalue(std::move(std::as_const(v))).get_name() == "center");
CHECK(align_type.value_to_evalue(std::move(v)).get_name() == "center");
}
{
meta::uvalue v = align::right;
CHECK(align_type.value_to_evalue(v).get_name() == "right");
CHECK(align_type.value_to_evalue(std::as_const(v)).get_name() == "right");
CHECK(align_type.value_to_evalue(std::move(std::as_const(v))).get_name() == "right");
CHECK(align_type.value_to_evalue(std::move(v)).get_name() == "right");
v = align::center;
CHECK(align_type.value_to_evalue(v).get_name() == "center");
CHECK(align_type.value_to_evalue(std::as_const(v)).get_name() == "center");
CHECK(align_type.value_to_evalue(std::move(std::as_const(v))).get_name() == "center");
CHECK(align_type.value_to_evalue(std::move(v)).get_name() == "center");
}
{
CHECK_FALSE(align_type.name_to_evalue(""));
CHECK_FALSE(align_type.name_to_evalue("middle"));
CHECK_FALSE(align_type.value_to_evalue(color::red));
CHECK_FALSE(align_type.value_to_evalue(meta::uvalue{color::red}));
}
}

View File

@@ -35,19 +35,19 @@ TEST_CASE("meta/meta_states/evalue") {
const meta::evalue evalue;
CHECK_FALSE(evalue);
CHECK_FALSE(evalue.is_valid());
CHECK(evalue == color_type.get_evalue("non-existent-evalue"));
CHECK(evalue == color_type.name_to_evalue("non-existent-evalue"));
}
SUBCASE("operators") {
const meta::evalue blue_e = color_type.get_evalue("blue");
const meta::evalue white_e = color_type.get_evalue("white");
const meta::evalue blue_e = color_type.name_to_evalue("blue");
const meta::evalue white_e = color_type.name_to_evalue("white");
CHECK(blue_e == blue_e);
CHECK(blue_e != white_e);
CHECK((blue_e < white_e || white_e < blue_e));
}
SUBCASE("green") {
const meta::evalue evalue = color_type.get_evalue("green");
const meta::evalue evalue = color_type.name_to_evalue("green");
REQUIRE(evalue);
CHECK(evalue.get_index().get_type() == evalue.get_type());

View File

@@ -77,7 +77,7 @@ TEST_CASE("meta/meta_states/metadata/enum") {
}
SUBCASE("color::red") {
const meta::evalue red_evalue = color_type.get_evalue("red");
const meta::evalue red_evalue = color_type.name_to_evalue("red");
REQUIRE(red_evalue);
CHECK_FALSE(red_evalue.get_metadata().contains("desc1"));
CHECK(red_evalue.get_metadata().at("desc2").as<std::string>() == "new-red-color"s);

View File

@@ -83,12 +83,12 @@ TEST_CASE("meta/meta_types/enum_type") {
CHECK(ecolor_type.get_evalues().size() == 4);
}
SUBCASE("color/get_evalue") {
SUBCASE("color/name_to_evalue") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
{
const meta::evalue green_value = color_type.get_evalue("green");
const meta::evalue green_value = color_type.name_to_evalue("green");
REQUIRE(green_value);
CHECK(green_value.get_value().as<color>() == color::green);
@@ -96,17 +96,17 @@ TEST_CASE("meta/meta_types/enum_type") {
}
{
const meta::evalue yellow_value = color_type.get_evalue("yellow");
const meta::evalue yellow_value = color_type.name_to_evalue("yellow");
CHECK_FALSE(yellow_value);
}
}
SUBCASE("ecolor/get_evalue") {
SUBCASE("ecolor/name_to_evalue") {
const meta::enum_type ecolor_type = meta::resolve_type<ecolor>();
REQUIRE(ecolor_type);
{
const meta::evalue green_value = ecolor_type.get_evalue("green");
const meta::evalue green_value = ecolor_type.name_to_evalue("green");
REQUIRE(green_value);
CHECK(green_value.get_value().as<ecolor>() == ecolor_green);
@@ -114,7 +114,7 @@ TEST_CASE("meta/meta_types/enum_type") {
}
{
const meta::evalue yellow_value = ecolor_type.get_evalue("yellow");
const meta::evalue yellow_value = ecolor_type.name_to_evalue("yellow");
CHECK_FALSE(yellow_value);
}
}
@@ -123,18 +123,18 @@ TEST_CASE("meta/meta_types/enum_type") {
const meta::enum_type color_type = meta::resolve_type<color>();
REQUIRE(color_type);
CHECK(color_type.value_to_name(color::red) == "red");
CHECK(color_type.value_to_name(color::blue) == "blue");
CHECK(color_type.value_to_name(color{100500}).empty());
CHECK(color_type.value_to_evalue(color::red).get_name() == "red");
CHECK(color_type.value_to_evalue(color::blue).get_name() == "blue");
CHECK_FALSE(color_type.value_to_evalue(color{100500}));
}
SUBCASE("ecolor/value_to_name") {
const meta::enum_type ecolor_type = meta::resolve_type<ecolor>();
REQUIRE(ecolor_type);
CHECK(ecolor_type.value_to_name(ecolor_red) == "red");
CHECK(ecolor_type.value_to_name(ecolor_blue) == "blue");
CHECK(ecolor_type.value_to_name(ecolor{100500}).empty());
CHECK(ecolor_type.value_to_evalue(ecolor_red).get_name() == "red");
CHECK(ecolor_type.value_to_evalue(ecolor_blue).get_name() == "blue");
CHECK_FALSE(ecolor_type.value_to_evalue(ecolor{100500}));
}
SUBCASE("color/name_to_value") {
@@ -142,12 +142,12 @@ TEST_CASE("meta/meta_types/enum_type") {
REQUIRE(color_type);
{
REQUIRE(color_type.name_to_value("blue"));
CHECK(color_type.name_to_value("blue").as<color>() == color::blue);
REQUIRE(color_type.name_to_evalue("blue"));
CHECK(color_type.name_to_evalue("blue").get_value().as<color>() == color::blue);
}
{
REQUIRE_FALSE(color_type.name_to_value("yellow"));
REQUIRE_FALSE(color_type.name_to_evalue("yellow"));
}
}
@@ -156,12 +156,12 @@ TEST_CASE("meta/meta_types/enum_type") {
REQUIRE(ecolor_type);
{
REQUIRE(ecolor_type.name_to_value("blue"));
CHECK(ecolor_type.name_to_value("blue").as<ecolor>() == ecolor_blue);
REQUIRE(ecolor_type.name_to_evalue("blue"));
CHECK(ecolor_type.name_to_evalue("blue").get_value().as<ecolor>() == ecolor_blue);
}
{
REQUIRE_FALSE(ecolor_type.name_to_value("yellow"));
REQUIRE_FALSE(ecolor_type.name_to_evalue("yellow"));
}
}
}

View File

@@ -66,7 +66,7 @@ TEST_CASE("meta/meta_utilities/hash") {
const meta::method ivec2_method = ivec2_type.get_method("add");
const meta::enum_type color_type = meta::resolve_type<color>();
const meta::evalue red_color = color_type.get_evalue("red");
const meta::evalue red_color = color_type.name_to_evalue("red");
const meta::scope local_scope = meta::local_scope_("local-scope")
.variable_("pi_v", &pi_v);

View File

@@ -98,10 +98,12 @@ namespace
return {l.x + r.x, l.y + r.y};
}
[[maybe_unused]]
bool operator==(const ivec2& l, const ivec2& r) noexcept {
return l.x == r.x && l.y == r.y;
}
[[maybe_unused]]
bool operator==(const ivec2_big& l, const ivec2_big& r) noexcept {
return l.x == r.x && l.y == r.y;
}
@@ -164,8 +166,8 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(std::as_const(val).get_data() == nullptr);
CHECK(std::as_const(val).get_cdata() == nullptr);
CHECK_FALSE(*val);
CHECK_FALSE(val[0]);
CHECK_THROWS(std::ignore = *val);
CHECK_THROWS(std::ignore = val[0]);
CHECK_FALSE(val.try_as<ivec2>());
CHECK_FALSE(std::as_const(val).try_as<ivec2>());
@@ -475,6 +477,13 @@ TEST_CASE("meta/meta_utilities/value") {
}
SUBCASE("copy") {
{
const meta::uvalue u{};
CHECK(u.has_copy_op());
const meta::uvalue v{u.copy()};
CHECK_FALSE(v);
}
{
const meta::uvalue u{42};
CHECK(u.has_copy_op());
@@ -486,7 +495,7 @@ TEST_CASE("meta/meta_utilities/value") {
{
const meta::uvalue u{std::unique_ptr<int>{}};
CHECK_FALSE(u.has_copy_op());
CHECK_FALSE(u.copy());
CHECK_THROWS(std::ignore = u.copy());
}
}
@@ -494,7 +503,7 @@ TEST_CASE("meta/meta_utilities/value") {
{
const meta::uvalue u{42};
CHECK_FALSE(u.has_unmap_op());
CHECK_FALSE(u.unmap());
CHECK_THROWS(std::ignore = u.unmap());
}
{
int i{42};
@@ -573,10 +582,10 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK_FALSE(meta::uvalue(p3).has_deref_op());
CHECK_FALSE(meta::uvalue(p4).has_deref_op());
CHECK_FALSE(*meta::uvalue(p1));
CHECK_FALSE(*meta::uvalue(p2));
CHECK_FALSE(*meta::uvalue(p3));
CHECK_FALSE(*meta::uvalue(p4));
CHECK_THROWS(std::ignore = *meta::uvalue(p1));
CHECK_THROWS(std::ignore = *meta::uvalue(p2));
CHECK_THROWS(std::ignore = *meta::uvalue(p3));
CHECK_THROWS(std::ignore = *meta::uvalue(p4));
}
{
int* p1 = nullptr;
@@ -615,6 +624,195 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK((*v).as<int>() == 42);
}
}
SUBCASE("less/equal") {
{
meta::uvalue l{};
meta::uvalue r{};
CHECK(l.has_less_op());
CHECK(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK_FALSE(l.less(r));
CHECK_FALSE(r.less(l));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK(l.equals(r));
CHECK(r.equals(l));
}
{
meta::uvalue l{};
meta::uvalue r{42};
CHECK(l.has_less_op());
CHECK(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK(l.less(r));
CHECK_FALSE(r.less(l));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
}
{
meta::uvalue l{21};
meta::uvalue r{42};
meta::uvalue r2{42};
CHECK(l.has_less_op());
CHECK(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK(l.less(r));
CHECK_FALSE(r.less(l));
CHECK_FALSE(r.less(r2));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
CHECK(r.equals(r2));
}
{
meta::uvalue l{42};
meta::uvalue r{'a'};
CHECK(l.has_less_op());
CHECK(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK(l.less(r) == (l.get_type() < r.get_type()));
CHECK(r.less(l) == (r.get_type() < l.get_type()));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
}
{
meta::uvalue l{42};
meta::uvalue r{ivec2{1,2}};
CHECK(l.has_less_op());
CHECK_FALSE(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK(l.less(r) == (l.get_type() < r.get_type()));
CHECK(r.less(l) == (r.get_type() < l.get_type()));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
}
{
meta::uvalue l{ivec2{1,2}};
meta::uvalue r{ivec2{1,2}};
CHECK_FALSE(l.has_less_op());
CHECK_FALSE(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK_THROWS(std::ignore = l.less(r));
CHECK_THROWS(std::ignore = r.less(l));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK(l.equals(r));
CHECK(r.equals(l));
}
{
meta::uvalue l{std::vector{1,2}};
meta::uvalue r{std::vector{1,3}};
CHECK(l.has_less_op());
CHECK(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK(l.less(r));
CHECK_FALSE(r.less(l));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
}
{
meta::uvalue l{std::vector{ivec2{1,2}}};
meta::uvalue r{std::vector{ivec2{1,3}}};
CHECK_FALSE(l.has_less_op());
CHECK_FALSE(r.has_less_op());
CHECK_FALSE(l.less(l));
CHECK_FALSE(r.less(r));
CHECK_THROWS(std::ignore = l.less(r));
CHECK_THROWS(std::ignore = r.less(l));
CHECK(l.has_equals_op());
CHECK(r.has_equals_op());
CHECK(l.equals(l));
CHECK(r.equals(r));
CHECK_FALSE(l.equals(r));
CHECK_FALSE(r.equals(l));
}
{
CHECK(meta::uvalue{std::array<int, 1>{42}}.has_less_op());
CHECK(meta::uvalue{std::tuple<std::string>{""}}.has_less_op());
CHECK(meta::uvalue{std::vector{std::string_view{""}}}.has_less_op());
CHECK(meta::uvalue{std::make_shared<int>(42)}.has_less_op());
CHECK(meta::uvalue{std::make_unique<int>(42)}.has_less_op());
CHECK_FALSE(meta::uvalue{std::array<ivec2, 1>{ivec2{1,2}}}.has_less_op());
CHECK_FALSE(meta::uvalue{std::tuple<ivec2>{ivec2{1,2}}}.has_less_op());
CHECK_FALSE(meta::uvalue{std::vector{ivec2{1,2}}}.has_less_op());
CHECK(meta::uvalue{std::make_shared<ivec2>(1,2)}.has_less_op());
CHECK(meta::uvalue{std::make_unique<ivec2>(1,2)}.has_less_op());
CHECK(meta::uvalue{std::array<int, 1>{42}}.has_equals_op());
CHECK(meta::uvalue{std::tuple<std::string>{""}}.has_equals_op());
CHECK(meta::uvalue{std::vector{std::string_view{""}}}.has_equals_op());
CHECK(meta::uvalue{std::make_shared<int>(42)}.has_equals_op());
CHECK(meta::uvalue{std::make_unique<int>(42)}.has_equals_op());
CHECK(meta::uvalue{std::array<ivec2, 1>{ivec2{1,2}}}.has_equals_op());
CHECK(meta::uvalue{std::tuple<ivec2>{ivec2{1,2}}}.has_equals_op());
CHECK(meta::uvalue{std::vector{ivec2{1,2}}}.has_equals_op());
CHECK(meta::uvalue{std::make_shared<ivec2>(1,2)}.has_equals_op());
CHECK(meta::uvalue{std::make_unique<ivec2>(1,2)}.has_equals_op());
{
int v1 = 42;
CHECK(meta::uvalue{std::ref(v1)}.has_less_op());
CHECK(meta::uvalue{std::cref(v1)}.has_less_op());
CHECK(meta::uvalue{std::ref(v1)}.has_equals_op());
CHECK(meta::uvalue{std::cref(v1)}.has_equals_op());
ivec2 v2{1,2};
CHECK_FALSE(meta::uvalue{std::ref(v2)}.has_less_op());
CHECK_FALSE(meta::uvalue{std::cref(v2)}.has_less_op());
CHECK(meta::uvalue{std::ref(v2)}.has_equals_op());
CHECK(meta::uvalue{std::cref(v2)}.has_equals_op());
}
}
}
}
TEST_CASE("meta/meta_utilities/value/arrays") {
@@ -624,7 +822,7 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{42};
CHECK(v.get_type() == meta::resolve_type<int>());
CHECK_FALSE(v.has_index_op());
CHECK_FALSE(v[0]);
CHECK_THROWS(std::ignore = v[0]);
}
SUBCASE("void*") {
@@ -633,7 +831,7 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{p};
CHECK(v.get_type() == meta::resolve_type<void*>());
CHECK_FALSE(v.has_index_op());
CHECK_FALSE(v[0]);
CHECK_THROWS(std::ignore = v[0]);
}
SUBCASE("const void*") {
@@ -642,7 +840,7 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{p};
CHECK(v.get_type() == meta::resolve_type<const void*>());
CHECK_FALSE(v.has_index_op());
CHECK_FALSE(v[0]);
CHECK_THROWS(std::ignore = v[0]);
}
SUBCASE("int[3]") {

View File

@@ -24,5 +24,6 @@ Diagnostics:
- readability-identifier-length
- readability-named-parameter
- readability-redundant-access-specifiers
- readability-redundant-member-init
- readability-simplify-boolean-expr
- readability-use-anyofallof

View File

@@ -188,3 +188,15 @@
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wsuggest-override")
#define META_HPP_DETAIL_IGNORE_OVERRIDE_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP()
//
//
//
#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH() \
META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_PUSH() \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wunknown-warning-option") \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wfloat-equal") \
META_HPP_DETAIL_CLANG_IGNORE_WARNING("-Wordered-compare-function-pointers")
#define META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP() META_HPP_DETAIL_CLANG_IGNORE_WARNINGS_POP()

View File

@@ -17,6 +17,7 @@ namespace meta_hpp::detail
bad_const_access,
bad_uvalue_access,
bad_uvalue_operation,
bad_argument_cast,
bad_instance_cast,
@@ -36,6 +37,8 @@ namespace meta_hpp::detail
return "bad const access";
case error_code::bad_uvalue_access:
return "bad uvalue access";
case error_code::bad_uvalue_operation:
return "bad uvalue operation";
case error_code::bad_argument_cast:
return "bad argument cast";
case error_code::bad_instance_cast:

View File

@@ -0,0 +1,124 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021-2024, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
#include "../../meta_uvalue.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct equals_traits;
template < typename T >
concept has_equals_traits //
= requires(const T& v) { equals_traits<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v == v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct equals_traits<T> {
bool operator()(const T& l, const T& r) const {
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH()
return l == r;
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP()
}
};
template < typename T, std::size_t Size >
requires has_equals_traits<T>
struct equals_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Traits >
requires has_equals_traits<T>
struct equals_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Allocator >
requires has_equals_traits<T>
struct equals_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
struct equals_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T, typename Deleter >
struct equals_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
template < typename T >
requires has_equals_traits<T>
struct equals_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() == r.get();
}
};
template < typename... Ts >
requires(... && has_equals_traits<Ts>)
struct equals_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
bool operator()(const value_t& l, const value_t& r) const {
return l == r;
}
};
}
#define META_HPP_DECLARE_EQUALS_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct equals_traits<T> { \
bool operator()(const T& l, const T& r) const { \
return l == r; \
} \
}; \
}

View File

@@ -0,0 +1,124 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/meta.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2021-2024, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
#include "../../meta_uvalue.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct less_traits;
template < typename T >
concept has_less_traits //
= requires(const T& v) { less_traits<T>{}(v, v); };
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v < v } -> std::convertible_to<bool>;
} && (!class_kind<T> || type_list_arity_v<typename class_traits<T>::argument_types> == 0)
struct less_traits<T> {
bool operator()(const T& l, const T& r) const {
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_PUSH()
return l < r;
META_HPP_DETAIL_IGNORE_COMPARISON_WARNINGS_POP()
}
};
template < typename T, std::size_t Size >
requires has_less_traits<T>
struct less_traits<std::array<T, Size>> {
using value_t = std::array<T, Size>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::basic_string<T, Traits, Allocator>> {
using value_t = std::basic_string<T, Traits, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Traits >
requires has_less_traits<T>
struct less_traits<std::basic_string_view<T, Traits>> {
using value_t = std::basic_string_view<T, Traits>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Allocator >
requires has_less_traits<T>
struct less_traits<std::vector<T, Allocator>> {
using value_t = std::vector<T, Allocator>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
struct less_traits<std::shared_ptr<T>> {
using value_t = std::shared_ptr<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T, typename Deleter >
struct less_traits<std::unique_ptr<T, Deleter>> {
using value_t = std::unique_ptr<T, Deleter>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
template < typename T >
requires has_less_traits<T>
struct less_traits<std::reference_wrapper<T>> {
using value_t = std::reference_wrapper<T>;
bool operator()(const value_t& l, const value_t& r) const {
return l.get() < r.get();
}
};
template < typename... Ts >
requires(... && has_less_traits<Ts>)
struct less_traits<std::tuple<Ts...>> {
using value_t = std::tuple<Ts...>;
bool operator()(const value_t& l, const value_t& r) const {
return l < r;
}
};
}
#define META_HPP_DECLARE_LESS_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct less_traits<T> { \
bool operator()(const T& l, const T& r) const { \
return l < r; \
} \
}; \
}

View File

@@ -291,11 +291,10 @@ namespace meta_hpp
[[nodiscard]] const evalue_list& get_evalues() const noexcept;
[[nodiscard]] evalue get_evalue(std::string_view name) const noexcept;
template < enum_kind Enum >
[[nodiscard]] std::string_view value_to_name(Enum value) const;
[[nodiscard]] const uvalue& name_to_value(std::string_view name) const noexcept;
[[nodiscard]] evalue value_to_evalue(Enum value) const;
[[nodiscard]] evalue value_to_evalue(const uvalue& value) const;
[[nodiscard]] evalue name_to_evalue(std::string_view name) const noexcept;
};
class function_type final : public type_base<function_type> {

View File

@@ -39,7 +39,36 @@ namespace meta_hpp
return data_->evalues;
}
inline evalue enum_type::get_evalue(std::string_view name) const noexcept {
template < enum_kind Enum >
evalue enum_type::value_to_evalue(Enum value) const {
if ( *this != resolve_type<Enum>() ) {
return evalue{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().as<Enum>() == value ) {
return evalue;
}
}
return evalue{};
}
inline evalue enum_type::value_to_evalue(const uvalue& value) const {
if ( *this != value.get_type() ) {
return evalue{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().equals(value) ) {
return evalue;
}
}
return evalue{};
}
inline evalue enum_type::name_to_evalue(std::string_view name) const noexcept {
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_name() == name ) {
return evalue;
@@ -47,27 +76,4 @@ namespace meta_hpp
}
return evalue{};
}
template < enum_kind Enum >
std::string_view enum_type::value_to_name(Enum value) const {
if ( resolve_type<Enum>() != *this ) {
return std::string_view{};
}
for ( const evalue& evalue : data_->evalues ) {
if ( evalue.get_value().as<Enum>() == value ) {
return evalue.get_name();
}
}
return std::string_view{};
}
inline const uvalue& enum_type::name_to_value(std::string_view name) const noexcept {
if ( const evalue& value = get_evalue(name) ) {
return value.get_value();
}
static const uvalue empty_value;
return empty_value;
}
}

View File

@@ -77,6 +77,12 @@ namespace meta_hpp
[[nodiscard]] uvalue unmap() const;
[[nodiscard]] bool has_unmap_op() const noexcept;
[[nodiscard]] bool less(const uvalue& other) const;
[[nodiscard]] bool has_less_op() const noexcept;
[[nodiscard]] bool equals(const uvalue& other) const;
[[nodiscard]] bool has_equals_op() const noexcept;
template < typename T >
[[nodiscard]] bool is() const noexcept;

View File

@@ -12,7 +12,9 @@
#include "../meta_detail/value_traits/copy_traits.hpp"
#include "../meta_detail/value_traits/deref_traits.hpp"
#include "../meta_detail/value_traits/equals_traits.hpp"
#include "../meta_detail/value_traits/index_traits.hpp"
#include "../meta_detail/value_traits/less_traits.hpp"
#include "../meta_detail/value_traits/unmap_traits.hpp"
#include "../meta_detail/value_utilities/uarg.hpp"
@@ -31,6 +33,9 @@ namespace meta_hpp
uvalue (*const deref)(const storage_u& self);
uvalue (*const index)(const storage_u& self, std::size_t i);
uvalue (*const unmap)(const storage_u& self);
bool (*const less)(const storage_u& l, const storage_u& r);
bool (*const equals)(const storage_u& l, const storage_u& r);
// NOLINTEND(*-avoid-const-or-ref-data-members)
template < typename T >
@@ -233,6 +238,26 @@ namespace meta_hpp
return nullptr;
}
}()},
.less{[]() {
if constexpr ( detail::has_less_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::less_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
.equals{[]() {
if constexpr ( detail::has_equals_traits<Tp> ) {
return +[](const storage_u& l, const storage_u& r) -> bool {
return detail::equals_traits<Tp>{}(*storage_cast<Tp>(l), *storage_cast<Tp>(r));
};
} else {
return nullptr;
}
}()},
};
return &table;
@@ -368,9 +393,12 @@ namespace meta_hpp
inline uvalue uvalue::operator*() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->deref != nullptr //
? vtable->deref(storage_)
: uvalue{};
if ( tag != storage_e::nothing && vtable->deref != nullptr ) {
return vtable->deref(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_deref_op() const noexcept {
@@ -380,9 +408,12 @@ namespace meta_hpp
inline uvalue uvalue::operator[](std::size_t index) const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->index != nullptr //
? vtable->index(storage_, index)
: uvalue{};
if ( tag != storage_e::nothing && vtable->index != nullptr ) {
return vtable->index(storage_, index);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_index_op() const noexcept {
@@ -392,21 +423,31 @@ namespace meta_hpp
inline uvalue uvalue::copy() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->copy != nullptr //
? vtable->copy(storage_)
: uvalue{};
if ( tag == storage_e::nothing ) {
return uvalue{};
}
if ( vtable->copy != nullptr ) {
return vtable->copy(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_copy_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->copy != nullptr;
return tag == storage_e::nothing || vtable->copy != nullptr;
}
inline uvalue uvalue::unmap() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->unmap != nullptr //
? vtable->unmap(storage_)
: uvalue{};
if ( tag != storage_e::nothing && vtable->unmap != nullptr ) {
return vtable->unmap(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_unmap_op() const noexcept {
@@ -414,6 +455,62 @@ namespace meta_hpp
return tag != storage_e::nothing && vtable->unmap != nullptr;
}
inline bool uvalue::less(const uvalue& other) const {
if ( this == &other ) {
return false;
}
auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this);
auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other);
if ( l_tag != r_tag || l_tag == storage_e::nothing ) {
return l_tag < r_tag;
}
if ( l_vtable != r_vtable ) {
return l_vtable->type < r_vtable->type;
}
if ( l_vtable->less != nullptr ) {
return l_vtable->less(storage_, other.storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_less_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag == storage_e::nothing || vtable->less != nullptr;
}
inline bool uvalue::equals(const uvalue& other) const {
if ( this == &other ) {
return true;
}
auto&& [l_tag, l_vtable] = vtable_t::unpack_vtag(*this);
auto&& [r_tag, r_vtable] = vtable_t::unpack_vtag(other);
if ( l_tag != r_tag || l_tag == storage_e::nothing ) {
return l_tag == r_tag;
}
if ( l_vtable != r_vtable ) {
return l_vtable->type == r_vtable->type;
}
if ( l_vtable->equals != nullptr ) {
return l_vtable->equals(storage_, other.storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_equals_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag == storage_e::nothing || vtable->equals != nullptr;
}
template < typename T >
bool uvalue::is() const noexcept {
static_assert(std::is_same_v<T, std::decay_t<T>>);

View File

@@ -191,6 +191,12 @@ public:
uvalue unmap() const;
bool has_unmap_op() const noexcept;
bool less(const uvalue& other) const;
bool has_less_op() const noexcept;
bool equals(const uvalue& other) const;
bool has_equals_op() const noexcept;
template < typename T >
bool is() const noexcept;

View File

@@ -308,11 +308,10 @@ public:
const evalue_list& get_evalues() const noexcept;
evalue get_evalue(std::string_view name) const noexcept;
template < enum_kind Enum >
std::string_view value_to_name(Enum value) const;
const uvalue& name_to_value(std::string_view name) const noexcept;
evalue value_to_evalue(Enum value) const;
evalue value_to_evalue(const uvalue& value) const;
evalue name_to_evalue(std::string_view name) const noexcept;
};
```