mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-14 19:41:29 +07:00
nullptr type
This commit is contained in:
1
TODO.md
1
TODO.md
@@ -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?
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_)}
|
||||
|
||||
45
headers/meta.hpp/meta_types/nullptr_type.hpp
Normal file
45
headers/meta.hpp/meta_types/nullptr_type.hpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user