new uvalue's size_traits

discussion: https://github.com/BlackMATov/meta.hpp/issues/114
This commit is contained in:
BlackMATov
2025-01-23 17:18:26 +07:00
parent 107c4767d4
commit 166e6f3cf2
7 changed files with 261 additions and 22 deletions

View File

@@ -17,6 +17,7 @@
#include <exception>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
@@ -2756,6 +2757,9 @@ namespace meta_hpp
[[nodiscard]] uvalue unmap() const;
[[nodiscard]] bool has_unmap_op() const noexcept;
[[nodiscard]] std::size_t size() const;
[[nodiscard]] bool has_size_op() const noexcept;
[[nodiscard]] bool less(const uvalue& other) const;
[[nodiscard]] bool has_less_op() const noexcept;
@@ -11280,6 +11284,71 @@ namespace meta_hpp::detail
}; \
}
namespace meta_hpp::detail
{
template < typename T >
struct size_traits;
template < typename T >
concept has_size_traits //
= requires(const T& v) { size_traits<std::remove_cv_t<T>>{}(v); };
}
namespace meta_hpp::detail
{
template < typename T, std::size_t Size >
struct size_traits<std::array<T, Size>> {
std::size_t operator()(const std::array<T, Size>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Traits, typename Allocator >
struct size_traits<std::basic_string<T, Traits, Allocator>> {
std::size_t operator()(const std::basic_string<T, Traits, Allocator>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Traits >
struct size_traits<std::basic_string_view<T, Traits>> {
std::size_t operator()(const std::basic_string_view<T, Traits>& v) const {
using std::size;
return size(v);
}
};
template < typename T, std::size_t Extent >
struct size_traits<std::span<T, Extent>> {
std::size_t operator()(const std::span<T, Extent>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Allocator >
struct size_traits<std::vector<T, Allocator>> {
std::size_t operator()(const std::vector<T, Allocator>& v) const {
using std::size;
return size(v);
}
};
}
#define META_HPP_DECLARE_SIZE_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct size_traits<T> { \
std::size_t operator()(const T& v) const { \
using std::size; \
return size(v); \
} \
}; \
}
namespace meta_hpp::detail
{
template < typename T >
@@ -11323,9 +11392,11 @@ namespace meta_hpp
void (*const move)(uvalue&& self, uvalue& to) noexcept;
void (*const reset)(uvalue& self) noexcept;
uvalue (*const index)(const storage_u& self, std::size_t i);
std::size_t (*const size)(const storage_u& self);
uvalue (*const copy)(const storage_u& self);
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);
@@ -11493,6 +11564,26 @@ namespace meta_hpp
self.storage_.vtag = 0;
}},
.index{[]() {
if constexpr ( detail::has_index_traits<Tp> ) {
return +[](const storage_u& self, std::size_t i) -> uvalue {
return detail::index_traits<Tp>{}(*storage_cast<Tp>(self), i);
};
} else {
return nullptr;
}
}()},
.size{[]() {
if constexpr ( detail::has_size_traits<Tp> ) {
return +[](const storage_u& self) -> std::size_t {
return detail::size_traits<Tp>{}(*storage_cast<Tp>(self));
};
} else {
return nullptr;
}
}()},
.copy{[]() {
if constexpr ( detail::has_copy_traits<Tp> ) {
return +[](const storage_u& self) -> uvalue {
@@ -11513,16 +11604,6 @@ namespace meta_hpp
}
}()},
.index{[]() {
if constexpr ( detail::has_index_traits<Tp> ) {
return +[](const storage_u& self, std::size_t i) -> uvalue {
return detail::index_traits<Tp>{}(*storage_cast<Tp>(self), i);
};
} else {
return nullptr;
}
}()},
.unmap{[]() {
if constexpr ( detail::has_unmap_traits<Tp> ) {
return +[](const storage_u& self) -> uvalue {
@@ -11749,6 +11830,21 @@ namespace meta_hpp
return tag != storage_e::nothing && vtable->unmap != nullptr;
}
inline std::size_t uvalue::size() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
if ( tag != storage_e::nothing && vtable->size != nullptr ) {
return vtable->size(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_size_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->size != nullptr;
}
inline bool uvalue::less(const uvalue& other) const {
if ( this == &other ) {
return false;

View File

@@ -102,6 +102,11 @@ namespace
return {l.x + r.x, l.y + r.y};
}
[[maybe_unused]]
std::size_t size(const ivec2&) {
return 2;
}
[[maybe_unused]]
bool operator==(const ivec2& l, const ivec2& r) noexcept {
return l.x == r.x && l.y == r.y;
@@ -136,6 +141,7 @@ META_HPP_DECLARE_COPY_TRAITS_FOR(ivec2_big)
META_HPP_DECLARE_DEREF_TRAITS_FOR(deref_custom_class)
META_HPP_DECLARE_INDEX_TRAITS_FOR(ivec2)
META_HPP_DECLARE_SIZE_TRAITS_FOR(ivec2)
META_HPP_DECLARE_EQUALS_TRAITS_FOR(ivec2)
@@ -911,7 +917,9 @@ 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.has_size_op());
CHECK_THROWS(std::ignore = v[0]);
CHECK_THROWS(std::ignore = v.size());
}
SUBCASE("void*") {
@@ -920,7 +928,9 @@ 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.has_size_op());
CHECK_THROWS(std::ignore = v[0]);
CHECK_THROWS(std::ignore = v.size());
}
SUBCASE("const void*") {
@@ -929,7 +939,9 @@ 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.has_size_op());
CHECK_THROWS(std::ignore = v[0]);
CHECK_THROWS(std::ignore = v.size());
}
SUBCASE("int[3]") {
@@ -938,7 +950,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{arr};
CHECK(v.get_type() == meta::resolve_type<int*>());
CHECK(v.has_index_op());
CHECK_FALSE(v.has_size_op());
CHECK_THROWS(std::ignore = v.size());
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
CHECK(v[2].as<int>() == 3);
@@ -948,6 +962,8 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{arr};
CHECK(v.get_type() == meta::resolve_type<int*>());
CHECK(v.has_index_op());
CHECK_FALSE(v.has_size_op());
CHECK_THROWS(std::ignore = v.size());
CHECK_FALSE(v[0]);
}
}
@@ -958,7 +974,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{arr};
CHECK(v.get_type() == meta::resolve_type<const int*>());
CHECK(v.has_index_op());
CHECK_FALSE(v.has_size_op());
CHECK_THROWS(std::ignore = v.size());
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
CHECK(v[2].as<int>() == 3);
@@ -968,6 +986,8 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{arr};
CHECK(v.get_type() == meta::resolve_type<const int*>());
CHECK(v.has_index_op());
CHECK_FALSE(v.has_size_op());
CHECK_THROWS(std::ignore = v.size());
CHECK_FALSE(v[0]);
}
}
@@ -976,7 +996,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{std::array{1,2,3}};
CHECK(v.get_type() == meta::resolve_type<std::array<int, 3>>());
CHECK(v.has_index_op());
CHECK(v.has_size_op());
CHECK(v.size() == 3);
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
CHECK(v[2].as<int>() == 3);
@@ -988,6 +1010,7 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
CHECK(v.get_type() == meta::resolve_type<std::string>());
CHECK(v.has_index_op());
CHECK(v.size() == 3);
CHECK(v[0].as<char>() == 'h');
CHECK(v[1].as<char>() == 'i');
CHECK(v[2].as<char>() == '!');
@@ -998,7 +1021,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{std::string_view{"hi!"}};
CHECK(v.get_type() == meta::resolve_type<std::string_view>());
CHECK(v.has_index_op());
CHECK(v.has_size_op());
CHECK(v.size() == 3);
CHECK(v[0].as<char>() == 'h');
CHECK(v[1].as<char>() == 'i');
CHECK(v[2].as<char>() == '!');
@@ -1010,7 +1035,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{std::span{arr}};
CHECK(v.get_type() == meta::resolve_type<std::span<int>>());
CHECK(v.has_index_op());
CHECK(v.has_size_op());
CHECK(v.size() == 3);
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
CHECK(v[2].as<int>() == 3);
@@ -1021,7 +1048,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
const meta::uvalue v{std::vector{1,2,3}};
CHECK(v.get_type() == meta::resolve_type<std::vector<int>>());
CHECK(v.has_index_op());
CHECK(v.has_size_op());
CHECK(v.size() == 3);
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
CHECK(v[2].as<int>() == 3);
@@ -1033,7 +1062,9 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{ivec2{1,2}};
CHECK(v.get_type() == meta::resolve_type<ivec2>());
CHECK(v.has_index_op());
CHECK(v.has_size_op());
CHECK(v.size() == 2);
CHECK(v[0].as<int>() == 1);
CHECK(v[1].as<int>() == 2);
}
@@ -1041,6 +1072,8 @@ TEST_CASE("meta/meta_utilities/value/arrays") {
meta::uvalue v{ivec3{1,2,3}};
CHECK(v.get_type() == meta::resolve_type<ivec3>());
CHECK_FALSE(v.has_index_op());
CHECK_FALSE(v.has_size_op());
CHECK_THROWS(std::ignore = v.size());
CHECK_THROWS(std::ignore = v[0]);
}
}

