Path: blob/21.2-virgl/src/gallium/frontends/clover/util/range.hpp
4572 views
//1// Copyright 2013 Francisco Jerez2//3// Permission is hereby granted, free of charge, to any person obtaining a4// copy of this software and associated documentation files (the "Software"),5// to deal in the Software without restriction, including without limitation6// the rights to use, copy, modify, merge, publish, distribute, sublicense,7// and/or sell copies of the Software, and to permit persons to whom the8// Software is furnished to do so, subject to the following conditions:9//10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19// OTHER DEALINGS IN THE SOFTWARE.20//2122#ifndef CLOVER_UTIL_RANGE_HPP23#define CLOVER_UTIL_RANGE_HPP2425#include <array>26#include <vector>2728#include "util/adaptor.hpp"2930namespace clover {31///32/// Class that identifies container types where the elements of a33/// range can be stored by the type conversion operator.34///35/// \a T identifies the range element type.36///37template<typename T, typename V>38struct range_store_traits;3940template<typename T, typename S>41struct range_store_traits<T, std::vector<S>> {42typedef void enable;4344template<typename R>45static std::vector<S>46create(const R &r) {47return { r.begin(), r.end() };48}49};5051template<typename T, typename S, std::size_t N>52struct range_store_traits<T, std::array<S, N>> {53typedef void enable;5455template<typename R>56static std::array<S, N>57create(const R &r) {58std::array<S, N> v;59assert(r.size() == v.size());60copy(r, v.begin());61return v;62}63};6465namespace detail {66///67/// Common functionality that is shared by other implementations68/// of the container concept.69///70template<typename R, typename I, typename CI>71class basic_range {72public:73typedef I iterator;74typedef CI const_iterator;75typedef typename std::iterator_traits<iterator>::value_type value_type;76typedef typename std::iterator_traits<iterator>::reference77reference;78typedef typename std::iterator_traits<const_iterator>::reference79const_reference;80typedef typename std::iterator_traits<iterator>::difference_type81difference_type;82typedef std::size_t size_type;8384bool85operator==(const basic_range &r) const {86return *static_cast<const R *>(this) == r;87}8889bool90operator!=(const basic_range &r) const {91return !(*this == r);92}9394iterator95begin() {96return static_cast<R *>(this)->begin();97}9899iterator100end() {101return static_cast<R *>(this)->end();102}103104const_iterator105begin() const {106return static_cast<const R *>(this)->begin();107}108109const_iterator110end() const {111return static_cast<const R *>(this)->end();112}113114std::reverse_iterator<iterator>115rbegin() {116return { begin() };117}118119std::reverse_iterator<iterator>120rend() {121return { end() };122}123124reference125front() {126return *begin();127}128129reference130back() {131return *(end() - 1);132}133134bool135empty() const {136return begin() == end();137}138139reference140at(size_type i) {141if (i >= static_cast<const R *>(this)->size())142throw std::out_of_range("");143144return begin()[i];145}146147const_reference148at(size_type i) const {149if (i >= static_cast<const R *>(this)->size())150throw std::out_of_range("");151152return begin()[i];153}154155reference156operator[](size_type i) {157return begin()[i];158}159160const_reference161operator[](size_type i) const {162return begin()[i];163}164165template<typename V>166using store_traits = range_store_traits<167typename std::remove_cv<value_type>::type, V168>;169170template<typename V,171typename = typename store_traits<V>::enable>172operator V() const {173return store_traits<V>::create(*static_cast<const R *>(this));174}175};176}177178///179/// Range that contains all elements delimited by an iterator pair180/// (\a i, \a j). Use range() as convenience constructor.181///182template<typename I>183class iterator_range : public detail::basic_range<iterator_range<I>, I, I> {184public:185typedef detail::basic_range<iterator_range<I>, I, I> super;186187iterator_range() : i(), j() {188}189190iterator_range(I i, I j) : i(i), j(j) {191}192193bool194operator==(const iterator_range &r) const {195return i == r.i && j == r.j;196}197198I199begin() const {200return i;201}202203I204end() const {205return j;206}207208typename super::size_type209size() const {210return end() - begin();211}212213private:214I i, j;215};216217namespace detail {218template<typename T>219using preferred_iterator_type = decltype(std::declval<T>().begin());220}221222///223/// Range that transforms the contents of a number of source ranges224/// \a os element-wise by using the provided functor \a f. Use225/// map() as convenience constructor.226///227template<typename F, typename... Os>228class adaptor_range :229public detail::basic_range<adaptor_range<F, Os...>,230detail::iterator_adaptor<231F, detail::preferred_iterator_type<Os>...>,232detail::iterator_adaptor<233F, detail::preferred_iterator_type<const Os>...>234> {235public:236typedef detail::basic_range<adaptor_range<F, Os...>,237detail::iterator_adaptor<238F, detail::preferred_iterator_type<Os>...>,239detail::iterator_adaptor<240F, detail::preferred_iterator_type<const Os>...>241> super;242243template<typename G, typename... Rs>244adaptor_range(G &&f, Rs &&... os) :245f(std::forward<G>(f)), os(std::forward<Rs>(os)...) {246}247248bool249operator==(const adaptor_range &r) const {250return f == r.f && os == r.os;251}252253typename super::iterator254begin() {255return { f, tuple::map(begins(), os) };256}257258typename super::iterator259end() {260return { f, tuple::map(advances_by(size()),261tuple::map(begins(), os)) };262}263264typename super::const_iterator265begin() const {266return { f, tuple::map(begins(), os) };267}268269typename super::const_iterator270end() const {271return { f, tuple::map(advances_by(size()),272tuple::map(begins(), os)) };273}274275typename super::size_type276size() const {277return tuple::apply(minimum(), tuple::map(sizes(), os));278}279280private:281F f;282std::tuple<Os...> os;283};284285///286/// Range that contains all elements delimited by the index pair287/// (\a i, \a j) in the source range \a r. Use slice() as288/// convenience constructor.289///290template<typename O>291class slice_range :292public detail::basic_range<slice_range<O>,293detail::preferred_iterator_type<O>,294detail::preferred_iterator_type<const O>> {295public:296typedef detail::basic_range<slice_range<O>,297detail::preferred_iterator_type<O>,298detail::preferred_iterator_type<const O>299> super;300301template<typename R>302slice_range(R &&r, typename super::size_type i,303typename super::size_type j) :304o(std::forward<R>(r)), i(i), j(j) {305}306307bool308operator==(const slice_range &r) const {309return o == r.o && i == r.i && j == r.j;310}311312typename super::iterator313begin() {314return std::next(o.begin(), i);315}316317typename super::iterator318end() {319return std::next(o.begin(), j);320}321322typename super::const_iterator323begin() const {324return std::next(o.begin(), i);325}326327typename super::const_iterator328end() const {329return std::next(o.begin(), j);330}331332typename super::size_type333size() const {334return j - i;335}336337private:338O o;339typename super::size_type i, j;340};341342///343/// Create a range from an iterator pair (\a i, \a j).344///345/// \sa iterator_range.346///347template<typename T>348iterator_range<T>349range(T i, T j) {350return { i, j };351}352353///354/// Create a range of \a n elements starting from iterator \a i.355///356/// \sa iterator_range.357///358template<typename T>359iterator_range<T>360range(T i, typename std::iterator_traits<T>::difference_type n) {361return { i, i + n };362}363364///365/// Create a range by transforming the contents of a number of366/// source ranges \a rs element-wise using a provided functor \a f.367///368/// \sa adaptor_range.369///370template<typename F, typename... Rs>371adaptor_range<F, Rs...>372map(F &&f, Rs &&... rs) {373return { std::forward<F>(f), std::forward<Rs>(rs)... };374}375376///377/// Create a range identical to another range \a r.378///379template<typename R>380adaptor_range<identity, R>381range(R &&r) {382return { identity(), std::forward<R>(r) };383}384385///386/// Create a range by taking the elements delimited by the index387/// pair (\a i, \a j) in a source range \a r.388///389/// \sa slice_range.390///391template<typename R>392slice_range<R>393slice(R &&r, typename slice_range<R>::size_type i,394typename slice_range<R>::size_type j) {395return { std::forward<R>(r), i, j };396}397398///399/// Range that behaves as a vector of references of type \a T.400///401/// Useful because STL containers cannot contain references to402/// objects as elements.403///404template<typename T>405class ref_vector : public adaptor_range<derefs, std::vector<T *>> {406public:407ref_vector(std::initializer_list<std::reference_wrapper<T>> il) :408adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) {409}410411template<typename R>412ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>(413derefs(), map(addresses(), std::forward<R>(r))) {414}415};416}417418#endif419420421