/******************************************************************************* * 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-2023, by Matvey Cherevko (blackmatov@gmail.com) ******************************************************************************/ #include "../meta_untests.hpp" namespace { template < typename Tag > struct clazz { int i{}; clazz(int ni) : i{ni} { ++constructor_counter; } clazz(clazz&& other) : i{other.i} { other.i = 0; ++move_constructor_counter; } clazz(const clazz& other) : i{other.i} { ++copy_constructor_counter; } clazz& operator=(clazz&& other) = delete; clazz& operator=(const clazz& other) = delete; ~clazz() { ++destructor_counter; } inline static int constructor_counter{}; inline static int destructor_counter{}; inline static int move_constructor_counter{}; inline static int copy_constructor_counter{}; }; template < typename Tag > struct clazz_noncopyable { int i{}; clazz_noncopyable(int ni) : i{ni} { ++constructor_counter; } clazz_noncopyable(clazz_noncopyable&& other) : i{other.i} { other.i = 0; ++move_constructor_counter; } clazz_noncopyable(const clazz_noncopyable& other) = delete; clazz_noncopyable& operator=(clazz_noncopyable&& other) = delete; clazz_noncopyable& operator=(const clazz_noncopyable& other) = delete; ~clazz_noncopyable() { ++destructor_counter; } inline static int constructor_counter{}; inline static int destructor_counter{}; inline static int move_constructor_counter{}; inline static int copy_constructor_counter{}; }; } TEST_CASE("meta/meta_states/ctor/noncopyable") { namespace meta = meta_hpp; using clazz_t = clazz_noncopyable; meta::class_() .constructor_(meta::constructor_policy::as_raw_pointer) .constructor_(meta::constructor_policy::as_raw_pointer); clazz_t::constructor_counter = 0; clazz_t::destructor_counter = 0; clazz_t::move_constructor_counter = 0; clazz_t::copy_constructor_counter = 0; const meta::class_type clazz_type = meta::resolve_type(); REQUIRE(clazz_type); SUBCASE("int") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { const meta::uvalue v = clazz_type.create(42); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); CHECK(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 1); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("clazz_t&&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::move(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); CHECK(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 1); CHECK(clazz_t::copy_constructor_counter == 0); } } TEST_CASE("meta/meta_states/ctor/as_object") { namespace meta = meta_hpp; using clazz_t = clazz; meta::class_() .constructor_(meta::constructor_policy::as_object) .constructor_(meta::constructor_policy::as_object) .constructor_(meta::constructor_policy::as_object); clazz_t::constructor_counter = 0; clazz_t::destructor_counter = 0; clazz_t::move_constructor_counter = 0; clazz_t::copy_constructor_counter = 0; const meta::class_type clazz_type = meta::resolve_type(); REQUIRE(clazz_type); alignas(clazz_t) std::byte clazz_mem[sizeof(clazz_t)]; SUBCASE("int") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { const meta::uvalue v = clazz_type.create(42); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as().i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 1); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("int/inplace") { { const meta::uvalue v = clazz_type .get_constructor_with() .create_at(clazz_mem, 42); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); clazz_type.get_destructor().destroy_at(clazz_mem); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 1); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("clazz_t&&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::move(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as().i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 1); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("clazz_t&&/inplace") { { clazz_t o{42}; const meta::uvalue v = clazz_type .get_constructor_with() .create_at(clazz_mem, std::move(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); clazz_type.get_destructor().destroy_at(clazz_mem); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 1); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("const clazz_t&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::as_const(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as().i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 1); } SUBCASE("const clazz_t&/inplace") { { clazz_t o{42}; const meta::uvalue v = clazz_type .get_constructor_with() .create_at(clazz_mem, std::as_const(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); clazz_type.get_destructor().destroy_at(clazz_mem); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 1); } } TEST_CASE("meta/meta_states/ctor/as_raw_pointer") { namespace meta = meta_hpp; using clazz_t = clazz; meta::class_() .constructor_(meta::constructor_policy::as_raw_pointer) .constructor_(meta::constructor_policy::as_raw_pointer) .constructor_(meta::constructor_policy::as_raw_pointer); clazz_t::constructor_counter = 0; clazz_t::destructor_counter = 0; clazz_t::move_constructor_counter = 0; clazz_t::copy_constructor_counter = 0; const meta::class_type clazz_type = meta::resolve_type(); REQUIRE(clazz_type); SUBCASE("int") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { const meta::uvalue v = clazz_type.create(42); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); CHECK(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 1); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("clazz_t&&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::move(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); CHECK(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 1); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("const clazz_t&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::as_const(o)); CHECK(v.get_type() == meta::resolve_type()); CHECK(v.get_as()->i == 42); CHECK(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 1); } } TEST_CASE("meta/meta_states/ctor/as_shared_pointer") { namespace meta = meta_hpp; using clazz_t = clazz; meta::class_() .constructor_(meta::constructor_policy::as_shared_pointer) .constructor_(meta::constructor_policy::as_shared_pointer) .constructor_(meta::constructor_policy::as_shared_pointer); clazz_t::constructor_counter = 0; clazz_t::destructor_counter = 0; clazz_t::move_constructor_counter = 0; clazz_t::copy_constructor_counter = 0; const meta::class_type clazz_type = meta::resolve_type(); REQUIRE(clazz_type); SUBCASE("int") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { const meta::uvalue v = clazz_type.create(42); CHECK(v.get_type() == meta::resolve_type>()); CHECK(v.get_as>()->i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 1); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("clazz_t&&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::move(o)); CHECK(v.get_type() == meta::resolve_type>()); CHECK(v.get_as>()->i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 1); CHECK(clazz_t::copy_constructor_counter == 0); } SUBCASE("const clazz_t&") { { const meta::constructor ctor = clazz_type.get_constructor_with(); REQUIRE(ctor); CHECK(ctor.get_type() == meta::resolve_constructor_type()); } { clazz_t o{42}; const meta::uvalue v = clazz_type.create(std::as_const(o)); CHECK(v.get_type() == meta::resolve_type>()); CHECK(v.get_as>()->i == 42); CHECK_FALSE(clazz_type.destroy(v)); } CHECK(clazz_t::constructor_counter == 1); CHECK(clazz_t::destructor_counter == 2); CHECK(clazz_t::move_constructor_counter == 0); CHECK(clazz_t::copy_constructor_counter == 1); } }