| // -*-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. */ | |
| #pragma once | |
| #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 <string> | |
| # 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, std::list, and | |
| // std::basic_string. Other sequential container support can be added if | |
| // needed. | |
| APPEND(std::vector) | |
| APPEND(std::list) | |
| APPEND(std::basic_string) | |
| APPEND_MIX(std::vector, std::list) | |
| APPEND_MIX(std::vector, std::basic_string) | |
| APPEND_MIX(std::list, std::basic_string) | |
| # 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 |