View File

@@ -18,6 +18,7 @@
#include <exception>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>

View File

@@ -0,0 +1,75 @@
/*******************************************************************************
* 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-2025, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
#include "../../meta_uvalue.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct size_traits;
template < typename T >
concept has_size_traits //
= requires(const T& v) { size_traits<std::remove_cv_t<T>>{}(v); };
}
namespace meta_hpp::detail
{
template < typename T, std::size_t Size >
struct size_traits<std::array<T, Size>> {
std::size_t operator()(const std::array<T, Size>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Traits, typename Allocator >
struct size_traits<std::basic_string<T, Traits, Allocator>> {
std::size_t operator()(const std::basic_string<T, Traits, Allocator>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Traits >
struct size_traits<std::basic_string_view<T, Traits>> {
std::size_t operator()(const std::basic_string_view<T, Traits>& v) const {
using std::size;
return size(v);
}
};
template < typename T, std::size_t Extent >
struct size_traits<std::span<T, Extent>> {
std::size_t operator()(const std::span<T, Extent>& v) const {
using std::size;
return size(v);
}
};
template < typename T, typename Allocator >
struct size_traits<std::vector<T, Allocator>> {
std::size_t operator()(const std::vector<T, Allocator>& v) const {
using std::size;
return size(v);
}
};
}
#define META_HPP_DECLARE_SIZE_TRAITS_FOR(T) \
namespace meta_hpp::detail \
{ \
template <> \
struct size_traits<T> { \
std::size_t operator()(const T& v) const { \
using std::size; \
return size(v); \
} \
}; \
}

View File

@@ -77,6 +77,9 @@ namespace meta_hpp
[[nodiscard]] uvalue unmap() const;
[[nodiscard]] bool has_unmap_op() const noexcept;
[[nodiscard]] std::size_t size() const;
[[nodiscard]] bool has_size_op() const noexcept;
[[nodiscard]] bool less(const uvalue& other) const;
[[nodiscard]] bool has_less_op() const noexcept;

View File

@@ -15,6 +15,7 @@
#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/size_traits.hpp"
#include "../meta_detail/value_traits/unmap_traits.hpp"
#include "../meta_detail/value_utilities/uarg.hpp"
@@ -29,9 +30,11 @@ namespace meta_hpp
void (*const move)(uvalue&& self, uvalue& to) noexcept;
void (*const reset)(uvalue& self) noexcept;
uvalue (*const index)(const storage_u& self, std::size_t i);
std::size_t (*const size)(const storage_u& self);
uvalue (*const copy)(const storage_u& self);
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);
@@ -199,6 +202,26 @@ namespace meta_hpp
self.storage_.vtag = 0;
}},
.index{[]() {
if constexpr ( detail::has_index_traits<Tp> ) {
return +[](const storage_u& self, std::size_t i) -> uvalue {
return detail::index_traits<Tp>{}(*storage_cast<Tp>(self), i);
};
} else {
return nullptr;
}
}()},
.size{[]() {
if constexpr ( detail::has_size_traits<Tp> ) {
return +[](const storage_u& self) -> std::size_t {
return detail::size_traits<Tp>{}(*storage_cast<Tp>(self));
};
} else {
return nullptr;
}
}()},
.copy{[]() {
if constexpr ( detail::has_copy_traits<Tp> ) {
return +[](const storage_u& self) -> uvalue {
@@ -219,16 +242,6 @@ namespace meta_hpp
}
}()},
.index{[]() {
if constexpr ( detail::has_index_traits<Tp> ) {
return +[](const storage_u& self, std::size_t i) -> uvalue {
return detail::index_traits<Tp>{}(*storage_cast<Tp>(self), i);
};
} else {
return nullptr;
}
}()},
.unmap{[]() {
if constexpr ( detail::has_unmap_traits<Tp> ) {
return +[](const storage_u& self) -> uvalue {
@@ -455,6 +468,21 @@ namespace meta_hpp
return tag != storage_e::nothing && vtable->unmap != nullptr;
}
inline std::size_t uvalue::size() const {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
if ( tag != storage_e::nothing && vtable->size != nullptr ) {
return vtable->size(storage_);
}
throw_exception(error_code::bad_uvalue_operation);
}
inline bool uvalue::has_size_op() const noexcept {
auto&& [tag, vtable] = vtable_t::unpack_vtag(*this);
return tag != storage_e::nothing && vtable->size != nullptr;
}
inline bool uvalue::less(const uvalue& other) const {
if ( this == &other ) {
return false;

View File

@@ -191,6 +191,9 @@ public:
uvalue unmap() const;
bool has_unmap_op() const noexcept;
std::size_t size() const;
bool has_size_op() const noexcept;
bool less(const uvalue& other) const;
bool has_less_op() const noexcept;