| // -*-c++-*- |
| // vim: set ft=cpp: |
| |
| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #ifndef cmext_algorithm |
| #define cmext_algorithm |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <memory> |
| #include <utility> |
| |
| #include <cm/type_traits> |
| #include <cmext/iterator> |
| #include <cmext/type_traits> |
| |
| #if defined(__SUNPRO_CC) && defined(__sparc) |
| # include <list> |
| # include <vector> |
| #endif |
| |
| namespace cm { |
| |
| #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 <typename T, typename U> \ |
| void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \ |
| { \ |
| std::transform( \ |
| r.begin(), r.end(), std::back_inserter(v), \ |
| [](std::unique_ptr<U>& item) { return std::move(item); }); \ |
| r.clear(); \ |
| } \ |
| \ |
| template <typename T, typename U> \ |
| void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \ |
| { \ |
| std::transform( \ |
| r.begin(), r.end(), std::back_inserter(v), \ |
| [](const std::unique_ptr<U>& item) { return item.get(); }); \ |
| } |
| |
| # define APPEND_ONE(C) \ |
| template <typename T, typename InputIt, \ |
| cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \ |
| 0> \ |
| void append(C<T>& v, InputIt first, InputIt last) \ |
| { \ |
| v.insert(v.end(), first, last); \ |
| } \ |
| \ |
| template <typename T, typename Range, \ |
| cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \ |
| void append(C<T>& 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<Container1>::value && |
| cm::is_unique_ptr<typename Container1::value_type>::value && |
| cm::is_unique_ptr<typename Container2::value_type>::value && |
| std::is_convertible<typename Container2::value_type::pointer, |
| typename Container1::value_type::pointer>::value, |
| int> = 0> |
| void append(Container1& v, Container2&& r) |
| { |
| std::transform( |
| r.begin(), r.end(), std::back_inserter(v), |
| [](typename Container2::value_type& item) { return std::move(item); }); |
| r.clear(); |
| } |
| |
| template <typename Container1, typename Container2, |
| cm::enable_if_t< |
| cm::is_sequence_container<Container1>::value && |
| std::is_pointer<typename Container1::value_type>::value && |
| cm::is_unique_ptr<typename Container2::value_type>::value && |
| std::is_convertible<typename Container2::value_type::pointer, |
| typename Container1::value_type>::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 typename Container2::value_type& item) { return item.get(); }); |
| } |
| |
| template < |
| typename Container, typename InputIt, |
| cm::enable_if_t< |
| cm::is_sequence_container<Container>::value && |
| cm::is_input_iterator<InputIt>::value && |
| std::is_convertible<typename std::iterator_traits<InputIt>::value_type, |
| typename Container::value_type>::value, |
| int> = 0> |
| void append(Container& v, InputIt first, InputIt last) |
| { |
| v.insert(v.end(), first, last); |
| } |
| |
| template <typename Container, typename Range, |
| cm::enable_if_t< |
| cm::is_sequence_container<Container>::value && |
| cm::is_input_range<Range>::value && |
| !cm::is_unique_ptr<typename Container::value_type>::value && |
| !cm::is_unique_ptr<typename Range::value_type>::value && |
| std::is_convertible<typename Range::value_type, |
| typename Container::value_type>::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 <typename T, typename U> |
| void append(T& v, U const& r) |
| { |
| cm::append(v, r, detail::overload_selector<1>{}); |
| } |
| # endif |
| #endif |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Iterator, typename Key> |
| auto contains(Iterator first, Iterator last, Key const& key, |
| detail::overload_selector<1>) -> decltype(first->first == key) |
| #else |
| template <typename Iterator, typename Key, |
| cm::enable_if_t< |
| cm::is_input_iterator<Iterator>::value && |
| std::is_convertible<Key, |
| typename std::iterator_traits< |
| Iterator>::value_type::first_type>::value, |
| int> = 0> |
| bool contains(Iterator first, Iterator last, Key const& key) |
| #endif |
| { |
| return std::find_if( |
| first, last, |
| [&key]( |
| typename std::iterator_traits<Iterator>::value_type const& item) { |
| return item.first == key; |
| }) != last; |
| } |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Iterator, typename Key> |
| bool contains(Iterator first, Iterator last, Key const& key, |
| detail::overload_selector<0>) |
| #else |
| template < |
| typename Iterator, typename Key, |
| cm::enable_if_t< |
| cm::is_input_iterator<Iterator>::value && |
| std::is_convertible< |
| Key, typename std::iterator_traits<Iterator>::value_type>::value, |
| int> = 0> |
| bool contains(Iterator first, Iterator last, Key const& key) |
| #endif |
| { |
| return std::find(first, last, key) != last; |
| } |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Iterator, typename Key> |
| bool contains(Iterator first, Iterator last, Key const& key) |
| { |
| return contains(first, last, key, detail::overload_selector<1>{}); |
| } |
| #endif |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Range, typename Key> |
| auto contains(Range const& range, Key const& key, detail::overload_selector<1>) |
| -> decltype(range.find(key) != range.end()) |
| #else |
| template < |
| typename Range, typename Key, |
| cm::enable_if_t<cm::is_associative_container<Range>::value || |
| cm::is_unordered_associative_container<Range>::value, |
| int> = 0> |
| bool contains(Range const& range, Key const& key) |
| #endif |
| { |
| return range.find(key) != range.end(); |
| } |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Range, typename Key> |
| bool contains(Range const& range, Key const& key, detail::overload_selector<0>) |
| #else |
| template < |
| typename Range, typename Key, |
| cm::enable_if_t<cm::is_input_range<Range>::value && |
| !(cm::is_associative_container<Range>::value || |
| cm::is_unordered_associative_container<Range>::value), |
| int> = 0> |
| bool contains(Range const& range, Key const& key) |
| #endif |
| { |
| return std::find(std::begin(range), std::end(range), key) != std::end(range); |
| } |
| |
| #if defined(__SUNPRO_CC) |
| template <typename Range, typename Key> |
| bool contains(Range const& range, Key const& key) |
| { |
| return contains(range, key, detail::overload_selector<1>{}); |
| } |
| #endif |
| |
| } // namespace cm |
| |
| #endif |