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_RANGE_HPP 24 #define CLOVER_UTIL_RANGE_HPP 25 26 #include <array> 27 #include <vector> 28 29 #include "util/adaptor.hpp" 30 31 namespace clover { 32 /// 33 /// Class that identifies container types where the elements of a 34 /// range can be stored by the type conversion operator. 35 /// 36 /// \a T identifies the range element type. 37 /// 38 template<typename T, typename V> 39 struct range_store_traits; 40 41 template<typename T, typename S> 42 struct range_store_traits<T, std::vector<S>> { 43 typedef void enable; 44 45 template<typename R> 46 static std::vector<S> createclover::range_store_traits47 create(const R &r) { 48 return { r.begin(), r.end() }; 49 } 50 }; 51 52 template<typename T, typename S, std::size_t N> 53 struct range_store_traits<T, std::array<S, N>> { 54 typedef void enable; 55 56 template<typename R> 57 static std::array<S, N> createclover::range_store_traits58 create(const R &r) { 59 std::array<S, N> v; 60 assert(r.size() == v.size()); 61 copy(r, v.begin()); 62 return v; 63 } 64 }; 65 66 namespace detail { 67 /// 68 /// Common functionality that is shared by other implementations 69 /// of the container concept. 70 /// 71 template<typename R, typename I, typename CI> 72 class basic_range { 73 public: 74 typedef I iterator; 75 typedef CI const_iterator; 76 typedef typename std::iterator_traits<iterator>::value_type value_type; 77 typedef typename std::iterator_traits<iterator>::reference 78 reference; 79 typedef typename std::iterator_traits<const_iterator>::reference 80 const_reference; 81 typedef typename std::iterator_traits<iterator>::difference_type 82 difference_type; 83 typedef std::size_t size_type; 84 85 bool operator ==(const basic_range & r) const86 operator==(const basic_range &r) const { 87 return *static_cast<const R *>(this) == r; 88 } 89 90 bool operator !=(const basic_range & r) const91 operator!=(const basic_range &r) const { 92 return !(*this == r); 93 } 94 95 iterator begin()96 begin() { 97 return static_cast<R *>(this)->begin(); 98 } 99 100 iterator end()101 end() { 102 return static_cast<R *>(this)->end(); 103 } 104 105 const_iterator begin() const106 begin() const { 107 return static_cast<const R *>(this)->begin(); 108 } 109 110 const_iterator end() const111 end() const { 112 return static_cast<const R *>(this)->end(); 113 } 114 115 std::reverse_iterator<iterator> rbegin()116 rbegin() { 117 return { begin() }; 118 } 119 120 std::reverse_iterator<iterator> rend()121 rend() { 122 return { end() }; 123 } 124 125 reference front()126 front() { 127 return *begin(); 128 } 129 130 reference back()131 back() { 132 return *(end() - 1); 133 } 134 135 bool empty() const136 empty() const { 137 return begin() == end(); 138 } 139 140 reference at(size_type i)141 at(size_type i) { 142 if (i >= static_cast<const R *>(this)->size()) 143 throw std::out_of_range(""); 144 145 return begin()[i]; 146 } 147 148 const_reference at(size_type i) const149 at(size_type i) const { 150 if (i >= static_cast<const R *>(this)->size()) 151 throw std::out_of_range(""); 152 153 return begin()[i]; 154 } 155 156 reference operator [](size_type i)157 operator[](size_type i) { 158 return begin()[i]; 159 } 160 161 const_reference operator [](size_type i) const162 operator[](size_type i) const { 163 return begin()[i]; 164 } 165 166 template<typename V> 167 using store_traits = range_store_traits< 168 typename std::remove_cv<value_type>::type, V 169 >; 170 171 template<typename V, 172 typename = typename store_traits<V>::enable> operator V() const173 operator V() const { 174 return store_traits<V>::create(*static_cast<const R *>(this)); 175 } 176 }; 177 } 178 179 /// 180 /// Range that contains all elements delimited by an iterator pair 181 /// (\a i, \a j). Use range() as convenience constructor. 182 /// 183 template<typename I> 184 class iterator_range : public detail::basic_range<iterator_range<I>, I, I> { 185 public: 186 typedef detail::basic_range<iterator_range<I>, I, I> super; 187 iterator_range()188 iterator_range() : i(), j() { 189 } 190 iterator_range(I i,I j)191 iterator_range(I i, I j) : i(i), j(j) { 192 } 193 194 bool operator ==(const iterator_range & r) const195 operator==(const iterator_range &r) const { 196 return i == r.i && j == r.j; 197 } 198 199 I begin() const200 begin() const { 201 return i; 202 } 203 204 I end() const205 end() const { 206 return j; 207 } 208 209 typename super::size_type size() const210 size() const { 211 return end() - begin(); 212 } 213 214 private: 215 I i, j; 216 }; 217 218 namespace detail { 219 template<typename T> 220 using preferred_iterator_type = decltype(std::declval<T>().begin()); 221 } 222 223 /// 224 /// Range that transforms the contents of a number of source ranges 225 /// \a os element-wise by using the provided functor \a f. Use 226 /// map() as convenience constructor. 227 /// 228 template<typename F, typename... Os> 229 class adaptor_range : 230 public detail::basic_range<adaptor_range<F, Os...>, 231 detail::iterator_adaptor< 232 F, detail::preferred_iterator_type<Os>...>, 233 detail::iterator_adaptor< 234 F, detail::preferred_iterator_type<const Os>...> 235 > { 236 public: 237 typedef detail::basic_range<adaptor_range<F, Os...>, 238 detail::iterator_adaptor< 239 F, detail::preferred_iterator_type<Os>...>, 240 detail::iterator_adaptor< 241 F, detail::preferred_iterator_type<const Os>...> 242 > super; 243 244 template<typename G, typename... Rs> adaptor_range(G && f,Rs &&...os)245 adaptor_range(G &&f, Rs &&... os) : 246 f(std::forward<G>(f)), os(std::forward<Rs>(os)...) { 247 } 248 249 bool operator ==(const adaptor_range & r) const250 operator==(const adaptor_range &r) const { 251 return f == r.f && os == r.os; 252 } 253 254 typename super::iterator begin()255 begin() { 256 return { f, tuple::map(begins(), os) }; 257 } 258 259 typename super::iterator end()260 end() { 261 return { f, tuple::map(advances_by(size()), 262 tuple::map(begins(), os)) }; 263 } 264 265 typename super::const_iterator begin() const266 begin() const { 267 return { f, tuple::map(begins(), os) }; 268 } 269 270 typename super::const_iterator end() const271 end() const { 272 return { f, tuple::map(advances_by(size()), 273 tuple::map(begins(), os)) }; 274 } 275 276 typename super::size_type size() const277 size() const { 278 return tuple::apply(minimum(), tuple::map(sizes(), os)); 279 } 280 281 private: 282 F f; 283 std::tuple<Os...> os; 284 }; 285 286 /// 287 /// Range that contains all elements delimited by the index pair 288 /// (\a i, \a j) in the source range \a r. Use slice() as 289 /// convenience constructor. 290 /// 291 template<typename O> 292 class slice_range : 293 public detail::basic_range<slice_range<O>, 294 detail::preferred_iterator_type<O>, 295 detail::preferred_iterator_type<const O>> { 296 public: 297 typedef detail::basic_range<slice_range<O>, 298 detail::preferred_iterator_type<O>, 299 detail::preferred_iterator_type<const O> 300 > super; 301 302 template<typename R> slice_range(R && r,typename super::size_type i,typename super::size_type j)303 slice_range(R &&r, typename super::size_type i, 304 typename super::size_type j) : 305 o(std::forward<R>(r)), i(i), j(j) { 306 } 307 308 bool operator ==(const slice_range & r) const309 operator==(const slice_range &r) const { 310 return o == r.o && i == r.i && j == r.j; 311 } 312 313 typename super::iterator begin()314 begin() { 315 return std::next(o.begin(), i); 316 } 317 318 typename super::iterator end()319 end() { 320 return std::next(o.begin(), j); 321 } 322 323 typename super::const_iterator begin() const324 begin() const { 325 return std::next(o.begin(), i); 326 } 327 328 typename super::const_iterator end() const329 end() const { 330 return std::next(o.begin(), j); 331 } 332 333 typename super::size_type size() const334 size() const { 335 return j - i; 336 } 337 338 private: 339 O o; 340 typename super::size_type i, j; 341 }; 342 343 /// 344 /// Create a range from an iterator pair (\a i, \a j). 345 /// 346 /// \sa iterator_range. 347 /// 348 template<typename T> 349 iterator_range<T> range(T i,T j)350 range(T i, T j) { 351 return { i, j }; 352 } 353 354 /// 355 /// Create a range of \a n elements starting from iterator \a i. 356 /// 357 /// \sa iterator_range. 358 /// 359 template<typename T> 360 iterator_range<T> range(T i,typename std::iterator_traits<T>::difference_type n)361 range(T i, typename std::iterator_traits<T>::difference_type n) { 362 return { i, i + n }; 363 } 364 365 /// 366 /// Create a range by transforming the contents of a number of 367 /// source ranges \a rs element-wise using a provided functor \a f. 368 /// 369 /// \sa adaptor_range. 370 /// 371 template<typename F, typename... Rs> 372 adaptor_range<F, Rs...> map(F && f,Rs &&...rs)373 map(F &&f, Rs &&... rs) { 374 return { std::forward<F>(f), std::forward<Rs>(rs)... }; 375 } 376 377 /// 378 /// Create a range identical to another range \a r. 379 /// 380 template<typename R> 381 adaptor_range<identity, R> range(R && r)382 range(R &&r) { 383 return { identity(), std::forward<R>(r) }; 384 } 385 386 /// 387 /// Create a range by taking the elements delimited by the index 388 /// pair (\a i, \a j) in a source range \a r. 389 /// 390 /// \sa slice_range. 391 /// 392 template<typename R> 393 slice_range<R> slice(R && r,typename slice_range<R>::size_type i,typename slice_range<R>::size_type j)394 slice(R &&r, typename slice_range<R>::size_type i, 395 typename slice_range<R>::size_type j) { 396 return { std::forward<R>(r), i, j }; 397 } 398 399 /// 400 /// Range that behaves as a vector of references of type \a T. 401 /// 402 /// Useful because STL containers cannot contain references to 403 /// objects as elements. 404 /// 405 template<typename T> 406 class ref_vector : public adaptor_range<derefs, std::vector<T *>> { 407 public: ref_vector(std::initializer_list<std::reference_wrapper<T>> il)408 ref_vector(std::initializer_list<std::reference_wrapper<T>> il) : 409 adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) { 410 } 411 412 template<typename R> ref_vector(R && r)413 ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>( 414 derefs(), map(addresses(), std::forward<R>(r))) { 415 } 416 }; 417 } 418 419 #endif 420