nullptr type

This commit is contained in:
BlackMATov
2022-01-16 10:54:01 +07:00
parent dffad68627
commit 0564b10557
12 changed files with 220 additions and 12 deletions

View File

@@ -3,7 +3,6 @@
- add array value access
- add return value policy
- add meta exception class;
- add conversion of nullptr to any pointers;
- void value?
- all string to hash?

View File

@@ -45,6 +45,7 @@
#include "meta_types/function_type.hpp"
#include "meta_types/member_type.hpp"
#include "meta_types/method_type.hpp"
#include "meta_types/nullptr_type.hpp"
#include "meta_types/number_type.hpp"
#include "meta_types/pointer_type.hpp"
#include "meta_types/reference_type.hpp"

View File

@@ -123,6 +123,7 @@ namespace meta_hpp
class function_type;
class member_type;
class method_type;
class nullptr_type;
class number_type;
class pointer_type;
class reference_type;
@@ -138,6 +139,7 @@ namespace meta_hpp
struct function_type_data;
struct member_type_data;
struct method_type_data;
struct nullptr_type_data;
struct number_type_data;
struct pointer_type_data;
struct reference_type_data;
@@ -151,6 +153,7 @@ namespace meta_hpp
using function_type_data_ptr = std::shared_ptr<function_type_data>;
using member_type_data_ptr = std::shared_ptr<member_type_data>;
using method_type_data_ptr = std::shared_ptr<method_type_data>;
using nullptr_type_data_ptr = std::shared_ptr<nullptr_type_data>;
using number_type_data_ptr = std::shared_ptr<number_type_data>;
using pointer_type_data_ptr = std::shared_ptr<pointer_type_data>;
using reference_type_data_ptr = std::shared_ptr<reference_type_data>;

View File

@@ -18,6 +18,7 @@ namespace meta_hpp
function_,
member_,
method_,
nullptr_,
number_,
pointer_,
reference_,
@@ -45,6 +46,9 @@ namespace meta_hpp::detail
template < typename T >
concept method_kind = std::is_member_function_pointer_v<T>;
template < typename T >
concept nullptr_kind = std::is_null_pointer_v<T>;
template < typename T >
concept number_kind = std::is_arithmetic_v<T>;
@@ -65,6 +69,7 @@ namespace meta_hpp::detail
if constexpr ( function_kind<T> ) { return type_kind::function_; }
if constexpr ( member_kind<T> ) { return type_kind::member_; }
if constexpr ( method_kind<T> ) { return type_kind::method_; }
if constexpr ( nullptr_kind<T> ) { return type_kind::nullptr_; }
if constexpr ( number_kind<T> ) { return type_kind::number_; }
if constexpr ( pointer_kind<T> ) { return type_kind::pointer_; }
if constexpr ( reference_kind<T> ) { return type_kind::reference_; }
@@ -119,6 +124,12 @@ namespace meta_hpp::detail
using kind_type_data = method_type_data;
};
template <>
struct type_kind_traits<type_kind::nullptr_> {
using kind_type = nullptr_type;
using kind_type_data = nullptr_type_data;
};
template <>
struct type_kind_traits<type_kind::number_> {
using kind_type = number_type;

View File

@@ -40,9 +40,6 @@ namespace meta_hpp::detail
template < reference_kind Reference >
struct reference_traits;
template < void_kind Void >
struct void_traits;
}
namespace meta_hpp

View File

