void variant::swap(variant& other) { if (this == &other) return; const bool is_this_valid = is_valid(); const bool is_other_valid = other.is_valid(); if (!is_this_valid && !is_other_valid) return; if (is_this_valid && is_other_valid) { detail::variant_data tmp_data; detail::variant_policy_func tmp_policy_func = other.m_policy; other.m_policy(detail::variant_policy_operation::SWAP, other.m_data, tmp_data); m_policy(detail::variant_policy_operation::SWAP, m_data, other.m_data); other.m_policy = m_policy; tmp_policy_func(detail::variant_policy_operation::SWAP, tmp_data, m_data); m_policy = tmp_policy_func; } else { detail::variant_data& full_data = is_this_valid ? m_data : other.m_data; detail::variant_data& empty_data = is_this_valid ? other.m_data : m_data; detail::variant_policy_func full_policy_func = is_this_valid ? m_policy : other.m_policy; full_policy_func(detail::variant_policy_operation::SWAP, full_data, empty_data); std::swap(m_policy, other.m_policy); } }
} //////////////////////////////////////////////////////////////////////////////////////// TEST_CASE("constructor - invoke general", "[constructor]") { type t = type::get<ctor_invoke_test>(); REQUIRE(t.is_valid() == true); SECTION("invoke default ctor") { constructor ctor = t.get_constructor(); REQUIRE(ctor.is_valid() == true); variant var = ctor.invoke(); CHECK(var.is_valid() == true); CHECK(var.get_type() == type::get<ctor_invoke_test*>()); ctor_invoke_test* obj = var.get_value<ctor_invoke_test*>(); CHECK(obj->default_ctor_invoked == true); CHECK(t.get_destructor().invoke(var) == true); } SECTION("invoke copy-ctor") { constructor ctor = t.get_constructor({type::get<ctor_invoke_test>()}); REQUIRE(ctor.is_valid() == true); variant var = ctor.invoke(12); CHECK(var.is_valid() == false); ctor_invoke_test obj_default;
} ///////////////////////////////////////////////////////////////////////////////////////// TEST_CASE("Test method", "[method]") { type t_meth = type::get("method_test"); REQUIRE(t_meth.is_valid() == true); variant inst = t_meth.create({}); method_test& obj = *inst.get_value<method_test*>(); //////////////////////////////////////////////////////////// // invoke tests variant ret = t_meth.get_method("method_1").invoke(inst); REQUIRE(obj.method_1_called == true); REQUIRE(ret.is_valid() == true); REQUIRE(ret.is_type<void>() == true); //////////////////////////////////////// obj.method_1_called = false; // reset method meth = t_meth.get_method("method_1"); meth.invoke_variadic(inst, {}); REQUIRE(obj.method_1_called == true); REQUIRE(meth.get_name() == "method_1"); REQUIRE(meth.get_parameter_types().empty() == true); //////////////////////////////////////// t_meth.get_method("method_2").invoke(inst); REQUIRE(obj.method_2_called == true); obj.method_2_called = false; meth = t_meth.get_method("method_2");
bool variant::convert(const type& target_type, variant& target_var) const { if (!is_valid()) return false; bool ok = false; const type source_type = get_type(); const bool source_is_arithmetic = source_type.is_arithmetic(); const bool target_is_arithmetic = target_type.is_arithmetic(); const type string_type = type::get<std::string>(); if (target_type == source_type) { target_var = *this; return true; // the current variant is already the target type, we don't need to do anything } else if (!source_type.is_wrapper() && target_type.is_wrapper() && target_type.get_wrapped_type() == source_type) { target_var = create_wrapped_value(target_type); ok = target_var.is_valid(); } else if (source_type.is_wrapper() && !target_type.is_wrapper()) { variant var = extract_wrapped_value(); ok = var.convert(target_type); target_var = var; } else if ((source_is_arithmetic && target_is_arithmetic) || (source_is_arithmetic && target_type == string_type) || (source_type == string_type && target_is_arithmetic) || (source_type.is_enumeration() && target_is_arithmetic) || (source_type.is_enumeration() && target_type == string_type)) { if (target_type == type::get<bool>()) { bool value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<char>()) { char value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<int8_t>()) { int8_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<int16_t>()) { int16_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<int32_t>()) { int32_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<int64_t>()) { int64_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<uint8_t>()) { uint8_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<uint16_t>()) { uint16_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<uint32_t>()) { uint32_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<uint64_t>()) { uint64_t value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<float>()) { float value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == type::get<double>()) { double value; if ((ok = try_basic_type_conversion(value)) == true) target_var = value; } else if (target_type == string_type) { std::string value; if ((ok = try_basic_type_conversion(value)) == true) target_var = std::move(value); } } else if ((source_is_arithmetic || source_type == string_type) && target_type.is_enumeration()) { variant var = target_type; auto wrapper = std::ref(var); if ((ok = try_basic_type_conversion(wrapper)) == true) target_var = std::move(var); } else { if (const auto& converter = source_type.get_type_converter(target_type)) { void* ptr = get_ptr(); target_var = converter->to_variant(ptr, ok); } else if (target_type == type::get<std::nullptr_t>() && is_nullptr()) { target_var = nullptr; ok = true; } else if (source_type.is_pointer() && (source_type.get_pointer_dimension() == 1 && target_type.get_pointer_dimension() == 1)) { void* raw_ptr = get_raw_ptr(); if (void* casted_ptr = type::apply_offset(raw_ptr, source_type, target_type)) { // although we forward a void* to create a variant, // it will create a variant for the specific class type target_var = target_type.create_variant(casted_ptr); if (target_var.is_valid()) ok = true; } } } return ok; }