value index operator

This commit is contained in:
BlackMATov
2022-01-16 09:42:51 +07:00
parent fb604ba61e
commit f942f8ffa0
17 changed files with 408 additions and 121 deletions

View File

@@ -5,6 +5,8 @@
- add meta exception class;
- add conversion of nullptr to any pointers;
- add conversion of any pointers to void pointer ( identically cv-qualified );
- void value?
- all string to hash?
* argument names
* argument defaults

View File

@@ -182,3 +182,50 @@ namespace meta_hpp
using scope_map = std::map<scope_index, scope, std::less<>>;
using variable_map = std::map<variable_index, variable, std::less<>>;
}
namespace meta_hpp::detail::stdex
{
template < typename T >
[[nodiscard]] constexpr std::underlying_type_t<T> to_underlying(T v) noexcept {
return static_cast<std::underlying_type_t<T>>(v);
}
}
namespace meta_hpp::detail::stdex
{
template < typename T, typename U >
concept same_as =
std::is_same_v<T, U> &&
std::is_same_v<U, T>;
template < typename Derived, typename Base >
concept derived_from =
std::is_base_of_v<Base, Derived> &&
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
template < typename From, typename To >
concept convertible_to =
std::is_convertible_v<From, To> &&
requires { static_cast<To>(std::declval<From>()); };
template < typename T >
concept destructible =
std::is_nothrow_destructible_v<T>;
template < typename T, typename... Args >
concept constructible_from =
destructible<T> &&
std::is_constructible_v<T, Args...>;
template < typename T >
concept move_constructible =
constructible_from<T, T> &&
convertible_to<T, T>;
template<typename T>
concept copy_constructible =
move_constructible<T> &&
constructible_from<T, T&> && convertible_to<T&, T> &&
constructible_from<T, const T&> && convertible_to<const T&, T> &&
constructible_from<T, const T> && convertible_to<const T, T>;
}

View File

