safe deref/index uvalue's operators

This commit is contained in:
BlackMATov
2023-01-18 02:58:06 +07:00
parent 0326ac3188
commit 702349dca9
7 changed files with 217 additions and 71 deletions

View File

@@ -23,6 +23,7 @@
#include <array>
#include <atomic>
#include <concepts>
#include <deque>
#include <functional>
#include <initializer_list>
#include <map>

View File

@@ -26,7 +26,7 @@ namespace meta_hpp::detail
requires std::is_copy_constructible_v<T>
struct deref_traits<T*> {
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>
struct deref_traits<const T*> {
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>
struct deref_traits<std::shared_ptr<T>> {
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>
struct deref_traits<std::unique_ptr<T>> {
uvalue operator()(const std::unique_ptr<T>& v) const {
return uvalue{*v};
return v != nullptr ? uvalue{*v} : uvalue{};
}
};
}

View File

@@ -27,7 +27,7 @@ namespace meta_hpp::detail
struct index_traits<T*> {
uvalue operator()(T* v, std::size_t i) const {
// 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*> {
uvalue operator()(const T* v, std::size_t i) const {
// 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>
struct index_traits<std::array<T, Size>> {
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>
struct index_traits<std::span<T, Extent>> {
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>
struct index_traits<std::basic_string<T, Traits, Allocator>> {
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>
struct index_traits<std::vector<T, Allocator>> {
uvalue operator()(const std::vector<T, Allocator>& v, std::size_t i) {
return uvalue{v[i]};
return i < v.size() ? uvalue{v[i]} : uvalue{};
}
};
}

View File

@@ -83,7 +83,10 @@ namespace meta_hpp
[[nodiscard]] const void* get_cdata() const noexcept;
[[nodiscard]] uvalue operator*() const;
[[nodiscard]] bool has_deref_op() const noexcept;
[[nodiscard]] uvalue operator[](std::size_t index) const;
[[nodiscard]] bool has_index_op() const noexcept;
template < typename T >
[[nodiscard]] T get_as() &&;

View File

@@ -180,21 +180,26 @@ namespace meta_hpp
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 {
if constexpr ( detail::has_index_traits<Tp> ) {
return detail::index_traits<Tp>{}(*storage_cast<Tp>(from), i);
.deref = [](){
if constexpr ( detail::has_deref_traits<Tp> ) {
return +[](const storage_u& from) -> uvalue {
return detail::deref_traits<Tp>{}(*storage_cast<Tp>(from));
};
} 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;
@@ -318,11 +323,19 @@ namespace meta_hpp
}
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 {
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 >