@@ -72,6 +72,7 @@ namespace meta_hpp
std::is_same_v<T, function_type> ||
std::is_same_v<T, member_type> ||
std::is_same_v<T, method_type> ||
std::is_same_v<T, nullptr_type> ||
std::is_same_v<T, number_type> ||
std::is_same_v<T, pointer_type> ||
std::is_same_v<T, reference_type> ||
@@ -135,6 +136,7 @@ namespace meta_hpp
any_type(const function_type& other) noexcept;
any_type(const member_type& other) noexcept;
any_type(const method_type& other) noexcept;
any_type(const nullptr_type& other) noexcept;
any_type(const number_type& other) noexcept;
any_type(const pointer_type& other) noexcept;
any_type(const reference_type& other) noexcept;
@@ -147,6 +149,7 @@ namespace meta_hpp
[[nodiscard]] bool is_function() const noexcept;
[[nodiscard]] bool is_member() const noexcept;
[[nodiscard]] bool is_method() const noexcept;
[[nodiscard]] bool is_nullptr() const noexcept;
[[nodiscard]] bool is_number() const noexcept;
[[nodiscard]] bool is_pointer() const noexcept;
[[nodiscard]] bool is_reference() const noexcept;
@@ -159,6 +162,7 @@ namespace meta_hpp
[[nodiscard]] function_type as_function() const noexcept;
[[nodiscard]] member_type as_member() const noexcept;
[[nodiscard]] method_type as_method() const noexcept;
[[nodiscard]] nullptr_type as_nullptr() const noexcept;
[[nodiscard]] number_type as_number() const noexcept;
[[nodiscard]] pointer_type as_pointer() const noexcept;
[[nodiscard]] reference_type as_reference() const noexcept;
@@ -352,6 +356,20 @@ namespace meta_hpp
friend auto detail::data_access<method_type>(const method_type&);
};
class nullptr_type final {
public:
nullptr_type() = default;
nullptr_type(detail::nullptr_type_data_ptr data);
[[nodiscard]] bool is_valid() const noexcept;
[[nodiscard]] explicit operator bool() const noexcept;
[[nodiscard]] type_id get_id() const noexcept;
private:
detail::nullptr_type_data_ptr data_;
friend auto detail::data_access<nullptr_type>(const nullptr_type&);
};
class number_type final {
public:
number_type() = default;
@@ -530,6 +548,14 @@ namespace meta_hpp::detail
[[nodiscard]] static method_type_data_ptr get_static();
};
struct nullptr_type_data final : type_data_base {
template < nullptr_kind Nullptr >
explicit nullptr_type_data(type_list<Nullptr>);
template < nullptr_kind Nullptr >
[[nodiscard]] static nullptr_type_data_ptr get_static();
};
struct number_type_data final : type_data_base {
const bitflags<number_flags> flags;
const std::size_t size;

View File

@@ -51,6 +51,9 @@ namespace meta_hpp
inline any_type::any_type(const method_type& other) noexcept
: data_{detail::data_access(other)} {}
inline any_type::any_type(const nullptr_type& other) noexcept
: data_{detail::data_access(other)} {}
inline any_type::any_type(const number_type& other) noexcept
: data_{detail::data_access(other)} {}
@@ -91,6 +94,10 @@ namespace meta_hpp
return data_ && data_->kind == type_kind::method_;
}
inline bool any_type::is_nullptr() const noexcept {
return data_ && data_->kind == type_kind::nullptr_;
}
inline bool any_type::is_number() const noexcept {
return data_ && data_->kind == type_kind::number_;
}
@@ -149,6 +156,12 @@ namespace meta_hpp
: method_type{};
}
inline nullptr_type any_type::as_nullptr() const noexcept {
return is_nullptr()
? nullptr_type{std::static_pointer_cast<detail::nullptr_type_data>(data_)}
: nullptr_type{};
}
inline number_type any_type::as_number() const noexcept {
return is_number()
? number_type{std::static_pointer_cast<detail::number_type_data>(data_)}

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* 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_types.hpp"
namespace meta_hpp::detail
{
template < nullptr_kind Nullptr >
struct nullptr_tag {};
template < nullptr_kind Nullptr >
// NOLINTNEXTLINE(readability-named-parameter)
nullptr_type_data::nullptr_type_data(type_list<Nullptr>)
: type_data_base{type_id{type_list<nullptr_tag<Nullptr>>{}}, type_kind::nullptr_} {}
template < nullptr_kind Nullptr >
nullptr_type_data_ptr nullptr_type_data::get_static() {
static nullptr_type_data_ptr data = std::make_shared<nullptr_type_data>(type_list<Nullptr>{});
return data;
}
}
namespace meta_hpp
{
inline nullptr_type::nullptr_type(detail::nullptr_type_data_ptr data)
: data_{std::move(data)} {}
inline bool nullptr_type::is_valid() const noexcept {
return !!data_;
}
inline nullptr_type::operator bool() const noexcept {
return is_valid();
}
inline type_id nullptr_type::get_id() const noexcept {
return data_->id;
}
}

View File

@@ -97,6 +97,10 @@ namespace meta_hpp::detail
};
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return true;
}
if ( to_type.is_pointer() && from_type.is_array() ) {
const pointer_type& to_type_ptr = to_type.as_pointer();
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
@@ -206,6 +210,10 @@ namespace meta_hpp::detail
const any_type& to_type = resolve_type<to_raw_type>();
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return static_cast<to_raw_type_cv>(nullptr);
}
if ( to_type.is_pointer() && from_type.is_array() ) {
const pointer_type& to_type_ptr = to_type.as_pointer();
const array_type& from_type_array = from_type.as_array();

View File

@@ -20,6 +20,7 @@ namespace
return v.x * v.x + v.y * v.y;
}
static bool arg_nullptr(const void* ptr) { return ptr == nullptr; }
static int arg_bounded_arr(ivec2 vs[2]) { return vs[0].x + vs[0].y + vs[1].x + vs[1].y; }
static int arg_unbounded_arr(ivec2 vs[]) { return vs[0].x + vs[0].y + vs[1].x + vs[1].y; }
static int arg_bounded_const_arr(const ivec2 vs[2]) { return vs[0].x + vs[0].y + vs[1].x + vs[1].y; }
@@ -37,6 +38,7 @@ TEST_CASE("meta/meta_states/function") {
meta::class_<ivec2>()
.function_("iadd", &ivec2::iadd)
.function_("ilength2", &ivec2::ilength2)
.function_("arg_nullptr", &ivec2::arg_nullptr)
.function_("arg_bounded_arr", &ivec2::arg_bounded_arr)
.function_("arg_unbounded_arr", &ivec2::arg_unbounded_arr)
.function_("arg_bounded_const_arr", &ivec2::arg_bounded_const_arr)
@@ -114,6 +116,19 @@ TEST_CASE("meta/meta_states/function") {
CHECK(func.invoke(ivec2{2,3}).value() == 13);
}
SUBCASE("arg_null") {
const meta::function func = ivec2_type.get_function("arg_nullptr");
REQUIRE(func);
CHECK(func.is_invocable_with<int*>());
CHECK(func.is_invocable_with<const int*>());
CHECK(func.is_invocable_with<nullptr_t>());
int i{42};
CHECK(func.invoke(&i) == false);
CHECK(func.invoke(nullptr) == true);
}
SUBCASE("arg_arr") {
ivec2 bounded_arr[2]{{1,2},{3,4}};
ivec2* unbounded_arr = bounded_arr;

View File

@@ -162,10 +162,28 @@ TEST_CASE("meta/meta_types/any_type") {
CHECK(type.is_method());
CHECK(type.get_kind() == meta::type_kind::method_);
CHECK_FALSE(type.is_nullptr());
CHECK_FALSE(type.as_nullptr());
const meta::method_type& specific_type = type.as_method();
REQUIRE(specific_type);
CHECK(specific_type.get_id() == type.get_id());
}
SUBCASE("nullptr") {
const meta::any_type& type = meta::resolve_type(nullptr);
REQUIRE(type);
REQUIRE(type == meta::resolve_type<nullptr_t>());
REQUIRE(type.get_id() == meta::resolve_type<nullptr_t>().get_id());
CHECK(type.is_nullptr());
CHECK(type.get_kind() == meta::type_kind::nullptr_);
CHECK_FALSE(type.is_number());
CHECK_FALSE(type.as_number());
const meta::method_type& specific_type = type.as_method();
const meta::nullptr_type& specific_type = type.as_nullptr();
REQUIRE(specific_type);
CHECK(specific_type.get_id() == type.get_id());
}

View File

@@ -46,13 +46,16 @@ TEST_CASE("meta/meta_utilities/arg7") {
meta::class_<D>().base_<B>().base_<C>();
}
TEST_CASE("meta/meta_utilities/arg7/cast") {
TEST_CASE("meta/meta_utilities/arg7/cast/to_void") {
namespace meta = meta_hpp;
using meta::detail::arg;
SUBCASE("int*") {
SUBCASE("int* -> void*") {
int i{42};
static_assert(std::is_invocable_v<void(void*), int*>);
static_assert(std::is_invocable_v<void(const void*), int*>);
CHECK(arg{&i}.can_cast_to<void*>());
CHECK(arg{&i}.can_cast_to<const void*>());
@@ -60,9 +63,12 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{&i}.cast<const void*>() == &i);
}
SUBCASE("const int*") {
SUBCASE("const int* -> void*") {
const int i{42};
static_assert(!std::is_invocable_v<void(void*), const int*>);
static_assert(std::is_invocable_v<void(const void*), const int*>);
CHECK_FALSE(arg{&i}.can_cast_to<void*>());
CHECK(arg{&i}.can_cast_to<const void*>());
@@ -70,7 +76,7 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{&i}.cast<const void*>() == &i);
}
SUBCASE("D*") {
SUBCASE("D* -> void*") {
D d;
static_assert(std::is_invocable_v<void(void*), D*>);
@@ -83,7 +89,7 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{&d}.cast<const void*>() == &d);
}
SUBCASE("const D*") {
SUBCASE("const D* -> void*") {
const D d;
static_assert(!std::is_invocable_v<void(void*), const D*>);
@@ -96,7 +102,7 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{&d}.cast<const void*>() == &d);
}
SUBCASE("D[2]") {
SUBCASE("D[2] -> void*") {
D arr[2];
static_assert(std::is_invocable_v<void(void*), D (&) [2]>);
@@ -109,7 +115,7 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{arr}.cast<const void*>() == &arr);
}
SUBCASE("const D[2]") {
SUBCASE("const D[2] -> void*") {
const D arr[2];
static_assert(!std::is_invocable_v<void(void*), const D (&) [2]>);
@@ -122,3 +128,69 @@ TEST_CASE("meta/meta_utilities/arg7/cast") {
CHECK(arg{arr}.cast<const void*>() == &arr);
}
}
TEST_CASE("meta/meta_utilities/arg7/cast/from_nullptr") {
namespace meta = meta_hpp;
using meta::detail::arg;
SUBCASE("nullptr -> *") {
static_assert(std::is_invocable_v<void(int*), nullptr_t>);
static_assert(std::is_invocable_v<void(int*), nullptr_t&>);
static_assert(std::is_invocable_v<void(int*), nullptr_t&&>);
static_assert(std::is_invocable_v<void(int*), const nullptr_t>);
static_assert(std::is_invocable_v<void(int*), const nullptr_t&>);
static_assert(std::is_invocable_v<void(int*), const nullptr_t&&>);
static_assert(std::is_invocable_v<void(const D*), nullptr_t>);
static_assert(std::is_invocable_v<void(const D*), nullptr_t&>);
static_assert(std::is_invocable_v<void(const D*), nullptr_t&&>);
static_assert(std::is_invocable_v<void(const D*), const nullptr_t>);
static_assert(std::is_invocable_v<void(const D*), const nullptr_t&>);
static_assert(std::is_invocable_v<void(const D*), const nullptr_t&&>);
nullptr_t n1{nullptr};
const nullptr_t n2{nullptr};
CHECK(arg{n1}.can_cast_to<int*>());
CHECK(arg{std::move(n1)}.can_cast_to<int*>());
CHECK(arg{n2}.can_cast_to<int*>());
CHECK(arg{std::move(n2)}.can_cast_to<int*>());
CHECK(arg{n1}.can_cast_to<const int*>());
CHECK(arg{std::move(n1)}.can_cast_to<const int*>());
CHECK(arg{n2}.can_cast_to<const int*>());
CHECK(arg{std::move(n2)}.can_cast_to<const int*>());
CHECK(arg{n1}.can_cast_to<D*>());
CHECK(arg{std::move(n1)}.can_cast_to<D*>());
CHECK(arg{n2}.can_cast_to<D*>());
CHECK(arg{std::move(n2)}.can_cast_to<D*>());
CHECK(arg{n1}.can_cast_to<const D*>());
CHECK(arg{std::move(n1)}.can_cast_to<const D*>());
CHECK(arg{n2}.can_cast_to<const D*>());
CHECK(arg{std::move(n2)}.can_cast_to<const D*>());
//
CHECK(arg{n1}.cast<int*>() == nullptr);
CHECK(arg{std::move(n1)}.cast<int*>() == nullptr);
CHECK(arg{n2}.cast<int*>() == nullptr);
CHECK(arg{std::move(n2)}.cast<int*>() == nullptr);
CHECK(arg{n1}.cast<const int*>() == nullptr);
CHECK(arg{std::move(n1)}.cast<const int*>() == nullptr);
CHECK(arg{n2}.cast<const int*>() == nullptr);
CHECK(arg{std::move(n2)}.cast<const int*>() == nullptr);
CHECK(arg{n1}.cast<D*>() == nullptr);
CHECK(arg{std::move(n1)}.cast<D*>() == nullptr);
CHECK(arg{n2}.cast<D*>() == nullptr);
CHECK(arg{std::move(n2)}.cast<D*>() == nullptr);
CHECK(arg{n1}.cast<const D*>() == nullptr);
CHECK(arg{std::move(n1)}.cast<const D*>() == nullptr);
CHECK(arg{n2}.cast<const D*>() == nullptr);
CHECK(arg{std::move(n2)}.cast<const D*>() == nullptr);
}
}