@@ -23,7 +23,7 @@ namespace meta_hpp
template < detail::class_kind Class >
template < typename... Args >
class_bind<Class>& class_bind<Class>::ctor_() {
static_assert(detail::constructible_from<Class, Args...>);
static_assert(detail::stdex::constructible_from<Class, Args...>);
auto ctor_state = detail::ctor_state::make<Class, Args...>();
data_->ctors.emplace(ctor_state->index, std::move(ctor_state));
return *this;
@@ -32,7 +32,7 @@ namespace meta_hpp
template < detail::class_kind Class >
template < detail::class_kind Base >
class_bind<Class>& class_bind<Class>::base_() {
static_assert(detail::derived_from<Class, Base>);
static_assert(detail::stdex::derived_from<Class, Base>);
data_->bases.emplace(resolve_type<Base>());
data_->bases_info.emplace(resolve_type<Base>(), detail::class_type_data::base_info{
.upcast = +[](void* derived) -> void* {

View File

@@ -17,7 +17,7 @@ namespace meta_hpp::detail
evalue_state::evalue_state(evalue_index index, Enum value)
: index{std::move(index)}
, enum_value{value}
, underlying_value{to_underlying(value)} {}
, underlying_value{stdex::to_underlying(value)} {}
template < enum_kind Enum >
evalue_state_ptr evalue_state::make(std::string name, Enum value) {

View File

@@ -34,36 +34,6 @@ namespace meta_hpp::detail
using copy_cvref_t = typename cvref_traits<From>::template copy_to<To>;
}
namespace meta_hpp::detail
{
template < typename T >
concept destructible =
std::is_nothrow_destructible_v<T>;
template < typename T, typename... Args >
concept constructible_from =
destructible<T> &&
std::is_constructible_v<T, Args...>;
template < typename Derived, typename Base >
concept derived_from =
std::is_base_of_v<Base, Derived> &&
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
template < typename From, typename To >
concept convertible_to =
std::is_convertible_v<From, To> &&
requires { static_cast<To>(std::declval<From>()); };
}
namespace meta_hpp::detail
{
template < typename T >
[[nodiscard]] constexpr std::underlying_type_t<T> to_underlying(T v) noexcept {
return static_cast<std::underlying_type_t<T>>(v);
}
}
namespace meta_hpp::detail
{
template < typename T >
@@ -114,34 +84,6 @@ namespace meta_hpp::detail
(std::is_rvalue_reference_v<T> && std::is_class_v<std::remove_reference_t<T>>);
}
namespace meta_hpp::detail
{
template < typename T >
concept has_deref_op_kind = requires(const T& v) {
{ *v } -> convertible_to<std::remove_pointer_t<T>>;
};
template < typename T >
concept has_less_op_kind = requires(const T& v) {
{ v < v } -> convertible_to<bool>;
};
template < typename T >
concept has_equals_op_kind = requires(const T& v) {
{ v == v } -> convertible_to<bool>;
};
template < typename T >
concept has_istream_op_kind = requires(std::istream& is, T& v) {
{ is >> v } -> convertible_to<std::istream&>;
};
template < typename T >
concept has_ostream_op_kind = requires(std::ostream& os, const T& v) {
{ os << v } -> convertible_to<std::ostream&>;
};
}
namespace meta_hpp::detail
{
class noncopyable {
@@ -187,9 +129,8 @@ namespace meta_hpp
[[nodiscard]] const void* data() const noexcept;
[[nodiscard]] const void* cdata() const noexcept;
[[nodiscard]] value deref();
[[nodiscard]] value deref() const;
[[nodiscard]] value cderef() const;
[[nodiscard]] value operator*() const;
[[nodiscard]] value operator[](std::size_t index) const;
template < typename T, typename Tp = std::decay_t<T> >
[[nodiscard]] Tp& cast() &;

View File

@@ -9,6 +9,13 @@
#include "../meta_base.hpp"
#include "../meta_utilities.hpp"
#include "value_traits/deref_traits.hpp"
#include "value_traits/equals_traits.hpp"
#include "value_traits/index_traits.hpp"
#include "value_traits/istream_traits.hpp"
#include "value_traits/less_traits.hpp"
#include "value_traits/ostream_traits.hpp"
namespace meta_hpp
{
struct value::traits final {
@@ -17,8 +24,8 @@ namespace meta_hpp
void* (*const data)(value&) noexcept;
const void* (*const cdata)(const value&) noexcept;
value (*const deref)(value&);
value (*const cderef)(const value&);
value (*const deref)(const value&);
value (*const index)(const value&, std::size_t);
bool (*const less)(const value&, const value&);
bool (*const equals)(const value&, const value&);
@@ -48,35 +55,35 @@ namespace meta_hpp
return v.try_cast<T>();
},
.deref = +[]([[maybe_unused]] value& v) -> value {
if constexpr ( detail::has_deref_op_kind<T> ) {
.deref = +[]([[maybe_unused]] const value& v) -> value {
if constexpr ( detail::has_value_deref_traits<T> ) {
return value{*v.cast<T>()};
} else {
throw std::logic_error("value type doesn't have deref operator");
throw std::logic_error("value type doesn't have value deref traits");
}
},
.cderef = +[]([[maybe_unused]] const value& v) -> value {
if constexpr ( detail::has_deref_op_kind<T> ) {
return value{*v.cast<T>()};
.index = +[]([[maybe_unused]] const value& v, [[maybe_unused]] std::size_t index) -> value {
if constexpr ( detail::has_value_index_traits<T> ) {
return detail::value_index_traits<T>{}(v.cast<T>(), index);
} else {
throw std::logic_error("value type doesn't have deref operator");
throw std::logic_error("value type doesn't have value index traits");
}
},
.less = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
if constexpr ( detail::has_less_op_kind<T> ) {
return l.cast<T>() < r.cast<T>();
if constexpr ( detail::has_value_less_traits<T> ) {
return detail::value_less_traits<T>{}(l.cast<T>(), r.cast<T>());
} else {
throw std::logic_error("value type doesn't have less operator");
throw std::logic_error("value type doesn't have value less traits");
}
},
.equals = +[]([[maybe_unused]] const value& l, [[maybe_unused]] const value& r) -> bool {
if constexpr ( detail::has_equals_op_kind<T> ) {
return l.cast<T>() == r.cast<T>();
if constexpr ( detail::has_value_equals_traits<T> ) {
return detail::value_equals_traits<T>{}(l.cast<T>(), r.cast<T>());
} else {
throw std::logic_error("value type doesn't have equality operator");
throw std::logic_error("value type doesn't have value equals traits");
}
},
@@ -97,18 +104,18 @@ namespace meta_hpp
},
.istream = +[]([[maybe_unused]] std::istream& is, [[maybe_unused]] value& v) -> std::istream& {
if constexpr ( detail::has_istream_op_kind<T> ) {
return is >> v.cast<T>();
if constexpr ( detail::has_value_istream_traits<T> ) {
return detail::value_istream_traits<T>{}(is, v.cast<T>());
} else {
throw std::logic_error("value type doesn't have istream operator");
throw std::logic_error("value type doesn't have value istream traits");
}
},
.ostream = +[]([[maybe_unused]] std::ostream& os, [[maybe_unused]] const value& v) -> std::ostream& {
if constexpr ( detail::has_ostream_op_kind<T> ) {
return os << v.cast<T>();
if constexpr ( detail::has_value_ostream_traits<T> ) {
return detail::value_ostream_traits<T>{}(os, v.cast<T>());
} else {
throw std::logic_error("value type doesn't have ostream operator");
throw std::logic_error("value type doesn't have value ostream traits");
}
},
};
@@ -181,16 +188,12 @@ namespace meta_hpp
return traits_->cdata(*this);
}
inline value value::deref() {
inline value value::operator*() const {
return traits_->deref(*this);
}
inline value value::deref() const {
return traits_->cderef(*this);
}
inline value value::cderef() const {
return traits_->cderef(*this);
inline value value::operator[](std::size_t index) const {
return traits_->index(*this, index);
}
template < typename T, typename Tp >

View File

@@ -0,0 +1,52 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
#include "../../meta_utilities.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_deref_traits;
template < typename T >
concept has_value_deref_traits = requires(const T& v) {
{ value_deref_traits<T>{}(v) } -> stdex::convertible_to<value>;
};
}
namespace meta_hpp::detail
{
template < stdex::copy_constructible T >
struct value_deref_traits<T*> {
value operator()(T* v) const {
return value{*v};
}
};
template < stdex::copy_constructible T >
struct value_deref_traits<const T*> {
value operator()(const T* v) const {
return value{*v};
}
};
template < stdex::copy_constructible T >
struct value_deref_traits<std::shared_ptr<T>> {
value operator()(const std::shared_ptr<T>& v) const {
return value{*v};
}
};
template < stdex::copy_constructible T >
struct value_deref_traits<std::unique_ptr<T>> {
value operator()(const std::unique_ptr<T>& v) const {
return value{*v};
}
};
}

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_equals_traits;
template < typename T >
concept has_value_equals_traits = requires(const T& v) {
{ value_equals_traits<T>{}(v, v) } -> stdex::convertible_to<bool>;
};
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v == v } -> stdex::convertible_to<bool>;
}
struct value_equals_traits<T> {
bool operator()(const T& l, const T& r) const {
return l == r;
}
};
}

View File

@@ -0,0 +1,66 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
#include "../../meta_utilities.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_index_traits;
template < typename T >
concept has_value_index_traits = requires(const T& v, std::size_t i) {
{ value_index_traits<T>{}(v, i) } -> stdex::convertible_to<value>;
};
}
namespace meta_hpp::detail
{
template < stdex::copy_constructible T >
struct value_index_traits<T*> {
value operator()(T* v, std::size_t i) const {
return value{*(v + i)};
}
};
template < stdex::copy_constructible T >
struct value_index_traits<const T*> {
value operator()(const T* v, std::size_t i) const {
return value{*(v + i)};
}
};
template < stdex::copy_constructible T, std::size_t Size >
struct value_index_traits<std::array<T, Size>> {
value operator()(const std::array<T, Size>& v, std::size_t i) const {
return value{v[i]};
}
};
template < stdex::copy_constructible T, std::size_t Extent >
struct value_index_traits<std::span<T, Extent>> {
value operator()(const std::span<T, Extent>& v, std::size_t i) const {
return value{v[i]};
}
};
template < stdex::copy_constructible T, typename Traits, typename Allocator >
struct value_index_traits<std::basic_string<T, Traits, Allocator>> {
value operator()(const std::basic_string<T, Traits, Allocator>& v, std::size_t i) const {
return value{v[i]};
}
};
template < stdex::copy_constructible T, typename Allocator >
struct value_index_traits<std::vector<T, Allocator>> {
value operator()(const std::vector<T, Allocator>& v, std::size_t i) {
return value{v[i]};
}
};
}

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_istream_traits;
template < typename T >
concept has_value_istream_traits = requires(std::istream& is, T& v) {
{ value_istream_traits<T>{}(is, v) } -> stdex::convertible_to<std::istream&>;
};
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(std::istream& is, T& v) {
{ is >> v } -> stdex::convertible_to<std::istream&>;
}
struct value_istream_traits<T> {
std::istream& operator()(std::istream& is, T& v) const {
return is >> v;
}
};
}

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_less_traits;
template < typename T >
concept has_value_less_traits = requires(const T& v) {
{ value_less_traits<T>{}(v, v) } -> stdex::convertible_to<bool>;
};
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(const T& v) {
{ v < v } -> stdex::convertible_to<bool>;
}
struct value_less_traits<T> {
bool operator()(const T& l, const T& r) const {
return l < r;
}
};
}

View File

@@ -0,0 +1,33 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "../../meta_base.hpp"
namespace meta_hpp::detail
{
template < typename T >
struct value_ostream_traits;
template < typename T >
concept has_value_ostream_traits = requires(std::ostream& is, const T& v) {
{ value_ostream_traits<T>{}(is, v) } -> stdex::convertible_to<std::ostream&>;
};
}
namespace meta_hpp::detail
{
template < typename T >
requires requires(std::ostream& os, const T& v) {
{ os << v } -> stdex::convertible_to<std::ostream&>;
}
struct value_ostream_traits<T> {
std::ostream& operator()(std::ostream& is, const T& v) const {
return is << v;
}
};
}

View File

@@ -1,15 +0,0 @@
/*******************************************************************************
* 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, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#include "../meta_manuals.hpp"
namespace
{
}
TEST_CASE("meta/meta_examples/references") {
namespace meta = meta_hpp;
}

View File

@@ -10,6 +10,6 @@ namespace
{
}
TEST_CASE("meta/meta_examples/pointers") {
TEST_CASE("meta/meta_examples/values") {
namespace meta = meta_hpp;
}

View File

@@ -56,7 +56,7 @@ TEST_CASE("meta/meta_states/evalue") {
CHECK(evalue.get_value() == color::green);
CHECK(evalue.get_value().get_type() == color_type);
CHECK(evalue.get_underlying_value() == meta::detail::to_underlying(color::green));
CHECK(evalue.get_underlying_value() == meta::detail::stdex::to_underlying(color::green));
CHECK(evalue.get_underlying_value().get_type() == color_type.get_underlying_type());
}
}

View File

@@ -90,7 +90,7 @@ TEST_CASE("meta/meta_types/enum_type") {
const meta::evalue green_value = color_type.get_evalue("green");
REQUIRE(green_value);
CHECK(green_value.get_value() == color::green);
CHECK(green_value.get_underlying_value() == meta::detail::to_underlying(color::green));
CHECK(green_value.get_underlying_value() == meta::detail::stdex::to_underlying(color::green));
}
{
@@ -107,7 +107,7 @@ TEST_CASE("meta/meta_types/enum_type") {
const meta::evalue green_value = ecolor_type.get_evalue("green");
REQUIRE(green_value);
CHECK(green_value.get_value() == ecolor_green);
CHECK(green_value.get_underlying_value() == meta::detail::to_underlying(ecolor_green));
CHECK(green_value.get_underlying_value() == meta::detail::stdex::to_underlying(ecolor_green));
}
{

View File

@@ -354,20 +354,20 @@ TEST_CASE("meta/meta_utilities/value") {
SUBCASE("deref") {
{
int i{42};
const meta::value v{meta::value{&i}.deref()};
const meta::value v{*meta::value{&i}};
CHECK(v.get_type() == meta::resolve_type<int>());
CHECK(v.data() != &i);
}
{
const char i{42};
const meta::value v{meta::value{&i}.deref()};
const meta::value v{*meta::value{&i}};
CHECK(v.get_type() == meta::resolve_type<char>());
CHECK(v.data() != &i);
}
{
const int i{42};
const int* const pi = &i;
const meta::value v{meta::value{&pi}.deref()};
const meta::value v{*meta::value{&pi}};
CHECK(v.get_type() == meta::resolve_type<const int*>() );
CHECK(v.cast<const int*>() == pi);
}
@@ -379,10 +379,10 @@ TEST_CASE("meta/meta_utilities/value") {
void* const& p3 = &i;
const void* const& p4 = &i;
CHECK_THROWS(std::ignore = meta::value(p1).deref());
CHECK_THROWS(std::ignore = meta::value(p2).deref());
CHECK_THROWS(std::ignore = meta::value(p3).deref());
CHECK_THROWS(std::ignore = meta::value(p4).deref());
CHECK_THROWS(std::ignore = *meta::value(p1));
CHECK_THROWS(std::ignore = *meta::value(p2));
CHECK_THROWS(std::ignore = *meta::value(p3));
CHECK_THROWS(std::ignore = *meta::value(p4));
}
{
ivec2 v{1,2};
@@ -390,18 +390,77 @@ TEST_CASE("meta/meta_utilities/value") {
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 0);
meta::value vv1{vp.deref()};
meta::value vv1{*vp};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 1);
meta::value vv2{std::move(vp).deref()};
meta::value vv2{*std::move(vp)};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 2);
meta::value vv3{vp.cderef()};
meta::value vv3{*std::as_const(vp)};
CHECK(ivec2::move_ctor_counter == 0);
CHECK(ivec2::copy_ctor_counter == 3);
}
{
meta::value v{std::make_shared<int>(42)};
CHECK(*v == 42);
}
}
}
TEST_CASE("meta/meta_utilities/value/arrays") {
namespace meta = meta_hpp;
SUBCASE("int[3]") {
int arr[3]{1,2,3};
meta::value v{arr};
CHECK(v.get_type() == meta::resolve_type<int*>());
CHECK(v[0] == 1);
CHECK(v[1] == 2);
CHECK(v[2] == 3);
}
SUBCASE("const int[3]") {
const int arr[3]{1,2,3};
meta::value v{arr};
CHECK(v.get_type() == meta::resolve_type<const int*>());
CHECK(v[0] == 1);
CHECK(v[1] == 2);
CHECK(v[2] == 3);
}
SUBCASE("std::array") {
meta::value v{std::array{1,2,3}};
CHECK(v.get_type() == meta::resolve_type<std::array<int, 3>>());
CHECK(v[0] == 1);
CHECK(v[1] == 2);
CHECK(v[2] == 3);
}
SUBCASE("std::string") {
meta::value v{std::string{"hi!"}};
CHECK(v.get_type() == meta::resolve_type<std::string>());
CHECK(v[0] == 'h');
CHECK(v[1] == 'i');
CHECK(v[2] == '!');
}
SUBCASE("std::span") {
std::vector arr{1,2,3};
meta::value v{std::span{arr}};
CHECK(v.get_type() == meta::resolve_type<std::span<int>>());
CHECK(v[0] == 1);
CHECK(v[1] == 2);
CHECK(v[2] == 3);
}
SUBCASE("std::vector") {
const meta::value v{std::vector{1,2,3}};
CHECK(v.get_type() == meta::resolve_type<std::vector<int>>());
CHECK(v[0] == 1);
CHECK(v[1] == 2);
CHECK(v[2] == 3);
}
}