+++ /dev/null
-//
-// Copyright 2013 Francisco Jerez
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation
-// the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-//
-
-#ifndef CLOVER_UTIL_RANGE_HPP
-#define CLOVER_UTIL_RANGE_HPP
-
-#include <array>
-#include <vector>
-
-#include "util/adaptor.hpp"
-
-namespace clover {
- ///
- /// Class that identifies container types where the elements of a
- /// range can be stored by the type conversion operator.
- ///
- /// \a T identifies the range element type.
- ///
- template<typename T, typename V>
- struct range_store_traits;
-
- template<typename T, typename S>
- struct range_store_traits<T, std::vector<S>> {
- typedef void enable;
-
- template<typename R>
- static std::vector<S>
- create(const R &r) {
- return { r.begin(), r.end() };
- }
- };
-
- template<typename T, typename S, std::size_t N>
- struct range_store_traits<T, std::array<S, N>> {
- typedef void enable;
-
- template<typename R>
- static std::array<S, N>
- create(const R &r) {
- std::array<S, N> v;
- assert(r.size() == v.size());
- copy(r, v.begin());
- return v;
- }
- };
-
- namespace detail {
- ///
- /// Common functionality that is shared by other implementations
- /// of the container concept.
- ///
- template<typename R, typename I, typename CI>
- class basic_range {
- public:
- typedef I iterator;
- typedef CI const_iterator;
- typedef typename std::iterator_traits<iterator>::value_type value_type;
- typedef typename std::iterator_traits<iterator>::reference
- reference;
- typedef typename std::iterator_traits<const_iterator>::reference
- const_reference;
- typedef typename std::iterator_traits<iterator>::difference_type
- difference_type;
- typedef std::size_t size_type;
-
- bool
- operator==(const basic_range &r) const {
- return *static_cast<const R *>(this) == r;
- }
-
- bool
- operator!=(const basic_range &r) const {
- return !(*this == r);
- }
-
- iterator
- begin() {
- return static_cast<R *>(this)->begin();
- }
-
- iterator
- end() {
- return static_cast<R *>(this)->end();
- }
-
- const_iterator
- begin() const {
- return static_cast<const R *>(this)->begin();
- }
-
- const_iterator
- end() const {
- return static_cast<const R *>(this)->end();
- }
-
- std::reverse_iterator<iterator>
- rbegin() {
- return { begin() };
- }
-
- std::reverse_iterator<iterator>
- rend() {
- return { end() };
- }
-
- reference
- front() {
- return *begin();
- }
-
- reference
- back() {
- return *(end() - 1);
- }
-
- bool
- empty() const {
- return begin() == end();
- }
-
- reference
- at(size_type i) {
- if (i >= static_cast<const R *>(this)->size())
- throw std::out_of_range("");
-
- return begin()[i];
- }
-
- const_reference
- at(size_type i) const {
- if (i >= static_cast<const R *>(this)->size())
- throw std::out_of_range("");
-
- return begin()[i];
- }
-
- reference
- operator[](size_type i) {
- return begin()[i];
- }
-
- const_reference
- operator[](size_type i) const {
- return begin()[i];
- }
-
- template<typename V>
- using store_traits = range_store_traits<
- typename std::remove_cv<value_type>::type, V
- >;
-
- template<typename V,
- typename = typename store_traits<V>::enable>
- operator V() const {
- return store_traits<V>::create(*static_cast<const R *>(this));
- }
- };
- }
-
- ///
- /// Range that contains all elements delimited by an iterator pair
- /// (\a i, \a j). Use range() as convenience constructor.
- ///
- template<typename I>
- class iterator_range : public detail::basic_range<iterator_range<I>, I, I> {
- public:
- typedef detail::basic_range<iterator_range<I>, I, I> super;
-
- iterator_range() : i(), j() {
- }
-
- iterator_range(I i, I j) : i(i), j(j) {
- }
-
- bool
- operator==(const iterator_range &r) const {
- return i == r.i && j == r.j;
- }
-
- I
- begin() const {
- return i;
- }
-
- I
- end() const {
- return j;
- }
-
- typename super::size_type
- size() const {
- return end() - begin();
- }
-
- private:
- I i, j;
- };
-
- namespace detail {
- template<typename T>
- using preferred_iterator_type = decltype(std::declval<T>().begin());
- }
-
- ///
- /// Range that transforms the contents of a number of source ranges
- /// \a os element-wise by using the provided functor \a f. Use
- /// map() as convenience constructor.
- ///
- template<typename F, typename... Os>
- class adaptor_range :
- public detail::basic_range<adaptor_range<F, Os...>,
- detail::iterator_adaptor<
- F, detail::preferred_iterator_type<Os>...>,
- detail::iterator_adaptor<
- F, detail::preferred_iterator_type<const Os>...>
- > {
- public:
- typedef detail::basic_range<adaptor_range<F, Os...>,
- detail::iterator_adaptor<
- F, detail::preferred_iterator_type<Os>...>,
- detail::iterator_adaptor<
- F, detail::preferred_iterator_type<const Os>...>
- > super;
-
- template<typename G, typename... Rs>
- adaptor_range(G &&f, Rs &&... os) :
- f(std::forward<G>(f)), os(std::forward<Rs>(os)...) {
- }
-
- bool
- operator==(const adaptor_range &r) const {
- return f == r.f && os == r.os;
- }
-
- typename super::iterator
- begin() {
- return { f, tuple::map(begins(), os) };
- }
-
- typename super::iterator
- end() {
- return { f, tuple::map(advances_by(size()),
- tuple::map(begins(), os)) };
- }
-
- typename super::const_iterator
- begin() const {
- return { f, tuple::map(begins(), os) };
- }
-
- typename super::const_iterator
- end() const {
- return { f, tuple::map(advances_by(size()),
- tuple::map(begins(), os)) };
- }
-
- typename super::size_type
- size() const {
- return tuple::apply(minimum(), tuple::map(sizes(), os));
- }
-
- private:
- F f;
- std::tuple<Os...> os;
- };
-
- ///
- /// Range that contains all elements delimited by the index pair
- /// (\a i, \a j) in the source range \a r. Use slice() as
- /// convenience constructor.
- ///
- template<typename O>
- class slice_range :
- public detail::basic_range<slice_range<O>,
- detail::preferred_iterator_type<O>,
- detail::preferred_iterator_type<const O>> {
- public:
- typedef detail::basic_range<slice_range<O>,
- detail::preferred_iterator_type<O>,
- detail::preferred_iterator_type<const O>
- > super;
-
- template<typename R>
- slice_range(R &&r, typename super::size_type i,
- typename super::size_type j) :
- o(std::forward<R>(r)), i(i), j(j) {
- }
-
- bool
- operator==(const slice_range &r) const {
- return o == r.o && i == r.i && j == r.j;
- }
-
- typename super::iterator
- begin() {
- return std::next(o.begin(), i);
- }
-
- typename super::iterator
- end() {
- return std::next(o.begin(), j);
- }
-
- typename super::const_iterator
- begin() const {
- return std::next(o.begin(), i);
- }
-
- typename super::const_iterator
- end() const {
- return std::next(o.begin(), j);
- }
-
- typename super::size_type
- size() const {
- return j - i;
- }
-
- private:
- O o;
- typename super::size_type i, j;
- };
-
- ///
- /// Create a range from an iterator pair (\a i, \a j).
- ///
- /// \sa iterator_range.
- ///
- template<typename T>
- iterator_range<T>
- range(T i, T j) {
- return { i, j };
- }
-
- ///
- /// Create a range of \a n elements starting from iterator \a i.
- ///
- /// \sa iterator_range.
- ///
- template<typename T>
- iterator_range<T>
- range(T i, typename std::iterator_traits<T>::difference_type n) {
- return { i, i + n };
- }
-
- ///
- /// Create a range by transforming the contents of a number of
- /// source ranges \a rs element-wise using a provided functor \a f.
- ///
- /// \sa adaptor_range.
- ///
- template<typename F, typename... Rs>
- adaptor_range<F, Rs...>
- map(F &&f, Rs &&... rs) {
- return { std::forward<F>(f), std::forward<Rs>(rs)... };
- }
-
- ///
- /// Create a range identical to another range \a r.
- ///
- template<typename R>
- adaptor_range<identity, R>
- range(R &&r) {
- return { identity(), std::forward<R>(r) };
- }
-
- ///
- /// Create a range by taking the elements delimited by the index
- /// pair (\a i, \a j) in a source range \a r.
- ///
- /// \sa slice_range.
- ///
- template<typename R>
- slice_range<R>
- slice(R &&r, typename slice_range<R>::size_type i,
- typename slice_range<R>::size_type j) {
- return { std::forward<R>(r), i, j };
- }
-
- ///
- /// Range that behaves as a vector of references of type \a T.
- ///
- /// Useful because STL containers cannot contain references to
- /// objects as elements.
- ///
- template<typename T>
- class ref_vector : public adaptor_range<derefs, std::vector<T *>> {
- public:
- ref_vector(std::initializer_list<std::reference_wrapper<T>> il) :
- adaptor_range<derefs, std::vector<T *>>(derefs(), map(addresses(), il)) {
- }
-
- template<typename R>
- ref_vector(R &&r) : adaptor_range<derefs, std::vector<T *>>(
- derefs(), map(addresses(), std::forward<R>(r))) {
- }
- };
-}
-
-#endif