Coverage Report

Created: 2026-02-09 06:05

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/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