2
// Copyright 2013 Francisco Jerez
4
// Permission is hereby granted, free of charge, to any person obtaining a
5
// copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
// OTHER DEALINGS IN THE SOFTWARE.
23
#ifndef CLOVER_UTIL_ALGORITHM_HPP
24
#define CLOVER_UTIL_ALGORITHM_HPP
30
#include "util/range.hpp"
31
#include "util/functional.hpp"
36
using preferred_reference_type = decltype(*std::declval<R>().begin());
40
/// Return the first element in a range.
43
detail::preferred_reference_type<R>
50
/// Return all elements in a range but the first.
56
return { std::forward<R>(r), 1, r.size() };
60
/// Return the only element in a range.
63
detail::preferred_reference_type<R>
66
throw std::out_of_range("");
72
/// Combine a variable number of ranges element-wise in a single
75
template<typename... Rs>
76
adaptor_range<zips, Rs...>
78
return map(zips(), std::forward<Rs>(rs)...);
82
/// Evaluate the elements of a range.
84
/// Useful because most of the range algorithms evaluate their
90
for (auto i = r.begin(), e = r.end(); i != e; ++i)
95
/// Apply functor \a f element-wise on a variable number of ranges
98
/// The functor \a f should take as many arguments as ranges are
101
template<typename F, typename... Rs>
103
for_each(F &&f, Rs &&... rs) {
104
eval(map(std::forward<F>(f), std::forward<Rs>(rs)...));
108
/// Copy all elements from range \a r into an output container
109
/// starting from iterator \a i.
111
template<typename R, typename I>
114
for (detail::preferred_reference_type<R> x : r)
119
/// Reduce the elements of range \a r by applying functor \a f
120
/// element by element.
122
/// \a f should take an accumulator value (which is initialized to
123
/// \a a) and an element value as arguments, and return an updated
124
/// accumulator value.
126
/// \returns The final value of the accumulator.
128
template<typename F, typename A, typename R>
130
fold(F &&f, A a, R &&r) {
131
for (detail::preferred_reference_type<R> x : r)
138
/// Return how many elements of range \a r are equal to \a x.
140
template<typename T, typename R>
141
typename std::remove_reference<R>::type::size_type
142
count(T &&x, R &&r) {
143
typename std::remove_reference<R>::type::size_type n = 0;
145
for (detail::preferred_reference_type<R> y : r) {
154
/// Return the first element in range \a r for which predicate \a f
155
/// evaluates to true.
157
template<typename F, typename R>
158
detail::preferred_reference_type<R>
160
for (detail::preferred_reference_type<R> x : r) {
165
throw std::out_of_range("");
169
/// Return true if the element-wise application of predicate \a f
170
/// on \a rs evaluates to true for all elements.
172
template<typename F, typename... Rs>
174
all_of(F &&f, Rs &&... rs) {
175
for (auto b : map(f, rs...)) {
184
/// Return true if the element-wise application of predicate \a f
185
/// on \a rs evaluates to true for any element.
187
template<typename F, typename... Rs>
189
any_of(F &&f, Rs &&... rs) {
190
for (auto b : map(f, rs...)) {
199
/// Erase elements for which predicate \a f evaluates to true from
202
template<typename F, typename R>
204
erase_if(F &&f, R &&r) {
205
auto i = r.begin(), e = r.end();
207
for (auto j = r.begin(); j != e; ++j) {
219
/// Build a vector of string from a space separated string
220
/// quoted parts content is preserved and unquoted
222
inline std::vector<std::string>
223
tokenize(const std::string &s) {
224
std::vector<std::string> ss;
225
std::ostringstream oss;
227
// OpenCL programs can pass a quoted argument, most frequently the
228
// include path. This is useful so that path containing spaces is
229
// treated as a single argument instead of being split by the spaces.
230
// Additionally, the argument should also be unquoted before being
231
// passed to the compiler. We avoid using std::string::replace here to
232
// remove quotes, as the single and double quote characters can be a
233
// part of the file name.
234
bool escape_next = false;
235
bool in_quote_double = false;
236
bool in_quote_single = false;
242
} else if (c == '\\') {
244
} else if (c == '"' && !in_quote_single) {
245
in_quote_double = !in_quote_double;
246
} else if (c == '\'' && !in_quote_double) {
247
in_quote_single = !in_quote_single;
248
} else if (c != ' ' || in_quote_single || in_quote_double) {
250
} else if (oss.tellp() > 0) {
251
ss.emplace_back(oss.str());
257
ss.emplace_back(oss.str());
259
if (in_quote_double || in_quote_single)
260
throw invalid_build_options_error();
266
/// Build a \a sep separated string from a vector of T
270
detokenize(const std::vector<T> &ss, const std::string &sep) {
273
for (const auto &s : ss)
274
r += (r.empty() ? "" : sep) + std::to_string(s);
280
/// Build a \a sep separated string from a vector of string
284
detokenize(const std::vector<std::string> &ss, const std::string &sep) {
287
for (const auto &s : ss)
288
r += (r.empty() || s.empty() ? "" : sep) + s;