739 lines
27 KiB
C++
739 lines
27 KiB
C++
//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief Iterator range type based on c++1y range proposal.
|
|
///
|
|
/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLD_CORE_RANGE_H
|
|
#define LLD_CORE_RANGE_H
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace lld {
|
|
// Nothing in this namespace is part of the exported interface.
|
|
namespace detail {
|
|
using std::begin;
|
|
using std::end;
|
|
/// Used as the result type of undefined functions.
|
|
struct undefined {};
|
|
|
|
template <typename R> class begin_result {
|
|
template <typename T> static auto check(T &&t) -> decltype(begin(t));
|
|
static undefined check(...);
|
|
public:
|
|
typedef decltype(check(std::declval<R>())) type;
|
|
};
|
|
|
|
template <typename R> class end_result {
|
|
template <typename T> static auto check(T &&t) -> decltype(end(t));
|
|
static undefined check(...);
|
|
public:
|
|
typedef decltype(check(std::declval<R>())) type;
|
|
};
|
|
|
|
// Things that begin and end work on, in compatible ways, are
|
|
// ranges. [stmt.ranged]
|
|
template <typename R>
|
|
struct is_range : std::is_same<typename detail::begin_result<R>::type,
|
|
typename detail::end_result<R>::type> {};
|
|
|
|
// This currently requires specialization and doesn't work for
|
|
// detecting \c range<>s or iterators. We should add
|
|
// \c contiguous_iterator_tag to fix that.
|
|
template <typename R> struct is_contiguous_range : std::false_type {};
|
|
template <typename R>
|
|
struct is_contiguous_range<R &> : is_contiguous_range<R> {};
|
|
template <typename R>
|
|
struct is_contiguous_range <R &&> : is_contiguous_range<R> {};
|
|
template <typename R>
|
|
struct is_contiguous_range<const R> : is_contiguous_range<R> {};
|
|
|
|
template <typename T, size_t N>
|
|
struct is_contiguous_range<T[N]> : std::true_type {};
|
|
template <typename T, size_t N>
|
|
struct is_contiguous_range<const T[N]> : std::true_type {};
|
|
template <typename T, size_t N>
|
|
struct is_contiguous_range<std::array<T, N> > : std::true_type {};
|
|
template <typename charT, typename traits, typename Allocator>
|
|
struct is_contiguous_range<
|
|
std::basic_string<charT, traits, Allocator> > : std::true_type {};
|
|
template <typename T, typename Allocator>
|
|
struct is_contiguous_range<std::vector<T, Allocator> > : std::true_type {};
|
|
|
|
// Removes cv qualifiers from all levels of a multi-level pointer
|
|
// type, not just the type level.
|
|
template <typename T> struct remove_all_cv_ptr {
|
|
typedef T type;
|
|
};
|
|
template <typename T> struct remove_all_cv_ptr<T *> {
|
|
typedef typename remove_all_cv_ptr<T>::type *type;
|
|
};
|
|
template <typename T> struct remove_all_cv_ptr<const T> {
|
|
typedef typename remove_all_cv_ptr<T>::type type;
|
|
};
|
|
template <typename T> struct remove_all_cv_ptr<volatile T> {
|
|
typedef typename remove_all_cv_ptr<T>::type type;
|
|
};
|
|
template <typename T> struct remove_all_cv_ptr<const volatile T> {
|
|
typedef typename remove_all_cv_ptr<T>::type type;
|
|
};
|
|
|
|
template <typename From, typename To>
|
|
struct conversion_preserves_array_indexing : std::false_type {};
|
|
|
|
template <typename FromVal, typename ToVal>
|
|
struct conversion_preserves_array_indexing<FromVal *,
|
|
ToVal *> : std::integral_constant<
|
|
bool, std::is_convertible<FromVal *, ToVal *>::value &&
|
|
std::is_same<typename remove_all_cv_ptr<FromVal>::type,
|
|
typename remove_all_cv_ptr<ToVal>::type>::value> {};
|
|
|
|
template <typename T>
|
|
LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) {
|
|
return begin(std::forward<T>(t));
|
|
}
|
|
|
|
template <typename T> LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) {
|
|
return end(std::forward<T>(t));
|
|
}
|
|
} // end namespace detail
|
|
|
|
/// A \c std::range<Iterator> represents a half-open iterator range
|
|
/// built from two iterators, \c 'begin', and \c 'end'. If \c end is
|
|
/// not reachable from \c begin, the behavior is undefined.
|
|
///
|
|
/// The mutability of elements of the range is controlled by the
|
|
/// Iterator argument. Instantiate
|
|
/// <code>range<<var>Foo</var>::iterator></code> or
|
|
/// <code>range<<var>T</var>*></code>, or call
|
|
/// <code>make_range(<var>non_const_container</var>)</code>, and you
|
|
/// get a mutable range. Instantiate
|
|
/// <code>range<<var>Foo</var>::const_iterator></code> or
|
|
/// <code>range<const <var>T</var>*></code>, or call
|
|
/// <code>make_range(<var>const_container</var>)</code>, and you get a
|
|
/// constant range.
|
|
///
|
|
/// \todo Inherit from std::pair<Iterator, Iterator>?
|
|
///
|
|
/// \todo This interface contains some functions that could be
|
|
/// provided as free algorithms rather than member functions, and all
|
|
/// of the <code>pop_*()</code> functions could be replaced by \c
|
|
/// slice() at the cost of some extra iterator copies. This makes
|
|
/// them more awkward to use, but makes it easier for users to write
|
|
/// their own types that follow the same interface. On the other hand,
|
|
/// a \c range_facade could be provided to help users write new
|
|
/// ranges, and it could provide the members. Such functions are
|
|
/// marked with a note in their documentation. (Of course, all of
|
|
/// these member functions could be provided as free functions using
|
|
/// the iterator access methods, but one goal here is to allow people
|
|
/// to program without touching iterators at all.)
|
|
template <typename Iterator> class range {
|
|
Iterator begin_, end_;
|
|
public:
|
|
/// \name types
|
|
/// @{
|
|
|
|
/// The iterator category of \c Iterator.
|
|
/// \todo Consider defining range categories. If they don't add
|
|
/// anything over the corresponding iterator categories, then
|
|
/// they're probably not worth defining.
|
|
typedef typename std::iterator_traits<
|
|
Iterator>::iterator_category iterator_category;
|
|
/// The type of elements of the range. Not cv-qualified.
|
|
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
|
/// The type of the size of the range and offsets within the range.
|
|
typedef typename std::iterator_traits<
|
|
Iterator>::difference_type difference_type;
|
|
/// The return type of element access methods: \c front(), \c back(), etc.
|
|
typedef typename std::iterator_traits<Iterator>::reference reference;
|
|
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
|
/// @}
|
|
|
|
/// \name constructors
|
|
/// @{
|
|
|
|
/// Creates a range of default-constructed (<em>not</em>
|
|
/// value-initialized) iterators. For most \c Iterator types, this
|
|
/// will be an invalid range.
|
|
range() : begin_(), end_() {}
|
|
|
|
/// \pre \c end is reachable from \c begin.
|
|
/// \post <code>this->begin() == begin && this->end() == end</code>
|
|
LLVM_CONSTEXPR range(Iterator begin, Iterator end)
|
|
: begin_(begin), end_(end) {}
|
|
|
|
/// \par Participates in overload resolution if:
|
|
/// - \c Iterator is not a pointer type,
|
|
/// - \c begin(r) and \c end(r) return the same type, and
|
|
/// - that type is convertible to \c Iterator.
|
|
///
|
|
/// \todo std::begin and std::end are overloaded between T& and
|
|
/// const T&, which means that if a container has only a non-const
|
|
/// begin or end method, then it's ill-formed to pass an rvalue to
|
|
/// the free function. To avoid that problem, we don't use
|
|
/// std::forward<> here, so begin() and end() are always called with
|
|
/// an lvalue. Another option would be to insist that rvalue
|
|
/// arguments to range() must have const begin() and end() methods.
|
|
template <typename R> LLVM_CONSTEXPR range(
|
|
R &&r,
|
|
typename std::enable_if<
|
|
!std::is_pointer<Iterator>::value &&
|
|
detail::is_range<R>::value &&
|
|
std::is_convertible<typename detail::begin_result<R>::type,
|
|
Iterator>::value>::type* = 0)
|
|
: begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {}
|
|
|
|
/// This constructor creates a \c range<T*> from any range with
|
|
/// contiguous iterators. Because dereferencing a past-the-end
|
|
/// iterator can be undefined behavior, empty ranges get initialized
|
|
/// with \c nullptr rather than \c &*begin().
|
|
///
|
|
/// \par Participates in overload resolution if:
|
|
/// - \c Iterator is a pointer type \c T*,
|
|
/// - \c begin(r) and \c end(r) return the same type,
|
|
/// - elements \c i of that type satisfy the invariant
|
|
/// <code>&*(i + N) == (&*i) + N</code>, and
|
|
/// - The result of <code>&*begin()</code> is convertible to \c T*
|
|
/// using only qualification conversions [conv.qual] (since
|
|
/// pointer conversions stop the pointer from pointing to an
|
|
/// array element).
|
|
///
|
|
/// \todo The <code>&*(i + N) == (&*i) + N</code> invariant is
|
|
/// currently impossible to check for user-defined types. We need a
|
|
/// \c contiguous_iterator_tag to let users assert it.
|
|
template <typename R> LLVM_CONSTEXPR range(
|
|
R &&r,
|
|
typename std::enable_if<
|
|
std::is_pointer<Iterator>::value &&
|
|
detail::is_contiguous_range<R>::value
|
|
// MSVC returns false for this in this context, but not if we lift it out of the
|
|
// constructor.
|
|
#ifndef _MSC_VER
|
|
&& detail::conversion_preserves_array_indexing<
|
|
decltype(&*detail::adl_begin(r)), Iterator>::value
|
|
#endif
|
|
>::type* = 0)
|
|
: begin_((detail::adl_begin(r) == detail::adl_end(r) &&
|
|
!std::is_pointer<decltype(detail::adl_begin(r))>::value)
|
|
// For non-pointers, &*begin(r) is only defined behavior
|
|
// if there's an element there. Otherwise, use nullptr
|
|
// since the user can't dereference it anyway. This _is_
|
|
// detectable.
|
|
? nullptr : &*detail::adl_begin(r)),
|
|
end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {}
|
|
|
|
/// @}
|
|
|
|
/// \name iterator access
|
|
/// @{
|
|
LLVM_CONSTEXPR Iterator begin() const { return begin_; }
|
|
LLVM_CONSTEXPR Iterator end() const { return end_; }
|
|
/// @}
|
|
|
|
/// \name element access
|
|
/// @{
|
|
|
|
/// \par Complexity:
|
|
/// O(1)
|
|
/// \pre \c !empty()
|
|
/// \returns a reference to the element at the front of the range.
|
|
LLVM_CONSTEXPR reference front() const { return *begin(); }
|
|
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to \c
|
|
/// std::bidirectional_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(2) (Involves copying and decrementing an iterator, so not
|
|
/// quite as cheap as \c front())
|
|
///
|
|
/// \pre \c !empty()
|
|
/// \returns a reference to the element at the front of the range.
|
|
LLVM_CONSTEXPR reference back() const {
|
|
static_assert(
|
|
std::is_convertible<iterator_category,
|
|
std::bidirectional_iterator_tag>::value,
|
|
"Can only retrieve the last element of a bidirectional range.");
|
|
using std::prev;
|
|
return *prev(end());
|
|
}
|
|
|
|
/// This method is drawn from scripting language indexing. It
|
|
/// indexes std::forward from the beginning of the range if the argument
|
|
/// is positive, or backwards from the end of the array if the
|
|
/// argument is negative.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1)
|
|
///
|
|
/// \pre <code>abs(index) < size() || index == -size()</code>
|
|
///
|
|
/// \returns if <code>index >= 0</code>, a reference to the
|
|
/// <code>index</code>'th element in the range. Otherwise, a
|
|
/// reference to the <code>size()+index</code>'th element.
|
|
LLVM_CONSTEXPR reference operator[](difference_type index) const {
|
|
static_assert(std::is_convertible<iterator_category,
|
|
std::random_access_iterator_tag>::value,
|
|
"Can only index into a random-access range.");
|
|
// Less readable construction for constexpr support.
|
|
return index < 0 ? end()[index]
|
|
: begin()[index];
|
|
}
|
|
/// @}
|
|
|
|
/// \name size
|
|
/// @{
|
|
|
|
/// \par Complexity:
|
|
/// O(1)
|
|
/// \returns \c true if the range contains no elements.
|
|
LLVM_CONSTEXPR bool empty() const { return begin() == end(); }
|
|
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::forward_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1) if \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag. O(<code>size()</code>)
|
|
/// otherwise.
|
|
///
|
|
/// \returns the number of times \c pop_front() can be called before
|
|
/// \c empty() becomes true.
|
|
LLVM_CONSTEXPR difference_type size() const {
|
|
static_assert(std::is_convertible<iterator_category,
|
|
std::forward_iterator_tag>::value,
|
|
"Calling size on an input range would destroy the range.");
|
|
return dispatch_size(iterator_category());
|
|
}
|
|
/// @}
|
|
|
|
/// \name traversal from the beginning of the range
|
|
/// @{
|
|
|
|
/// Advances the beginning of the range by one element.
|
|
/// \pre \c !empty()
|
|
void pop_front() { ++begin_; }
|
|
|
|
/// Advances the beginning of the range by \c n elements.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1) if \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
|
|
///
|
|
/// \pre <code>n >= 0</code>, and there must be at least \c n
|
|
/// elements in the range.
|
|
void pop_front(difference_type n) { advance(begin_, n); }
|
|
|
|
/// Advances the beginning of the range by at most \c n elements,
|
|
/// stopping if the range becomes empty. A negative argument causes
|
|
/// no change.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1) if \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag, O(<code>min(n,
|
|
/// <var>#-elements-in-range</var>)</code>) otherwise.
|
|
///
|
|
/// \note Could be provided as a free function with little-to-no
|
|
/// loss in efficiency.
|
|
void pop_front_upto(difference_type n) {
|
|
advance_upto(begin_, std::max<difference_type>(0, n), end_,
|
|
iterator_category());
|
|
}
|
|
|
|
/// @}
|
|
|
|
/// \name traversal from the end of the range
|
|
/// @{
|
|
|
|
/// Moves the end of the range earlier by one element.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::bidirectional_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1)
|
|
///
|
|
/// \pre \c !empty()
|
|
void pop_back() {
|
|
static_assert(std::is_convertible<iterator_category,
|
|
std::bidirectional_iterator_tag>::value,
|
|
"Can only access the end of a bidirectional range.");
|
|
--end_;
|
|
}
|
|
|
|
/// Moves the end of the range earlier by \c n elements.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::bidirectional_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1) if \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
|
|
///
|
|
/// \pre <code>n >= 0</code>, and there must be at least \c n
|
|
/// elements in the range.
|
|
void pop_back(difference_type n) {
|
|
static_assert(std::is_convertible<iterator_category,
|
|
std::bidirectional_iterator_tag>::value,
|
|
"Can only access the end of a bidirectional range.");
|
|
advance(end_, -n);
|
|
}
|
|
|
|
/// Moves the end of the range earlier by <code>min(n,
|
|
/// size())</code> elements. A negative argument causes no change.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::bidirectional_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// O(1) if \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag, O(<code>min(n,
|
|
/// <var>#-elements-in-range</var>)</code>) otherwise.
|
|
///
|
|
/// \note Could be provided as a free function with little-to-no
|
|
/// loss in efficiency.
|
|
void pop_back_upto(difference_type n) {
|
|
static_assert(std::is_convertible<iterator_category,
|
|
std::bidirectional_iterator_tag>::value,
|
|
"Can only access the end of a bidirectional range.");
|
|
advance_upto(end_, -std::max<difference_type>(0, n), begin_,
|
|
iterator_category());
|
|
}
|
|
|
|
/// @}
|
|
|
|
/// \name creating derived ranges
|
|
/// @{
|
|
|
|
/// Divides the range into two pieces at \c index, where a positive
|
|
/// \c index represents an offset from the beginning of the range
|
|
/// and a negative \c index represents an offset from the end.
|
|
/// <code>range[index]</code> is the first element in the second
|
|
/// piece. If <code>index >= size()</code>, the second piece
|
|
/// will be empty. If <code>index < -size()</code>, the first
|
|
/// piece will be empty.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::forward_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// - If \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag: O(1)
|
|
/// - Otherwise, if \c iterator_category is convertible to \c
|
|
/// std::bidirectional_iterator_tag, \c abs(index) iterator increments
|
|
/// or decrements
|
|
/// - Otherwise, if <code>index >= 0</code>, \c index iterator
|
|
/// increments
|
|
/// - Otherwise, <code>size() + (size() + index)</code>
|
|
/// iterator increments.
|
|
///
|
|
/// \returns a pair of adjacent ranges.
|
|
///
|
|
/// \post
|
|
/// - <code>result.first.size() == min(index, this->size())</code>
|
|
/// - <code>result.first.end() == result.second.begin()</code>
|
|
/// - <code>result.first.size() + result.second.size()</code> <code>==
|
|
/// this->size()</code>
|
|
///
|
|
/// \todo split() could take an arbitrary number of indices and
|
|
/// return an <code>N+1</code>-element \c tuple<>. This is tricky to
|
|
/// implement with negative indices in the optimal number of
|
|
/// increments or decrements for a bidirectional iterator, but it
|
|
/// should be possible. Do we want it?
|
|
std::pair<range, range> split(difference_type index) const {
|
|
static_assert(
|
|
std::is_convertible<iterator_category,
|
|
std::forward_iterator_tag>::value,
|
|
"Calling split on a non-std::forward range would return a useless "
|
|
"first result.");
|
|
if (index >= 0) {
|
|
range second = *this;
|
|
second.pop_front_upto(index);
|
|
return make_pair(range(begin(), second.begin()), second);
|
|
} else {
|
|
return dispatch_split_neg(index, iterator_category());
|
|
}
|
|
}
|
|
|
|
/// \returns A sub-range from \c start to \c stop (not including \c
|
|
/// stop, as usual). \c start and \c stop are interpreted as for
|
|
/// <code>operator[]</code>, with negative values offsetting from
|
|
/// the end of the range. Omitting the \c stop argument makes the
|
|
/// sub-range continue to the end of the original range. Positive
|
|
/// arguments saturate to the end of the range, and negative
|
|
/// arguments saturate to the beginning. If \c stop is before \c
|
|
/// start, returns an empty range beginning and ending at \c start.
|
|
///
|
|
/// \par Ill-formed unless:
|
|
/// \c iterator_category is convertible to
|
|
/// \c std::forward_iterator_tag.
|
|
///
|
|
/// \par Complexity:
|
|
/// - If \c iterator_category is convertible to \c
|
|
/// std::random_access_iterator_tag: O(1)
|
|
/// - Otherwise, if \c iterator_category is convertible to \c
|
|
/// std::bidirectional_iterator_tag, at most <code>min(abs(start),
|
|
/// size()) + min(abs(stop), size())</code> iterator
|
|
/// increments or decrements
|
|
/// - Otherwise, if <code>start >= 0 && stop >= 0</code>,
|
|
/// <code>max(start, stop)</code> iterator increments
|
|
/// - Otherwise, <code>size() + max(start', stop')</code>
|
|
/// iterator increments, where \c start' and \c stop' are the
|
|
/// offsets of the elements \c start and \c stop refer to.
|
|
///
|
|
/// \note \c slice(start) should be implemented with a different
|
|
/// overload, rather than defaulting \c stop to
|
|
/// <code>numeric_limits<difference_type>::max()</code>, because
|
|
/// using a default would force non-random-access ranges to use an
|
|
/// O(<code>size()</code>) algorithm to compute the end rather
|
|
/// than the O(1) they're capable of.
|
|
range slice(difference_type start, difference_type stop) const {
|
|
static_assert(
|
|
std::is_convertible<iterator_category,
|
|
std::forward_iterator_tag>::value,
|
|
"Calling slice on a non-std::forward range would destroy the original "
|
|
"range.");
|
|
return dispatch_slice(start, stop, iterator_category());
|
|
}
|
|
|
|
range slice(difference_type start) const {
|
|
static_assert(
|
|
std::is_convertible<iterator_category,
|
|
std::forward_iterator_tag>::value,
|
|
"Calling slice on a non-std::forward range would destroy the original "
|
|
"range.");
|
|
return split(start).second;
|
|
}
|
|
|
|
/// @}
|
|
|
|
private:
|
|
// advance_upto: should be added to <algorithm>, but I'll use it as
|
|
// a helper function here.
|
|
//
|
|
// These return the number of increments that weren't applied
|
|
// because we ran into 'limit' (or 0 if we didn't run into limit).
|
|
static difference_type advance_upto(Iterator &it, difference_type n,
|
|
Iterator limit, std::input_iterator_tag) {
|
|
if (n < 0)
|
|
return 0;
|
|
while (it != limit && n > 0) {
|
|
++it;
|
|
--n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static difference_type advance_upto(Iterator &it, difference_type n,
|
|
Iterator limit,
|
|
std::bidirectional_iterator_tag) {
|
|
if (n < 0) {
|
|
while (it != limit && n < 0) {
|
|
--it;
|
|
++n;
|
|
}
|
|
} else {
|
|
while (it != limit && n > 0) {
|
|
++it;
|
|
--n;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static difference_type advance_upto(Iterator &it, difference_type n,
|
|
Iterator limit,
|
|
std::random_access_iterator_tag) {
|
|
difference_type distance = limit - it;
|
|
if (distance < 0)
|
|
assert(n <= 0);
|
|
else if (distance > 0)
|
|
assert(n >= 0);
|
|
|
|
if (abs(distance) > abs(n)) {
|
|
it += n;
|
|
return 0;
|
|
} else {
|
|
it = limit;
|
|
return n - distance;
|
|
}
|
|
}
|
|
|
|
// Dispatch functions.
|
|
difference_type dispatch_size(std::forward_iterator_tag) const {
|
|
return std::distance(begin(), end());
|
|
}
|
|
|
|
LLVM_CONSTEXPR difference_type dispatch_size(
|
|
std::random_access_iterator_tag) const {
|
|
return end() - begin();
|
|
}
|
|
|
|
std::pair<range, range> dispatch_split_neg(difference_type index,
|
|
std::forward_iterator_tag) const {
|
|
assert(index < 0);
|
|
difference_type size = this->size();
|
|
return split(std::max<difference_type>(0, size + index));
|
|
}
|
|
|
|
std::pair<range, range> dispatch_split_neg(
|
|
difference_type index, std::bidirectional_iterator_tag) const {
|
|
assert(index < 0);
|
|
range first = *this;
|
|
first.pop_back_upto(-index);
|
|
return make_pair(first, range(first.end(), end()));
|
|
}
|
|
|
|
range dispatch_slice(difference_type start, difference_type stop,
|
|
std::forward_iterator_tag) const {
|
|
if (start < 0 || stop < 0) {
|
|
difference_type size = this->size();
|
|
if (start < 0)
|
|
start = std::max<difference_type>(0, size + start);
|
|
if (stop < 0)
|
|
stop = size + stop; // Possibly negative; will be fixed in 2 lines.
|
|
}
|
|
stop = std::max<difference_type>(start, stop);
|
|
|
|
Iterator first = begin();
|
|
advance_upto(first, start, end(), iterator_category());
|
|
Iterator last = first;
|
|
advance_upto(last, stop - start, end(), iterator_category());
|
|
return range(first, last);
|
|
}
|
|
|
|
range dispatch_slice(const difference_type start, const difference_type stop,
|
|
std::bidirectional_iterator_tag) const {
|
|
Iterator first;
|
|
if (start < 0) {
|
|
first = end();
|
|
advance_upto(first, start, begin(), iterator_category());
|
|
} else {
|
|
first = begin();
|
|
advance_upto(first, start, end(), iterator_category());
|
|
}
|
|
Iterator last;
|
|
if (stop < 0) {
|
|
last = end();
|
|
advance_upto(last, stop, first, iterator_category());
|
|
} else {
|
|
if (start >= 0) {
|
|
last = first;
|
|
if (stop > start)
|
|
advance_upto(last, stop - start, end(), iterator_category());
|
|
} else {
|
|
// Complicated: 'start' walked from the end of the sequence,
|
|
// but 'stop' needs to walk from the beginning.
|
|
Iterator dummy = begin();
|
|
// Walk up to 'stop' increments from begin(), stopping when we
|
|
// get to 'first', and capturing the remaining number of
|
|
// increments.
|
|
difference_type increments_past_start =
|
|
advance_upto(dummy, stop, first, iterator_category());
|
|
if (increments_past_start == 0) {
|
|
// If this is 0, then stop was before start.
|
|
last = first;
|
|
} else {
|
|
// Otherwise, count that many spaces beyond first.
|
|
last = first;
|
|
advance_upto(last, increments_past_start, end(), iterator_category());
|
|
}
|
|
}
|
|
}
|
|
return range(first, last);
|
|
}
|
|
|
|
range dispatch_slice(difference_type start, difference_type stop,
|
|
std::random_access_iterator_tag) const {
|
|
const difference_type size = this->size();
|
|
if (start < 0)
|
|
start = size + start;
|
|
if (start < 0)
|
|
start = 0;
|
|
if (start > size)
|
|
start = size;
|
|
|
|
if (stop < 0)
|
|
stop = size + stop;
|
|
if (stop < start)
|
|
stop = start;
|
|
if (stop > size)
|
|
stop = size;
|
|
|
|
return range(begin() + start, begin() + stop);
|
|
}
|
|
};
|
|
|
|
/// \name deducing constructor wrappers
|
|
/// \relates std::range
|
|
/// \xmlonly <nonmember/> \endxmlonly
|
|
///
|
|
/// These functions do the same thing as the constructor with the same
|
|
/// signature. They just allow users to avoid writing the iterator
|
|
/// type.
|
|
/// @{
|
|
|
|
/// \todo I'd like to define a \c make_range taking a single iterator
|
|
/// argument representing the beginning of a range that ends with a
|
|
/// default-constructed \c Iterator. This would help with using
|
|
/// iterators like \c istream_iterator. However, using just \c
|
|
/// make_range() could be confusing and lead to people writing
|
|
/// incorrect ranges of more common iterators. Is there a better name?
|
|
template <typename Iterator>
|
|
LLVM_CONSTEXPR range<Iterator> make_range(Iterator begin, Iterator end) {
|
|
return range<Iterator>(begin, end);
|
|
}
|
|
|
|
/// \par Participates in overload resolution if:
|
|
/// \c begin(r) and \c end(r) return the same type.
|
|
template <typename Range> LLVM_CONSTEXPR auto make_range(
|
|
Range &&r,
|
|
typename std::enable_if<detail::is_range<Range>::value>::type* = 0)
|
|
-> range<decltype(detail::adl_begin(r))> {
|
|
return range<decltype(detail::adl_begin(r))>(r);
|
|
}
|
|
|
|
/// \par Participates in overload resolution if:
|
|
/// - \c begin(r) and \c end(r) return the same type,
|
|
/// - that type satisfies the invariant that <code>&*(i + N) ==
|
|
/// (&*i) + N</code>, and
|
|
/// - \c &*begin(r) has a pointer type.
|
|
template <typename Range> LLVM_CONSTEXPR auto make_ptr_range(
|
|
Range &&r,
|
|
typename std::enable_if<
|
|
detail::is_contiguous_range<Range>::value &&
|
|
std::is_pointer<decltype(&*detail::adl_begin(r))>::value>::type* = 0)
|
|
-> range<decltype(&*detail::adl_begin(r))> {
|
|
return range<decltype(&*detail::adl_begin(r))>(r);
|
|
}
|
|
/// @}
|
|
} // end namespace lld
|
|
|
|
#endif
|