1 // 2 // Copyright 2013 Francisco Jerez 3 // 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: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 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. 21 // 22 23 #ifndef CLOVER_UTIL_ALGORITHM_HPP 24 #define CLOVER_UTIL_ALGORITHM_HPP 25 26 #include <algorithm> 27 #include <sstream> 28 #include <stdexcept> 29 30 #include "util/range.hpp" 31 #include "util/functional.hpp" 32 33 namespace clover { 34 namespace detail { 35 template<typename R> 36 using preferred_reference_type = decltype(*std::declval<R>().begin()); 37 } 38 39 /// 40 /// Return the first element in a range. 41 /// 42 template<typename R> 43 detail::preferred_reference_type<R> head(R && r)44 head(R &&r) { 45 assert(!r.empty()); 46 return r.front(); 47 } 48 49 /// 50 /// Return all elements in a range but the first. 51 /// 52 template<typename R> 53 slice_range<R> tail(R && r)54 tail(R &&r) { 55 assert(!r.empty()); 56 return { std::forward<R>(r), 1, r.size() }; 57 } 58 59 /// 60 /// Return the only element in a range. 61 /// 62 template<typename R> 63 detail::preferred_reference_type<R> unique(R && r)64 unique(R &&r) { 65 if (r.size() != 1) 66 throw std::out_of_range(""); 67 68 return r.front(); 69 } 70 71 /// 72 /// Combine a variable number of ranges element-wise in a single 73 /// range of tuples. 74 /// 75 template<typename... Rs> 76 adaptor_range<zips, Rs...> zip(Rs &&...rs)77 zip(Rs &&... rs) { 78 return map(zips(), std::forward<Rs>(rs)...); 79 } 80 81 /// 82 /// Evaluate the elements of a range. 83 /// 84 /// Useful because most of the range algorithms evaluate their 85 /// result lazily. 86 /// 87 template<typename R> 88 void eval(R && r)89 eval(R &&r) { 90 for (auto i = r.begin(), e = r.end(); i != e; ++i) 91 *i; 92 } 93 94 /// 95 /// Apply functor \a f element-wise on a variable number of ranges 96 /// \a rs. 97 /// 98 /// The functor \a f should take as many arguments as ranges are 99 /// provided. 100 /// 101 template<typename F, typename... Rs> 102 void for_each(F && f,Rs &&...rs)103 for_each(F &&f, Rs &&... rs) { 104 eval(map(std::forward<F>(f), std::forward<Rs>(rs)...)); 105 } 106 107 /// 108 /// Copy all elements from range \a r into an output container 109 /// starting from iterator \a i. 110 /// 111 template<typename R, typename I> 112 void copy(R && r,I i)113 copy(R &&r, I i) { 114 for (detail::preferred_reference_type<R> x : r) 115 *(i++) = x; 116 } 117 118 /// 119 /// Reduce the elements of range \a r by applying functor \a f 120 /// element by element. 121 /// 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. 125 /// 126 /// \returns The final value of the accumulator. 127 /// 128 template<typename F, typename A, typename R> 129 A fold(F && f,A a,R && r)130 fold(F &&f, A a, R &&r) { 131 for (detail::preferred_reference_type<R> x : r) 132 a = f(a, x); 133 134 return a; 135 } 136 137 /// 138 /// Return how many elements of range \a r are equal to \a x. 139 /// 140 template<typename T, typename R> 141 typename std::remove_reference<R>::type::size_type count(T && x,R && r)142 count(T &&x, R &&r) { 143 typename std::remove_reference<R>::type::size_type n = 0; 144 145 for (detail::preferred_reference_type<R> y : r) { 146 if (x == y) 147 n++; 148 } 149 150 return n; 151 } 152 153 /// 154 /// Return the first element in range \a r for which predicate \a f 155 /// evaluates to true. 156 /// 157 template<typename F, typename R> 158 detail::preferred_reference_type<R> find(F && f,R && r)159 find(F &&f, R &&r) { 160 for (detail::preferred_reference_type<R> x : r) { 161 if (f(x)) 162 return x; 163 } 164 165 throw std::out_of_range(""); 166 } 167 168 /// 169 /// Return true if the element-wise application of predicate \a f 170 /// on \a rs evaluates to true for all elements. 171 /// 172 template<typename F, typename... Rs> 173 bool all_of(F && f,Rs &&...rs)174 all_of(F &&f, Rs &&... rs) { 175 for (auto b : map(f, rs...)) { 176 if (!b) 177 return false; 178 } 179 180 return true; 181 } 182 183 /// 184 /// Return true if the element-wise application of predicate \a f 185 /// on \a rs evaluates to true for any element. 186 /// 187 template<typename F, typename... Rs> 188 bool any_of(F && f,Rs &&...rs)189 any_of(F &&f, Rs &&... rs) { 190 for (auto b : map(f, rs...)) { 191 if (b) 192 return true; 193 } 194 195 return false; 196 } 197 198 /// 199 /// Erase elements for which predicate \a f evaluates to true from 200 /// container \a r. 201 /// 202 template<typename F, typename R> 203 void erase_if(F && f,R && r)204 erase_if(F &&f, R &&r) { 205 auto i = r.begin(), e = r.end(); 206 207 for (auto j = r.begin(); j != e; ++j) { 208 if (!f(*j)) { 209 if (j != i) 210 *i = std::move(*j); 211 ++i; 212 } 213 } 214 215 r.erase(i, e); 216 } 217 218 /// 219 /// Build a vector of string from a space separated string 220 /// quoted parts content is preserved and unquoted 221 /// 222 inline std::vector<std::string> tokenize(const std::string & s)223 tokenize(const std::string &s) { 224 std::vector<std::string> ss; 225 std::ostringstream oss; 226 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; 237 238 for (auto c : s) { 239 if (escape_next) { 240 oss.put(c); 241 escape_next = false; 242 } else if (c == '\\') { 243 escape_next = true; 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) { 249 oss.put(c); 250 } else if (oss.tellp() > 0) { 251 ss.emplace_back(oss.str()); 252 oss.str(""); 253 } 254 } 255 256 if (oss.tellp() > 0) 257 ss.emplace_back(oss.str()); 258 259 if (in_quote_double || in_quote_single) 260 throw invalid_build_options_error(); 261 262 return ss; 263 } 264 265 /// 266 /// Build a \a sep separated string from a vector of T 267 /// 268 template<typename T> 269 std::string detokenize(const std::vector<T> & ss,const std::string & sep)270 detokenize(const std::vector<T> &ss, const std::string &sep) { 271 std::string r; 272 273 for (const auto &s : ss) 274 r += (r.empty() ? "" : sep) + std::to_string(s); 275 276 return r; 277 } 278 279 /// 280 /// Build a \a sep separated string from a vector of string 281 /// 282 template <> 283 inline std::string detokenize(const std::vector<std::string> & ss,const std::string & sep)284 detokenize(const std::vector<std::string> &ss, const std::string &sep) { 285 std::string r; 286 287 for (const auto &s : ss) 288 r += (r.empty() || s.empty() ? "" : sep) + s; 289 290 return r; 291 } 292 } 293 294 #endif 295