From 73d1da4f86e4f5abd6a3fdb58097e1762576326c Mon Sep 17 00:00:00 2001 From: Marc Chevrier Date: Mon, 20 Jan 2020 18:12:35 +0100 Subject: Stl support: cm::append now supports any sequential container --- Tests/CMakeLib/testCMExtAlgorithm.cxx | 1 + Utilities/std/cmext/algorithm | 143 ++++++++++++++++++++++++++++++---- Utilities/std/cmext/type_traits | 18 +++++ 3 files changed, 146 insertions(+), 16 deletions(-) diff --git a/Tests/CMakeLib/testCMExtAlgorithm.cxx b/Tests/CMakeLib/testCMExtAlgorithm.cxx index c731b72..b8319c3 100644 --- a/Tests/CMakeLib/testCMExtAlgorithm.cxx +++ b/Tests/CMakeLib/testCMExtAlgorithm.cxx @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/Utilities/std/cmext/algorithm b/Utilities/std/cmext/algorithm index 609860c..44e61f4 100644 --- a/Utilities/std/cmext/algorithm +++ b/Utilities/std/cmext/algorithm @@ -10,43 +10,154 @@ #include #include #include -#include #include #include +#if defined(__SUNPRO_CC) && defined(__sparc) +# include +# include +#else +# include +#endif + namespace cm { -template -void append(std::vector>& v, - std::vector>&& r) +#if defined(__SUNPRO_CC) && defined(__sparc) +// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile +// templates with constraints. +// So, on this platform, use only simple templates. +# define APPEND_TWO(C1, C2) \ + template \ + void append(C1>& v, C2>&& r) \ + { \ + std::transform( \ + r.begin(), r.end(), std::back_inserter(v), \ + [](std::unique_ptr& item) { return std::move(item); }); \ + r.clear(); \ + } \ + \ + template \ + void append(C1& v, C2> const& r) \ + { \ + std::transform( \ + r.begin(), r.end(), std::back_inserter(v), \ + [](const std::unique_ptr& item) { return item.get(); }); \ + } + +# define APPEND_ONE(C) \ + template ::value, int> = \ + 0> \ + void append(C& v, InputIt first, InputIt last) \ + { \ + v.insert(v.end(), first, last); \ + } \ + \ + template ::value, int> = 0> \ + void append(C& v, Range const& r) \ + { \ + v.insert(v.end(), r.begin(), r.end()); \ + } + +# define APPEND(C) \ + APPEND_TWO(C, C) \ + APPEND_ONE(C) + +# define APPEND_MIX(C1, C2) \ + APPEND_TWO(C1, C2) \ + APPEND_TWO(C2, C1) + +// For now, manage only support for std::vector and std::list. +// Other sequential container support can be added if needed. +APPEND(std::vector) +APPEND(std::list) +APPEND_MIX(std::vector, std::list) + +# undef APPEND +# undef APPEND_MIX +# undef APPEND_TWO +# undef APPEND_ONE + +#else + +template < + typename Container1, typename Container2, + cm::enable_if_t< + cm::is_sequence_container::value && + cm::is_unique_ptr::value && + cm::is_unique_ptr::value && + std::is_convertible::value, + int> = 0> +void append(Container1& v, Container2&& r) { - std::transform(r.begin(), r.end(), std::back_inserter(v), - [](std::unique_ptr& item) { return std::move(item); }); + std::transform( + r.begin(), r.end(), std::back_inserter(v), + [](typename Container2::value_type& item) { return std::move(item); }); r.clear(); } -template -void append(std::vector& v, std::vector> const& r) +template ::value && + std::is_pointer::value && + cm::is_unique_ptr::value && + std::is_convertible::value, + int> = 0> +# if defined(__SUNPRO_CC) +void append(Container1& v, Container2 const& r, detail::overload_selector<0>) +# else +void append(Container1& v, Container2 const& r) +# endif { - std::transform(r.begin(), r.end(), std::back_inserter(v), - [](const std::unique_ptr& item) { return item.get(); }); + std::transform( + r.begin(), r.end(), std::back_inserter(v), + [](const typename Container2::value_type& item) { return item.get(); }); } -template ::value, int> = 0> -void append(std::vector& v, InputIt first, InputIt last) +template < + typename Container, typename InputIt, + cm::enable_if_t< + cm::is_sequence_container::value && + cm::is_input_iterator::value && + std::is_convertible::value_type, + typename Container::value_type>::value, + int> = 0> +void append(Container& v, InputIt first, InputIt last) { v.insert(v.end(), first, last); } -template ::value, int> = 0> -void append(std::vector& v, Range const& r) +template ::value && + cm::is_input_range::value && + !cm::is_unique_ptr::value && + !cm::is_unique_ptr::value && + std::is_convertible::value, + int> = 0> +# if defined(__SUNPRO_CC) +void append(Container& v, Range const& r, detail::overload_selector<1>) +# else +void append(Container& v, Range const& r) +# endif { v.insert(v.end(), r.begin(), r.end()); } +# if defined(__SUNPRO_CC) +template +void append(T& v, U const& r) +{ + cm::append(v, r, detail::overload_selector<1>{}); +} +# endif +#endif + } // namespace cm #endif diff --git a/Utilities/std/cmext/type_traits b/Utilities/std/cmext/type_traits index da6550d..00984cb 100644 --- a/Utilities/std/cmext/type_traits +++ b/Utilities/std/cmext/type_traits @@ -10,6 +10,24 @@ namespace cm { +#if defined(__SUNPRO_CC) +// Oracle DeveloperStudio C++ compiler do not support overloaded templates with +// same signature but different constraints over template arguments +// (i.e. meta-programming). +// As a work-around, use a structure to avoid templates with same signature. +namespace detail { +template +struct overload_selector : overload_selector +{ +}; + +template <> +struct overload_selector<0> +{ +}; +} +#endif + // type traits for managed pointer types template struct is_unique_ptr : std::false_type -- cgit v0.12