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