1// -*-c++-*- 2// vim: set ft=cpp: 3 4/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying 5 file Copyright.txt or https://cmake.org/licensing for details. */ 6#pragma once 7 8#include <algorithm> 9#include <iterator> 10#include <memory> 11#include <utility> 12 13#include <cm/type_traits> 14#include <cmext/iterator> 15#include <cmext/type_traits> 16 17#if defined(__SUNPRO_CC) && defined(__sparc) 18# include <list> 19# include <vector> 20#endif 21 22namespace cm { 23 24#if defined(__SUNPRO_CC) && defined(__sparc) 25// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile 26// templates with constraints. 27// So, on this platform, use only simple templates. 28# define APPEND_TWO(C1, C2) \ 29 template <typename T, typename U> \ 30 void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \ 31 { \ 32 std::transform( \ 33 r.begin(), r.end(), std::back_inserter(v), \ 34 [](std::unique_ptr<U>& item) { return std::move(item); }); \ 35 r.clear(); \ 36 } \ 37 \ 38 template <typename T, typename U> \ 39 void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \ 40 { \ 41 std::transform( \ 42 r.begin(), r.end(), std::back_inserter(v), \ 43 [](const std::unique_ptr<U>& item) { return item.get(); }); \ 44 } 45 46# define APPEND_ONE(C) \ 47 template <typename T, typename InputIt, \ 48 cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \ 49 0> \ 50 void append(C<T>& v, InputIt first, InputIt last) \ 51 { \ 52 v.insert(v.end(), first, last); \ 53 } \ 54 \ 55 template <typename T, typename Range, \ 56 cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \ 57 void append(C<T>& v, Range const& r) \ 58 { \ 59 v.insert(v.end(), r.begin(), r.end()); \ 60 } 61 62# define APPEND(C) \ 63 APPEND_TWO(C, C) \ 64 APPEND_ONE(C) 65 66# define APPEND_MIX(C1, C2) \ 67 APPEND_TWO(C1, C2) \ 68 APPEND_TWO(C2, C1) 69 70// For now, manage only support for std::vector and std::list. 71// Other sequential container support can be added if needed. 72APPEND(std::vector) 73APPEND(std::list) 74APPEND_MIX(std::vector, std::list) 75 76# undef APPEND 77# undef APPEND_MIX 78# undef APPEND_TWO 79# undef APPEND_ONE 80 81#else 82 83template < 84 typename Container1, typename Container2, 85 cm::enable_if_t< 86 cm::is_sequence_container<Container1>::value && 87 cm::is_unique_ptr<typename Container1::value_type>::value && 88 cm::is_unique_ptr<typename Container2::value_type>::value && 89 std::is_convertible<typename Container2::value_type::pointer, 90 typename Container1::value_type::pointer>::value, 91 int> = 0> 92void append(Container1& v, Container2&& r) 93{ 94 std::transform( 95 r.begin(), r.end(), std::back_inserter(v), 96 [](typename Container2::value_type& item) { return std::move(item); }); 97 r.clear(); 98} 99 100template <typename Container1, typename Container2, 101 cm::enable_if_t< 102 cm::is_sequence_container<Container1>::value && 103 std::is_pointer<typename Container1::value_type>::value && 104 cm::is_unique_ptr<typename Container2::value_type>::value && 105 std::is_convertible<typename Container2::value_type::pointer, 106 typename Container1::value_type>::value, 107 int> = 0> 108# if defined(__SUNPRO_CC) 109void append(Container1& v, Container2 const& r, detail::overload_selector<0>) 110# else 111void append(Container1& v, Container2 const& r) 112# endif 113{ 114 std::transform( 115 r.begin(), r.end(), std::back_inserter(v), 116 [](const typename Container2::value_type& item) { return item.get(); }); 117} 118 119template < 120 typename Container, typename InputIt, 121 cm::enable_if_t< 122 cm::is_sequence_container<Container>::value && 123 cm::is_input_iterator<InputIt>::value && 124 std::is_convertible<typename std::iterator_traits<InputIt>::value_type, 125 typename Container::value_type>::value, 126 int> = 0> 127void append(Container& v, InputIt first, InputIt last) 128{ 129 v.insert(v.end(), first, last); 130} 131 132template <typename Container, typename Range, 133 cm::enable_if_t< 134 cm::is_sequence_container<Container>::value && 135 cm::is_input_range<Range>::value && 136 !cm::is_unique_ptr<typename Container::value_type>::value && 137 !cm::is_unique_ptr<typename Range::value_type>::value && 138 std::is_convertible<typename Range::value_type, 139 typename Container::value_type>::value, 140 int> = 0> 141# if defined(__SUNPRO_CC) 142void append(Container& v, Range const& r, detail::overload_selector<1>) 143# else 144void append(Container& v, Range const& r) 145# endif 146{ 147 v.insert(v.end(), r.begin(), r.end()); 148} 149 150# if defined(__SUNPRO_CC) 151template <typename T, typename U> 152void append(T& v, U const& r) 153{ 154 cm::append(v, r, detail::overload_selector<1>{}); 155} 156# endif 157#endif 158 159#if defined(__SUNPRO_CC) 160template <typename Iterator, typename Key> 161auto contains(Iterator first, Iterator last, Key const& key, 162 detail::overload_selector<1>) -> decltype(first->first == key) 163#else 164template <typename Iterator, typename Key, 165 cm::enable_if_t< 166 cm::is_input_iterator<Iterator>::value && 167 std::is_convertible<Key, 168 typename std::iterator_traits< 169 Iterator>::value_type::first_type>::value, 170 int> = 0> 171bool contains(Iterator first, Iterator last, Key const& key) 172#endif 173{ 174 return std::find_if( 175 first, last, 176 [&key]( 177 typename std::iterator_traits<Iterator>::value_type const& item) { 178 return item.first == key; 179 }) != last; 180} 181 182#if defined(__SUNPRO_CC) 183template <typename Iterator, typename Key> 184bool contains(Iterator first, Iterator last, Key const& key, 185 detail::overload_selector<0>) 186#else 187template < 188 typename Iterator, typename Key, 189 cm::enable_if_t< 190 cm::is_input_iterator<Iterator>::value && 191 std::is_convertible< 192 Key, typename std::iterator_traits<Iterator>::value_type>::value, 193 int> = 0> 194bool contains(Iterator first, Iterator last, Key const& key) 195#endif 196{ 197 return std::find(first, last, key) != last; 198} 199 200#if defined(__SUNPRO_CC) 201template <typename Iterator, typename Key> 202bool contains(Iterator first, Iterator last, Key const& key) 203{ 204 return contains(first, last, key, detail::overload_selector<1>{}); 205} 206#endif 207 208#if defined(__SUNPRO_CC) 209template <typename Range, typename Key> 210auto contains(Range const& range, Key const& key, detail::overload_selector<1>) 211 -> decltype(range.find(key) != range.end()) 212#else 213template < 214 typename Range, typename Key, 215 cm::enable_if_t<cm::is_associative_container<Range>::value || 216 cm::is_unordered_associative_container<Range>::value, 217 int> = 0> 218bool contains(Range const& range, Key const& key) 219#endif 220{ 221 return range.find(key) != range.end(); 222} 223 224#if defined(__SUNPRO_CC) 225template <typename Range, typename Key> 226bool contains(Range const& range, Key const& key, detail::overload_selector<0>) 227#else 228template < 229 typename Range, typename Key, 230 cm::enable_if_t<cm::is_input_range<Range>::value && 231 !(cm::is_associative_container<Range>::value || 232 cm::is_unordered_associative_container<Range>::value), 233 int> = 0> 234bool contains(Range const& range, Key const& key) 235#endif 236{ 237 return std::find(std::begin(range), std::end(range), key) != std::end(range); 238} 239 240#if defined(__SUNPRO_CC) 241template <typename Range, typename Key> 242bool contains(Range const& range, Key const& key) 243{ 244 return contains(range, key, detail::overload_selector<1>{}); 245} 246#endif 247 248} // namespace cm 249