Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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