@@ -263,6 +263,12 @@ constexpr bool empty(const T &RangeOrContainer) {
263263 return adl_begin (RangeOrContainer) == adl_end (RangeOrContainer);
264264}
265265
266+ // / Returns true of the given range only contains a single element.
267+ template <typename ContainerTy> bool hasSingleElement (ContainerTy &&c) {
268+ auto it = std::begin (c), e = std::end (c);
269+ return it != e && std::next (it) == e;
270+ }
271+
266272// / Return a range covering \p RangeOrContainer with the first N elements
267273// / excluded.
268274template <typename T> auto drop_begin (T &&RangeOrContainer, size_t N) {
@@ -1017,6 +1023,213 @@ detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) {
10171023 std::forward<RangeTs>(Ranges)...);
10181024}
10191025
1026+ // / A utility class used to implement an iterator that contains some base object
1027+ // / and an index. The iterator moves the index but keeps the base constant.
1028+ template <typename DerivedT, typename BaseT, typename T,
1029+ typename PointerT = T *, typename ReferenceT = T &>
1030+ class indexed_accessor_iterator
1031+ : public llvm::iterator_facade_base<DerivedT,
1032+ std::random_access_iterator_tag, T,
1033+ std::ptrdiff_t , PointerT, ReferenceT> {
1034+ public:
1035+ ptrdiff_t operator -(const indexed_accessor_iterator &rhs) const {
1036+ assert (base == rhs.base && " incompatible iterators" );
1037+ return index - rhs.index ;
1038+ }
1039+ bool operator ==(const indexed_accessor_iterator &rhs) const {
1040+ return base == rhs.base && index == rhs.index ;
1041+ }
1042+ bool operator <(const indexed_accessor_iterator &rhs) const {
1043+ assert (base == rhs.base && " incompatible iterators" );
1044+ return index < rhs.index ;
1045+ }
1046+
1047+ DerivedT &operator +=(ptrdiff_t offset) {
1048+ this ->index += offset;
1049+ return static_cast <DerivedT &>(*this );
1050+ }
1051+ DerivedT &operator -=(ptrdiff_t offset) {
1052+ this ->index -= offset;
1053+ return static_cast <DerivedT &>(*this );
1054+ }
1055+
1056+ // / Returns the current index of the iterator.
1057+ ptrdiff_t getIndex () const { return index; }
1058+
1059+ // / Returns the current base of the iterator.
1060+ const BaseT &getBase () const { return base; }
1061+
1062+ protected:
1063+ indexed_accessor_iterator (BaseT base, ptrdiff_t index)
1064+ : base(base), index(index) {}
1065+ BaseT base;
1066+ ptrdiff_t index;
1067+ };
1068+
1069+ namespace detail {
1070+ // / The class represents the base of a range of indexed_accessor_iterators. It
1071+ // / provides support for many different range functionalities, e.g.
1072+ // / drop_front/slice/etc.. Derived range classes must implement the following
1073+ // / static methods:
1074+ // / * ReferenceT dereference_iterator(const BaseT &base, ptrdiff_t index)
1075+ // / - Dereference an iterator pointing to the base object at the given
1076+ // / index.
1077+ // / * BaseT offset_base(const BaseT &base, ptrdiff_t index)
1078+ // / - Return a new base that is offset from the provide base by 'index'
1079+ // / elements.
1080+ template <typename DerivedT, typename BaseT, typename T,
1081+ typename PointerT = T *, typename ReferenceT = T &>
1082+ class indexed_accessor_range_base {
1083+ public:
1084+ using RangeBaseT =
1085+ indexed_accessor_range_base<DerivedT, BaseT, T, PointerT, ReferenceT>;
1086+
1087+ // / An iterator element of this range.
1088+ class iterator : public indexed_accessor_iterator <iterator, BaseT, T,
1089+ PointerT, ReferenceT> {
1090+ public:
1091+ // Index into this iterator, invoking a static method on the derived type.
1092+ ReferenceT operator *() const {
1093+ return DerivedT::dereference_iterator (this ->getBase (), this ->getIndex ());
1094+ }
1095+
1096+ private:
1097+ iterator (BaseT owner, ptrdiff_t curIndex)
1098+ : indexed_accessor_iterator<iterator, BaseT, T, PointerT, ReferenceT>(
1099+ owner, curIndex) {}
1100+
1101+ // / Allow access to the constructor.
1102+ friend indexed_accessor_range_base<DerivedT, BaseT, T, PointerT,
1103+ ReferenceT>;
1104+ };
1105+
1106+ indexed_accessor_range_base (iterator begin, iterator end)
1107+ : base(DerivedT::offset_base(begin.getBase(), begin.getIndex())),
1108+ count (end.getIndex() - begin.getIndex()) {}
1109+ indexed_accessor_range_base (const iterator_range<iterator> &range)
1110+ : indexed_accessor_range_base(range.begin(), range.end()) {}
1111+ indexed_accessor_range_base (BaseT base, ptrdiff_t count)
1112+ : base(base), count(count) {}
1113+
1114+ iterator begin () const { return iterator (base, 0 ); }
1115+ iterator end () const { return iterator (base, count); }
1116+ ReferenceT operator [](unsigned index) const {
1117+ assert (index < size () && " invalid index for value range" );
1118+ return DerivedT::dereference_iterator (base, index);
1119+ }
1120+
1121+ // / Compare this range with another.
1122+ template <typename OtherT> bool operator ==(const OtherT &other) {
1123+ return size () == std::distance (other.begin (), other.end ()) &&
1124+ std::equal (begin (), end (), other.begin ());
1125+ }
1126+
1127+ // / Return the size of this range.
1128+ size_t size () const { return count; }
1129+
1130+ // / Return if the range is empty.
1131+ bool empty () const { return size () == 0 ; }
1132+
1133+ // / Drop the first N elements, and keep M elements.
1134+ DerivedT slice (size_t n, size_t m) const {
1135+ assert (n + m <= size () && " invalid size specifiers" );
1136+ return DerivedT (DerivedT::offset_base (base, n), m);
1137+ }
1138+
1139+ // / Drop the first n elements.
1140+ DerivedT drop_front (size_t n = 1 ) const {
1141+ assert (size () >= n && " Dropping more elements than exist" );
1142+ return slice (n, size () - n);
1143+ }
1144+ // / Drop the last n elements.
1145+ DerivedT drop_back (size_t n = 1 ) const {
1146+ assert (size () >= n && " Dropping more elements than exist" );
1147+ return DerivedT (base, size () - n);
1148+ }
1149+
1150+ // / Take the first n elements.
1151+ DerivedT take_front (size_t n = 1 ) const {
1152+ return n < size () ? drop_back (size () - n)
1153+ : static_cast <const DerivedT &>(*this );
1154+ }
1155+
1156+ // / Take the last n elements.
1157+ DerivedT take_back (size_t n = 1 ) const {
1158+ return n < size () ? drop_front (size () - n)
1159+ : static_cast <const DerivedT &>(*this );
1160+ }
1161+
1162+ // / Allow conversion to any type accepting an iterator_range.
1163+ template <typename RangeT, typename = std::enable_if_t <std::is_constructible<
1164+ RangeT, iterator_range<iterator>>::value>>
1165+ operator RangeT () const {
1166+ return RangeT (iterator_range<iterator>(*this ));
1167+ }
1168+
1169+ protected:
1170+ indexed_accessor_range_base (const indexed_accessor_range_base &) = default ;
1171+ indexed_accessor_range_base (indexed_accessor_range_base &&) = default ;
1172+ indexed_accessor_range_base &
1173+ operator =(const indexed_accessor_range_base &) = default ;
1174+
1175+ // / The base that owns the provided range of values.
1176+ BaseT base;
1177+ // / The size from the owning range.
1178+ ptrdiff_t count;
1179+ };
1180+ } // end namespace detail
1181+
1182+ // / This class provides an implementation of a range of
1183+ // / indexed_accessor_iterators where the base is not indexable. Ranges with
1184+ // / bases that are offsetable should derive from indexed_accessor_range_base
1185+ // / instead. Derived range classes are expected to implement the following
1186+ // / static method:
1187+ // / * ReferenceT dereference(const BaseT &base, ptrdiff_t index)
1188+ // / - Dereference an iterator pointing to a parent base at the given index.
1189+ template <typename DerivedT, typename BaseT, typename T,
1190+ typename PointerT = T *, typename ReferenceT = T &>
1191+ class indexed_accessor_range
1192+ : public detail::indexed_accessor_range_base<
1193+ DerivedT, std::pair<BaseT, ptrdiff_t >, T, PointerT, ReferenceT> {
1194+ public:
1195+ indexed_accessor_range (BaseT base, ptrdiff_t startIndex, ptrdiff_t count)
1196+ : detail::indexed_accessor_range_base<
1197+ DerivedT, std::pair<BaseT, ptrdiff_t >, T, PointerT, ReferenceT>(
1198+ std::make_pair (base, startIndex), count) {}
1199+ using detail::indexed_accessor_range_base<
1200+ DerivedT, std::pair<BaseT, ptrdiff_t >, T, PointerT,
1201+ ReferenceT>::indexed_accessor_range_base;
1202+
1203+ // / Returns the current base of the range.
1204+ const BaseT &getBase () const { return this ->base .first ; }
1205+
1206+ // / Returns the current start index of the range.
1207+ ptrdiff_t getStartIndex () const { return this ->base .second ; }
1208+
1209+ // / See `detail::indexed_accessor_range_base` for details.
1210+ static std::pair<BaseT, ptrdiff_t >
1211+ offset_base (const std::pair<BaseT, ptrdiff_t > &base, ptrdiff_t index) {
1212+ // We encode the internal base as a pair of the derived base and a start
1213+ // index into the derived base.
1214+ return std::make_pair (base.first , base.second + index);
1215+ }
1216+ // / See `detail::indexed_accessor_range_base` for details.
1217+ static ReferenceT
1218+ dereference_iterator (const std::pair<BaseT, ptrdiff_t > &base,
1219+ ptrdiff_t index) {
1220+ return DerivedT::dereference (base.first , base.second + index);
1221+ }
1222+ };
1223+
1224+ // / Given a container of pairs, return a range over the second elements.
1225+ template <typename ContainerTy> auto make_second_range (ContainerTy &&c) {
1226+ return llvm::map_range (
1227+ std::forward<ContainerTy>(c),
1228+ [](decltype ((*std::begin (c))) elt) -> decltype ((elt.second )) {
1229+ return elt.second ;
1230+ });
1231+ }
1232+
10201233// ===----------------------------------------------------------------------===//
10211234// Extra additions to <utility>
10221235// ===----------------------------------------------------------------------===//
0 commit comments