mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 11:52:08 +07:00
safe deref/index uvalue's operators
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -2536,7 +2537,10 @@ namespace meta_hpp
|
|||||||
[[nodiscard]] const void* get_cdata() const noexcept;
|
[[nodiscard]] const void* get_cdata() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] uvalue operator*() const;
|
[[nodiscard]] uvalue operator*() const;
|
||||||
|
[[nodiscard]] bool has_deref_op() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] uvalue operator[](std::size_t index) const;
|
[[nodiscard]] uvalue operator[](std::size_t index) const;
|
||||||
|
[[nodiscard]] bool has_index_op() const noexcept;
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
[[nodiscard]] T get_as() &&;
|
[[nodiscard]] T get_as() &&;
|
||||||
@@ -8134,7 +8138,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<T*> {
|
struct deref_traits<T*> {
|
||||||
uvalue operator()(T* v) const {
|
uvalue operator()(T* v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8142,7 +8146,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<const T*> {
|
struct deref_traits<const T*> {
|
||||||
uvalue operator()(const T* v) const {
|
uvalue operator()(const T* v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8150,7 +8154,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<std::shared_ptr<T>> {
|
struct deref_traits<std::shared_ptr<T>> {
|
||||||
uvalue operator()(const std::shared_ptr<T>& v) const {
|
uvalue operator()(const std::shared_ptr<T>& v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8158,7 +8162,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<std::unique_ptr<T>> {
|
struct deref_traits<std::unique_ptr<T>> {
|
||||||
uvalue operator()(const std::unique_ptr<T>& v) const {
|
uvalue operator()(const std::unique_ptr<T>& v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -8181,7 +8185,7 @@ namespace meta_hpp::detail
|
|||||||
struct index_traits<T*> {
|
struct index_traits<T*> {
|
||||||
uvalue operator()(T* v, std::size_t i) const {
|
uvalue operator()(T* v, std::size_t i) const {
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return uvalue{v[i]};
|
return v != nullptr ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8190,7 +8194,7 @@ namespace meta_hpp::detail
|
|||||||
struct index_traits<const T*> {
|
struct index_traits<const T*> {
|
||||||
uvalue operator()(const T* v, std::size_t i) const {
|
uvalue operator()(const T* v, std::size_t i) const {
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return uvalue{v[i]};
|
return v != nullptr ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8198,7 +8202,15 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::array<T, Size>> {
|
struct index_traits<std::array<T, Size>> {
|
||||||
uvalue operator()(const std::array<T, Size>& v, std::size_t i) const {
|
uvalue operator()(const std::array<T, Size>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T, typename Allocator >
|
||||||
|
requires std::is_copy_constructible_v<T>
|
||||||
|
struct index_traits<std::deque<T, Allocator>> {
|
||||||
|
uvalue operator()(const std::deque<T, Allocator>& v, std::size_t i) {
|
||||||
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8206,7 +8218,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::span<T, Extent>> {
|
struct index_traits<std::span<T, Extent>> {
|
||||||
uvalue operator()(const std::span<T, Extent>& v, std::size_t i) const {
|
uvalue operator()(const std::span<T, Extent>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8214,7 +8226,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::basic_string<T, Traits, Allocator>> {
|
struct index_traits<std::basic_string<T, Traits, Allocator>> {
|
||||||
uvalue operator()(const std::basic_string<T, Traits, Allocator>& v, std::size_t i) const {
|
uvalue operator()(const std::basic_string<T, Traits, Allocator>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -8222,7 +8234,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::vector<T, Allocator>> {
|
struct index_traits<std::vector<T, Allocator>> {
|
||||||
uvalue operator()(const std::vector<T, Allocator>& v, std::size_t i) {
|
uvalue operator()(const std::vector<T, Allocator>& v, std::size_t i) {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -8392,21 +8404,26 @@ namespace meta_hpp
|
|||||||
self.vtable_ = nullptr;
|
self.vtable_ = nullptr;
|
||||||
},
|
},
|
||||||
|
|
||||||
.deref = +[]([[maybe_unused]] const storage_u& from) -> uvalue {
|
|
||||||
if constexpr ( detail::has_deref_traits<Tp> ) {
|
|
||||||
return detail::deref_traits<Tp>{}(*storage_cast<Tp>(from));
|
|
||||||
} else {
|
|
||||||
META_HPP_THROW_AS(exception, "value type doesn't have value deref traits");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.index = +[]([[maybe_unused]] const storage_u& from, [[maybe_unused]] std::size_t i) -> uvalue {
|
.deref = [](){
|
||||||
if constexpr ( detail::has_index_traits<Tp> ) {
|
if constexpr ( detail::has_deref_traits<Tp> ) {
|
||||||
return detail::index_traits<Tp>{}(*storage_cast<Tp>(from), i);
|
return +[](const storage_u& from) -> uvalue {
|
||||||
|
return detail::deref_traits<Tp>{}(*storage_cast<Tp>(from));
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
META_HPP_THROW_AS(exception, "value type doesn't have value index traits");
|
return nullptr;
|
||||||
}
|
}
|
||||||
},
|
}(),
|
||||||
|
|
||||||
|
.index = [](){
|
||||||
|
if constexpr ( detail::has_index_traits<Tp> ) {
|
||||||
|
return +[](const storage_u& from, std::size_t i) -> uvalue {
|
||||||
|
return detail::index_traits<Tp>{}(*storage_cast<Tp>(from), i);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return &table;
|
return &table;
|
||||||
@@ -8530,11 +8547,19 @@ namespace meta_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uvalue uvalue::operator*() const {
|
inline uvalue uvalue::operator*() const {
|
||||||
return vtable_ != nullptr ? vtable_->deref(storage_) : uvalue{};
|
return has_deref_op() ? vtable_->deref(storage_) : uvalue{};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool uvalue::has_deref_op() const noexcept {
|
||||||
|
return vtable_ != nullptr && vtable_->deref != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uvalue uvalue::operator[](std::size_t index) const {
|
inline uvalue uvalue::operator[](std::size_t index) const {
|
||||||
return vtable_ != nullptr ? vtable_->index(storage_, index) : uvalue{};
|
return has_index_op() ? vtable_->index(storage_, index) : uvalue{};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool uvalue::has_index_op() const noexcept {
|
||||||
|
return vtable_ != nullptr && vtable_->index != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
|
|||||||
@@ -385,35 +385,59 @@ TEST_CASE("meta/meta_utilities/value") {
|
|||||||
SUBCASE("deref") {
|
SUBCASE("deref") {
|
||||||
{
|
{
|
||||||
int i{42};
|
int i{42};
|
||||||
const meta::uvalue v{*meta::uvalue{&i}};
|
meta::uvalue u{&i};
|
||||||
|
CHECK(u.has_deref_op());
|
||||||
|
|
||||||
|
const meta::uvalue v{*u};
|
||||||
CHECK(v.get_type() == meta::resolve_type<int>());
|
CHECK(v.get_type() == meta::resolve_type<int>());
|
||||||
CHECK(v.get_data() != &i);
|
CHECK(v.get_data() != &i);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const char i{42};
|
const char i{42};
|
||||||
const meta::uvalue v{*meta::uvalue{&i}};
|
meta::uvalue u{&i};
|
||||||
|
CHECK(u.has_deref_op());
|
||||||
|
|
||||||
|
const meta::uvalue v{*u};
|
||||||
CHECK(v.get_type() == meta::resolve_type<char>());
|
CHECK(v.get_type() == meta::resolve_type<char>());
|
||||||
CHECK(v.get_data() != &i);
|
CHECK(v.get_data() != &i);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const int i{42};
|
const int i{42};
|
||||||
const int* const pi = &i;
|
const int* const pi = &i;
|
||||||
const meta::uvalue v{*meta::uvalue{&pi}};
|
meta::uvalue u{&pi};
|
||||||
|
CHECK(u.has_deref_op());
|
||||||
|
|
||||||
|
const meta::uvalue v{*u};
|
||||||
CHECK(v.get_type() == meta::resolve_type<const int*>() );
|
CHECK(v.get_type() == meta::resolve_type<const int*>() );
|
||||||
CHECK(v.get_as<const int*>() == pi);
|
CHECK(v.get_as<const int*>() == pi);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int i{42};
|
int i{42};
|
||||||
|
|
||||||
[[maybe_unused]] void* p1 = &i;
|
void* p1 = &i;
|
||||||
[[maybe_unused]] const void* p2 = &i;
|
const void* p2 = &i;
|
||||||
[[maybe_unused]] void* const& p3 = &i;
|
void* const& p3 = &i;
|
||||||
[[maybe_unused]] const void* const& p4 = &i;
|
const void* const& p4 = &i;
|
||||||
|
|
||||||
CHECK_THROWS(std::ignore = *meta::uvalue(p1));
|
CHECK_FALSE(meta::uvalue(p1).has_deref_op());
|
||||||
CHECK_THROWS(std::ignore = *meta::uvalue(p2));
|
CHECK_FALSE(meta::uvalue(p2).has_deref_op());
|
||||||
CHECK_THROWS(std::ignore = *meta::uvalue(p3));
|
CHECK_FALSE(meta::uvalue(p3).has_deref_op());
|
||||||
CHECK_THROWS(std::ignore = *meta::uvalue(p4));
|
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));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int* p1 = nullptr;
|
||||||
|
const int* p2 = nullptr;
|
||||||
|
|
||||||
|
CHECK(meta::uvalue{p1}.has_deref_op());
|
||||||
|
CHECK(meta::uvalue{p2}.has_deref_op());
|
||||||
|
|
||||||
|
CHECK_FALSE(*meta::uvalue{p1});
|
||||||
|
CHECK_FALSE(*meta::uvalue{p2});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ivec2 v{1,2};
|
ivec2 v{1,2};
|
||||||
@@ -443,55 +467,127 @@ TEST_CASE("meta/meta_utilities/value") {
|
|||||||
TEST_CASE("meta/meta_utilities/value/arrays") {
|
TEST_CASE("meta/meta_utilities/value/arrays") {
|
||||||
namespace meta = meta_hpp;
|
namespace meta = meta_hpp;
|
||||||
|
|
||||||
|
SUBCASE("int") {
|
||||||
|
meta::uvalue v{42};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<int>());
|
||||||
|
CHECK_FALSE(v.has_index_op());
|
||||||
|
CHECK_FALSE(v[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("void*") {
|
||||||
|
int i{42};
|
||||||
|
void* p{&i};
|
||||||
|
meta::uvalue v{p};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<void*>());
|
||||||
|
CHECK_FALSE(v.has_index_op());
|
||||||
|
CHECK_FALSE(v[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("const void*") {
|
||||||
|
int i{42};
|
||||||
|
const void* p{&i};
|
||||||
|
meta::uvalue v{p};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<const void*>());
|
||||||
|
CHECK_FALSE(v.has_index_op());
|
||||||
|
CHECK_FALSE(v[0]);
|
||||||
|
}
|
||||||
|
|
||||||
SUBCASE("int[3]") {
|
SUBCASE("int[3]") {
|
||||||
int arr[3]{1,2,3};
|
{
|
||||||
meta::uvalue v{arr};
|
int arr[3]{1,2,3};
|
||||||
CHECK(v.get_type() == meta::resolve_type<int*>());
|
meta::uvalue v{arr};
|
||||||
CHECK(v[0].get_as<int>() == 1);
|
CHECK(v.get_type() == meta::resolve_type<int*>());
|
||||||
CHECK(v[1].get_as<int>() == 2);
|
CHECK(v.has_index_op());
|
||||||
CHECK(v[2].get_as<int>() == 3);
|
|
||||||
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int* arr = nullptr;
|
||||||
|
meta::uvalue v{arr};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<int*>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
|
CHECK_FALSE(v[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("const int[3]") {
|
SUBCASE("const int[3]") {
|
||||||
const int arr[3]{1,2,3};
|
{
|
||||||
meta::uvalue v{arr};
|
const int arr[3]{1,2,3};
|
||||||
CHECK(v.get_type() == meta::resolve_type<const int*>());
|
meta::uvalue v{arr};
|
||||||
CHECK(v[0].get_as<int>() == 1);
|
CHECK(v.get_type() == meta::resolve_type<const int*>());
|
||||||
CHECK(v[1].get_as<int>() == 2);
|
CHECK(v.has_index_op());
|
||||||
CHECK(v[2].get_as<int>() == 3);
|
|
||||||
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const int* arr = nullptr;
|
||||||
|
meta::uvalue v{arr};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<const int*>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
|
CHECK_FALSE(v[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("std::array") {
|
SUBCASE("std::array") {
|
||||||
meta::uvalue v{std::array{1,2,3}};
|
meta::uvalue v{std::array{1,2,3}};
|
||||||
CHECK(v.get_type() == meta::resolve_type<std::array<int, 3>>());
|
CHECK(v.get_type() == meta::resolve_type<std::array<int, 3>>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
CHECK(v[0].get_as<int>() == 1);
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
CHECK(v[1].get_as<int>() == 2);
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
CHECK(v[2].get_as<int>() == 3);
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
CHECK_FALSE(v[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("std::deque") {
|
||||||
|
const meta::uvalue v{std::deque{1,2,3}};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<std::deque<int>>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
CHECK_FALSE(v[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("std::string") {
|
SUBCASE("std::string") {
|
||||||
meta::uvalue v{std::string{"hi!"}};
|
meta::uvalue v{std::string{"hi!"}};
|
||||||
CHECK(v.get_type() == meta::resolve_type<std::string>());
|
CHECK(v.get_type() == meta::resolve_type<std::string>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
CHECK(v[0].get_as<char>() == 'h');
|
CHECK(v[0].get_as<char>() == 'h');
|
||||||
CHECK(v[1].get_as<char>() == 'i');
|
CHECK(v[1].get_as<char>() == 'i');
|
||||||
CHECK(v[2].get_as<char>() == '!');
|
CHECK(v[2].get_as<char>() == '!');
|
||||||
|
CHECK_FALSE(v[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("std::span") {
|
SUBCASE("std::span") {
|
||||||
std::vector arr{1,2,3};
|
std::vector arr{1,2,3};
|
||||||
meta::uvalue v{std::span{arr}};
|
meta::uvalue v{std::span{arr}};
|
||||||
CHECK(v.get_type() == meta::resolve_type<std::span<int>>());
|
CHECK(v.get_type() == meta::resolve_type<std::span<int>>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
CHECK(v[0].get_as<int>() == 1);
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
CHECK(v[1].get_as<int>() == 2);
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
CHECK(v[2].get_as<int>() == 3);
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
CHECK_FALSE(v[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("std::vector") {
|
SUBCASE("std::vector") {
|
||||||
const meta::uvalue v{std::vector{1,2,3}};
|
const meta::uvalue v{std::vector{1,2,3}};
|
||||||
CHECK(v.get_type() == meta::resolve_type<std::vector<int>>());
|
CHECK(v.get_type() == meta::resolve_type<std::vector<int>>());
|
||||||
|
CHECK(v.has_index_op());
|
||||||
|
|
||||||
CHECK(v[0].get_as<int>() == 1);
|
CHECK(v[0].get_as<int>() == 1);
|
||||||
CHECK(v[1].get_as<int>() == 2);
|
CHECK(v[1].get_as<int>() == 2);
|
||||||
CHECK(v[2].get_as<int>() == 3);
|
CHECK(v[2].get_as<int>() == 3);
|
||||||
|
CHECK_FALSE(v[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<T*> {
|
struct deref_traits<T*> {
|
||||||
uvalue operator()(T* v) const {
|
uvalue operator()(T* v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<const T*> {
|
struct deref_traits<const T*> {
|
||||||
uvalue operator()(const T* v) const {
|
uvalue operator()(const T* v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<std::shared_ptr<T>> {
|
struct deref_traits<std::shared_ptr<T>> {
|
||||||
uvalue operator()(const std::shared_ptr<T>& v) const {
|
uvalue operator()(const std::shared_ptr<T>& v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct deref_traits<std::unique_ptr<T>> {
|
struct deref_traits<std::unique_ptr<T>> {
|
||||||
uvalue operator()(const std::unique_ptr<T>& v) const {
|
uvalue operator()(const std::unique_ptr<T>& v) const {
|
||||||
return uvalue{*v};
|
return v != nullptr ? uvalue{*v} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace meta_hpp::detail
|
|||||||
struct index_traits<T*> {
|
struct index_traits<T*> {
|
||||||
uvalue operator()(T* v, std::size_t i) const {
|
uvalue operator()(T* v, std::size_t i) const {
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return uvalue{v[i]};
|
return v != nullptr ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ namespace meta_hpp::detail
|
|||||||
struct index_traits<const T*> {
|
struct index_traits<const T*> {
|
||||||
uvalue operator()(const T* v, std::size_t i) const {
|
uvalue operator()(const T* v, std::size_t i) const {
|
||||||
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
// NOLINTNEXTLINE(*-pointer-arithmetic)
|
||||||
return uvalue{v[i]};
|
return v != nullptr ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,7 +44,15 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::array<T, Size>> {
|
struct index_traits<std::array<T, Size>> {
|
||||||
uvalue operator()(const std::array<T, Size>& v, std::size_t i) const {
|
uvalue operator()(const std::array<T, Size>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T, typename Allocator >
|
||||||
|
requires std::is_copy_constructible_v<T>
|
||||||
|
struct index_traits<std::deque<T, Allocator>> {
|
||||||
|
uvalue operator()(const std::deque<T, Allocator>& v, std::size_t i) {
|
||||||
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,7 +60,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::span<T, Extent>> {
|
struct index_traits<std::span<T, Extent>> {
|
||||||
uvalue operator()(const std::span<T, Extent>& v, std::size_t i) const {
|
uvalue operator()(const std::span<T, Extent>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,7 +68,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::basic_string<T, Traits, Allocator>> {
|
struct index_traits<std::basic_string<T, Traits, Allocator>> {
|
||||||
uvalue operator()(const std::basic_string<T, Traits, Allocator>& v, std::size_t i) const {
|
uvalue operator()(const std::basic_string<T, Traits, Allocator>& v, std::size_t i) const {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,7 +76,7 @@ namespace meta_hpp::detail
|
|||||||
requires std::is_copy_constructible_v<T>
|
requires std::is_copy_constructible_v<T>
|
||||||
struct index_traits<std::vector<T, Allocator>> {
|
struct index_traits<std::vector<T, Allocator>> {
|
||||||
uvalue operator()(const std::vector<T, Allocator>& v, std::size_t i) {
|
uvalue operator()(const std::vector<T, Allocator>& v, std::size_t i) {
|
||||||
return uvalue{v[i]};
|
return i < v.size() ? uvalue{v[i]} : uvalue{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,10 @@ namespace meta_hpp
|
|||||||
[[nodiscard]] const void* get_cdata() const noexcept;
|
[[nodiscard]] const void* get_cdata() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] uvalue operator*() const;
|
[[nodiscard]] uvalue operator*() const;
|
||||||
|
[[nodiscard]] bool has_deref_op() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] uvalue operator[](std::size_t index) const;
|
[[nodiscard]] uvalue operator[](std::size_t index) const;
|
||||||
|
[[nodiscard]] bool has_index_op() const noexcept;
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
[[nodiscard]] T get_as() &&;
|
[[nodiscard]] T get_as() &&;
|
||||||
|
|||||||
@@ -180,21 +180,26 @@ namespace meta_hpp
|
|||||||
self.vtable_ = nullptr;
|
self.vtable_ = nullptr;
|
||||||
},
|
},
|
||||||
|
|
||||||
.deref = +[]([[maybe_unused]] const storage_u& from) -> uvalue {
|
|
||||||
if constexpr ( detail::has_deref_traits<Tp> ) {
|
|
||||||
return detail::deref_traits<Tp>{}(*storage_cast<Tp>(from));
|
|
||||||
} else {
|
|
||||||
META_HPP_THROW_AS(exception, "value type doesn't have value deref traits");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.index = +[]([[maybe_unused]] const storage_u& from, [[maybe_unused]] std::size_t i) -> uvalue {
|
.deref = [](){
|
||||||
if constexpr ( detail::has_index_traits<Tp> ) {
|
if constexpr ( detail::has_deref_traits<Tp> ) {
|
||||||
return detail::index_traits<Tp>{}(*storage_cast<Tp>(from), i);
|
return +[](const storage_u& from) -> uvalue {
|
||||||
|
return detail::deref_traits<Tp>{}(*storage_cast<Tp>(from));
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
META_HPP_THROW_AS(exception, "value type doesn't have value index traits");
|
return nullptr;
|
||||||
}
|
}
|
||||||
},
|
}(),
|
||||||
|
|
||||||
|
.index = [](){
|
||||||
|
if constexpr ( detail::has_index_traits<Tp> ) {
|
||||||
|
return +[](const storage_u& from, std::size_t i) -> uvalue {
|
||||||
|
return detail::index_traits<Tp>{}(*storage_cast<Tp>(from), i);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return &table;
|
return &table;
|
||||||
@@ -318,11 +323,19 @@ namespace meta_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline uvalue uvalue::operator*() const {
|
inline uvalue uvalue::operator*() const {
|
||||||
return vtable_ != nullptr ? vtable_->deref(storage_) : uvalue{};
|
return has_deref_op() ? vtable_->deref(storage_) : uvalue{};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool uvalue::has_deref_op() const noexcept {
|
||||||
|
return vtable_ != nullptr && vtable_->deref != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uvalue uvalue::operator[](std::size_t index) const {
|
inline uvalue uvalue::operator[](std::size_t index) const {
|
||||||
return vtable_ != nullptr ? vtable_->index(storage_, index) : uvalue{};
|
return has_index_op() ? vtable_->index(storage_, index) : uvalue{};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool uvalue::has_index_op() const noexcept {
|
||||||
|
return vtable_ != nullptr && vtable_->index != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
|
|||||||
Reference in New Issue
Block a user