diff --git a/docs.in/reference/apply_product.cpp b/docs.in/reference/apply_product.cpp index cf4d2663..89c112c2 100644 --- a/docs.in/reference/apply_product.cpp +++ b/docs.in/reference/apply_product.cpp @@ -26,7 +26,7 @@ the n-fold Cartesian product of the input `mp_list` lists. #include using namespace yorel::yomm2; -using boost::mp11::mp_list; +using detail::types; struct a; struct b; @@ -41,10 +41,10 @@ static_assert( std::is_same_v< apply_product< templates, - mp_list, - mp_list + types, + types >, - mp_list< + types< bin1, bin1, bin1, bin1, bin1, bin1, diff --git a/docs.in/reference/product.cpp b/docs.in/reference/product.cpp index 75e8e763..172a1297 100644 --- a/docs.in/reference/product.cpp +++ b/docs.in/reference/product.cpp @@ -6,7 +6,7 @@ headers:yorel/yomm2/templates.hpp> template using product = /*unspecified*/; ``` -`product` takes a list of ->mp_list lists, and evaluates to a `mp_list` list +`product` takes a list of ->types lists, and evaluates to a `types` list consisting of the n-fold Cartesian product of the input lists. ## Example @@ -19,11 +19,9 @@ consisting of the n-fold Cartesian product of the input lists. #include #include -#include #include namespace yomm2 = yorel::yomm2; -using boost::mp11::mp_list; struct a; struct b; @@ -34,12 +32,12 @@ struct z; static_assert( std::is_same_v< yomm2::product< - mp_list, - mp_list + yomm2::types, + yomm2::types >, - mp_list< - mp_list, mp_list, mp_list, - mp_list, mp_list, mp_list + yomm2::types< + yomm2::types, yomm2::types, yomm2::types, + yomm2::types, yomm2::types, yomm2::types > >); diff --git a/docs.in/tutorials/templates_tutorial.cpp b/docs.in/tutorials/templates_tutorial.cpp index 724057f3..2cb2e1d6 100644 --- a/docs.in/tutorials/templates_tutorial.cpp +++ b/docs.in/tutorials/templates_tutorial.cpp @@ -19,13 +19,12 @@ std::ostream &operator<<(std::ostream &os, const std::type_info &ti) { #define elided -#include #include +#include #include #include using namespace yorel::yomm2; -using boost::mp11::mp_list; // md< @@ -229,7 +228,6 @@ vector reals(new concrete_vector{4., 5., 6.}); // code< #include -#include #include using namespace yorel::yomm2; @@ -293,9 +291,9 @@ inline bool operator==(const vector& a, const vector& b) { // ``` // This "closed" approach is lazy, and defies the purpose of *open* methods. It -// is not for the author of the library to decide which mp_list to support. The +// is not for the author of the library to decide which types to support. The // user may have no interest in integer vectors, but may need `complex` vectors. -// Or vectors of `decimal` floating-point numbers. Or, mp_list from another +// Or vectors of `decimal` floating-point numbers. Or, types from another // library, or perhaps created by the user himself. An advanced user may also // want to add new operations or vector subtypes (like large sparse vectors). // All this must be possible, and not unduly complex. Extensibility is what open @@ -311,14 +309,14 @@ inline bool operator==(const vector& a, const vector& b) { // 1. Put the definitions in one or several templates, where the method being // defined is the first template argument. // 2. Create a meta-function that generates interesting combinations of methods -// and mp_list. +// and types. // 3. Instantiate the container(s) for these combinations. The resulting classes // must satisfy the requirements of a definition container, *or* be derived // from class `not_defined`. Add the definition containers to the method, // extracted from the first template argument. // The meta-programming library comprises: -// - containers for mp_list and templates +// - containers for types and templates // - meta-functions that generate Cartesian products of these containers. // - a mechanism for instantiating the resulting definitions. @@ -328,7 +326,7 @@ inline bool operator==(const vector& a, const vector& b) { // 1. Make it very easy for a new user to use the library with all the defaults. // 2. Make it easy for a "normal" user to specify which parts of the library to // use. -// 3. Make it possible for an advanced user to extend the library with new mp_list +// 3. Make it possible for an advanced user to extend the library with new types // and new operations. // Let's apply these ideas to the `vector` methods. First we declare a container @@ -344,7 +342,7 @@ struct definition; // md< // Let's create partial specializations that defines addition, subtraction and -// comparison for vectors or two underlying mp_list: +// comparison for vectors or two underlying types: // > @@ -403,15 +401,15 @@ struct definition { // ...then add the resulting definitions to their respective method. // For the Cartesian product, we can use two constructs provided by YOMM2: the -// `mp_list` container, and the `product` meta-function. +// `types` container, and the `product` meta-function. -// `mp_list` is a simple list of mp_list. It is similar to Boost.Mp11's -// `mp_list`. Unlike `mp_list`, `mp_list` does not have a body. This helps detect +// `types` is a simple list of types. It is similar to Boost.Mp11's +// `mp_list`. Unlike `mp_list`, `types` does not have a body. This helps detect // meta-programming bugs. -// `product` takes any number of `mp_list` lists, and -// returns a `mp_list` list containing all the combinations of one element taken -// from each input list, each combination being itself wrapped in a `mp_list`. For +// `product` takes any number of `types` lists, and +// returns a `types` list containing all the combinations of one element taken +// from each input list, each combination being itself wrapped in a `types`. For // example: // > @@ -421,12 +419,12 @@ struct definition { static_assert( std::is_same_v< product< - mp_list, - mp_list + types, + types >, - mp_list< - mp_list, mp_list, mp_list, - mp_list, mp_list, mp_list + types< + types, types, types, + types, types, types > >); @@ -456,9 +454,9 @@ use_classes< use_definitions< definition, product< - mp_list, - mp_list, - mp_list + types, + types, + types > > YOMM2_GENSYM; @@ -506,7 +504,7 @@ BOOST_AUTO_TEST_CASE(test_vectors) { // ## Writing a user-friendly instantiation function // Now we have everything we need to write a single template that allows users -// to initialize the library for the mp_list they need. For that we use +// to initialize the library for the types they need. For that we use // `std::tuple` to lump teh registration object together: // > @@ -523,9 +521,9 @@ using use_vector_library = std::tuple< use_definitions< definition, product< - mp_list, - mp_list, - mp_list + types, + types, + types > > >; @@ -535,7 +533,7 @@ using use_vector_library = std::tuple< // md< // All the user of the library needs to do now is to create an instance (object) -// of `use_vector_library`, instantiated with the required mp_list: +// of `use_vector_library`, instantiated with the required types: // > @@ -606,7 +604,7 @@ use_vector_library init_vectors; // For brevity, we will consider only ordinary (i.e. non-square), square and // symmetric matrices. Also, we will omit all maths and storage management, to -// focus on dealing with mp_list. +// focus on dealing with types. // Here is the implementation of these classes, and the intermediary abstract // classes: @@ -702,7 +700,7 @@ struct symmetric : any_symmetric { // importantly, better interfaces. For example, square matrices have a // determinant, which ordinary matrices do not have. Also, type errors can be // diagnosed by the compiler. However, compile-time specialization is possible -// only if the mp_list of the matrices is known in advance. It may not always be +// only if the types of the matrices is known in advance. It may not always be // the case. // Thus, as library designers, we face a dilemma: which users to serve best? @@ -909,7 +907,7 @@ auto operator~(const handle>& m) { // 1. `Matrix` is actually one of our `matrix` templates; without (1), *any* // template would match. // 2. `Matrix` is abstract; without (2), we would have an ambiguity with our -// own `operator~` defined above for concrete matrix mp_list. +// own `operator~` defined above for concrete matrix types. // C++20 concepts offer a much cleaner solution for taming template // instantiations. @@ -919,7 +917,7 @@ auto operator~(const handle>& m) { // methods, e.g. `negate`. For that we use a templatized definition container // called `unary_definition`. We want to instantiate it for every combination of // method template, abstract base class, concrete implementation of the abstract -// class, and this for the required numeric mp_list. E.g.: +// class, and this for the required numeric types. E.g.: // - `transpose>`, `any`, `ordinary` // - `transpose>`, `any_square`, `square` // - `transpose>`, `any_square`, `symmetrical` @@ -939,14 +937,14 @@ auto operator~(const handle>& m) { // M = { unary method templates: transpose, negate, etc } // A = { abstract class templates } // C = { concrete class templates } -// T = { required numeric mp_list } +// T = { required numeric types } // ``` // ...and selecting the combinations that satisfy the condition: // - `A` is a base of `C` // This time, we need to make a Cartesian product that involves templates as -// well as mp_list. For this, YOMM2 provides two constructs: +// well as types. For this, YOMM2 provides two constructs: // - `template_ typename>` wraps a template in a type. It // contains a nested template `fn`, which applies the original // template to `Ts...`. Thus we have the identity: @@ -954,7 +952,7 @@ auto operator~(const handle>& m) { // template_::template fn = F // ``` // - `templates typename...>` wraps a list of templates in -// a `mp_list` list of `template_`s. +// a `types` list of `template_`s. // We can now implement `unary_definition`: @@ -1032,27 +1030,27 @@ use_definitions< unary_definition, product< templates, abstract_matrix_templates, - concrete_matrix_templates, mp_list>> + concrete_matrix_templates, types>> YOMM2_GENSYM; // > // md< // We must not forget to register all the matrix classes, for both numeric -// mp_list. For that, we can use another YOMM2 helper: `apply_product`. It takes a -// `templates` list, and any number of `mp_list` list; forms the Cartesian +// types. For that, we can use another YOMM2 helper: `apply_product`. It takes a +// `templates` list, and any number of `types` list; forms the Cartesian // product; and, for each resulting combination, applies the first element - a -// template - to the other elements. The result is a `mp_list` list of template +// template - to the other elements. The result is a `types` list of template // instantiations. // We saw that `use_classes` takes a list of classes. It also works with a -// list of `mp_list` lists. We can thus inject the result of `apply_product` into +// list of `types` lists. We can thus inject the result of `apply_product` into // `use_classes`: // > // code< -YOMM2_STATIC(use_classes>>); +YOMM2_STATIC(use_classes>>); // > #endif @@ -1088,12 +1086,12 @@ BOOST_AUTO_TEST_CASE(test_dynamic_transpose) { // `any_square`. // Fortunately, we can leverage the static `operator+` to deduce the return type -// of additions that involve one or two abstract mp_list. This is what the nested -// `abstract_type` and `concrete_type` aliases are for. We can convert the mp_list +// of additions that involve one or two abstract types. This is what the nested +// `abstract_type` and `concrete_type` aliases are for. We can convert the types // of the arguments to their nearest concrete type: for a // `any_symmetric`, it is a `symmetric`; for a `square`, // it is `square`. Then we can "pretend" to add two handles to objects -// of the two mp_list, and extract the result's type using `decltype`. And +// of the two types, and extract the result's type using `decltype`. And // finally, we convert that type to its abstract base class, using // `abstract_type`. @@ -1182,7 +1180,7 @@ auto operator+(const handle& a, const handle& b) { // M = { unary method templates: transpose, negate, etc } // A1, A2 = { abstract class templates } // C1, C2 = { concrete class templates } -// T1, T2 = { required numeric mp_list } +// T1, T2 = { required numeric types } // ``` // ...and selecting the combinations that satisfy the condition: @@ -1287,8 +1285,8 @@ use_definitions< binary_definition, product< templates, abstract_matrix_templates, concrete_matrix_templates, - mp_list, abstract_matrix_templates, - concrete_matrix_templates, mp_list>> + types, abstract_matrix_templates, + concrete_matrix_templates, types>> YOMM2_GENSYM; // > @@ -1326,7 +1324,7 @@ BOOST_AUTO_TEST_CASE(test_dynamic_operations) { // Now we need to create a mechanism that enable users to instantiate just the // method definitions they want. This is more complicated than for the vector // library, because users need to be able to select from three sets: the -// underlying numeric mp_list, the matrix mp_list, and the methods. For example: +// underlying numeric types, the matrix types, and the methods. For example: // > @@ -1338,11 +1336,11 @@ BOOST_AUTO_TEST_CASE(test_dynamic_operations) { // use_polymorphic_matrices<>::with YOMM2_GENSYM; // 5 // ``` -// 1. all matrix mp_list of `double`, with all operations -// 2. all matrix mp_list of `int` and `double`, with all operations +// 1. all matrix types of `double`, with all operations +// 2. all matrix types of `int` and `double`, with all operations // 3. square and symmetric matrices of `double`, with all operations // 4. square and symmetric matrices of `int` and `double`, polymorphic addition only -// 5. all matrix mp_list of `double`, with all operations +// 5. all matrix types of `double`, with all operations // Let's implement this. First we need a few helpers. @@ -1424,17 +1422,17 @@ struct definition_traits : binary_definition_traits {}; template typename... Ms> struct use_polymorphic_matrices { - using abstract_matrix_templates = mp_list< + using abstract_matrix_templates = types< typename template_of::abstract_type>::type...>; using concrete_matrix_templates = templates; template struct of { - using numeric_types = mp_list; + using numeric_types = types; template typename... Ops> struct with : use_classes< - apply_product>, - apply_product>>, + apply_product>, + apply_product>>, definition_traits::template fn< abstract_matrix_templates, concrete_matrix_templates, numeric_types>... {}; diff --git a/include/yorel/yomm2/core.hpp b/include/yorel/yomm2/core.hpp index 57934bfd..ebf180fb 100644 --- a/include/yorel/yomm2/core.hpp +++ b/include/yorel/yomm2/core.hpp @@ -23,14 +23,6 @@ struct virtual_; template struct virtual_ptr; -} // namespace yomm2 -} // namespace yorel - -#include - -namespace yorel { -namespace yomm2 { - // ----------------------------------------------------------------------------- // Method @@ -41,7 +33,7 @@ template struct method : detail::method_info { using self_type = method; using policy_type = Policy; - using declared_argument_types = boost::mp11::mp_list; + using declared_argument_types = detail::types; using call_argument_types = boost::mp11::mp_transform< detail::remove_virtual, declared_argument_types>; using virtual_argument_types = @@ -190,7 +182,7 @@ struct class_declaration detail::get_policy, detail::remove_policy> {}; template -struct class_declaration> +struct class_declaration> : detail::class_declaration_aux< detail::get_policy, detail::remove_policy> {}; @@ -453,9 +445,9 @@ method::resolve(const ArgType&... args) const { std::uintptr_t pf; if constexpr (arity == 1) { - pf = resolve_uni, ArgType...>(args...); + pf = resolve_uni, ArgType...>(args...); } else { - pf = resolve_multi_first<0, boost::mp11::mp_list, ArgType...>( + pf = resolve_multi_first<0, types, ArgType...>( args...); } diff --git a/include/yorel/yomm2/detail.hpp b/include/yorel/yomm2/detail.hpp index 5884cc75..c0da834e 100644 --- a/include/yorel/yomm2/detail.hpp +++ b/include/yorel/yomm2/detail.hpp @@ -1,13 +1,10 @@ #ifndef YOREL_YOMM2_DETAIL_HPP #define YOREL_YOMM2_DETAIL_HPP -#include -#include -#include -#include - #include +#include + namespace yorel { namespace yomm2 { namespace detail { @@ -25,7 +22,7 @@ template struct type_id_list; template -struct type_id_list> { +struct type_id_list> { // If using deferred 'static_type', add an extra element in 'value', // default-initialized to zero, indicating the ids need to be resolved. Set // to 1 after this is done. @@ -37,18 +34,18 @@ struct type_id_list> { }; template -type_id type_id_list>::value[values] = { +type_id type_id_list>::value[values] = { collect_static_type_id()...}; template -type_id* type_id_list>::begin = value; +type_id* type_id_list>::begin = value; template -type_id* type_id_list>::end = +type_id* type_id_list>::end = value + sizeof...(T); template -struct type_id_list> { +struct type_id_list> { static constexpr type_id* const begin = nullptr; static constexpr auto end = begin; }; @@ -70,12 +67,12 @@ struct parameter_type_list; template struct parameter_type_list { - using type = boost::mp11::mp_list; + using type = types; }; template struct parameter_type_list { - using type = boost::mp11::mp_list; + using type = types; }; template @@ -139,14 +136,14 @@ template struct class_declaration_aux; template -struct class_declaration_aux> +struct class_declaration_aux> : class_info { class_declaration_aux() { this->type = collect_static_type_id(); this->first_base = - type_id_list>::begin; + type_id_list>::begin; this->last_base = - type_id_list>::end; + type_id_list>::end; Policy::classes.push_back(*this); this->is_abstract = std::is_abstract_v; this->static_vptr = &Policy::template static_vptr; @@ -159,7 +156,7 @@ struct class_declaration_aux> template constexpr auto arity = - boost::mp11::mp_count_if, is_virtual>::value; + boost::mp11::mp_count_if, is_virtual>::value; inline definition_info::~definition_info() { if (method) { @@ -171,7 +168,7 @@ template struct is_policy_aux : std::is_base_of {}; template -struct is_policy_aux> : std::false_type {}; +struct is_policy_aux> : std::false_type {}; template constexpr bool is_policy = is_policy_aux::value; @@ -340,8 +337,8 @@ constexpr bool is_virtual_ptr = is_virtual_ptr_aux::value; template using virtual_ptr_class = std::conditional_t< sizeof...(Ts) == 2, - boost::mp11::mp_second>, - boost::mp11::mp_first>>; + boost::mp11::mp_second>, + boost::mp11::mp_first>>; template struct argument_traits { @@ -500,19 +497,19 @@ inline uintptr_t get_tip(const T& arg) { template using get_policy = std::conditional_t< - is_policy>>, - boost::mp11::mp_back>, + is_policy>>, + boost::mp11::mp_back>, YOMM2_DEFAULT_POLICY>; template using remove_policy = std::conditional_t< - is_policy>>, - boost::mp11::mp_pop_back>, - boost::mp11::mp_list>; + is_policy>>, + boost::mp11::mp_pop_back>, + types>; template using virtual_ptr_policy = std::conditional_t< - sizeof...(Ts) == 2, boost::mp11::mp_first>, + sizeof...(Ts) == 2, boost::mp11::mp_first>, YOMM2_DEFAULT_POLICY>; // ----------------------------------------------------------------------------- @@ -526,12 +523,12 @@ template< typename... SPEC_PARAM> struct thunk< Policy, BASE_RETURN(BASE_PARAM...), SPEC, - boost::mp11::mp_list> { + types> { static BASE_RETURN fn(remove_virtual... arg) { using base_type = - boost::mp11::mp_first>; + boost::mp11::mp_first>; using spec_type = - boost::mp11::mp_first>; + boost::mp11::mp_first>; return SPEC( argument_traits::template cast( remove_virtual(arg))...); @@ -563,40 +560,40 @@ struct member_function_thunk { // base. The direct and its direct and indirect proper bases are included. The // runtime will extract the direct proper bases. See unit tests for an example. template -using inheritance_map = boost::mp11::mp_list, - boost::mp11::mp_list>, + types>, Cs>...>; template struct use_classes_aux; template -struct use_classes_aux> { +struct use_classes_aux> { using type = boost::mp11::mp_apply< std::tuple, boost::mp11::mp_transform_q< boost::mp11::mp_bind_front, boost::mp11::mp_apply< - inheritance_map, boost::mp11::mp_list>>>; + inheritance_map, types>>>; }; template struct use_classes_aux< Policy, - boost::mp11::mp_list, MoreClassLists...>> + types, MoreClassLists...>> : use_classes_aux< Policy, boost::mp11::mp_append< - boost::mp11::mp_list, MoreClassLists...>> + types, MoreClassLists...>> {}; template using second_last = boost::mp11::mp_at_c< - boost::mp11::mp_list, - boost::mp11::mp_size>::value - 2>; + types, + boost::mp11::mp_size>::value - 2>; template using use_classes_macro = typename std::conditional_t< @@ -604,10 +601,10 @@ using use_classes_macro = typename std::conditional_t< use_classes_aux< second_last, boost::mp11::mp_pop_back< - boost::mp11::mp_pop_back>>>, + boost::mp11::mp_pop_back>>>, use_classes_aux< - boost::mp11::mp_back>, - boost::mp11::mp_pop_back>>>::type; + boost::mp11::mp_back>, + boost::mp11::mp_pop_back>>>::type; struct empty_base {}; diff --git a/include/yorel/yomm2/detail/compiler.hpp b/include/yorel/yomm2/detail/compiler.hpp index 9137342d..2a3f6aa5 100644 --- a/include/yorel/yomm2/detail/compiler.hpp +++ b/include/yorel/yomm2/detail/compiler.hpp @@ -36,32 +36,32 @@ struct aggregate_reports; template struct aggregate_reports< - boost::mp11::mp_list, - boost::mp11::mp_list, + types, + types, std::void_t> { using type = typename aggregate_reports< - boost::mp11::mp_list, - boost::mp11::mp_list>::type; + types, + types>::type; }; template struct aggregate_reports< - boost::mp11::mp_list, - boost::mp11::mp_list, Void> { + types, + types, Void> { using type = typename aggregate_reports< - boost::mp11::mp_list, - boost::mp11::mp_list>::type; + types, + types>::type; }; template struct aggregate_reports< - boost::mp11::mp_list, boost::mp11::mp_list<>, Void> { + types, types<>, Void> { struct type : Reports... {}; }; template using report_type = typename aggregate_reports< - boost::mp11::mp_list, typename Policy::facets>::type; + types, typename Policy::facets>::type; inline void merge_into(boost::dynamic_bitset<>& a, boost::dynamic_bitset<>& b) { if (b.size() < a.size()) { @@ -242,7 +242,7 @@ struct compiler : detail::generic_compiler { using type_index_type = decltype(Policy::type_index(0)); typename detail::aggregate_reports< - boost::mp11::mp_list, typename Policy::facets>::type + detail::types, typename Policy::facets>::type report; std::unordered_map class_map; diff --git a/include/yorel/yomm2/detail/ostdstream.hpp b/include/yorel/yomm2/detail/ostdstream.hpp index abfa87d2..ed989358 100644 --- a/include/yorel/yomm2/detail/ostdstream.hpp +++ b/include/yorel/yomm2/detail/ostdstream.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include namespace yorel { namespace yomm2 { diff --git a/include/yorel/yomm2/detail/trace.hpp b/include/yorel/yomm2/detail/trace.hpp index 26384ef6..5a83b6bc 100644 --- a/include/yorel/yomm2/detail/trace.hpp +++ b/include/yorel/yomm2/detail/trace.hpp @@ -1,6 +1,8 @@ #ifndef YOREL_YOMM2_DETAIL_TRACE_HPP #define YOREL_YOMM2_DETAIL_TRACE_HPP +#include + namespace yorel { namespace yomm2 { namespace detail { diff --git a/include/yorel/yomm2/detail/types.hpp b/include/yorel/yomm2/detail/types.hpp new file mode 100644 index 00000000..fefb7bb5 --- /dev/null +++ b/include/yorel/yomm2/detail/types.hpp @@ -0,0 +1,40 @@ +#ifndef YOREL_YOMM2_DETAIL_TYPES_HPP +#define YOREL_YOMM2_DETAIL_TYPES_HPP + +#include +#include + +#if defined(YOMM2_SHARED) +#if defined(_MSC_VER) +#if !defined(yOMM2_API_msc) +#define yOMM2_API_msc __declspec(dllimport) +#endif +#endif +#endif + +#if !defined(yOMM2_API_gcc) +#define yOMM2_API_gcc +#endif + +#if !defined(yOMM2_API_msc) +#define yOMM2_API_msc +#endif + +#define yOMM2_API yOMM2_API_gcc yOMM2_API_msc + +namespace yorel { +namespace yomm2 { + +using type_id = std::uintptr_t; +constexpr type_id invalid_type = (std::numeric_limits::max)(); + +namespace detail { + +template +struct types; + +} +} // namespace yomm2 +} // namespace yorel + +#endif diff --git a/include/yorel/yomm2/policies/basic_error_output.hpp b/include/yorel/yomm2/policies/basic_error_output.hpp new file mode 100644 index 00000000..9cdb8bbe --- /dev/null +++ b/include/yorel/yomm2/policies/basic_error_output.hpp @@ -0,0 +1,29 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_BASIC_ERROR_OUTPUT_HPP +#define YOREL_YOMM2_POLICY_BASIC_ERROR_OUTPUT_HPP + +#include +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc basic_error_output : virtual error_output { + static Stream error_stream; +}; + +template +Stream basic_error_output::error_stream; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/basic_indirect_vptr.hpp b/include/yorel/yomm2/policies/basic_indirect_vptr.hpp new file mode 100644 index 00000000..2a872ba9 --- /dev/null +++ b/include/yorel/yomm2/policies/basic_indirect_vptr.hpp @@ -0,0 +1,29 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_BASIC_INDIRECT_VPTR_HPP +#define YOREL_YOMM2_POLICY_BASIC_INDIRECT_VPTR_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc basic_indirect_vptr : virtual indirect_vptr { + static std::vector indirect_vptrs; +}; + +template +std::vector + basic_indirect_vptr::indirect_vptrs; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/basic_trace_output.hpp b/include/yorel/yomm2/policies/basic_trace_output.hpp new file mode 100644 index 00000000..3d8deda1 --- /dev/null +++ b/include/yorel/yomm2/policies/basic_trace_output.hpp @@ -0,0 +1,35 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_BASIC_TRACE_OUTPUT_HPP +#define YOREL_YOMM2_POLICY_BASIC_TRACE_OUTPUT_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc basic_trace_output : virtual trace_output { + static Stream trace_stream; + static bool trace_enabled; +}; + +template +Stream basic_trace_output::trace_stream; + +template +bool basic_trace_output::trace_enabled([]() { + auto env = getenv("YOMM2_TRACE"); + return env && *env++ == '1' && *env++ == 0; +}()); + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/core.hpp b/include/yorel/yomm2/policies/core.hpp index 549d4799..a0fd74ea 100644 --- a/include/yorel/yomm2/policies/core.hpp +++ b/include/yorel/yomm2/policies/core.hpp @@ -1,38 +1,21 @@ +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + #ifndef YOREL_YOMM2_POLICIES_CORE_HPP #define YOREL_YOMM2_POLICIES_CORE_HPP +#include #include -#if defined(YOMM2_SHARED) -#if defined(_MSC_VER) -#if !defined(yOMM2_API_msc) -#define yOMM2_API_msc __declspec(dllimport) -#endif -#endif -#endif +#include +#include -#if !defined(yOMM2_API_gcc) -#define yOMM2_API_gcc -#endif - -#if !defined(yOMM2_API_msc) -#define yOMM2_API_msc -#endif - -#define yOMM2_API yOMM2_API_gcc yOMM2_API_msc - -// ----------------------------------------------------------------------------- -// Forward declarations needed by "detail.hpp" +#include namespace yorel { namespace yomm2 { - -struct context; -struct catalog; - -using type_id = std::uintptr_t; -constexpr type_id invalid_type = (std::numeric_limits::max)(); - namespace detail { // ----------------------------------------------------------------------------- @@ -207,6 +190,75 @@ detail::method_catalog basic_domain::methods; template std::vector basic_domain::dispatch_data; +template +struct rebind_facet { + using type = Facet; +}; + +template< + typename NewPolicy, typename OldPolicy, + template class GenericFacet, typename... Args> +struct rebind_facet> { + using type = GenericFacet; +}; + +template +struct basic_policy : virtual abstract_policy, + virtual basic_domain, + virtual Facets... { + using facets = detail::types; + + template + static constexpr bool has_facet = std::is_base_of_v; + + template + using use_facet = boost::mp11::mp_first, Facet>, + facets>>; + + template + using rebind = basic_policy< + NewPolicy, typename rebind_facet::type...>; + + template + using replace = boost::mp11::mp_apply< + basic_policy, + boost::mp11::mp_push_front< + boost::mp11::mp_replace_if_q< + facets, + boost::mp11::mp_bind_front_q< + boost::mp11::mp_quote_trait, Base>, + Facet>, + Policy>>; + + template + using remove = boost::mp11::mp_apply< + basic_policy, + boost::mp11::mp_push_front< + boost::mp11::mp_remove_if_q< + facets, + boost::mp11::mp_bind_front_q< + boost::mp11::mp_quote_trait, Base>>, + Policy>>; +}; + +template +constexpr bool has_facet = Policy::template has_facet; + +struct rtti { + static type_id type_index(type_id type) { + return type; + } + + template + static void type_name(type_id type, Stream& stream) { + stream << "type_id(" << type << ")"; + } +}; + +struct deferred_static_rtti : virtual rtti {}; + } // namespace policy } // namespace yomm2 diff --git a/include/yorel/yomm2/policies/fast_perfect_hash.hpp b/include/yorel/yomm2/policies/fast_perfect_hash.hpp new file mode 100644 index 00000000..c4ee7c62 --- /dev/null +++ b/include/yorel/yomm2/policies/fast_perfect_hash.hpp @@ -0,0 +1,202 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_FAST_PERFECT_HASH_HPP +#define YOREL_YOMM2_POLICY_FAST_PERFECT_HASH_HPP + +#include + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc fast_perfect_hash : virtual type_hash { + struct report { + std::size_t method_table_size, dispatch_table_size; + std::size_t hash_search_attempts; + }; + + static type_id hash_mult; + static std::size_t hash_shift; + static std::size_t hash_length; + static std::size_t hash_min; + static std::size_t hash_max; + +#ifdef _MSC_VER + __forceinline +#endif + static type_id + hash_type_id(type_id type) { + return (hash_mult * type) >> hash_shift; + } + + template + static void hash_initialize(ForwardIterator first, ForwardIterator last) { + std::vector buckets; + hash_initialize(first, last, buckets); + } + + template + static void hash_initialize( + ForwardIterator first, ForwardIterator last, + std::vector& buckets); +}; + +template +template +void fast_perfect_hash::hash_initialize( + ForwardIterator first, ForwardIterator last, + std::vector& buckets) { + using namespace policy; + + constexpr bool trace_enabled = Policy::template has_facet; + const auto N = std::distance(first, last); + + if constexpr (trace_enabled) { + if (Policy::trace_enabled) { + Policy::trace_stream << "Finding hash factor for " << N + << " types\n"; + } + } + + std::default_random_engine rnd(13081963); + std::size_t total_attempts = 0; + std::size_t M = 1; + + for (auto size = N * 5 / 4; size >>= 1;) { + ++M; + } + + std::uniform_int_distribution uniform_dist; + + for (std::size_t pass = 0; pass < 4; ++pass, ++M) { + hash_shift = 8 * sizeof(type_id) - M; + auto hash_size = 1 << M; + + if constexpr (trace_enabled) { + if (Policy::trace_enabled) { + Policy::trace_stream << " trying with M = " << M << ", " + << hash_size << " buckets\n"; + } + } + + bool found = false; + std::size_t attempts = 0; + buckets.resize(hash_size); + hash_length = 0; + + while (!found && attempts < 100000) { + std::fill(buckets.begin(), buckets.end(), static_cast(-1)); + ++attempts; + ++total_attempts; + found = true; + hash_mult = uniform_dist(rnd) | 1; + + for (auto iter = first; iter != last; ++iter) { + for (auto type_iter = iter->type_id_begin(); + type_iter != iter->type_id_end(); ++type_iter) { + auto type = *type_iter; + auto index = (type * hash_mult) >> hash_shift; + hash_min = (std::min)(hash_min, index); + hash_max = (std::max)(hash_max, index); + + if (buckets[index] != static_cast(-1)) { + found = false; + break; + } + + buckets[index] = type; + } + } + } + + // metrics.hash_search_attempts = total_attempts; + // metrics.hash_search_time = + // std::chrono::steady_clock::now() - start_time; + // metrics.hash_table_size = hash_size; + + if (found) { + hash_length = hash_max + 1; + + if constexpr (trace_enabled) { + if (Policy::trace_enabled) { + Policy::trace_stream << " found " << hash_mult << " after " + << total_attempts + << " attempts; min = " << hash_min + << ", max = " << hash_max << "\n"; + } + } + + return; + } + } + + hash_search_error error; + error.attempts = total_attempts; + // error.duration = std::chrono::steady_clock::now() - start_time; + error.buckets = 1 << M; + + if constexpr (has_facet) { + Policy::error(error_type(error)); + } + + abort(); +} + +template +type_id fast_perfect_hash::hash_mult; +template +std::size_t fast_perfect_hash::hash_shift; +template +std::size_t fast_perfect_hash::hash_length; +template +std::size_t fast_perfect_hash::hash_min; +template +std::size_t fast_perfect_hash::hash_max; + +template +struct yOMM2_API_gcc checked_perfect_hash : virtual fast_perfect_hash, + virtual runtime_checks { + static std::vector control; + + static type_id hash_type_id(type_id type) { + auto index = fast_perfect_hash::hash_type_id(type); + + if (index >= fast_perfect_hash::hash_length || + control[index] != type) { + using namespace policy; + + if constexpr (Policy::template has_facet) { + unknown_class_error error; + error.context = unknown_class_error::update; + error.type = type; + Policy::error(error); + } + + abort(); + } + + return index; + } + + template + static void hash_initialize(ForwardIterator first, ForwardIterator last) { + fast_perfect_hash::hash_initialize(first, last, control); + control.resize(fast_perfect_hash::hash_length); + } +}; + +template +std::vector checked_perfect_hash::control; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/minimal_rtti.hpp b/include/yorel/yomm2/policies/minimal_rtti.hpp new file mode 100644 index 00000000..8cfebcac --- /dev/null +++ b/include/yorel/yomm2/policies/minimal_rtti.hpp @@ -0,0 +1,28 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_MINIMAL_RTTI_HPP +#define YOREL_YOMM2_POLICY_MINIMAL_RTTI_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +struct minimal_rtti : virtual rtti { + template + static type_id static_type() { + static char id; + return reinterpret_cast(&id); + } +}; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/std_rtti.hpp b/include/yorel/yomm2/policies/std_rtti.hpp new file mode 100644 index 00000000..95309d59 --- /dev/null +++ b/include/yorel/yomm2/policies/std_rtti.hpp @@ -0,0 +1,57 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_STD_RTTI_HPP +#define YOREL_YOMM2_POLICY_STD_RTTI_HPP + +#include + +#ifndef BOOST_NO_RTTI +#include +#include +#include +#endif + +namespace yorel { +namespace yomm2 { +namespace policy { + +struct std_rtti : virtual rtti { +#ifndef BOOST_NO_RTTI + template + static type_id static_type() { + auto tip = &typeid(Class); + return reinterpret_cast(tip); + } + + template + static type_id dynamic_type(const Class& obj) { + auto tip = &typeid(obj); + return reinterpret_cast(tip); + } + + template + static void type_name(type_id type, Stream& stream) { + stream << boost::core::demangle( + reinterpret_cast(type)->name()); + } + + static std::type_index type_index(type_id type) { + return std::type_index(*reinterpret_cast(type)); + } + + template + static D dynamic_cast_ref(B&& obj) { + return dynamic_cast(obj); + } +#endif +}; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/throw_error.hpp b/include/yorel/yomm2/policies/throw_error.hpp new file mode 100644 index 00000000..20c6a004 --- /dev/null +++ b/include/yorel/yomm2/policies/throw_error.hpp @@ -0,0 +1,25 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_THROW_ERROR_HPP +#define YOREL_YOMM2_POLICY_THROW_ERROR_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { +struct yOMM2_API_gcc throw_error : virtual error_handler { + static void error(const error_type& error_v) { + std::visit([](auto&& arg) { throw arg; }, error_v); + } +}; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/vectored_error.hpp b/include/yorel/yomm2/policies/vectored_error.hpp new file mode 100644 index 00000000..6da609eb --- /dev/null +++ b/include/yorel/yomm2/policies/vectored_error.hpp @@ -0,0 +1,71 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_VECTORED_ERROR_HPP +#define YOREL_YOMM2_POLICY_VECTORED_ERROR_HPP + +#include +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc vectored_error : virtual error_handler { + static error_handler_type error; + + static void default_error_handler(const error_type& error_v) { + using namespace detail; + using namespace policy; + + if constexpr (Policy::template has_facet) { + if (auto error = std::get_if(&error_v)) { + const char* explanation[] = { + "no applicable definition", "ambiguous call"}; + Policy::error_stream + << explanation + [error->status - resolution_error::no_definition] + << " for " << error->method_name << "("; + auto comma = ""; + + for (auto ti : + range{error->types, error->types + error->arity}) { + Policy::error_stream << comma; + Policy::type_name(ti, Policy::error_stream); + comma = ", "; + } + + Policy::error_stream << ")\n"; + } else if ( + auto error = std::get_if(&error_v)) { + Policy::error_stream << "unknown class "; + Policy::type_name(error->type, Policy::error_stream); + Policy::error_stream << "\n"; + } else if (auto error = std::get_if(&error_v)) { + Policy::error_stream << "invalid method table for "; + Policy::type_name(error->type, Policy::error_stream); + Policy::error_stream << "\n"; + } else if (auto error = std::get_if(&error_v)) { + Policy::error_stream << "could not find hash factors after " + << error->attempts << "s using " + << error->buckets << " buckets\n"; + } + } + } +}; + +template +error_handler_type vectored_error::error = + std::conditional_t< + std::is_same_v, vectored_error, + DefaultHandlerProvider>::default_error_handler; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/vptr_map.hpp b/include/yorel/yomm2/policies/vptr_map.hpp new file mode 100644 index 00000000..e5b60435 --- /dev/null +++ b/include/yorel/yomm2/policies/vptr_map.hpp @@ -0,0 +1,45 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_VPTR_MAP_HPP +#define YOREL_YOMM2_POLICY_VPTR_MAP_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template< + class Policy, + class Map = std::unordered_map> +struct yOMM2_API_gcc vptr_map : virtual external_vptr { + static Map vptrs; + + template + static void publish_vptrs(ForwardIterator first, ForwardIterator last) { + for (auto iter = first; iter != last; ++iter) { + for (auto type_iter = iter->type_id_begin(); + type_iter != iter->type_id_end(); ++type_iter) { + vptrs[*type_iter] = iter->vptr(); + } + } + } + + template + static auto dynamic_vptr(const Class& arg) { + return vptrs.find(Policy::dynamic_type(arg))->second; + } +}; + +template +Map vptr_map::vptrs; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policies/vptr_vector.hpp b/include/yorel/yomm2/policies/vptr_vector.hpp new file mode 100644 index 00000000..5689396c --- /dev/null +++ b/include/yorel/yomm2/policies/vptr_vector.hpp @@ -0,0 +1,85 @@ + +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef YOREL_YOMM2_POLICY_VPTR_VECTOR_HPP +#define YOREL_YOMM2_POLICY_VPTR_VECTOR_HPP + +#include + +namespace yorel { +namespace yomm2 { +namespace policy { + +template +struct yOMM2_API_gcc vptr_vector : virtual external_vptr { + static std::vector vptrs; + + template + static void publish_vptrs(ForwardIterator first, ForwardIterator last) { + using namespace policy; + + std::size_t size; + + if constexpr (has_facet) { + Policy::hash_initialize(first, last); + size = Policy::hash_length; + } else { + size = 0; + + for (auto iter = first; iter != last; ++iter) { + for (auto type_iter = iter->type_id_begin(); + type_iter != iter->type_id_end(); ++type_iter) { + size = (std::max)(size, *type_iter); + } + } + + ++size; + } + + vptrs.resize(size); + + if constexpr (has_facet) { + Policy::indirect_vptrs.resize(size); + } + + for (auto iter = first; iter != last; ++iter) { + for (auto type_iter = iter->type_id_begin(); + type_iter != iter->type_id_end(); ++type_iter) { + auto index = *type_iter; + + if constexpr (has_facet) { + index = Policy::hash_type_id(index); + } + + vptrs[index] = iter->vptr(); + + if constexpr (has_facet) { + Policy::indirect_vptrs[index] = iter->indirect_vptr(); + } + } + } + } + + template + static const std::uintptr_t* dynamic_vptr(const Class& arg) { + auto index = Policy::dynamic_type(arg); + + if constexpr (has_facet) { + index = Policy::hash_type_id(index); + } + + return vptrs[index]; + } +}; + +template +std::vector vptr_vector::vptrs; + +} +} +} + +#endif diff --git a/include/yorel/yomm2/policy.hpp b/include/yorel/yomm2/policy.hpp index 614961b8..73779dd9 100644 --- a/include/yorel/yomm2/policy.hpp +++ b/include/yorel/yomm2/policy.hpp @@ -1,505 +1,36 @@ +// Copyright (c) 2018-2024 Jean-Louis Leroy +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + #ifndef YOREL_YOMM2_POLICY_HPP #define YOREL_YOMM2_POLICY_HPP -#include -#include #include -#include #include -#include -#include -#include #include #include -#ifndef BOOST_NO_RTTI -#include -#include -#include -#endif +#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include -#include -#include +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif namespace yorel { namespace yomm2 { namespace policy { -struct rtti { - static type_id type_index(type_id type) { - return type; - } - - template - static void type_name(type_id type, Stream& stream) { - stream << "type_id(" << type << ")"; - } -}; - -struct minimal_rtti : virtual rtti { - template - static type_id static_type() { - static char id; - return reinterpret_cast(&id); - } -}; - -struct std_rtti : virtual rtti { -#ifndef BOOST_NO_RTTI - template - static type_id static_type() { - auto tip = &typeid(Class); - return reinterpret_cast(tip); - } - - template - static type_id dynamic_type(const Class& obj) { - auto tip = &typeid(obj); - return reinterpret_cast(tip); - } - - template - static void type_name(type_id type, Stream& stream) { - stream << boost::core::demangle( - reinterpret_cast(type)->name()); - } - - static std::type_index type_index(type_id type) { - return std::type_index(*reinterpret_cast(type)); - } - - template - static D dynamic_cast_ref(B&& obj) { - return dynamic_cast(obj); - } -#endif -}; - -struct deferred_static_rtti : virtual rtti {}; - -template -constexpr bool implemented = !std::is_same_v; - -template -struct rebind_facet { - using type = Facet; -}; - -template< - typename NewPolicy, typename OldPolicy, - template class GenericFacet, typename... Args> -struct rebind_facet> { - using type = GenericFacet; -}; - -template -struct basic_policy : virtual abstract_policy, - virtual basic_domain, - virtual Facets... { - using facets = boost::mp11::mp_list; - - template - static constexpr bool has_facet = std::is_base_of_v; - - template - using use_facet = boost::mp11::mp_first, Facet>, - facets>>; - - template - using rebind = basic_policy< - NewPolicy, typename rebind_facet::type...>; - - template - using replace = boost::mp11::mp_apply< - basic_policy, - boost::mp11::mp_push_front< - boost::mp11::mp_replace_if_q< - facets, - boost::mp11::mp_bind_front_q< - boost::mp11::mp_quote_trait, Base>, - Facet>, - Policy>>; - - template - using remove = boost::mp11::mp_apply< - basic_policy, - boost::mp11::mp_push_front< - boost::mp11::mp_remove_if_q< - facets, - boost::mp11::mp_bind_front_q< - boost::mp11::mp_quote_trait, Base>>, - Policy>>; -}; - -template -constexpr bool has_facet = Policy::template has_facet; - -template -struct yOMM2_API_gcc vptr_vector : virtual external_vptr { - static std::vector vptrs; - - template - static void publish_vptrs(ForwardIterator first, ForwardIterator last) { - using namespace policy; - - std::size_t size; - - if constexpr (has_facet) { - Policy::hash_initialize(first, last); - size = Policy::hash_length; - } else { - size = 0; - - for (auto iter = first; iter != last; ++iter) { - for (auto type_iter = iter->type_id_begin(); - type_iter != iter->type_id_end(); ++type_iter) { - size = (std::max)(size, *type_iter); - } - } - - ++size; - } - - vptrs.resize(size); - - if constexpr (has_facet) { - Policy::indirect_vptrs.resize(size); - } - - for (auto iter = first; iter != last; ++iter) { - for (auto type_iter = iter->type_id_begin(); - type_iter != iter->type_id_end(); ++type_iter) { - auto index = *type_iter; - - if constexpr (has_facet) { - index = Policy::hash_type_id(index); - } - - vptrs[index] = iter->vptr(); - - if constexpr (has_facet) { - Policy::indirect_vptrs[index] = iter->indirect_vptr(); - } - } - } - } - - template - static const std::uintptr_t* dynamic_vptr(const Class& arg) { - auto index = Policy::dynamic_type(arg); - - if constexpr (has_facet) { - index = Policy::hash_type_id(index); - } - - return vptrs[index]; - } -}; - -template -std::vector vptr_vector::vptrs; - -template< - class Policy, - class Map = std::unordered_map> -struct yOMM2_API_gcc vptr_map : virtual external_vptr { - static Map vptrs; - - template - static void publish_vptrs(ForwardIterator first, ForwardIterator last) { - for (auto iter = first; iter != last; ++iter) { - for (auto type_iter = iter->type_id_begin(); - type_iter != iter->type_id_end(); ++type_iter) { - vptrs[*type_iter] = iter->vptr(); - } - } - } - - template - static auto dynamic_vptr(const Class& arg) { - return vptrs.find(Policy::dynamic_type(arg))->second; - } -}; - -template -Map vptr_map::vptrs; - -template -struct yOMM2_API_gcc basic_indirect_vptr : virtual indirect_vptr { - static std::vector indirect_vptrs; -}; - -template -std::vector - basic_indirect_vptr::indirect_vptrs; - -template -struct yOMM2_API_gcc basic_error_output : virtual error_output { - static Stream error_stream; -}; - -template -Stream basic_error_output::error_stream; - -template -struct yOMM2_API_gcc basic_trace_output : virtual trace_output { - static Stream trace_stream; - static bool trace_enabled; -}; - -template -Stream basic_trace_output::trace_stream; - -template -bool basic_trace_output::trace_enabled([]() { - auto env = getenv("YOMM2_TRACE"); - return env && *env++ == '1' && *env++ == 0; -}()); - -template -struct yOMM2_API_gcc fast_perfect_hash : virtual type_hash { - struct report { - std::size_t method_table_size, dispatch_table_size; - std::size_t hash_search_attempts; - }; - - static type_id hash_mult; - static std::size_t hash_shift; - static std::size_t hash_length; - static std::size_t hash_min; - static std::size_t hash_max; - -#ifdef _MSC_VER - __forceinline -#endif - static type_id - hash_type_id(type_id type) { - return (hash_mult * type) >> hash_shift; - } - - template - static void hash_initialize(ForwardIterator first, ForwardIterator last) { - std::vector buckets; - hash_initialize(first, last, buckets); - } - - template - static void hash_initialize( - ForwardIterator first, ForwardIterator last, - std::vector& buckets); -}; - -template -template -void fast_perfect_hash::hash_initialize( - ForwardIterator first, ForwardIterator last, - std::vector& buckets) { - using namespace policy; - - constexpr bool trace_enabled = Policy::template has_facet; - const auto N = std::distance(first, last); - - if constexpr (trace_enabled) { - if (Policy::trace_enabled) { - Policy::trace_stream << "Finding hash factor for " << N - << " boost::mp11::mp_list\n"; - } - } - - std::default_random_engine rnd(13081963); - std::size_t total_attempts = 0; - std::size_t M = 1; - - for (auto size = N * 5 / 4; size >>= 1;) { - ++M; - } - - std::uniform_int_distribution uniform_dist; - - for (std::size_t pass = 0; pass < 4; ++pass, ++M) { - hash_shift = 8 * sizeof(type_id) - M; - auto hash_size = 1 << M; - - if constexpr (trace_enabled) { - if (Policy::trace_enabled) { - Policy::trace_stream << " trying with M = " << M << ", " - << hash_size << " buckets\n"; - } - } - - bool found = false; - std::size_t attempts = 0; - buckets.resize(hash_size); - hash_length = 0; - - while (!found && attempts < 100000) { - std::fill(buckets.begin(), buckets.end(), static_cast(-1)); - ++attempts; - ++total_attempts; - found = true; - hash_mult = uniform_dist(rnd) | 1; - - for (auto iter = first; iter != last; ++iter) { - for (auto type_iter = iter->type_id_begin(); - type_iter != iter->type_id_end(); ++type_iter) { - auto type = *type_iter; - auto index = (type * hash_mult) >> hash_shift; - hash_min = (std::min)(hash_min, index); - hash_max = (std::max)(hash_max, index); - - if (buckets[index] != static_cast(-1)) { - found = false; - break; - } - - buckets[index] = type; - } - } - } - - // metrics.hash_search_attempts = total_attempts; - // metrics.hash_search_time = - // std::chrono::steady_clock::now() - start_time; - // metrics.hash_table_size = hash_size; - - if (found) { - hash_length = hash_max + 1; - - if constexpr (trace_enabled) { - if (Policy::trace_enabled) { - Policy::trace_stream << " found " << hash_mult << " after " - << total_attempts - << " attempts; min = " << hash_min - << ", max = " << hash_max << "\n"; - } - } - - return; - } - } - - hash_search_error error; - error.attempts = total_attempts; - // error.duration = std::chrono::steady_clock::now() - start_time; - error.buckets = 1 << M; - - if constexpr (has_facet) { - Policy::error(error_type(error)); - } - - abort(); -} - -template -type_id fast_perfect_hash::hash_mult; -template -std::size_t fast_perfect_hash::hash_shift; -template -std::size_t fast_perfect_hash::hash_length; -template -std::size_t fast_perfect_hash::hash_min; -template -std::size_t fast_perfect_hash::hash_max; - -template -struct yOMM2_API_gcc checked_perfect_hash : virtual fast_perfect_hash, - virtual runtime_checks { - static std::vector control; - - static type_id hash_type_id(type_id type) { - auto index = fast_perfect_hash::hash_type_id(type); - - if (index >= fast_perfect_hash::hash_length || - control[index] != type) { - using namespace policy; - - if constexpr (Policy::template has_facet) { - unknown_class_error error; - error.context = unknown_class_error::update; - error.type = type; - Policy::error(error); - } - - abort(); - } - - return index; - } - - template - static void hash_initialize(ForwardIterator first, ForwardIterator last) { - fast_perfect_hash::hash_initialize(first, last, control); - control.resize(fast_perfect_hash::hash_length); - } -}; - -template -std::vector checked_perfect_hash::control; - -#ifdef __cpp_exceptions -struct yOMM2_API_gcc throw_error : virtual error_handler { - static void error(const error_type& error_v) { - std::visit([](auto&& arg) { throw arg; }, error_v); - } -}; -#endif - -template -struct yOMM2_API_gcc vectored_error : virtual error_handler { - static error_handler_type error; - - static void default_error_handler(const error_type& error_v) { - using namespace detail; - using namespace policy; - - if constexpr (Policy::template has_facet) { - if (auto error = std::get_if(&error_v)) { - const char* explanation[] = { - "no applicable definition", "ambiguous call"}; - Policy::error_stream - << explanation - [error->status - resolution_error::no_definition] - << " for " << error->method_name << "("; - auto comma = ""; - - for (auto ti : range{ - error->types, - error->types + error->arity}) { - Policy::error_stream << comma; - Policy::type_name(ti, Policy::error_stream); - comma = ", "; - } - - Policy::error_stream << ")\n"; - } else if ( - auto error = std::get_if(&error_v)) { - Policy::error_stream << "unknown class "; - Policy::type_name(error->type, Policy::error_stream); - Policy::error_stream << "\n"; - } else if (auto error = std::get_if(&error_v)) { - Policy::error_stream << "invalid method table for "; - Policy::type_name(error->type, Policy::error_stream); - Policy::error_stream << "\n"; - } else if (auto error = std::get_if(&error_v)) { - Policy::error_stream << "could not find hash factors after " - << error->attempts << "s using " - << error->buckets << " buckets\n"; - } - } - } -}; - -template -error_handler_type vectored_error::error = - std::conditional_t< - std::is_same_v, vectored_error, - DefaultHandlerProvider>::default_error_handler; - struct yOMM2_API_gcc release : basic_policy< release, std_rtti, fast_perfect_hash, vptr_vector, @@ -511,40 +42,6 @@ struct yOMM2_API_gcc debug basic_error_output, basic_trace_output, vectored_error> {}; -#if defined(_MSC_VER) && !defined(yOMM2_DLL) -extern template class __declspec(dllimport) basic_domain; -extern template class __declspec(dllimport) vptr_vector; -extern template class __declspec(dllimport) fast_perfect_hash; -extern template class __declspec(dllimport) checked_perfect_hash; -extern template class __declspec(dllimport) -basic_trace_output; -extern template class __declspec(dllimport) -basic_error_output; -extern template class __declspec(dllimport) checked_perfect_hash; -extern template class __declspec(dllimport) vectored_error; -extern template class __declspec(dllimport) basic_policy< - debug_shared, vptr_vector, std_rtti, - checked_perfect_hash, basic_error_output, - basic_trace_output, vectored_error>; -#endif - -#ifndef BOOST_NO_RTTI -struct yOMM2_API_gcc debug_shared - : basic_policy< - debug_shared, std_rtti, checked_perfect_hash, - vptr_vector, basic_error_output, - basic_trace_output, vectored_error> {}; - -struct yOMM2_API_gcc release_shared : debug_shared { - template - static const std::uintptr_t* dynamic_vptr(const Class& arg) { - auto index = dynamic_type(arg); - index = fast_perfect_hash::hash_type_id(index); - return vptrs[index]; - } -}; -#endif - #ifdef NDEBUG using default_static = policy::release; #else diff --git a/include/yorel/yomm2/templates.hpp b/include/yorel/yomm2/templates.hpp index cd5c240c..f8e37573 100644 --- a/include/yorel/yomm2/templates.hpp +++ b/include/yorel/yomm2/templates.hpp @@ -14,32 +14,32 @@ namespace yorel { namespace yomm2 { -using boost::mp11::mp_list; +using detail::types; struct not_defined {}; template typename Template> struct template_ { template - using fn = boost::mp11::mp_apply>; + using fn = boost::mp11::mp_apply>; // using fn = Template would not work because Template is not // necessarily variadic, but mp_apply can cope with this situation. }; template typename... Templates> -using templates = mp_list...>; +using templates = types...>; namespace detail { // template