//===--- Range.h - Classes for conveniently working with ranges -*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// /// \file /// /// This file provides classes and functions for conveniently working /// with ranges, /// /// map creates an iterator_range which applies a function to all the elements /// in another iterator_range. /// /// IntRange is a template class for iterating over a range of /// integers. /// /// indices returns the range of indices from [0..size()) on a /// subscriptable type. /// //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_RANGE_H #define SWIFT_BASIC_RANGE_H #include #include #include #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" namespace swift { using llvm::make_range; // Wrapper for std::transform that creates a new back-insertable container // and transforms a range into it. template T map(InputRange &&range, MapFn &&mapFn) { T result; std::transform(std::begin(range), std::end(range), std::back_inserter(result), std::forward(mapFn)); return result; } template ::value> struct IntRangeTraits; template struct IntRangeTraits { static_assert(std::is_integral::value, "argument type of IntRange is either an integer nor an enum"); using int_type = T; using difference_type = typename std::make_signed::type; static T addOffset(T value, difference_type quantity) { return T(difference_type(value) + quantity); } static difference_type distance(T begin, T end) { return difference_type(end) - difference_type(begin); } }; template struct IntRangeTraits { using int_type = typename std::underlying_type::type; using difference_type = typename std::make_signed::type; static T addOffset(T value, difference_type quantity) { return T(difference_type(value) + quantity); } static difference_type distance(T begin, T end) { return difference_type(end) - difference_type(begin); } }; /// A range of integers or enum values. This type behaves roughly /// like an ArrayRef. template > class IntRange { T Begin; T End; using int_type = typename Traits::int_type; using difference_type = typename Traits::difference_type; public: IntRange() : Begin(0), End(0) {} IntRange(T end) : Begin(0), End(end) {} IntRange(T begin, T end) : Begin(begin), End(end) { assert(begin <= end); } class iterator { friend class IntRange; T Value; iterator(T value) : Value(value) {} public: using value_type = T; using reference = T; using pointer = void; using difference_type = typename std::make_signed::type; using iterator_category = std::random_access_iterator_tag; T operator*() const { return Value; } iterator &operator++() { return *this += 1; } iterator operator++(int) { auto copy = *this; *this += 1; return copy; } iterator &operator--() { return *this -= 1; } iterator operator--(int) { auto copy = *this; *this -= 1; return copy; } bool operator==(iterator rhs) const { return Value == rhs.Value; } bool operator!=(iterator rhs) const { return Value != rhs.Value; } iterator &operator+=(difference_type i) { Value = Traits::addOffset(Value, i); return *this; } iterator operator+(difference_type i) const { return iterator(Traits::addOffset(Value, i)); } friend iterator operator+(difference_type i, iterator base) { return iterator(Traits::addOffset(base.Value, i)); } iterator &operator-=(difference_type i) { Value = Traits::addOffset(Value, -i); return *this; } iterator operator-(difference_type i) const { return iterator(Traits::addOffset(Value, -i)); } difference_type operator-(iterator rhs) const { return Traits::distance(rhs.Value, Value); } T operator[](difference_type i) const { return Traits::addOffset(Value, i); } bool operator<(iterator rhs) const { return Value < rhs.Value; } bool operator<=(iterator rhs) const { return Value <= rhs.Value; } bool operator>(iterator rhs) const { return Value > rhs.Value; } bool operator>=(iterator rhs) const { return Value >= rhs.Value; } }; iterator begin() const { return iterator(Begin); } iterator end() const { return iterator(End); } std::reverse_iterator rbegin() const { return std::reverse_iterator(end()); } std::reverse_iterator rend() const { return std::reverse_iterator(begin()); } bool empty() const { return Begin == End; } size_t size() const { return size_t(Traits::distance(Begin, End)); } T operator[](size_t i) const { assert(i < size()); return Traits::addOffset(Begin, i); } T front() const { assert(!empty()); return Begin; } T back() const { assert(!empty()); return Traits::addOffset(End, -1); } IntRange drop_back(size_t length = 1) const { assert(length <= size()); return IntRange(Begin, Traits::addOffset(End, -length)); } IntRange slice(size_t start) const { assert(start <= size()); return IntRange(Traits::addOffset(Begin, start), End); } IntRange slice(size_t start, size_t length) const { assert(start <= size()); auto newBegin = Traits::addOffset(Begin, start); auto newSize = std::min(length, size_t(Traits::distance(newBegin, End))); return IntRange(newBegin, Traits::addOffset(newBegin, newSize)); } bool operator==(IntRange other) const { return Begin == other.Begin && End == other.End; } bool operator!=(IntRange other) const { return !(operator==(other)); } }; /// indices - Given a type that's subscriptable with integers, return /// an IntRange consisting of the valid subscripts. template typename std::enable_if()[size_t(1)]) != 0, IntRange().size())>>::type indices(const T &collection) { return IntRange().size())>(0, collection.size()); } /// Returns an Int range [start, end). static inline IntRange range(unsigned start, unsigned end) { assert(start <= end && "Invalid integral range"); return IntRange(start, end); } /// Returns an Int range [0, end). static inline IntRange range(unsigned end) { return range(0, end); } /// Returns a reverse Int range (start, end]. static inline auto reverse_range(unsigned start, unsigned end) -> decltype(llvm::reverse(range(start+1, end+1))) { assert(start <= end && "Invalid integral range"); return llvm::reverse(range(start+1, end+1)); } } // end namespace swift #endif // SWIFT_BASIC_RANGE_H