eedb/share/include/range/v3/view_interface.hpp
Wieczorek Bartosz f4ef592706 add ranges lib
2017-03-18 08:15:40 +01:00

305 lines
12 KiB
C++

/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//
#ifndef RANGES_V3_VIEW_INTERFACE_HPP
#define RANGES_V3_VIEW_INTERFACE_HPP
#include <iosfwd>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/range_concepts.hpp>
#include <range/v3/range_traits.hpp>
#include <range/v3/begin_end.hpp>
#include <range/v3/to_container.hpp>
#include <range/v3/utility/concepts.hpp>
#include <range/v3/utility/iterator.hpp>
#include <range/v3/utility/common_iterator.hpp>
namespace ranges
{
inline namespace v3
{
/// \cond
namespace detail
{
template<typename From, typename To = From>
struct slice_bounds
{
From from;
To to;
template<typename F, typename T,
CONCEPT_REQUIRES_(ConvertibleTo<F, From>() && ConvertibleTo<T, To>())>
slice_bounds(F from, T to)
: from(from), to(to)
{}
};
template<typename Int>
struct from_end_
{
Int dist_;
template<typename Other,
CONCEPT_REQUIRES_(Integral<Other>() && ExplicitlyConvertibleTo<Other, Int>())>
operator from_end_<Other> () const
{
return {static_cast<Other>(dist_)};
}
};
}
/// \endcond
/// \addtogroup group-core
/// @{
template<typename Derived, cardinality Cardinality /* = finite*/>
struct view_interface
: basic_view<Cardinality>
{
protected:
Derived & derived()
{
return static_cast<Derived &>(*this);
}
/// \overload
Derived const & derived() const
{
return static_cast<Derived const &>(*this);
}
~view_interface() = default;
public:
view_interface() = default;
view_interface(view_interface &&) = default;
view_interface(view_interface const &) = default;
view_interface &operator=(view_interface &&) = default;
view_interface &operator=(view_interface const &) = default;
// A few ways of testing whether a range can be empty:
constexpr bool empty() const
{
return Cardinality == 0 ? true : derived().begin() == derived().end();
}
constexpr bool operator!() const
{
return empty();
}
constexpr explicit operator bool() const
{
return !empty();
}
/// Access the size of the range, if it can be determined:
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && Cardinality >= 0)>
constexpr range_size_type_t<D> size() const
{
return (range_size_type_t<D>)Cardinality;
}
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && Cardinality < 0 &&
SizedSentinel<sentinel_t<const D>, iterator_t<const D>>())>
constexpr range_size_type_t<D> size() const
{
return iter_size(derived().begin(), derived().end());
}
/// Access the first element in a range:
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>())>
range_reference_t<D> front()
{
return *derived().begin();
}
/// \overload
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>())>
range_reference_t<D const> front() const
{
return *derived().begin();
}
/// Access the last element in a range:
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && BoundedRange<D &>() && BidirectionalRange<D &>())>
range_reference_t<D> back()
{
return *prev(derived().end());
}
/// \overload
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && BoundedRange<D const &>() && BidirectionalRange<D const &>())>
range_reference_t<D const> back() const
{
return *prev(derived().end());
}
/// Simple indexing:
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && RandomAccessRange<D &>())>
auto operator[](range_difference_type_t<D> n) ->
decltype(std::declval<D &>().begin()[n])
{
return derived().begin()[n];
}
/// \overload
template<typename D = Derived,
CONCEPT_REQUIRES_(Same<D, Derived>() && RandomAccessRange<D const &>())>
auto operator[](range_difference_type_t<D> n) const ->
decltype(std::declval<D const &>().begin()[n])
{
return derived().begin()[n];
}
/// Python-ic slicing:
// rng[{4,6}]
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>> offs) ->
decltype(std::declval<Slice>()(std::declval<D &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>> offs) const ->
decltype(std::declval<Slice>()(std::declval<D const &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
// rng[{4,end-2}]
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>,
detail::from_end_<range_difference_type_t<D>>> offs) ->
decltype(std::declval<Slice>()(std::declval<D &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>,
detail::from_end_<range_difference_type_t<D>>> offs) const ->
decltype(std::declval<Slice>()(std::declval<D const &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
// rng[{end-4,end-2}]
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<detail::from_end_<range_difference_type_t<D>>,
detail::from_end_<range_difference_type_t<D>>> offs) ->
decltype(std::declval<Slice>()(std::declval<D &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<detail::from_end_<range_difference_type_t<D>>,
detail::from_end_<range_difference_type_t<D>>> offs) const ->
decltype(std::declval<Slice>()(std::declval<D const &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
// rng[{4,end}]
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>, end_fn> offs) ->
decltype(std::declval<Slice>()(std::declval<D &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<range_difference_type_t<D>, end_fn> offs) const ->
decltype(std::declval<Slice>()(std::declval<D const &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
// rng[{end-4,end}]
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<detail::from_end_<range_difference_type_t<D>>, end_fn> offs) ->
decltype(std::declval<Slice>()(std::declval<D &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// \overload
template<typename D = Derived, typename Slice = view::slice_fn,
CONCEPT_REQUIRES_(Same<D, Derived>())>
auto operator[](detail::slice_bounds<detail::from_end_<range_difference_type_t<D>>, end_fn> offs) const ->
decltype(std::declval<Slice>()(std::declval<D const &>(), offs.from, offs.to))
{
return Slice{}(derived(), offs.from, offs.to);
}
/// Implicit conversion to something that looks like a container.
template<typename Container, typename D = Derived,
typename Alloc = typename Container::allocator_type, // HACKHACK
CONCEPT_REQUIRES_(detail::ConvertibleToContainer<D, Container>())>
operator Container ()
{
return ranges::to_<Container>(derived());
}
/// \overload
template<typename Container, typename D = Derived,
typename Alloc = typename Container::allocator_type, // HACKHACK
CONCEPT_REQUIRES_(detail::ConvertibleToContainer<D const, Container>())>
operator Container () const
{
return ranges::to_<Container>(derived());
}
/// \brief Print a range to an ostream
template<bool B = true, typename Stream = meta::if_c<B, std::ostream>>
friend Stream &operator<<(Stream &sout, Derived &rng)
{
auto it = ranges::begin(rng);
auto const e = ranges::end(rng);
if(it == e)
return sout << "[]";
sout << '[' << *it;
while(++it != e)
sout << ',' << *it;
sout << ']';
return sout;
}
/// \overload
template<bool B = true, typename Stream = meta::if_c<B, std::ostream>,
typename D = Derived, CONCEPT_REQUIRES_(InputRange<D const &>())>
friend Stream &operator<<(Stream &sout, Derived const &rng)
{
auto it = ranges::begin(rng);
auto const e = ranges::end(rng);
if(it == e)
{
sout << "[]";
return sout;
}
sout << '[' << *it;
while(++it != e)
sout << ',' << *it;
sout << ']';
return sout;
}
/// \overload
template<bool B = true, typename Stream = meta::if_c<B, std::ostream>>
friend Stream &operator<<(Stream &sout, Derived &&rng)
{
sout << rng;
return sout;
}
};
/// @}
}
}
#endif