1bf215546Sopenharmony_ci// 2bf215546Sopenharmony_ci// Copyright 2013 Francisco Jerez 3bf215546Sopenharmony_ci// 4bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci// 11bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in 12bf215546Sopenharmony_ci// all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci// 14bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci// 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci#ifndef CLOVER_UTIL_RANGE_HPP 24bf215546Sopenharmony_ci#define CLOVER_UTIL_RANGE_HPP 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <array> 27bf215546Sopenharmony_ci#include <vector> 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "util/adaptor.hpp" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_cinamespace clover { 32bf215546Sopenharmony_ci /// 33bf215546Sopenharmony_ci /// Class that identifies container types where the elements of a 34bf215546Sopenharmony_ci /// range can be stored by the type conversion operator. 35bf215546Sopenharmony_ci /// 36bf215546Sopenharmony_ci /// \a T identifies the range element type. 37bf215546Sopenharmony_ci /// 38bf215546Sopenharmony_ci template<typename T, typename V> 39bf215546Sopenharmony_ci struct range_store_traits; 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci template<typename T, typename S> 42bf215546Sopenharmony_ci struct range_store_traits<T, std::vector<S>> { 43bf215546Sopenharmony_ci typedef void enable; 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci template<typename R> 46bf215546Sopenharmony_ci static std::vector<S> 47bf215546Sopenharmony_ci create(const R &r) { 48bf215546Sopenharmony_ci return { r.begin(), r.end() }; 49bf215546Sopenharmony_ci } 50bf215546Sopenharmony_ci }; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci template<typename T, typename S, std::size_t N> 53bf215546Sopenharmony_ci struct range_store_traits<T, std::array<S, N>> { 54bf215546Sopenharmony_ci typedef void enable; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci template<typename R> 57bf215546Sopenharmony_ci static std::array<S, N> 58bf215546Sopenharmony_ci create(const R &r) { 59bf215546Sopenharmony_ci std::array<S, N> v; 60bf215546Sopenharmony_ci assert(r.size() == v.size()); 61bf215546Sopenharmony_ci copy(r, v.begin()); 62bf215546Sopenharmony_ci return v; 63bf215546Sopenharmony_ci } 64bf215546Sopenharmony_ci }; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci namespace detail { 67bf215546Sopenharmony_ci /// 68bf215546Sopenharmony_ci /// Common functionality that is shared by other implementations 69bf215546Sopenharmony_ci /// of the container concept. 70bf215546Sopenharmony_ci /// 71bf215546Sopenharmony_ci template<typename R, typename I, typename CI> 72bf215546Sopenharmony_ci class basic_range { 73bf215546Sopenharmony_ci public: 74bf215546Sopenharmony_ci typedef I iterator; 75bf215546Sopenharmony_ci typedef CI const_iterator; 76bf215546Sopenharmony_ci typedef typename std::iterator_traits<iterator>::value_type value_type; 77bf215546Sopenharmony_ci typedef typename std::iterator_traits<iterator>::reference 78bf215546Sopenharmony_ci reference; 79bf215546Sopenharmony_ci typedef typename std::iterator_traits<const_iterator>::reference 80bf215546Sopenharmony_ci const_reference; 81bf215546Sopenharmony_ci typedef typename std::iterator_traits<iterator>::difference_type 82bf215546Sopenharmony_ci difference_type; 83bf215546Sopenharmony_ci typedef std::size_t size_type; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci bool 86bf215546Sopenharmony_ci operator==(const basic_range &r) const { 87bf215546Sopenharmony_ci return *static_cast<const R *>(this) == r; 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci bool 91bf215546Sopenharmony_ci operator!=(const basic_range &r) const { 92bf215546Sopenharmony_ci return !(*this == r); 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci iterator 96bf215546Sopenharmony_ci begin() { 97bf215546Sopenharmony_ci return static_cast<R *>(this)->begin(); 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci iterator 101bf215546Sopenharmony_ci end() { 102bf215546Sopenharmony_ci return static_cast<R *>(this)->end(); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci const_iterator 106bf215546Sopenharmony_ci begin() const { 107bf215546Sopenharmony_ci return static_cast<const R *>(this)->begin(); 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci const_iterator 111bf215546Sopenharmony_ci end() const { 112bf215546Sopenharmony_ci return static_cast<const R *>(this)->end(); 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci std::reverse_iterator<iterator> 116bf215546Sopenharmony_ci rbegin() { 117bf215546Sopenharmony_ci return { begin() }; 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci std::reverse_iterator<iterator> 121bf215546Sopenharmony_ci rend() { 122bf215546Sopenharmony_ci return { end() }; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci reference 126bf215546Sopenharmony_ci front() { 127bf215546Sopenharmony_ci return *begin(); 128bf215546Sopenharmony_ci } 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci reference 131bf215546Sopenharmony_ci back() { 132bf215546Sopenharmony_ci return *(end() - 1); 133bf215546Sopenharmony_ci } 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci bool 136bf215546Sopenharmony_ci empty() const { 137bf215546Sopenharmony_ci return begin() == end(); 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci reference 141bf215546Sopenharmony_ci at(size_type i) { 142bf215546Sopenharmony_ci if (i >= static_cast<const R *>(this)->size()) 143bf215546Sopenharmony_ci throw std::out_of_range(""); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci return begin()[i]; 146bf215546Sopenharmony_ci } 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci const_reference 149bf215546Sopenharmony_ci at(size_type i) const { 150bf215546Sopenharmony_ci if (i >= static_cast<const R *>(this)->size()) 151bf215546Sopenharmony_ci throw std::out_of_range(""); 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci return begin()[i]; 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci reference 157bf215546Sopenharmony_ci operator[](size_type i) { 158bf215546Sopenharmony_ci return begin()[i]; 159bf215546Sopenharmony_ci } 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci const_reference 162bf215546Sopenharmony_ci operator[](size_type i) const { 163bf215546Sopenharmony_ci return begin()[i]; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci template<typename V> 167bf215546Sopenharmony_ci using store_traits = range_store_traits< 168bf215546Sopenharmony_ci typename std::remove_cv<value_type>::type, V 169bf215546Sopenharmony_ci >; 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci template<typename V, 172bf215546Sopenharmony_ci typename = typename store_traits<V>::enable> 173bf215546Sopenharmony_ci operator V() const { 174bf215546Sopenharmony_ci return store_traits<V>::create(*static_cast<const R *>(this)); 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci }; 177bf215546Sopenharmony_ci } 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci /// 180bf215546Sopenharmony_ci /// Range that contains all elements delimited by an iterator pair 181bf215546Sopenharmony_ci /// (\a i, \a j). Use range() as convenience constructor. 182bf215546Sopenharmony_ci /// 183bf215546Sopenharmony_ci template<typename I> 184bf215546Sopenharmony_ci class iterator_range : public detail::basic_range<iterator_range<I>, I, I> { 185bf215546Sopenharmony_ci public: 186bf215546Sopenharmony_ci typedef detail::basic_range<iterator_range<I>, I, I> super; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci iterator_range() : i(), j() { 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci iterator_range(I i, I j) : i(i), j(j) { 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci bool 195bf215546Sopenharmony_ci operator==(const iterator_range &r) const { 196bf215546Sopenharmony_ci return i == r.i && j == r.j; 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci I 200bf215546Sopenharmony_ci begin() const { 201bf215546Sopenharmony_ci return i; 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci I 205bf215546Sopenharmony_ci end() const { 206bf215546Sopenharmony_ci return j; 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci typename super::size_type 210bf215546Sopenharmony_ci size() const { 211bf215546Sopenharmony_ci return end() - begin(); 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci private: 215bf215546Sopenharmony_ci I i, j; 216bf215546Sopenharmony_ci }; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci namespace detail { 219bf215546Sopenharmony_ci template<typename T> 220bf215546Sopenharmony_ci using preferred_iterator_type = decltype(std::declval<T>().begin()); 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /// 224bf215546Sopenharmony_ci /// Range that transforms the contents of a number of source ranges 225bf215546Sopenharmony_ci /// \a os element-wise by using the provided functor \a f. Use 226bf215546Sopenharmony_ci /// map() as convenience constructor. 227bf215546Sopenharmony_ci /// 228bf215546Sopenharmony_ci template<typename F, typename... Os> 229bf215546Sopenharmony_ci class adaptor_range : 230bf215546Sopenharmony_ci public detail::basic_range<adaptor_range<F, Os...>, 231bf215546Sopenharmony_ci detail::iterator_adaptor< 232bf215546Sopenharmony_ci F, detail::preferred_iterator_type<Os>...>, 233bf215546Sopenharmony_ci detail::iterator_adaptor< 234bf215546Sopenharmony_ci F, detail::preferred_iterator_type<const Os>...> 235bf215546Sopenharmony_ci > { 236bf215546Sopenharmony_ci public: 237bf215546Sopenharmony_ci typedef detail::basic_range<adaptor_range<F, Os...>, 238bf215546Sopenharmony_ci detail::iterator_adaptor< 239bf215546Sopenharmony_ci F, detail::preferred_iterator_type<Os>...>, 240bf215546Sopenharmony_ci detail::iterator_adaptor< 241bf215546Sopenharmony_ci F, detail::preferred_iterator_type<const Os>...> 242bf215546Sopenharmony_ci > super; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci template<typename G, typename... Rs> 245bf215546Sopenharmony_ci adaptor_range(G &&f, Rs &&... os) : 246bf215546Sopenharmony_ci f(std::forward<G>(f)), os(std::forward<Rs>(os)...) { 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci bool 250bf215546Sopenharmony_ci operator==(const adaptor_range &r) const { 251bf215546Sopenharmony_ci return f == r.f && os == r.os; 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci typename super::iterator 255bf215546Sopenharmony_ci begin() { 256bf215546Sopenharmony_ci return { f, tuple::map(begins(), os) }; 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci typename super::iterator 260bf215546Sopenharmony_ci end() { 261bf215546Sopenharmony_ci return { f, tuple::map(advances_by(size()), 262bf215546Sopenharmony_ci tuple::map(begins(), os)) }; 263bf215546Sopenharmony_ci } 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci typename super::const_iterator 266bf215546Sopenharmony_ci begin() const { 267bf215546Sopenharmony_ci return { f, tuple::map(begins(), os) }; 268bf215546Sopenharmony_ci } 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci typename super::const_iterator 271bf215546Sopenharmony_ci end() const { 272bf215546Sopenharmony_ci return { f, tuple::map(advances_by(size()), 273bf215546Sopenharmony_ci tuple::map(begins(), os)) }; 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci typename super::size_type 277bf215546Sopenharmony_ci size() const { 278bf215546Sopenharmony_ci return tuple::apply(minimum(), tuple::map(sizes(), os)); 279bf215546Sopenharmony_ci } 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci private: 282bf215546Sopenharmony_ci F f; 283bf215546Sopenharmony_ci std::tuple<Os...> os; 284bf215546Sopenharmony_ci }; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci /// 287bf215546Sopenharmony_ci /// Range that contains all elements delimited by the index pair 288bf215546Sopenharmony_ci /// (\a i, \a j) in the source range \a r. Use slice() as 289bf215546Sopenharmony_ci /// convenience constructor. 290bf215546Sopenharmony_ci /// 291bf215546Sopenharmony_ci template<typename O> 292bf215546Sopenharmony_ci class slice_range : 293bf215546Sopenharmony_ci public detail::basic_range<slice_range<O>, 294bf215546Sopenharmony_ci detail::preferred_iterator_type<O>, 295bf215546Sopenharmony_ci detail::preferred_iterator_type<const O>> { 296bf215546Sopenharmony_ci public: 297bf215546Sopenharmony_ci typedef detail::basic_range<slice_range<O>, 298bf215546Sopenharmony_ci detail::preferred_iterator_type<O>, 299bf215546Sopenharmony_ci detail::preferred_iterator_type<const O> 300bf215546Sopenharmony_ci > super; 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci template<typename R> 303bf215546Sopenharmony_ci slice_range(R &&r, typename super::size_type i, 304bf215546Sopenharmony_ci typename super::size_type j) : 305bf215546Sopenharmony_ci o(std::forward<R>(r)), i(i), j(j) { 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci bool 309bf215546Sopenharmony_ci operator==(const slice_range &r) const { 310bf215546Sopenharmony_ci return o == r.o && i == r.i && j == r.j; 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci typename super::iterator 314bf215546Sopenharmony_ci begin() { 315bf215546Sopenharmony_ci return std::next(o.begin(), i); 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci typename super::iterator 319bf215546Sopenharmony_ci end() { 320bf215546Sopenharmony_ci return std::next(o.begin(), j); 321bf215546Sopenharmony_ci } 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci typename super::const_iterator 324bf215546Sopenharmony_ci begin() const { 325bf215546Sopenharmony_ci return std::next(o.begin(), i); 326bf215546Sopenharmony_ci } 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci typename super::const_iterator 329bf215546Sopenharmony_ci end() const { 330bf215546Sopenharmony_ci return std::next(o.begin(), j); 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci typename super::size_type 334bf215546Sopenharmony_ci size() const { 335bf215546Sopenharmony_ci return j - i; 336bf215546Sopenharmony_ci } 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci private: 339bf215546Sopenharmony_ci O o; 340bf215546Sopenharmony_ci typename super::size_type i, j; 341bf215546Sopenharmony_ci }; 342bf215546Sopenharmony_ci 343bf215546Sopenharmony_ci /// 344bf215546Sopenharmony_ci /// Create a range from an iterator pair (\a i, \a j). 345bf215546Sopenharmony_ci /// 346bf215546Sopenharmony_ci /// \sa iterator_range. 347bf215546Sopenharmony_ci /// 348bf215546Sopenharmony_ci template<typename T> 349bf215546Sopenharmony_ci iterator_range<T> 350bf215546Sopenharmony_ci range(T i, T j) { 351bf215546Sopenharmony_ci return { i, j }; 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci /// 355bf215546Sopenharmony_ci /// Create a range of \a n elements starting from iterator \a i. 356bf215546Sopenharmony_ci /// 357bf215546Sopenharmony_ci /// \sa iterator_range. 358bf215546Sopenharmony_ci /// 359bf215546Sopenharmony_ci template<typename T> 360bf215546Sopenharmony_ci iterator_range<T> 361bf215546Sopenharmony_ci range(T i, typename std::iterator_traits<T>::difference_type n) { 362bf215546Sopenharmony_ci return { i, i + n }; 363bf215546Sopenharmony_ci } 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci /// 366bf215546Sopenharmony_ci /// Create a range by transforming the contents of a number of 367bf215546Sopenharmony_ci /// source ranges \a rs element-wise using a provided functor \a f. 368bf215546Sopenharmony_ci /// 369bf215546Sopenharmony_ci /// \sa adaptor_range. 370bf215546Sopenharmony_ci /// 371bf215546Sopenharmony_ci template<typename F, typename... Rs> 372bf215546Sopenharmony_ci adaptor_range<F, Rs...> 373bf215546Sopenharmony_ci map(F &&f, Rs &&... rs) { 374bf215546Sopenharmony_ci return { std::forward<F>(f), std::forward<Rs>(rs)... }; 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci /// 378bf215546Sopenharmony_ci /// Create a range identical to another range \a r. 379bf215546Sopenharmony_ci /// 380bf215546Sopenharmony_ci template<typename R> 381bf215546Sopenharmony_ci adaptor_range<identity, R> 382bf215546Sopenharmony_ci range(R &&r) { 383bf215546Sopenharmony_ci return { identity(), std::forward<R>(r) }; 384bf215546Sopenharmony_ci } 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci /// 387bf215546Sopenharmony_ci /// Create a range by taking the elements delimited by the index 388bf215546Sopenharmony_ci /// pair (\a i, \a j) in a source range \a r. 389bf215546Sopenharmony_ci /// 390bf215546Sopenharmony_ci /// \sa slice_range. 391bf215546Sopenharmony_ci /// 392bf215546Sopenharmony_ci template<typename R> 393bf215546Sopenharmony_ci slice_range<R> 394bf215546Sopenharmony_ci slice(R &&r, typename slice_range<R>::size_type i, 395bf215546Sopenharmony_ci typename slice_range<R>::size_type j) { 396bf215546Sopenharmony_ci return { std::forward<R>(r), i, j }; 397bf215546Sopenharmony_ci } 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci /// 400bf215546Sopenharmony_ci /// Range that behaves as a vector of references of type \a T. 401bf215546Sopenharmony_ci /// 402bf215546Sopenharmony_ci /// Useful because STL containers cannot contain references to 403bf215546Sopenharmony_ci /// objects as elements. 404bf215546Sopenharmony_ci /// 405bf215546Sopenharmony_ci template<typename T> 406bf215546Sopenharmony_ci class ref_vector : public adaptor_range<derefs, std::vector<T *>> { 407bf215546Sopenharmony_ci public: 408bf215546Sopenharmony_ci ref_vector(std::initializer_list<std::reference_wrapper<T>> il) : 409bf215546Sopenharmony_ci adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) { 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci template<typename R> 413bf215546Sopenharmony_ci ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>( 414bf215546Sopenharmony_ci derefs(), map(addresses(), std::forward<R>(r))) { 415bf215546Sopenharmony_ci } 416bf215546Sopenharmony_ci }; 417bf215546Sopenharmony_ci} 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci#endif 420