/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/ranges> |
14 | | #include <cm/type_traits> |
15 | | #include <cmext/iterator> |
16 | | #include <cmext/type_traits> |
17 | | |
18 | | #if defined(__SUNPRO_CC) && defined(__sparc) |
19 | | # include <list> |
20 | | # include <string> |
21 | | # include <vector> |
22 | | #endif |
23 | | |
24 | | namespace cm { |
25 | | |
26 | | #if defined(__SUNPRO_CC) && defined(__sparc) |
27 | | // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile |
28 | | // templates with constraints. |
29 | | // So, on this platform, use only simple templates. |
30 | | # define APPEND_TWO(C1, C2) \ |
31 | | template <typename T, typename U> \ |
32 | | void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \ |
33 | | { \ |
34 | | std::transform( \ |
35 | | r.begin(), r.end(), std::back_inserter(v), \ |
36 | | [](std::unique_ptr<U>& item) { return std::move(item); }); \ |
37 | | r.clear(); \ |
38 | | } \ |
39 | | \ |
40 | | template <typename T, typename U> \ |
41 | | void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \ |
42 | | { \ |
43 | | std::transform( \ |
44 | | r.begin(), r.end(), std::back_inserter(v), \ |
45 | | [](const std::unique_ptr<U>& item) { return item.get(); }); \ |
46 | | } |
47 | | |
48 | | # define APPEND_ONE(C) \ |
49 | | template <typename T, typename InputIt, \ |
50 | | cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \ |
51 | | 0> \ |
52 | | void append(C<T>& v, InputIt first, InputIt last) \ |
53 | | { \ |
54 | | v.insert(v.end(), first, last); \ |
55 | | } \ |
56 | | \ |
57 | | template <typename T, typename Range, \ |
58 | | cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \ |
59 | | void append(C<T>& v, Range const& r) \ |
60 | | { \ |
61 | | v.insert(v.end(), r.begin(), r.end()); \ |
62 | | } |
63 | | |
64 | | # define APPEND(C) \ |
65 | | APPEND_TWO(C, C) \ |
66 | | APPEND_ONE(C) |
67 | | |
68 | | # define APPEND_MIX(C1, C2) \ |
69 | | APPEND_TWO(C1, C2) \ |
70 | | APPEND_TWO(C2, C1) |
71 | | |
72 | | // For now, manage only support for std::vector, std::list, and |
73 | | // std::basic_string. Other sequential container support can be added if |
74 | | // needed. |
75 | | APPEND(std::vector) |
76 | | APPEND(std::list) |
77 | | APPEND(std::basic_string) |
78 | | APPEND_MIX(std::vector, std::list) |
79 | | APPEND_MIX(std::vector, std::basic_string) |
80 | | APPEND_MIX(std::list, std::basic_string) |
81 | | |
82 | | # undef APPEND |
83 | | # undef APPEND_MIX |
84 | | # undef APPEND_TWO |
85 | | # undef APPEND_ONE |
86 | | |
87 | | #else |
88 | | |
89 | | template < |
90 | | typename Container1, typename Container2, |
91 | | cm::enable_if_t< |
92 | | cm::is_sequence_container<Container1>::value && |
93 | | cm::is_unique_ptr<typename Container1::value_type>::value && |
94 | | cm::is_unique_ptr<typename Container2::value_type>::value && |
95 | | std::is_convertible<typename Container2::value_type::pointer, |
96 | | typename Container1::value_type::pointer>::value, |
97 | | int> = 0> |
98 | | void append(Container1& v, Container2&& r) |
99 | | { |
100 | | std::transform( |
101 | | r.begin(), r.end(), std::back_inserter(v), |
102 | | [](typename Container2::value_type& item) { return std::move(item); }); |
103 | | r.clear(); |
104 | | } |
105 | | |
106 | | template <typename Container1, typename Container2, |
107 | | cm::enable_if_t< |
108 | | cm::is_sequence_container<Container1>::value && |
109 | | std::is_pointer<typename Container1::value_type>::value && |
110 | | cm::is_unique_ptr<typename Container2::value_type>::value && |
111 | | std::is_convertible<typename Container2::value_type::pointer, |
112 | | typename Container1::value_type>::value, |
113 | | int> = 0> |
114 | | # if defined(__SUNPRO_CC) |
115 | | void append(Container1& v, Container2 const& r, detail::overload_selector<0>) |
116 | | # else |
117 | | void append(Container1& v, Container2 const& r) |
118 | | # endif |
119 | | { |
120 | | std::transform( |
121 | | r.begin(), r.end(), std::back_inserter(v), |
122 | | [](typename Container2::value_type const& item) { return item.get(); }); |
123 | | } |
124 | | |
125 | | template < |
126 | | typename Container, typename InputIt, |
127 | | cm::enable_if_t< |
128 | | cm::is_sequence_container<Container>::value && |
129 | | cm::is_input_iterator<InputIt>::value && |
130 | | std::is_convertible<typename std::iterator_traits<InputIt>::value_type, |
131 | | typename Container::value_type>::value, |
132 | | int> = 0> |
133 | | void append(Container& v, InputIt first, InputIt last) |
134 | 0 | { |
135 | 0 | v.insert(v.end(), first, last); |
136 | 0 | } |
137 | | |
138 | | template <typename Container, typename Range, |
139 | | cm::enable_if_t< |
140 | | cm::is_sequence_container<Container>::value && |
141 | | cm::is_input_range<Range>::value && |
142 | | !cm::is_unique_ptr<typename Container::value_type>::value && |
143 | | !cm::is_unique_ptr<typename Range::value_type>::value && |
144 | | std::is_convertible<typename Range::value_type, |
145 | | typename Container::value_type>::value, |
146 | | int> = 0> |
147 | | # if defined(__SUNPRO_CC) |
148 | | void append(Container& v, Range const& r, detail::overload_selector<1>) |
149 | | # else |
150 | | void append(Container& v, Range const& r) |
151 | | # endif |
152 | | { |
153 | | v.insert(v.end(), r.begin(), r.end()); |
154 | | } |
155 | | |
156 | | # if defined(__SUNPRO_CC) |
157 | | template <typename T, typename U> |
158 | | void append(T& v, U const& r) |
159 | | { |
160 | | cm::append(v, r, detail::overload_selector<1>{}); |
161 | | } |
162 | | # endif |
163 | | #endif |
164 | | |
165 | | #if defined(__SUNPRO_CC) |
166 | | template <typename Iterator, typename Key> |
167 | | auto contains(Iterator first, Iterator last, Key const& key, |
168 | | detail::overload_selector<1>) -> decltype(first->first == key) |
169 | | #else |
170 | | template <typename Iterator, typename Key, |
171 | | cm::enable_if_t< |
172 | | cm::is_input_iterator<Iterator>::value && |
173 | | std::is_convertible<Key, |
174 | | typename std::iterator_traits< |
175 | | Iterator>::value_type::first_type>::value, |
176 | | int> = 0> |
177 | | bool contains(Iterator first, Iterator last, Key const& key) |
178 | | #endif |
179 | | { |
180 | | return std::find_if( |
181 | | first, last, |
182 | | [&key]( |
183 | | typename std::iterator_traits<Iterator>::value_type const& item) { |
184 | | return item.first == key; |
185 | | }) != last; |
186 | | } |
187 | | |
188 | | #if defined(__SUNPRO_CC) |
189 | | template <typename Iterator, typename Key> |
190 | | bool contains(Iterator first, Iterator last, Key const& key, |
191 | | detail::overload_selector<0>) |
192 | | #else |
193 | | template < |
194 | | typename Iterator, typename Key, |
195 | | cm::enable_if_t< |
196 | | cm::is_input_iterator<Iterator>::value && |
197 | | std::is_convertible< |
198 | | Key, typename std::iterator_traits<Iterator>::value_type>::value, |
199 | | int> = 0> |
200 | | bool contains(Iterator first, Iterator last, Key const& key) |
201 | | #endif |
202 | | { |
203 | | return std::find(first, last, key) != last; |
204 | | } |
205 | | |
206 | | #if defined(__SUNPRO_CC) |
207 | | template <typename Iterator, typename Key> |
208 | | bool contains(Iterator first, Iterator last, Key const& key) |
209 | | { |
210 | | return contains(first, last, key, detail::overload_selector<1>{}); |
211 | | } |
212 | | #endif |
213 | | |
214 | | #if defined(__SUNPRO_CC) |
215 | | template <typename Range, typename Key> |
216 | | auto contains(Range const& range, Key const& key, |
217 | | detail::overload_selector<1>) -> decltype(range.find(key) != |
218 | | range.end()) |
219 | | #else |
220 | | template < |
221 | | typename Range, typename Key, |
222 | | cm::enable_if_t<cm::is_associative_container<Range>::value || |
223 | | cm::is_unordered_associative_container<Range>::value, |
224 | | int> = 0> |
225 | | bool contains(Range const& range, Key const& key) |
226 | | #endif |
227 | | { |
228 | | return range.find(key) != range.end(); |
229 | | } |
230 | | |
231 | | #if defined(__SUNPRO_CC) |
232 | | template <typename Range, typename Key> |
233 | | bool contains(Range const& range, Key const& key, detail::overload_selector<0>) |
234 | | #else |
235 | | template < |
236 | | typename Range, typename Key, |
237 | | cm::enable_if_t<cm::is_input_range<Range>::value && |
238 | | !(cm::is_associative_container<Range>::value || |
239 | | cm::is_unordered_associative_container<Range>::value), |
240 | | int> = 0> |
241 | | bool contains(Range const& range, Key const& key) |
242 | | #endif |
243 | 0 | { |
244 | 0 | return std::find(std::begin(range), std::end(range), key) != std::end(range); |
245 | 0 | } |
246 | | |
247 | | #if defined(__SUNPRO_CC) |
248 | | template <typename Range, typename Key> |
249 | | bool contains(Range const& range, Key const& key) |
250 | | { |
251 | | return contains(range, key, detail::overload_selector<1>{}); |
252 | | } |
253 | | #endif |
254 | | |
255 | | template < |
256 | | typename Range, |
257 | | cm::enable_if_t<cm::is_associative_container<Range>::value || |
258 | | cm::is_unordered_associative_container<Range>::value, |
259 | | int> = 0> |
260 | | std::vector<typename Range::key_type> keys(Range const& range) |
261 | | { |
262 | | #if defined(CMake_HAVE_CXX_RANGES) |
263 | | using key_type = typename Range::key_type; |
264 | | |
265 | | # if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) |
266 | | return std::vector<key_type>{ std::from_range, std::views::keys(range) }; |
267 | | # else |
268 | | auto view = std::views::keys(range); |
269 | | return std::vector<key_type>{ view.begin(), view.end() }; |
270 | | # endif |
271 | | #else |
272 | | return cm::views::keys(range); |
273 | | #endif |
274 | | } |
275 | | |
276 | | template < |
277 | | typename Range, |
278 | | cm::enable_if_t<cm::is_associative_container<Range>::value || |
279 | | cm::is_unordered_associative_container<Range>::value, |
280 | | int> = 0> |
281 | | std::vector<typename Range::mapped_type> values(Range const& range) |
282 | | { |
283 | | #if defined(CMake_HAVE_CXX_RANGES) |
284 | | using value_type = typename Range::mapped_type; |
285 | | |
286 | | # if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) |
287 | | return std::vector<value_type>{ std::from_range, std::views::values(range) }; |
288 | | # else |
289 | | auto view = std::views::values(range); |
290 | | return std::vector<value_type>{ view.begin(), view.end() }; |
291 | | # endif |
292 | | #else |
293 | | return cm::views::values(range); |
294 | | #endif |
295 | | } |
296 | | |
297 | | // sequence containers with std::pair<> or std::tuple<> as elements |
298 | | template <typename Range, |
299 | | cm::enable_if_t<cm::is_sequence_container<Range>::value && |
300 | | cm::is_tuple<1, typename Range::value_type>::value, |
301 | | int> = 0> |
302 | | std::vector<typename std::tuple_element<0, typename Range::value_type>::type> |
303 | | keys(Range const& range) |
304 | | { |
305 | | #if defined(CMake_HAVE_CXX_RANGES) |
306 | | using key_type = |
307 | | typename std::tuple_element<0, typename Range::value_type>::type; |
308 | | |
309 | | # if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) |
310 | | return std::vector<key_type>{ std::from_range, std::views::keys(range) }; |
311 | | # else |
312 | | auto view = std::views::keys(range); |
313 | | return std::vector<key_type>{ view.begin(), view.end() }; |
314 | | # endif |
315 | | #else |
316 | | return cm::views::keys(range); |
317 | | #endif |
318 | | } |
319 | | |
320 | | template <typename Range, |
321 | | cm::enable_if_t<cm::is_sequence_container<Range>::value && |
322 | | cm::is_tuple<2, typename Range::value_type>::value, |
323 | | int> = 0> |
324 | | std::vector<typename std::tuple_element<1, typename Range::value_type>::type> |
325 | | values(Range const& range) |
326 | | { |
327 | | #if defined(CMake_HAVE_CXX_RANGES) |
328 | | using value_type = |
329 | | typename std::tuple_element<1, typename Range::value_type>::type; |
330 | | |
331 | | # if __cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L) |
332 | | return std::vector<value_type>{ std::from_range, std::views::values(range) }; |
333 | | # else |
334 | | auto view = std::views::values(range); |
335 | | return std::vector<value_type>{ view.begin(), view.end() }; |
336 | | # endif |
337 | | #else |
338 | | return cm::views::values(range); |
339 | | #endif |
340 | | } |
341 | | |
342 | | } // namespace cm |