Hello community, here is the log from the commit of package xtl for openSUSE:Factory checked in at 2020-09-16 19:38:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xtl (Old) and /work/SRC/openSUSE:Factory/.xtl.new.4249 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xtl" Wed Sep 16 19:38:49 2020 rev:3 rq:834832 version:0.6.18 Changes: -------- --- /work/SRC/openSUSE:Factory/xtl/xtl.changes 2020-08-18 12:02:55.639422522 +0200 +++ /work/SRC/openSUSE:Factory/.xtl.new.4249/xtl.changes 2020-09-16 19:38:56.382772228 +0200 @@ -1,0 +2,9 @@ +Fri Sep 4 20:44:59 UTC 2020 - Dirk Mueller <[email protected]> + +- update to 0.6.18: + - Replaced throw with XTL_THROW to support disabling exceptions + - Implemented ``index_of`` for ``mpl::vector`` + - Implemented multimethods pattern + - Implemented visitor pattern + +------------------------------------------------------------------- Old: ---- xtl-0.6.16.tar.gz New: ---- xtl-0.6.18.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xtl.spec ++++++ --- /var/tmp/diff_new_pack.pHU7Y3/_old 2020-09-16 19:38:57.950773991 +0200 +++ /var/tmp/diff_new_pack.pHU7Y3/_new 2020-09-16 19:38:57.954773996 +0200 @@ -17,7 +17,7 @@ Name: xtl -Version: 0.6.16 +Version: 0.6.18 Release: 0 Summary: The x template library License: BSD-3-Clause ++++++ xtl-0.6.16.tar.gz -> xtl-0.6.18.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/CMakeLists.txt new/xtl-0.6.18/CMakeLists.txt --- old/xtl-0.6.16/CMakeLists.txt 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/CMakeLists.txt 2020-09-02 11:10:31.000000000 +0200 @@ -56,6 +56,7 @@ ${XTL_INCLUDE_DIR}/xtl/xmasked_value_meta.hpp ${XTL_INCLUDE_DIR}/xtl/xmasked_value.hpp ${XTL_INCLUDE_DIR}/xtl/xmeta_utils.hpp + ${XTL_INCLUDE_DIR}/xtl/xmultimethods.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional_meta.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional.hpp ${XTL_INCLUDE_DIR}/xtl/xoptional_sequence.hpp @@ -65,6 +66,7 @@ ${XTL_INCLUDE_DIR}/xtl/xtype_traits.hpp ${XTL_INCLUDE_DIR}/xtl/xvariant.hpp ${XTL_INCLUDE_DIR}/xtl/xvariant_impl.hpp + ${XTL_INCLUDE_DIR}/xtl/xvisitor.hpp ) add_library(xtl INTERFACE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/docs/source/changelog.rst new/xtl-0.6.18/docs/source/changelog.rst --- old/xtl-0.6.16/docs/source/changelog.rst 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/docs/source/changelog.rst 2020-09-02 11:10:31.000000000 +0200 @@ -7,6 +7,19 @@ Changelog ========= +0.6.18 +------ + +- Relaxed dimension constraint on multidispatcher +- Replaced throw with XTL_THROW to support disabling exceptions + +0.6.17 +------ + +- Implemented ``index_of`` for ``mpl::vector`` +- Implemented multimethods pattern +- Implemented visitor pattern + 0.6.16 ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/include/xtl/xmeta_utils.hpp new/xtl-0.6.18/include/xtl/xmeta_utils.hpp --- old/xtl-0.6.16/include/xtl/xmeta_utils.hpp 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/include/xtl/xmeta_utils.hpp 2020-09-02 11:10:31.000000000 +0200 @@ -11,6 +11,7 @@ #define XTL_XMETA_UTILS_HPP #include <cstddef> +#include <cstdint> #include <type_traits> #include "xfunctional.hpp" @@ -224,6 +225,40 @@ { }; + /************ + * index_of * + ************/ + + namespace detail + { + template <class L, class V> + struct index_of_impl; + + template <template <class...> class L, class V> + struct index_of_impl<L<>, V> + { + static constexpr size_t value = SIZE_MAX; + }; + + template <template <class...> class L, class... T, class V> + struct index_of_impl<L<V, T...>, V> + { + static constexpr size_t value = 0u; + }; + + template <template <class...> class L, class U, class... T, class V> + struct index_of_impl<L<U, T...>, V> + { + static constexpr size_t tmp = index_of_impl<L<T...>, V>::value; + static constexpr size_t value = tmp == SIZE_MAX ? SIZE_MAX : 1u + tmp; + }; + } + + template <class L, class T> + struct index_of : detail::index_of_impl<L, T> + { + }; + /************ * contains * ************/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/include/xtl/xmultimethods.hpp new/xtl-0.6.18/include/xtl/xmultimethods.hpp --- old/xtl-0.6.16/include/xtl/xmultimethods.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/xtl-0.6.18/include/xtl/xmultimethods.hpp 2020-09-02 11:10:31.000000000 +0200 @@ -0,0 +1,417 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTL_MULTIMETHODS_HPP +#define XTL_MULTIMETHODS_HPP + +#include <array> +#include <cstdint> +#include <functional> +#include <map> +#include <typeindex> +#include <type_traits> +#include <vector> + +#include "xmeta_utils.hpp" + +namespace xtl +{ + // Loki's multimethods ported to modern C++ and generalized to N arguments + // Original implementation can be found at + // https://github.com/snaewe/loki-lib/blob/master/include/loki/MultiMethods.h + + struct symmetric_dispatch {}; + struct antisymmetric_dispatch {}; + + /********************* + * static_dispatcher * + *********************/ + + template + < + class executor, + class base_lhs, + class lhs_type_list, + class return_type = void, + class symmetric = antisymmetric_dispatch, + class base_rhs = base_lhs, + class rhs_type_list = lhs_type_list + > + class static_dispatcher + { + private: + + template <class lhs_type, class rhs_type> + static return_type invoke_executor(lhs_type& lhs, + rhs_type& rhs, + executor& exec, + std::false_type) + { + return exec.run(lhs, rhs); + } + + template <class lhs_type, class rhs_type> + static return_type invoke_executor(lhs_type& lhs, + rhs_type& rhs, + executor& exec, + std::true_type) + { + return exec.run(rhs, lhs); + } + + template <class lhs_type> + static return_type dispatch_rhs(lhs_type& lhs, + base_rhs& rhs, + executor& exec, + mpl::vector<>) + { + return exec.on_error(lhs, rhs); + } + + template <class lhs_type, class T, class... U> + static return_type dispatch_rhs(lhs_type& lhs, + base_rhs& rhs, + executor& exec, + mpl::vector<T, U...>) + { + if (T* p = dynamic_cast<T*>(&rhs)) + { + constexpr size_t lhs_index = mpl::index_of<lhs_type_list, lhs_type>::value; + constexpr size_t rhs_index = mpl::index_of<rhs_type_list, T>::value; + + using invoke_flag = std::integral_constant<bool, + std::is_same<symmetric, symmetric_dispatch>::value && (rhs_index < lhs_index)>; + return invoke_executor(lhs, *p, exec, invoke_flag()); + } + return dispatch_rhs(lhs, rhs, exec, mpl::vector<U...>()); + } + + static return_type dispatch_lhs(base_lhs& lhs, + base_rhs& rhs, + executor& exec, + mpl::vector<>) + { + return exec.on_error(lhs, rhs); + } + + template <class T, class... U> + static return_type dispatch_lhs(base_lhs& lhs, + base_rhs& rhs, + executor& exec, + mpl::vector<T, U...>) + { + if (T* p = dynamic_cast<T*>(&lhs)) + { + return dispatch_rhs(*p, rhs, exec, rhs_type_list()); + } + return dispatch_lhs(lhs, rhs, exec, mpl::vector<U...>()); + } + + public: + + static return_type dispatch(base_lhs& lhs, base_rhs& rhs, executor& exec) + { + return dispatch_lhs(lhs, rhs, exec, lhs_type_list()); + } + }; + + // TODO: generalize to N-D with mpl::vector of mpl:vector + // Warning: this is hardcore ;) + + /******************** + * basic_dispatcher * + ********************/ + + template + < + class type_list, + class return_type, + class callback_type + > + class basic_dispatcher; + + template + < + class return_type, + class callback_type, + class... B + > + class basic_dispatcher<mpl::vector<B...>, return_type, callback_type> + { + private: + + using key_type = std::array<std::type_index, sizeof...(B)>; + using map_type = std::map<key_type, callback_type>; + map_type m_callback_map; + + template <class... U> + key_type make_key() const + { + return {{std::type_index(typeid(U))...}}; + } + + public: + + template <class... D> + void insert(callback_type&& cb) + { + static_assert(sizeof...(D) == sizeof...(B), + "Number of callback arguments must match dispatcher dimension"); + m_callback_map[make_key<D...>()] = std::move(cb); + } + + template <class... D> + void erase() + { + static_assert(sizeof...(D) == sizeof...(B), + "Number of callback arguments must match dispatcher dimension"); + m_callback_map.erase(make_key<D...>()); + } + + inline return_type dispatch(B&... args) const + { + key_type k = {{std::type_index(typeid(args))...}}; + auto it = m_callback_map.find(k); + if (it == m_callback_map.end()) + { + XTL_THROW(std::runtime_error, "callback not found"); + } + return (it->second)(args...); + } + }; + + /************************* + * basic_fast_dispatcher * + *************************/ + +#define XTL_IMPLEMENT_INDEXABLE_CLASS() \ + static size_t& get_class_static_index() \ + { \ + static size_t index = SIZE_MAX; \ + return index; \ + } \ + virtual size_t get_class_index() const \ + { \ + return get_class_static_index(); \ + } + + namespace detail + { + template <class T> + class recursive_container_impl : private std::vector<T> + { + public: + + using base_type = std::vector<T>; + + using base_type::base_type; + using base_type::operator[]; + using base_type::size; + using base_type::resize; + }; + + template <class callback_type, size_t level> + class recursive_container + : public recursive_container_impl<recursive_container<callback_type, level-1>> + { + }; + + template <class callback> + class recursive_container<callback, 0> + : public recursive_container_impl<callback> + { + }; + } + + template + < + class type_list, + class return_type, + class callback_type + > + class basic_fast_dispatcher; + + template + < + class return_type, + class callback_type, + class... B + > + class basic_fast_dispatcher<mpl::vector<B...>, return_type, callback_type> + { + private: + + static constexpr size_t nb_args = sizeof...(B); + + using storage_type = detail::recursive_container<callback_type, sizeof...(B) - 1>; + using index_type = std::array<size_t, nb_args>; + using index_ref_type = std::array<std::reference_wrapper<size_t>, nb_args>; + + storage_type m_callbacks; + size_t m_next_index; + + template <size_t I, class C> + void resize_container(C& c, const index_ref_type& index) + { + size_t& idx = index[I]; + if (idx == SIZE_MAX) + { + c.resize(++m_next_index); + idx = c.size() - 1u; + } + else if(c.size() <= idx) + { + c.resize(idx + 1u); + } + } + + template <size_t I, class C> + std::enable_if_t<I + 1 == nb_args> + insert_impl(callback_type&& cb, C& c, const index_ref_type& index) + { + resize_container<I>(c, index); + c[index[I]] = std::move(cb); + } + + template <size_t I, class C> + std::enable_if_t<I + 1 != nb_args> + insert_impl(callback_type&& cb, C& c, const index_ref_type& index) + { + resize_container<I>(c, index); + insert_impl<I+1>(std::move(cb), c[index[I]], index); + } + + template <size_t I, class C> + void check_size(C& c, const index_type& index) const + { + if (index[I] >= c.size()) + { + XTL_THROW(std::runtime_error, "callback not found"); + } + } + + template <size_t I, class C> + std::enable_if_t<I + 1 == nb_args, return_type> + dispatch_impl(C& c, const index_type& index, B&... args) const + { + check_size<I>(c, index); + return c[index[I]](args...); + } + + template <size_t I, class C> + std::enable_if_t<I + 1 != nb_args, return_type> + dispatch_impl(C& c, const index_type& index, B&... args) const + { + check_size<I>(c, index); + return dispatch_impl<I+1>(c[index[I]], index, args...); + } + + public: + + inline basic_fast_dispatcher() + : m_next_index(0) + { + } + + template <class... D> + void insert(callback_type&& cb) + { + static_assert(sizeof...(D) == sizeof...(B), + "Number of callback arguments must match dispatcher dimension"); + index_ref_type index = {{std::ref(D::get_class_static_index())...}}; + insert_impl<0>(std::move(cb), m_callbacks, index); + } + + inline return_type dispatch(B&... args) const + { + index_type index = {{args.get_class_index()...}}; + return dispatch_impl<0>(m_callbacks, index, args...); + } + }; + + /****************************** + * dynamic and static casters * + ******************************/ + + template <class T, class F> + struct static_caster + { + static T& cast(F& f) + { + return static_cast<T&>(f); + } + }; + + template <class T, class F> + struct dynamic_caster + { + static T& cast(F& f) + { + return dynamic_cast<T&>(f); + } + }; + + /********************** + * functor_dispatcher * + **********************/ + + template + < + class type_list, + class return_type, + template <class, class> class casting_policy = dynamic_caster, + template <class, class, class> class dispatcher = basic_dispatcher + > + class functor_dispatcher; + + template + < + class return_type, + template <class, class> class casting_policy, + template <class, class, class> class dispatcher, + class... B + > + class functor_dispatcher<mpl::vector<B...>, return_type, casting_policy, dispatcher> + { + private: + + using functor_type = std::function<return_type (B&...)>; + using backend = dispatcher<mpl::vector<B...>, + return_type, + functor_type>; + backend m_backend; + + public: + + template <class... D, class Fun> + void insert(const Fun& fun) + { + functor_type f([fun](B&... args) -> return_type + { + return fun(casting_policy<D&, B&>::cast(args)...); + }); + m_backend.template insert<D...>(std::move(f)); + } + + template <class... D> + void erase() + { + m_backend.template erase<D...>(); + } + + inline return_type dispatch(B&... args) const + { + return m_backend.dispatch(args...); + } + }; + +} + +#endif + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/include/xtl/xtl_config.hpp new/xtl-0.6.18/include/xtl/xtl_config.hpp --- old/xtl-0.6.16/include/xtl/xtl_config.hpp 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/include/xtl/xtl_config.hpp 2020-09-02 11:10:31.000000000 +0200 @@ -12,7 +12,7 @@ #define XTL_VERSION_MAJOR 0 #define XTL_VERSION_MINOR 6 -#define XTL_VERSION_PATCH 16 +#define XTL_VERSION_PATCH 18 #ifndef __has_feature #define __has_feature(x) 0 @@ -26,4 +26,14 @@ #define XTL_NO_EXCEPTIONS #endif +#if defined(XTL_NO_EXCEPTIONS) +#define XTL_THROW(_, msg) \ + { \ + std::cerr << msg << std::endl; \ + std::abort(); \ + } +#else +#define XTL_THROW(exception, msg) throw exception(msg) +#endif + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/include/xtl/xvisitor.hpp new/xtl-0.6.18/include/xtl/xvisitor.hpp --- old/xtl-0.6.16/include/xtl/xvisitor.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/xtl-0.6.18/include/xtl/xvisitor.hpp 2020-09-02 11:10:31.000000000 +0200 @@ -0,0 +1,195 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTL_VISITOR_HPP +#define XTL_VISITOR_HPP + +#include <stdexcept> +#include "xmeta_utils.hpp" + +namespace xtl +{ + // Loki's visitor ported to C++14 + // Original implementation can be found at: + // https://github.com/snaewe/loki-lib/blob/master/include/loki/Visitor.h + + /**************** + * base_visitor * + ****************/ + + class base_visitor + { + public: + + virtual ~base_visitor() = default; + }; + + /*********** + * visitor * + ***********/ + + template <class T, class R = void, bool is_const = true> + class visitor + { + public: + + using return_type = R; + using param_type = std::conditional_t<is_const, const T, T>; + + virtual ~visitor() = default; + + virtual return_type visit(param_type&) = 0; + }; + + template <class R, bool is_const> + class visitor<mpl::vector<>, R, is_const> + { + }; + + template <class R, bool is_const, class T, class... U> + class visitor<mpl::vector<T, U...>, R, is_const> + : public visitor<T, R, is_const> + , public visitor<mpl::vector<U...>, R, is_const> + { + }; + + /********************** + * catch_all policies * + **********************/ + + template <class R, class T> + struct default_catch_all + { + static R on_unknown_visitor(T&, base_visitor&) + { + return R(); + } + }; + + template <class R, class T> + struct throwing_catch_all + { + static R on_unknown_visitor(T&, base_visitor&) + { + XTL_THROW(std::runtime_error, "Unknown visited type"); + } + }; + + /****************** + * base_visitable * + ******************/ + + template + < + class R = void, + bool const_visitable = false, + template <class, class> class catch_all = default_catch_all + > + class base_visitable; + + template <class R, template <class, class> class catch_all> + class base_visitable<R, false, catch_all> + { + public: + + using return_type = R; + + virtual ~base_visitable() = default; + virtual return_type accept(base_visitor&) = 0; + + protected: + + template <class T> + static return_type accept_impl(T& visited, base_visitor& vis) + { + if (auto* p = dynamic_cast<visitor<T, R, false>*>(&vis)) + { + return p->visit(visited); + } + return catch_all<R, T>::on_unknown_visitor(visited, vis); + } + }; + + template <class R, template <class, class> class catch_all> + class base_visitable<R, true, catch_all> + { + public: + + using return_type = R; + + virtual ~base_visitable() = default; + virtual return_type accept(base_visitor&) const = 0; + + protected: + + template <class T> + static return_type accept_impl(const T& visited, base_visitor& vis) + { + if (auto* p = dynamic_cast<visitor<T, R, true>*>(&vis)) + { + return p->visit(visited); + } + return catch_all<R, const T>::on_unknown_visitor(visited, vis); + } + }; + + /************************ + * XTL_DEFINE_VISITABLE * + ************************/ + +#define XTL_DEFINE_VISITABLE() \ + return_type accept(::xtl::base_visitor& vis) override \ + { return accept_impl(*this, vis); } + +#define XTL_DEFINE_CONST_VISITABLE() \ + return_type accept(::xtl::base_visitor& vis) const override \ + { return accept_impl(*this, vis); } + + /****************** + * cyclic_visitor * + ******************/ + + template <class T, class R, bool is_const = true> + class cyclic_visitor; + + template <class R, bool is_const, class... T> + class cyclic_visitor<mpl::vector<T...>, R, is_const> + : public visitor<mpl::vector<T...>, R, is_const> + { + public: + + using return_type = R; + + template <class V> + return_type generic_visit(V& visited) + { + visitor<std::remove_const_t<V>, return_type, is_const>& sub_obj = *this; + return sub_obj.visit(visited); + } + }; + + /******************************* + * XTL_DEFINE_CYCLIC_VISITABLE * + *******************************/ + +#define XTL_DEFINE_CYCLIC_VISITABLE(some_visitor) \ + virtual some_visitor::return_type accept(some_visitor& vis) \ + { \ + return vis.generic_visit(*this); \ + } + +#define XTL_DEFINE_CONST_CYCLIC_VISITABLE(some_visitor) \ + virtual some_visitor::return_type accept(some_visitor& vis) const \ + { \ + return vis.generic_visit(*this); \ + } +} + +#endif + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/test/CMakeLists.txt new/xtl-0.6.18/test/CMakeLists.txt --- old/xtl-0.6.16/test/CMakeLists.txt 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/test/CMakeLists.txt 2020-09-02 11:10:31.000000000 +0200 @@ -127,11 +127,13 @@ test_xiterator_base.cpp test_xmasked_value.cpp test_xmeta_utils.cpp + test_xmultimethods.cpp test_xoptional.cpp test_xsequence.cpp test_xtype_traits.cpp test_xproxy_wrapper.cpp test_xvariant.cpp + test_xvisitor.cpp ) if(nlohmann_json_FOUND) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/test/test_xmeta_utils.cpp new/xtl-0.6.18/test/test_xmeta_utils.cpp --- old/xtl-0.6.16/test/test_xmeta_utils.cpp 2020-08-11 11:44:33.000000000 +0200 +++ new/xtl-0.6.18/test/test_xmeta_utils.cpp 2020-09-02 11:10:31.000000000 +0200 @@ -88,6 +88,20 @@ EXPECT_FALSE(res3); } + TEST(mpl, index_of) + { + using type1 = mpl::vector<int, double, float>; + std::size_t res1 = mpl::index_of<type1, int>::value; + std::size_t res2 = mpl::index_of<type1, double>::value; + std::size_t res3 = mpl::index_of<type1, float>::value; + std::size_t res4 = mpl::index_of<type1, short>::value; + + EXPECT_EQ(res1, 0u); + EXPECT_EQ(res2, 1u); + EXPECT_EQ(res3, 2u); + EXPECT_EQ(res4, SIZE_MAX); + } + TEST(mpl, front) { using type = mpl::front_t<variant_t>; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/test/test_xmultimethods.cpp new/xtl-0.6.18/test/test_xmultimethods.cpp --- old/xtl-0.6.16/test/test_xmultimethods.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/xtl-0.6.18/test/test_xmultimethods.cpp 2020-09-02 11:10:31.000000000 +0200 @@ -0,0 +1,245 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#include <iostream> +#include "xtl/xmultimethods.hpp" + +#include "gtest/gtest.h" + +namespace xtl +{ + enum class shape_id + { + unknown_id, + rectangle_id, + circle_id, + triangle_id + }; + + class shape + { + public: + + XTL_IMPLEMENT_INDEXABLE_CLASS() + + virtual ~shape() = default; + + shape(const shape&) = delete; + shape(shape&&) = delete; + + shape& operator=(const shape&) = delete; + shape& operator=(shape&&) = delete; + + protected: + + shape() = default; + }; + + template <shape_id id> + class shape_impl : public shape + { + public: + + XTL_IMPLEMENT_INDEXABLE_CLASS() + + shape_impl() = default; + virtual ~shape_impl() = default; + + shape_id get_id() const + { + return id; + } + }; + + using rectangle = shape_impl<shape_id::rectangle_id>; + using circle = shape_impl<shape_id::circle_id>; + using triangle = shape_impl<shape_id::triangle_id>; + + using dispatch_return_type = std::pair<shape_id, shape_id>; + + namespace + { + template <class T1, class T2> + dispatch_return_type dispatch_shape_impl(const T1& t1, const T2& t2) + { + return std::make_pair(t1.get_id(), t2.get_id()); + } + +#define DEFINE_DISPATCH_SHAPE(T1, T2) \ + dispatch_return_type dispatch_##T1##_##T2(const T1& t1, const T2& t2) \ + { return dispatch_shape_impl(t1, t2); } + + DEFINE_DISPATCH_SHAPE(rectangle, circle) + DEFINE_DISPATCH_SHAPE(rectangle, triangle) + DEFINE_DISPATCH_SHAPE(circle, rectangle) + DEFINE_DISPATCH_SHAPE(circle, triangle) + DEFINE_DISPATCH_SHAPE(triangle, rectangle) + DEFINE_DISPATCH_SHAPE(triangle, circle) + } + + class dispatch_tester + { + public: + + using return_type = dispatch_return_type; + + template <class T1, class T2> + return_type run(const T1& t1, const T2& t2) const + { + return dispatch_shape_impl(t1, t2); + } + + return_type on_error(const shape&, const shape&) const + { + return std::make_pair(shape_id::unknown_id, shape_id::unknown_id); + } + }; + + TEST(multimethods, static_dispatch) + { + using return_type = dispatch_tester::return_type; + using dispatcher_type = static_dispatcher + < + dispatch_tester, + const shape, + mpl::vector<const rectangle, const circle, const triangle>, + return_type + >; + rectangle r; + circle c; + triangle t; + shape* p1 = &r; + shape* p2 = &c; + shape* p3 = &t; + dispatch_tester tester; + + return_type r1 = dispatcher_type::dispatch(*p1, *p2, tester); + return_type r2 = dispatcher_type::dispatch(*p1, *p3, tester); + return_type r3 = dispatcher_type::dispatch(*p2, *p1, tester); + return_type r4 = dispatcher_type::dispatch(*p2, *p3, tester); + return_type r5 = dispatcher_type::dispatch(*p3, *p1, tester); + return_type r6 = dispatcher_type::dispatch(*p3, *p2, tester); + + EXPECT_EQ(r1, return_type(shape_id::rectangle_id, shape_id::circle_id)); + EXPECT_EQ(r2, return_type(shape_id::rectangle_id, shape_id::triangle_id)); + EXPECT_EQ(r3, return_type(shape_id::circle_id, shape_id::rectangle_id)); + EXPECT_EQ(r4, return_type(shape_id::circle_id, shape_id::triangle_id)); + EXPECT_EQ(r5, return_type(shape_id::triangle_id, shape_id::rectangle_id)); + EXPECT_EQ(r6, return_type(shape_id::triangle_id, shape_id::circle_id)); + } + + TEST(multimethods, static_dispatch_symmetry) + { + using return_type = dispatch_tester::return_type; + using dispatcher_type = static_dispatcher + < + dispatch_tester, + const shape, + mpl::vector<const rectangle, const circle, const triangle>, + return_type, + symmetric_dispatch + >; + rectangle r; + circle c; + triangle t; + shape* p1 = &r; + shape* p2 = &c; + shape* p3 = &t; + dispatch_tester tester; + + return_type r1 = dispatcher_type::dispatch(*p1, *p2, tester); + return_type r2 = dispatcher_type::dispatch(*p1, *p3, tester); + return_type r3 = dispatcher_type::dispatch(*p2, *p1, tester); + return_type r4 = dispatcher_type::dispatch(*p2, *p3, tester); + return_type r5 = dispatcher_type::dispatch(*p3, *p1, tester); + return_type r6 = dispatcher_type::dispatch(*p3, *p2, tester); + + EXPECT_EQ(r1, return_type(shape_id::rectangle_id, shape_id::circle_id)); + EXPECT_EQ(r2, return_type(shape_id::rectangle_id, shape_id::triangle_id)); + EXPECT_EQ(r3, return_type(shape_id::rectangle_id, shape_id::circle_id)); + EXPECT_EQ(r4, return_type(shape_id::circle_id, shape_id::triangle_id)); + EXPECT_EQ(r5, return_type(shape_id::rectangle_id, shape_id::triangle_id)); + EXPECT_EQ(r6, return_type(shape_id::circle_id, shape_id::triangle_id)); + } + + template <class D> + void test_function_dispatcher() + { + using dispatcher_type = D; + using return_type = dispatch_return_type; + dispatcher_type d; + d.template insert<const rectangle, const circle>(&dispatch_rectangle_circle); + d.template insert<const rectangle, const triangle>(&dispatch_rectangle_triangle); + d.template insert<const circle, const rectangle>(&dispatch_circle_rectangle); + d.template insert<const circle, const triangle>(&dispatch_circle_triangle); + d.template insert<const triangle, const rectangle>(&dispatch_triangle_rectangle); + d.template insert<const triangle, const circle>(&dispatch_triangle_circle); + + rectangle r; + circle c; + triangle t; + shape* p1 = &r; + shape* p2 = &c; + shape* p3 = &t; + + return_type r1 = d.dispatch(*p1, *p2); + return_type r2 = d.dispatch(*p1, *p3); + return_type r3 = d.dispatch(*p2, *p1); + return_type r4 = d.dispatch(*p2, *p3); + return_type r5 = d.dispatch(*p3, *p1); + return_type r6 = d.dispatch(*p3, *p2); + + EXPECT_EQ(r1, return_type(shape_id::rectangle_id, shape_id::circle_id)); + EXPECT_EQ(r2, return_type(shape_id::rectangle_id, shape_id::triangle_id)); + EXPECT_EQ(r3, return_type(shape_id::circle_id, shape_id::rectangle_id)); + EXPECT_EQ(r4, return_type(shape_id::circle_id, shape_id::triangle_id)); + EXPECT_EQ(r5, return_type(shape_id::triangle_id, shape_id::rectangle_id)); + EXPECT_EQ(r6, return_type(shape_id::triangle_id, shape_id::circle_id)); + } + + TEST(multimethods, function_dispatcher) + { + using return_type = dispatch_return_type; + using dispatcher_type = functor_dispatcher + < + mpl::vector<const shape, const shape>, + return_type + >; + + test_function_dispatcher<dispatcher_type>(); + } + + TEST(multimethods, function_dispatcher_static_cast) + { + using return_type = dispatch_return_type; + using dispatcher_type = functor_dispatcher + < + mpl::vector<const shape, const shape>, + return_type, + static_caster + >; + + test_function_dispatcher<dispatcher_type>(); + } + + TEST(multimethods, fast_function_dispatcher) + { + using return_type = dispatch_return_type; + using dispatcher_type = functor_dispatcher + < + mpl::vector<const shape, const shape>, + return_type, + static_caster, + basic_fast_dispatcher + >; + + test_function_dispatcher<dispatcher_type>(); + } +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xtl-0.6.16/test/test_xvisitor.cpp new/xtl-0.6.18/test/test_xvisitor.cpp --- old/xtl-0.6.16/test/test_xvisitor.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/xtl-0.6.18/test/test_xvisitor.cpp 2020-09-02 11:10:31.000000000 +0200 @@ -0,0 +1,236 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#include "xtl/xvisitor.hpp" + +#include "gtest/gtest.h" + +namespace xtl +{ + class root : public base_visitable<int, false> + { + public: + + XTL_DEFINE_VISITABLE() + }; + + class leaf_one : public root + { + public: + + XTL_DEFINE_VISITABLE() + }; + + class leaf_two : public root + { + public: + + XTL_DEFINE_VISITABLE() + }; + + class acyclic_visitor_tester + : public base_visitor + , public visitor<mpl::vector<leaf_one, leaf_two>, int, false> + { + public: + + int visit(leaf_one&) override + { + return 1; + } + + int visit(leaf_two&) override + { + return 2; + } + }; + + TEST(visitor, acyclic_visitor) + { + leaf_one l1; + leaf_two l2; + root* r1 = &l1; + root* r2 = &l2; + + acyclic_visitor_tester t; + + int res1 = r1->accept(t); + EXPECT_EQ(res1, 1); + + int res2 = r2->accept(t); + EXPECT_EQ(res2, 2); + } + + class const_root : public base_visitable<int, true> + { + public: + + XTL_DEFINE_CONST_VISITABLE() + }; + + class const_leaf_one : public const_root + { + public: + + XTL_DEFINE_CONST_VISITABLE() + }; + + class const_leaf_two : public const_root + { + public: + + XTL_DEFINE_CONST_VISITABLE() + }; + + class const_acyclic_visitor_tester + : public base_visitor + , public visitor<mpl::vector<const_leaf_one, const_leaf_two>, int, true> + { + public: + + int visit(const const_leaf_one&) override + { + return 1; + } + + int visit(const const_leaf_two&) override + { + return 2; + } + }; + + TEST(visitor, const_acyclic_visitor) + { + const_leaf_one l1; + const_leaf_two l2; + const_root* r1 = &l1; + const_root* r2 = &l2; + + const_acyclic_visitor_tester t; + + int res1 = r1->accept(t); + EXPECT_EQ(res1, 1); + + int res2 = r2->accept(t); + EXPECT_EQ(res2, 2); + } + + class cleaf_one; + class cleaf_two; + + class cyclic_visitor_tester + : public cyclic_visitor<mpl::vector<cleaf_one, cleaf_two>, int, false> + { + public: + + int visit(cleaf_one&) override + { + return 1; + } + + int visit(cleaf_two&) override + { + return 2; + } + }; + + class croot + { + public: + + virtual int accept(cyclic_visitor_tester&) = 0; + }; + + class cleaf_one : public croot + { + public: + + XTL_DEFINE_CYCLIC_VISITABLE(cyclic_visitor_tester) + }; + + class cleaf_two : public croot + { + public: + + XTL_DEFINE_CYCLIC_VISITABLE(cyclic_visitor_tester) + }; + + TEST(visitor, cyclic_visitor) + { + cleaf_one l1; + cleaf_two l2; + croot* r1 = &l1; + croot* r2 = &l2; + + cyclic_visitor_tester t; + + int res1 = r1->accept(t); + EXPECT_EQ(res1, 1); + + int res2 = r2->accept(t); + EXPECT_EQ(res2, 2); + } + + class ccleaf_one; + class ccleaf_two; + + class ccyclic_visitor_tester + : public cyclic_visitor<mpl::vector<ccleaf_one, ccleaf_two>, int, true> + { + public: + + int visit(const ccleaf_one&) override + { + return 1; + } + + int visit(const ccleaf_two&) override + { + return 2; + } + }; + + class ccroot + { + public: + + virtual int accept(ccyclic_visitor_tester&) const = 0; + }; + + class ccleaf_one : public ccroot + { + public: + + XTL_DEFINE_CONST_CYCLIC_VISITABLE(ccyclic_visitor_tester) + }; + + class ccleaf_two : public ccroot + { + public: + + XTL_DEFINE_CONST_CYCLIC_VISITABLE(ccyclic_visitor_tester) + }; + + TEST(visitor, const_cyclic_visitor) + { + ccleaf_one l1; + ccleaf_two l2; + ccroot* r1 = &l1; + ccroot* r2 = &l2; + + ccyclic_visitor_tester t; + + int res1 = r1->accept(t); + EXPECT_EQ(res1, 1); + + int res2 = r2->accept(t); + EXPECT_EQ(res2, 2); + } +} +
