10b57cec5SDimitry Andric //===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 81fd87a68SDimitry Andric /// 91fd87a68SDimitry Andric /// \file 101fd87a68SDimitry Andric /// This file contains some templates that are useful if you are working with 111fd87a68SDimitry Andric /// the STL at all. 121fd87a68SDimitry Andric /// 131fd87a68SDimitry Andric /// No library is required when using these functions. 141fd87a68SDimitry Andric /// 150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #ifndef LLVM_ADT_STLEXTRAS_H 180b57cec5SDimitry Andric #define LLVM_ADT_STLEXTRAS_H 190b57cec5SDimitry Andric 2006c3fb27SDimitry Andric #include "llvm/ADT/ADL.h" 21bdd1243dSDimitry Andric #include "llvm/ADT/Hashing.h" 22fe6060f1SDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 2304eeddc0SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h" 240b57cec5SDimitry Andric #include "llvm/ADT/iterator.h" 250b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h" 260b57cec5SDimitry Andric #include "llvm/Config/abi-breaking.h" 270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 280b57cec5SDimitry Andric #include <algorithm> 290b57cec5SDimitry Andric #include <cassert> 300b57cec5SDimitry Andric #include <cstddef> 310b57cec5SDimitry Andric #include <cstdint> 320b57cec5SDimitry Andric #include <cstdlib> 330b57cec5SDimitry Andric #include <functional> 340b57cec5SDimitry Andric #include <initializer_list> 350b57cec5SDimitry Andric #include <iterator> 360b57cec5SDimitry Andric #include <limits> 370b57cec5SDimitry Andric #include <memory> 38bdd1243dSDimitry Andric #include <optional> 390b57cec5SDimitry Andric #include <tuple> 400b57cec5SDimitry Andric #include <type_traits> 410b57cec5SDimitry Andric #include <utility> 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 440b57cec5SDimitry Andric #include <random> // for std::mt19937 450b57cec5SDimitry Andric #endif 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric namespace llvm { 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 500b57cec5SDimitry Andric // Extra additions to <type_traits> 510b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric template <typename T> struct make_const_ptr { 54bdd1243dSDimitry Andric using type = std::add_pointer_t<std::add_const_t<T>>; 550b57cec5SDimitry Andric }; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric template <typename T> struct make_const_ref { 58bdd1243dSDimitry Andric using type = std::add_lvalue_reference_t<std::add_const_t<T>>; 590b57cec5SDimitry Andric }; 600b57cec5SDimitry Andric 615ffd83dbSDimitry Andric namespace detail { 625ffd83dbSDimitry Andric template <class, template <class...> class Op, class... Args> struct detector { 635ffd83dbSDimitry Andric using value_t = std::false_type; 645ffd83dbSDimitry Andric }; 655ffd83dbSDimitry Andric template <template <class...> class Op, class... Args> 66bdd1243dSDimitry Andric struct detector<std::void_t<Op<Args...>>, Op, Args...> { 675ffd83dbSDimitry Andric using value_t = std::true_type; 685ffd83dbSDimitry Andric }; 695ffd83dbSDimitry Andric } // end namespace detail 705ffd83dbSDimitry Andric 71fe6060f1SDimitry Andric /// Detects if a given trait holds for some set of arguments 'Args'. 72fe6060f1SDimitry Andric /// For example, the given trait could be used to detect if a given type 73fe6060f1SDimitry Andric /// has a copy assignment operator: 74fe6060f1SDimitry Andric /// template<class T> 75fe6060f1SDimitry Andric /// using has_copy_assign_t = decltype(std::declval<T&>() 76fe6060f1SDimitry Andric /// = std::declval<const T&>()); 77fe6060f1SDimitry Andric /// bool fooHasCopyAssign = is_detected<has_copy_assign_t, FooClass>::value; 785ffd83dbSDimitry Andric template <template <class...> class Op, class... Args> 795ffd83dbSDimitry Andric using is_detected = typename detail::detector<void, Op, Args...>::value_t; 805ffd83dbSDimitry Andric 815ffd83dbSDimitry Andric /// This class provides various trait information about a callable object. 825ffd83dbSDimitry Andric /// * To access the number of arguments: Traits::num_args 835ffd83dbSDimitry Andric /// * To access the type of an argument: Traits::arg_t<Index> 845ffd83dbSDimitry Andric /// * To access the type of the result: Traits::result_t 855ffd83dbSDimitry Andric template <typename T, bool isClass = std::is_class<T>::value> 865ffd83dbSDimitry Andric struct function_traits : public function_traits<decltype(&T::operator())> {}; 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric /// Overload for class function types. 895ffd83dbSDimitry Andric template <typename ClassType, typename ReturnType, typename... Args> 905ffd83dbSDimitry Andric struct function_traits<ReturnType (ClassType::*)(Args...) const, false> { 915ffd83dbSDimitry Andric /// The number of arguments to this function. 925ffd83dbSDimitry Andric enum { num_args = sizeof...(Args) }; 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric /// The result type of this function. 955ffd83dbSDimitry Andric using result_t = ReturnType; 965ffd83dbSDimitry Andric 975ffd83dbSDimitry Andric /// The type of an argument to this function. 985ffd83dbSDimitry Andric template <size_t Index> 99bdd1243dSDimitry Andric using arg_t = std::tuple_element_t<Index, std::tuple<Args...>>; 1005ffd83dbSDimitry Andric }; 1015ffd83dbSDimitry Andric /// Overload for class function types. 1025ffd83dbSDimitry Andric template <typename ClassType, typename ReturnType, typename... Args> 1035ffd83dbSDimitry Andric struct function_traits<ReturnType (ClassType::*)(Args...), false> 10481ad6265SDimitry Andric : public function_traits<ReturnType (ClassType::*)(Args...) const> {}; 1055ffd83dbSDimitry Andric /// Overload for non-class function types. 1065ffd83dbSDimitry Andric template <typename ReturnType, typename... Args> 1075ffd83dbSDimitry Andric struct function_traits<ReturnType (*)(Args...), false> { 1085ffd83dbSDimitry Andric /// The number of arguments to this function. 1095ffd83dbSDimitry Andric enum { num_args = sizeof...(Args) }; 1105ffd83dbSDimitry Andric 1115ffd83dbSDimitry Andric /// The result type of this function. 1125ffd83dbSDimitry Andric using result_t = ReturnType; 1135ffd83dbSDimitry Andric 1145ffd83dbSDimitry Andric /// The type of an argument to this function. 1155ffd83dbSDimitry Andric template <size_t i> 116bdd1243dSDimitry Andric using arg_t = std::tuple_element_t<i, std::tuple<Args...>>; 1175ffd83dbSDimitry Andric }; 11881ad6265SDimitry Andric template <typename ReturnType, typename... Args> 11981ad6265SDimitry Andric struct function_traits<ReturnType (*const)(Args...), false> 12081ad6265SDimitry Andric : public function_traits<ReturnType (*)(Args...)> {}; 1215ffd83dbSDimitry Andric /// Overload for non-class function type references. 1225ffd83dbSDimitry Andric template <typename ReturnType, typename... Args> 1235ffd83dbSDimitry Andric struct function_traits<ReturnType (&)(Args...), false> 1245ffd83dbSDimitry Andric : public function_traits<ReturnType (*)(Args...)> {}; 1255ffd83dbSDimitry Andric 1260eae32dcSDimitry Andric /// traits class for checking whether type T is one of any of the given 1270eae32dcSDimitry Andric /// types in the variadic list. 1280eae32dcSDimitry Andric template <typename T, typename... Ts> 129bdd1243dSDimitry Andric using is_one_of = std::disjunction<std::is_same<T, Ts>...>; 1300eae32dcSDimitry Andric 1310eae32dcSDimitry Andric /// traits class for checking whether type T is a base class for all 1320eae32dcSDimitry Andric /// the given types in the variadic list. 1330eae32dcSDimitry Andric template <typename T, typename... Ts> 134bdd1243dSDimitry Andric using are_base_of = std::conjunction<std::is_base_of<T, Ts>...>; 1350eae32dcSDimitry Andric 1360eae32dcSDimitry Andric namespace detail { 1370eae32dcSDimitry Andric template <typename T, typename... Us> struct TypesAreDistinct; 1380eae32dcSDimitry Andric template <typename T, typename... Us> 1390eae32dcSDimitry Andric struct TypesAreDistinct 1400eae32dcSDimitry Andric : std::integral_constant<bool, !is_one_of<T, Us...>::value && 1410eae32dcSDimitry Andric TypesAreDistinct<Us...>::value> {}; 1420eae32dcSDimitry Andric template <typename T> struct TypesAreDistinct<T> : std::true_type {}; 1430eae32dcSDimitry Andric } // namespace detail 1440eae32dcSDimitry Andric 1450eae32dcSDimitry Andric /// Determine if all types in Ts are distinct. 1460eae32dcSDimitry Andric /// 1470eae32dcSDimitry Andric /// Useful to statically assert when Ts is intended to describe a non-multi set 1480eae32dcSDimitry Andric /// of types. 1490eae32dcSDimitry Andric /// 1500eae32dcSDimitry Andric /// Expensive (currently quadratic in sizeof(Ts...)), and so should only be 1510eae32dcSDimitry Andric /// asserted once per instantiation of a type which requires it. 1520eae32dcSDimitry Andric template <typename... Ts> struct TypesAreDistinct; 1530eae32dcSDimitry Andric template <> struct TypesAreDistinct<> : std::true_type {}; 1540eae32dcSDimitry Andric template <typename... Ts> 1550eae32dcSDimitry Andric struct TypesAreDistinct 1560eae32dcSDimitry Andric : std::integral_constant<bool, detail::TypesAreDistinct<Ts...>::value> {}; 1570eae32dcSDimitry Andric 1580eae32dcSDimitry Andric /// Find the first index where a type appears in a list of types. 1590eae32dcSDimitry Andric /// 1600eae32dcSDimitry Andric /// FirstIndexOfType<T, Us...>::value is the first index of T in Us. 1610eae32dcSDimitry Andric /// 1620eae32dcSDimitry Andric /// Typically only meaningful when it is otherwise statically known that the 1630eae32dcSDimitry Andric /// type pack has no duplicate types. This should be guaranteed explicitly with 1640eae32dcSDimitry Andric /// static_assert(TypesAreDistinct<Us...>::value). 1650eae32dcSDimitry Andric /// 1660eae32dcSDimitry Andric /// It is a compile-time error to instantiate when T is not present in Us, i.e. 1670eae32dcSDimitry Andric /// if is_one_of<T, Us...>::value is false. 1680eae32dcSDimitry Andric template <typename T, typename... Us> struct FirstIndexOfType; 1690eae32dcSDimitry Andric template <typename T, typename U, typename... Us> 1700eae32dcSDimitry Andric struct FirstIndexOfType<T, U, Us...> 1710eae32dcSDimitry Andric : std::integral_constant<size_t, 1 + FirstIndexOfType<T, Us...>::value> {}; 1720eae32dcSDimitry Andric template <typename T, typename... Us> 1730eae32dcSDimitry Andric struct FirstIndexOfType<T, T, Us...> : std::integral_constant<size_t, 0> {}; 1740eae32dcSDimitry Andric 1750eae32dcSDimitry Andric /// Find the type at a given index in a list of types. 1760eae32dcSDimitry Andric /// 1770eae32dcSDimitry Andric /// TypeAtIndex<I, Ts...> is the type at index I in Ts. 1780eae32dcSDimitry Andric template <size_t I, typename... Ts> 1790eae32dcSDimitry Andric using TypeAtIndex = std::tuple_element_t<I, std::tuple<Ts...>>; 1800eae32dcSDimitry Andric 18181ad6265SDimitry Andric /// Helper which adds two underlying types of enumeration type. 18281ad6265SDimitry Andric /// Implicit conversion to a common type is accepted. 18381ad6265SDimitry Andric template <typename EnumTy1, typename EnumTy2, 18481ad6265SDimitry Andric typename UT1 = std::enable_if_t<std::is_enum<EnumTy1>::value, 18581ad6265SDimitry Andric std::underlying_type_t<EnumTy1>>, 18681ad6265SDimitry Andric typename UT2 = std::enable_if_t<std::is_enum<EnumTy2>::value, 18781ad6265SDimitry Andric std::underlying_type_t<EnumTy2>>> 18881ad6265SDimitry Andric constexpr auto addEnumValues(EnumTy1 LHS, EnumTy2 RHS) { 18981ad6265SDimitry Andric return static_cast<UT1>(LHS) + static_cast<UT2>(RHS); 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric 1920b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1930b57cec5SDimitry Andric // Extra additions to <iterator> 1940b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1950b57cec5SDimitry Andric 196bdd1243dSDimitry Andric namespace callable_detail { 197bdd1243dSDimitry Andric 198bdd1243dSDimitry Andric /// Templated storage wrapper for a callable. 199bdd1243dSDimitry Andric /// 200bdd1243dSDimitry Andric /// This class is consistently default constructible, copy / move 201bdd1243dSDimitry Andric /// constructible / assignable. 202bdd1243dSDimitry Andric /// 203bdd1243dSDimitry Andric /// Supported callable types: 204bdd1243dSDimitry Andric /// - Function pointer 205bdd1243dSDimitry Andric /// - Function reference 206bdd1243dSDimitry Andric /// - Lambda 207bdd1243dSDimitry Andric /// - Function object 208bdd1243dSDimitry Andric template <typename T, 209bdd1243dSDimitry Andric bool = std::is_function_v<std::remove_pointer_t<remove_cvref_t<T>>>> 210bdd1243dSDimitry Andric class Callable { 211bdd1243dSDimitry Andric using value_type = std::remove_reference_t<T>; 212bdd1243dSDimitry Andric using reference = value_type &; 213bdd1243dSDimitry Andric using const_reference = value_type const &; 214bdd1243dSDimitry Andric 215bdd1243dSDimitry Andric std::optional<value_type> Obj; 216bdd1243dSDimitry Andric 217bdd1243dSDimitry Andric static_assert(!std::is_pointer_v<value_type>, 218bdd1243dSDimitry Andric "Pointers to non-functions are not callable."); 219bdd1243dSDimitry Andric 220bdd1243dSDimitry Andric public: 221bdd1243dSDimitry Andric Callable() = default; 222bdd1243dSDimitry Andric Callable(T const &O) : Obj(std::in_place, O) {} 223bdd1243dSDimitry Andric 224bdd1243dSDimitry Andric Callable(Callable const &Other) = default; 225bdd1243dSDimitry Andric Callable(Callable &&Other) = default; 226bdd1243dSDimitry Andric 227bdd1243dSDimitry Andric Callable &operator=(Callable const &Other) { 228bdd1243dSDimitry Andric Obj = std::nullopt; 229bdd1243dSDimitry Andric if (Other.Obj) 230bdd1243dSDimitry Andric Obj.emplace(*Other.Obj); 231bdd1243dSDimitry Andric return *this; 232bdd1243dSDimitry Andric } 233bdd1243dSDimitry Andric 234bdd1243dSDimitry Andric Callable &operator=(Callable &&Other) { 235bdd1243dSDimitry Andric Obj = std::nullopt; 236bdd1243dSDimitry Andric if (Other.Obj) 237bdd1243dSDimitry Andric Obj.emplace(std::move(*Other.Obj)); 238bdd1243dSDimitry Andric return *this; 239bdd1243dSDimitry Andric } 240bdd1243dSDimitry Andric 241bdd1243dSDimitry Andric template <typename... Pn, 242bdd1243dSDimitry Andric std::enable_if_t<std::is_invocable_v<T, Pn...>, int> = 0> 243bdd1243dSDimitry Andric decltype(auto) operator()(Pn &&...Params) { 244bdd1243dSDimitry Andric return (*Obj)(std::forward<Pn>(Params)...); 245bdd1243dSDimitry Andric } 246bdd1243dSDimitry Andric 247bdd1243dSDimitry Andric template <typename... Pn, 248bdd1243dSDimitry Andric std::enable_if_t<std::is_invocable_v<T const, Pn...>, int> = 0> 249bdd1243dSDimitry Andric decltype(auto) operator()(Pn &&...Params) const { 250bdd1243dSDimitry Andric return (*Obj)(std::forward<Pn>(Params)...); 251bdd1243dSDimitry Andric } 252bdd1243dSDimitry Andric 253bdd1243dSDimitry Andric bool valid() const { return Obj != std::nullopt; } 254bdd1243dSDimitry Andric bool reset() { return Obj = std::nullopt; } 255bdd1243dSDimitry Andric 256bdd1243dSDimitry Andric operator reference() { return *Obj; } 257bdd1243dSDimitry Andric operator const_reference() const { return *Obj; } 258bdd1243dSDimitry Andric }; 259bdd1243dSDimitry Andric 260bdd1243dSDimitry Andric // Function specialization. No need to waste extra space wrapping with a 261bdd1243dSDimitry Andric // std::optional. 262bdd1243dSDimitry Andric template <typename T> class Callable<T, true> { 263bdd1243dSDimitry Andric static constexpr bool IsPtr = std::is_pointer_v<remove_cvref_t<T>>; 264bdd1243dSDimitry Andric 265bdd1243dSDimitry Andric using StorageT = std::conditional_t<IsPtr, T, std::remove_reference_t<T> *>; 266bdd1243dSDimitry Andric using CastT = std::conditional_t<IsPtr, T, T &>; 267bdd1243dSDimitry Andric 268bdd1243dSDimitry Andric private: 269bdd1243dSDimitry Andric StorageT Func = nullptr; 270bdd1243dSDimitry Andric 271bdd1243dSDimitry Andric private: 272bdd1243dSDimitry Andric template <typename In> static constexpr auto convertIn(In &&I) { 273bdd1243dSDimitry Andric if constexpr (IsPtr) { 274bdd1243dSDimitry Andric // Pointer... just echo it back. 275bdd1243dSDimitry Andric return I; 276bdd1243dSDimitry Andric } else { 277bdd1243dSDimitry Andric // Must be a function reference. Return its address. 278bdd1243dSDimitry Andric return &I; 279bdd1243dSDimitry Andric } 280bdd1243dSDimitry Andric } 281bdd1243dSDimitry Andric 282bdd1243dSDimitry Andric public: 283bdd1243dSDimitry Andric Callable() = default; 284bdd1243dSDimitry Andric 285bdd1243dSDimitry Andric // Construct from a function pointer or reference. 286bdd1243dSDimitry Andric // 287bdd1243dSDimitry Andric // Disable this constructor for references to 'Callable' so we don't violate 288bdd1243dSDimitry Andric // the rule of 0. 289bdd1243dSDimitry Andric template < // clang-format off 290bdd1243dSDimitry Andric typename FnPtrOrRef, 291bdd1243dSDimitry Andric std::enable_if_t< 292bdd1243dSDimitry Andric !std::is_same_v<remove_cvref_t<FnPtrOrRef>, Callable>, int 293bdd1243dSDimitry Andric > = 0 294bdd1243dSDimitry Andric > // clang-format on 295bdd1243dSDimitry Andric Callable(FnPtrOrRef &&F) : Func(convertIn(F)) {} 296bdd1243dSDimitry Andric 297bdd1243dSDimitry Andric template <typename... Pn, 298bdd1243dSDimitry Andric std::enable_if_t<std::is_invocable_v<T, Pn...>, int> = 0> 299bdd1243dSDimitry Andric decltype(auto) operator()(Pn &&...Params) const { 300bdd1243dSDimitry Andric return Func(std::forward<Pn>(Params)...); 301bdd1243dSDimitry Andric } 302bdd1243dSDimitry Andric 303bdd1243dSDimitry Andric bool valid() const { return Func != nullptr; } 304bdd1243dSDimitry Andric void reset() { Func = nullptr; } 305bdd1243dSDimitry Andric 306bdd1243dSDimitry Andric operator T const &() const { 307bdd1243dSDimitry Andric if constexpr (IsPtr) { 308bdd1243dSDimitry Andric // T is a pointer... just echo it back. 309bdd1243dSDimitry Andric return Func; 310bdd1243dSDimitry Andric } else { 311bdd1243dSDimitry Andric static_assert(std::is_reference_v<T>, 312bdd1243dSDimitry Andric "Expected a reference to a function."); 313bdd1243dSDimitry Andric // T is a function reference... dereference the stored pointer. 314bdd1243dSDimitry Andric return *Func; 315bdd1243dSDimitry Andric } 316bdd1243dSDimitry Andric } 317bdd1243dSDimitry Andric }; 318bdd1243dSDimitry Andric 319bdd1243dSDimitry Andric } // namespace callable_detail 320bdd1243dSDimitry Andric 3215ffd83dbSDimitry Andric /// Returns true if the given container only contains a single element. 3225ffd83dbSDimitry Andric template <typename ContainerTy> bool hasSingleElement(ContainerTy &&C) { 3235ffd83dbSDimitry Andric auto B = std::begin(C), E = std::end(C); 3245ffd83dbSDimitry Andric return B != E && std::next(B) == E; 3255ffd83dbSDimitry Andric } 3265ffd83dbSDimitry Andric 327480093f4SDimitry Andric /// Return a range covering \p RangeOrContainer with the first N elements 328480093f4SDimitry Andric /// excluded. 329e8d8bef9SDimitry Andric template <typename T> auto drop_begin(T &&RangeOrContainer, size_t N = 1) { 330480093f4SDimitry Andric return make_range(std::next(adl_begin(RangeOrContainer), N), 331480093f4SDimitry Andric adl_end(RangeOrContainer)); 332480093f4SDimitry Andric } 333480093f4SDimitry Andric 33481ad6265SDimitry Andric /// Return a range covering \p RangeOrContainer with the last N elements 33581ad6265SDimitry Andric /// excluded. 33681ad6265SDimitry Andric template <typename T> auto drop_end(T &&RangeOrContainer, size_t N = 1) { 33781ad6265SDimitry Andric return make_range(adl_begin(RangeOrContainer), 33881ad6265SDimitry Andric std::prev(adl_end(RangeOrContainer), N)); 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 3410b57cec5SDimitry Andric // mapped_iterator - This is a simple iterator adapter that causes a function to 3420b57cec5SDimitry Andric // be applied whenever operator* is invoked on the iterator. 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric template <typename ItTy, typename FuncTy, 345349cc55cSDimitry Andric typename ReferenceTy = 3460b57cec5SDimitry Andric decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))> 3470b57cec5SDimitry Andric class mapped_iterator 3480b57cec5SDimitry Andric : public iterator_adaptor_base< 3490b57cec5SDimitry Andric mapped_iterator<ItTy, FuncTy>, ItTy, 3500b57cec5SDimitry Andric typename std::iterator_traits<ItTy>::iterator_category, 351349cc55cSDimitry Andric std::remove_reference_t<ReferenceTy>, 352349cc55cSDimitry Andric typename std::iterator_traits<ItTy>::difference_type, 353349cc55cSDimitry Andric std::remove_reference_t<ReferenceTy> *, ReferenceTy> { 3540b57cec5SDimitry Andric public: 355bdd1243dSDimitry Andric mapped_iterator() = default; 3560b57cec5SDimitry Andric mapped_iterator(ItTy U, FuncTy F) 3570b57cec5SDimitry Andric : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {} 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric ItTy getCurrent() { return this->I; } 3600b57cec5SDimitry Andric 361349cc55cSDimitry Andric const FuncTy &getFunction() const { return F; } 362349cc55cSDimitry Andric 363349cc55cSDimitry Andric ReferenceTy operator*() const { return F(*this->I); } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric private: 366bdd1243dSDimitry Andric callable_detail::Callable<FuncTy> F{}; 3670b57cec5SDimitry Andric }; 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric // map_iterator - Provide a convenient way to create mapped_iterators, just like 3700b57cec5SDimitry Andric // make_pair is useful for creating pairs... 3710b57cec5SDimitry Andric template <class ItTy, class FuncTy> 3720b57cec5SDimitry Andric inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) { 3730b57cec5SDimitry Andric return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F)); 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric template <class ContainerTy, class FuncTy> 3775ffd83dbSDimitry Andric auto map_range(ContainerTy &&C, FuncTy F) { 37806c3fb27SDimitry Andric return make_range(map_iterator(std::begin(C), F), 37906c3fb27SDimitry Andric map_iterator(std::end(C), F)); 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 382349cc55cSDimitry Andric /// A base type of mapped iterator, that is useful for building derived 383349cc55cSDimitry Andric /// iterators that do not need/want to store the map function (as in 384349cc55cSDimitry Andric /// mapped_iterator). These iterators must simply provide a `mapElement` method 385349cc55cSDimitry Andric /// that defines how to map a value of the iterator to the provided reference 386349cc55cSDimitry Andric /// type. 387349cc55cSDimitry Andric template <typename DerivedT, typename ItTy, typename ReferenceTy> 388349cc55cSDimitry Andric class mapped_iterator_base 389349cc55cSDimitry Andric : public iterator_adaptor_base< 390349cc55cSDimitry Andric DerivedT, ItTy, 391349cc55cSDimitry Andric typename std::iterator_traits<ItTy>::iterator_category, 392349cc55cSDimitry Andric std::remove_reference_t<ReferenceTy>, 393349cc55cSDimitry Andric typename std::iterator_traits<ItTy>::difference_type, 394349cc55cSDimitry Andric std::remove_reference_t<ReferenceTy> *, ReferenceTy> { 395349cc55cSDimitry Andric public: 396349cc55cSDimitry Andric using BaseT = mapped_iterator_base; 397349cc55cSDimitry Andric 398349cc55cSDimitry Andric mapped_iterator_base(ItTy U) 399349cc55cSDimitry Andric : mapped_iterator_base::iterator_adaptor_base(std::move(U)) {} 400349cc55cSDimitry Andric 401349cc55cSDimitry Andric ItTy getCurrent() { return this->I; } 402349cc55cSDimitry Andric 403349cc55cSDimitry Andric ReferenceTy operator*() const { 404349cc55cSDimitry Andric return static_cast<const DerivedT &>(*this).mapElement(*this->I); 405349cc55cSDimitry Andric } 406349cc55cSDimitry Andric }; 407349cc55cSDimitry Andric 4080fca6ea1SDimitry Andric namespace detail { 4090fca6ea1SDimitry Andric template <typename Range> 4100fca6ea1SDimitry Andric using check_has_free_function_rbegin = 4110fca6ea1SDimitry Andric decltype(adl_rbegin(std::declval<Range &>())); 4120b57cec5SDimitry Andric 4130fca6ea1SDimitry Andric template <typename Range> 4140fca6ea1SDimitry Andric static constexpr bool HasFreeFunctionRBegin = 4150fca6ea1SDimitry Andric is_detected<check_has_free_function_rbegin, Range>::value; 4160fca6ea1SDimitry Andric } // namespace detail 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric // Returns an iterator_range over the given container which iterates in reverse. 419bdd1243dSDimitry Andric template <typename ContainerTy> auto reverse(ContainerTy &&C) { 4200fca6ea1SDimitry Andric if constexpr (detail::HasFreeFunctionRBegin<ContainerTy>) 4210fca6ea1SDimitry Andric return make_range(adl_rbegin(C), adl_rend(C)); 422bdd1243dSDimitry Andric else 4230fca6ea1SDimitry Andric return make_range(std::make_reverse_iterator(adl_end(C)), 4240fca6ea1SDimitry Andric std::make_reverse_iterator(adl_begin(C))); 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric /// An iterator adaptor that filters the elements of given inner iterators. 4280b57cec5SDimitry Andric /// 4290b57cec5SDimitry Andric /// The predicate parameter should be a callable object that accepts the wrapped 4300b57cec5SDimitry Andric /// iterator's reference type and returns a bool. When incrementing or 4310b57cec5SDimitry Andric /// decrementing the iterator, it will call the predicate on each element and 4320b57cec5SDimitry Andric /// skip any where it returns false. 4330b57cec5SDimitry Andric /// 4340b57cec5SDimitry Andric /// \code 4350b57cec5SDimitry Andric /// int A[] = { 1, 2, 3, 4 }; 4360b57cec5SDimitry Andric /// auto R = make_filter_range(A, [](int N) { return N % 2 == 1; }); 4370b57cec5SDimitry Andric /// // R contains { 1, 3 }. 4380b57cec5SDimitry Andric /// \endcode 4390b57cec5SDimitry Andric /// 4400b57cec5SDimitry Andric /// Note: filter_iterator_base implements support for forward iteration. 4410b57cec5SDimitry Andric /// filter_iterator_impl exists to provide support for bidirectional iteration, 4420b57cec5SDimitry Andric /// conditional on whether the wrapped iterator supports it. 4430b57cec5SDimitry Andric template <typename WrappedIteratorT, typename PredicateT, typename IterTag> 4440b57cec5SDimitry Andric class filter_iterator_base 4450b57cec5SDimitry Andric : public iterator_adaptor_base< 4460b57cec5SDimitry Andric filter_iterator_base<WrappedIteratorT, PredicateT, IterTag>, 4470b57cec5SDimitry Andric WrappedIteratorT, 448bdd1243dSDimitry Andric std::common_type_t<IterTag, 449bdd1243dSDimitry Andric typename std::iterator_traits< 450bdd1243dSDimitry Andric WrappedIteratorT>::iterator_category>> { 451349cc55cSDimitry Andric using BaseT = typename filter_iterator_base::iterator_adaptor_base; 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric protected: 4540b57cec5SDimitry Andric WrappedIteratorT End; 4550b57cec5SDimitry Andric PredicateT Pred; 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric void findNextValid() { 4580b57cec5SDimitry Andric while (this->I != End && !Pred(*this->I)) 4590b57cec5SDimitry Andric BaseT::operator++(); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 462bdd1243dSDimitry Andric filter_iterator_base() = default; 463bdd1243dSDimitry Andric 4640b57cec5SDimitry Andric // Construct the iterator. The begin iterator needs to know where the end 4650b57cec5SDimitry Andric // is, so that it can properly stop when it gets there. The end iterator only 4660b57cec5SDimitry Andric // needs the predicate to support bidirectional iteration. 4670b57cec5SDimitry Andric filter_iterator_base(WrappedIteratorT Begin, WrappedIteratorT End, 4680b57cec5SDimitry Andric PredicateT Pred) 4690b57cec5SDimitry Andric : BaseT(Begin), End(End), Pred(Pred) { 4700b57cec5SDimitry Andric findNextValid(); 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric public: 4740b57cec5SDimitry Andric using BaseT::operator++; 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric filter_iterator_base &operator++() { 4770b57cec5SDimitry Andric BaseT::operator++(); 4780b57cec5SDimitry Andric findNextValid(); 4790b57cec5SDimitry Andric return *this; 4800b57cec5SDimitry Andric } 48181ad6265SDimitry Andric 48281ad6265SDimitry Andric decltype(auto) operator*() const { 48381ad6265SDimitry Andric assert(BaseT::wrapped() != End && "Cannot dereference end iterator!"); 48481ad6265SDimitry Andric return BaseT::operator*(); 48581ad6265SDimitry Andric } 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric decltype(auto) operator->() const { 48881ad6265SDimitry Andric assert(BaseT::wrapped() != End && "Cannot dereference end iterator!"); 48981ad6265SDimitry Andric return BaseT::operator->(); 49081ad6265SDimitry Andric } 4910b57cec5SDimitry Andric }; 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric /// Specialization of filter_iterator_base for forward iteration only. 4940b57cec5SDimitry Andric template <typename WrappedIteratorT, typename PredicateT, 4950b57cec5SDimitry Andric typename IterTag = std::forward_iterator_tag> 4960b57cec5SDimitry Andric class filter_iterator_impl 4970b57cec5SDimitry Andric : public filter_iterator_base<WrappedIteratorT, PredicateT, IterTag> { 4980b57cec5SDimitry Andric public: 499bdd1243dSDimitry Andric filter_iterator_impl() = default; 500bdd1243dSDimitry Andric 5010b57cec5SDimitry Andric filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, 5020b57cec5SDimitry Andric PredicateT Pred) 503349cc55cSDimitry Andric : filter_iterator_impl::filter_iterator_base(Begin, End, Pred) {} 5040b57cec5SDimitry Andric }; 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric /// Specialization of filter_iterator_base for bidirectional iteration. 5070b57cec5SDimitry Andric template <typename WrappedIteratorT, typename PredicateT> 5080b57cec5SDimitry Andric class filter_iterator_impl<WrappedIteratorT, PredicateT, 5090b57cec5SDimitry Andric std::bidirectional_iterator_tag> 5100b57cec5SDimitry Andric : public filter_iterator_base<WrappedIteratorT, PredicateT, 5110b57cec5SDimitry Andric std::bidirectional_iterator_tag> { 512349cc55cSDimitry Andric using BaseT = typename filter_iterator_impl::filter_iterator_base; 513349cc55cSDimitry Andric 5140b57cec5SDimitry Andric void findPrevValid() { 5150b57cec5SDimitry Andric while (!this->Pred(*this->I)) 5160b57cec5SDimitry Andric BaseT::operator--(); 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric public: 5200b57cec5SDimitry Andric using BaseT::operator--; 5210b57cec5SDimitry Andric 522bdd1243dSDimitry Andric filter_iterator_impl() = default; 523bdd1243dSDimitry Andric 5240b57cec5SDimitry Andric filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, 5250b57cec5SDimitry Andric PredicateT Pred) 5260b57cec5SDimitry Andric : BaseT(Begin, End, Pred) {} 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric filter_iterator_impl &operator--() { 5290b57cec5SDimitry Andric BaseT::operator--(); 5300b57cec5SDimitry Andric findPrevValid(); 5310b57cec5SDimitry Andric return *this; 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric }; 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric namespace detail { 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric template <bool is_bidirectional> struct fwd_or_bidi_tag_impl { 5380b57cec5SDimitry Andric using type = std::forward_iterator_tag; 5390b57cec5SDimitry Andric }; 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric template <> struct fwd_or_bidi_tag_impl<true> { 5420b57cec5SDimitry Andric using type = std::bidirectional_iterator_tag; 5430b57cec5SDimitry Andric }; 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric /// Helper which sets its type member to forward_iterator_tag if the category 5460b57cec5SDimitry Andric /// of \p IterT does not derive from bidirectional_iterator_tag, and to 5470b57cec5SDimitry Andric /// bidirectional_iterator_tag otherwise. 5480b57cec5SDimitry Andric template <typename IterT> struct fwd_or_bidi_tag { 5490b57cec5SDimitry Andric using type = typename fwd_or_bidi_tag_impl<std::is_base_of< 5500b57cec5SDimitry Andric std::bidirectional_iterator_tag, 5510b57cec5SDimitry Andric typename std::iterator_traits<IterT>::iterator_category>::value>::type; 5520b57cec5SDimitry Andric }; 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric } // namespace detail 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric /// Defines filter_iterator to a suitable specialization of 5570b57cec5SDimitry Andric /// filter_iterator_impl, based on the underlying iterator's category. 5580b57cec5SDimitry Andric template <typename WrappedIteratorT, typename PredicateT> 5590b57cec5SDimitry Andric using filter_iterator = filter_iterator_impl< 5600b57cec5SDimitry Andric WrappedIteratorT, PredicateT, 5610b57cec5SDimitry Andric typename detail::fwd_or_bidi_tag<WrappedIteratorT>::type>; 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric /// Convenience function that takes a range of elements and a predicate, 5640b57cec5SDimitry Andric /// and return a new filter_iterator range. 5650b57cec5SDimitry Andric /// 5660b57cec5SDimitry Andric /// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the 5670b57cec5SDimitry Andric /// lifetime of that temporary is not kept by the returned range object, and the 5680b57cec5SDimitry Andric /// temporary is going to be dropped on the floor after the make_iterator_range 5690b57cec5SDimitry Andric /// full expression that contains this function call. 5700b57cec5SDimitry Andric template <typename RangeT, typename PredicateT> 5710b57cec5SDimitry Andric iterator_range<filter_iterator<detail::IterOfRange<RangeT>, PredicateT>> 5720b57cec5SDimitry Andric make_filter_range(RangeT &&Range, PredicateT Pred) { 5730b57cec5SDimitry Andric using FilterIteratorT = 5740b57cec5SDimitry Andric filter_iterator<detail::IterOfRange<RangeT>, PredicateT>; 5750b57cec5SDimitry Andric return make_range( 5760b57cec5SDimitry Andric FilterIteratorT(std::begin(std::forward<RangeT>(Range)), 5770b57cec5SDimitry Andric std::end(std::forward<RangeT>(Range)), Pred), 5780b57cec5SDimitry Andric FilterIteratorT(std::end(std::forward<RangeT>(Range)), 5790b57cec5SDimitry Andric std::end(std::forward<RangeT>(Range)), Pred)); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric /// A pseudo-iterator adaptor that is designed to implement "early increment" 5830b57cec5SDimitry Andric /// style loops. 5840b57cec5SDimitry Andric /// 5850b57cec5SDimitry Andric /// This is *not a normal iterator* and should almost never be used directly. It 5860b57cec5SDimitry Andric /// is intended primarily to be used with range based for loops and some range 5870b57cec5SDimitry Andric /// algorithms. 5880b57cec5SDimitry Andric /// 5890b57cec5SDimitry Andric /// The iterator isn't quite an `OutputIterator` or an `InputIterator` but 5900b57cec5SDimitry Andric /// somewhere between them. The constraints of these iterators are: 5910b57cec5SDimitry Andric /// 5920b57cec5SDimitry Andric /// - On construction or after being incremented, it is comparable and 5930b57cec5SDimitry Andric /// dereferencable. It is *not* incrementable. 5940b57cec5SDimitry Andric /// - After being dereferenced, it is neither comparable nor dereferencable, it 5950b57cec5SDimitry Andric /// is only incrementable. 5960b57cec5SDimitry Andric /// 5970b57cec5SDimitry Andric /// This means you can only dereference the iterator once, and you can only 5980b57cec5SDimitry Andric /// increment it once between dereferences. 5990b57cec5SDimitry Andric template <typename WrappedIteratorT> 6000b57cec5SDimitry Andric class early_inc_iterator_impl 6010b57cec5SDimitry Andric : public iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>, 6020b57cec5SDimitry Andric WrappedIteratorT, std::input_iterator_tag> { 603349cc55cSDimitry Andric using BaseT = typename early_inc_iterator_impl::iterator_adaptor_base; 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric using PointerT = typename std::iterator_traits<WrappedIteratorT>::pointer; 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric protected: 6080b57cec5SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 6090b57cec5SDimitry Andric bool IsEarlyIncremented = false; 6100b57cec5SDimitry Andric #endif 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric public: 6130b57cec5SDimitry Andric early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {} 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric using BaseT::operator*; 616e8d8bef9SDimitry Andric decltype(*std::declval<WrappedIteratorT>()) operator*() { 6170b57cec5SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 6180b57cec5SDimitry Andric assert(!IsEarlyIncremented && "Cannot dereference twice!"); 6190b57cec5SDimitry Andric IsEarlyIncremented = true; 6200b57cec5SDimitry Andric #endif 6210b57cec5SDimitry Andric return *(this->I)++; 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric using BaseT::operator++; 6250b57cec5SDimitry Andric early_inc_iterator_impl &operator++() { 6260b57cec5SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 6270b57cec5SDimitry Andric assert(IsEarlyIncremented && "Cannot increment before dereferencing!"); 6280b57cec5SDimitry Andric IsEarlyIncremented = false; 6290b57cec5SDimitry Andric #endif 6300b57cec5SDimitry Andric return *this; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 633e8d8bef9SDimitry Andric friend bool operator==(const early_inc_iterator_impl &LHS, 634e8d8bef9SDimitry Andric const early_inc_iterator_impl &RHS) { 6350b57cec5SDimitry Andric #if LLVM_ENABLE_ABI_BREAKING_CHECKS 636e8d8bef9SDimitry Andric assert(!LHS.IsEarlyIncremented && "Cannot compare after dereferencing!"); 6370b57cec5SDimitry Andric #endif 638e8d8bef9SDimitry Andric return (const BaseT &)LHS == (const BaseT &)RHS; 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric }; 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric /// Make a range that does early increment to allow mutation of the underlying 6430b57cec5SDimitry Andric /// range without disrupting iteration. 6440b57cec5SDimitry Andric /// 6450b57cec5SDimitry Andric /// The underlying iterator will be incremented immediately after it is 6460b57cec5SDimitry Andric /// dereferenced, allowing deletion of the current node or insertion of nodes to 6470b57cec5SDimitry Andric /// not disrupt iteration provided they do not invalidate the *next* iterator -- 6480b57cec5SDimitry Andric /// the current iterator can be invalidated. 6490b57cec5SDimitry Andric /// 6500b57cec5SDimitry Andric /// This requires a very exact pattern of use that is only really suitable to 6510b57cec5SDimitry Andric /// range based for loops and other range algorithms that explicitly guarantee 6520b57cec5SDimitry Andric /// to dereference exactly once each element, and to increment exactly once each 6530b57cec5SDimitry Andric /// element. 6540b57cec5SDimitry Andric template <typename RangeT> 6550b57cec5SDimitry Andric iterator_range<early_inc_iterator_impl<detail::IterOfRange<RangeT>>> 6560b57cec5SDimitry Andric make_early_inc_range(RangeT &&Range) { 6570b57cec5SDimitry Andric using EarlyIncIteratorT = 6580b57cec5SDimitry Andric early_inc_iterator_impl<detail::IterOfRange<RangeT>>; 6590b57cec5SDimitry Andric return make_range(EarlyIncIteratorT(std::begin(std::forward<RangeT>(Range))), 6600b57cec5SDimitry Andric EarlyIncIteratorT(std::end(std::forward<RangeT>(Range)))); 6610b57cec5SDimitry Andric } 6620b57cec5SDimitry Andric 663bdd1243dSDimitry Andric // Forward declarations required by zip_shortest/zip_equal/zip_first/zip_longest 6640b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 6650b57cec5SDimitry Andric bool all_of(R &&range, UnaryPredicate P); 666bdd1243dSDimitry Andric 6670b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 6680b57cec5SDimitry Andric bool any_of(R &&range, UnaryPredicate P); 6690b57cec5SDimitry Andric 670bdd1243dSDimitry Andric template <typename T> bool all_equal(std::initializer_list<T> Values); 671bdd1243dSDimitry Andric 67206c3fb27SDimitry Andric template <typename R> constexpr size_t range_size(R &&Range); 67306c3fb27SDimitry Andric 6740b57cec5SDimitry Andric namespace detail { 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric using std::declval; 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric // We have to alias this since inlining the actual type at the usage site 6790b57cec5SDimitry Andric // in the parameter list of iterator_facade_base<> below ICEs MSVC 2017. 6800b57cec5SDimitry Andric template<typename... Iters> struct ZipTupleType { 6810b57cec5SDimitry Andric using type = std::tuple<decltype(*declval<Iters>())...>; 6820b57cec5SDimitry Andric }; 6830b57cec5SDimitry Andric 68406c3fb27SDimitry Andric template <typename ZipType, typename ReferenceTupleType, typename... Iters> 6850b57cec5SDimitry Andric using zip_traits = iterator_facade_base< 686bdd1243dSDimitry Andric ZipType, 687bdd1243dSDimitry Andric std::common_type_t< 688bdd1243dSDimitry Andric std::bidirectional_iterator_tag, 689bdd1243dSDimitry Andric typename std::iterator_traits<Iters>::iterator_category...>, 6900b57cec5SDimitry Andric // ^ TODO: Implement random access methods. 69106c3fb27SDimitry Andric ReferenceTupleType, 692bdd1243dSDimitry Andric typename std::iterator_traits< 693bdd1243dSDimitry Andric std::tuple_element_t<0, std::tuple<Iters...>>>::difference_type, 6940b57cec5SDimitry Andric // ^ FIXME: This follows boost::make_zip_iterator's assumption that all 6950b57cec5SDimitry Andric // inner iterators have the same difference_type. It would fail if, for 6960b57cec5SDimitry Andric // instance, the second field's difference_type were non-numeric while the 6970b57cec5SDimitry Andric // first is. 69806c3fb27SDimitry Andric ReferenceTupleType *, ReferenceTupleType>; 6990b57cec5SDimitry Andric 70006c3fb27SDimitry Andric template <typename ZipType, typename ReferenceTupleType, typename... Iters> 70106c3fb27SDimitry Andric struct zip_common : public zip_traits<ZipType, ReferenceTupleType, Iters...> { 70206c3fb27SDimitry Andric using Base = zip_traits<ZipType, ReferenceTupleType, Iters...>; 70306c3fb27SDimitry Andric using IndexSequence = std::index_sequence_for<Iters...>; 7040b57cec5SDimitry Andric using value_type = typename Base::value_type; 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric std::tuple<Iters...> iterators; 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric protected: 7098bcb0991SDimitry Andric template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const { 7100b57cec5SDimitry Andric return value_type(*std::get<Ns>(iterators)...); 7110b57cec5SDimitry Andric } 7120b57cec5SDimitry Andric 71306c3fb27SDimitry Andric template <size_t... Ns> void tup_inc(std::index_sequence<Ns...>) { 71406c3fb27SDimitry Andric (++std::get<Ns>(iterators), ...); 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric 71706c3fb27SDimitry Andric template <size_t... Ns> void tup_dec(std::index_sequence<Ns...>) { 71806c3fb27SDimitry Andric (--std::get<Ns>(iterators), ...); 7190b57cec5SDimitry Andric } 7200b57cec5SDimitry Andric 721349cc55cSDimitry Andric template <size_t... Ns> 722349cc55cSDimitry Andric bool test_all_equals(const zip_common &other, 723349cc55cSDimitry Andric std::index_sequence<Ns...>) const { 724bdd1243dSDimitry Andric return ((std::get<Ns>(this->iterators) == std::get<Ns>(other.iterators)) && 725bdd1243dSDimitry Andric ...); 726349cc55cSDimitry Andric } 727349cc55cSDimitry Andric 7280b57cec5SDimitry Andric public: 7290b57cec5SDimitry Andric zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {} 7300b57cec5SDimitry Andric 73106c3fb27SDimitry Andric value_type operator*() const { return deref(IndexSequence{}); } 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric ZipType &operator++() { 73406c3fb27SDimitry Andric tup_inc(IndexSequence{}); 73506c3fb27SDimitry Andric return static_cast<ZipType &>(*this); 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric ZipType &operator--() { 7390b57cec5SDimitry Andric static_assert(Base::IsBidirectional, 7400b57cec5SDimitry Andric "All inner iterators must be at least bidirectional."); 74106c3fb27SDimitry Andric tup_dec(IndexSequence{}); 74206c3fb27SDimitry Andric return static_cast<ZipType &>(*this); 7430b57cec5SDimitry Andric } 744349cc55cSDimitry Andric 745349cc55cSDimitry Andric /// Return true if all the iterator are matching `other`'s iterators. 746349cc55cSDimitry Andric bool all_equals(zip_common &other) { 74706c3fb27SDimitry Andric return test_all_equals(other, IndexSequence{}); 748349cc55cSDimitry Andric } 7490b57cec5SDimitry Andric }; 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric template <typename... Iters> 75206c3fb27SDimitry Andric struct zip_first : zip_common<zip_first<Iters...>, 75306c3fb27SDimitry Andric typename ZipTupleType<Iters...>::type, Iters...> { 75406c3fb27SDimitry Andric using zip_common<zip_first, typename ZipTupleType<Iters...>::type, 75506c3fb27SDimitry Andric Iters...>::zip_common; 7560b57cec5SDimitry Andric 75706c3fb27SDimitry Andric bool operator==(const zip_first &other) const { 7580b57cec5SDimitry Andric return std::get<0>(this->iterators) == std::get<0>(other.iterators); 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric }; 7610b57cec5SDimitry Andric 7620b57cec5SDimitry Andric template <typename... Iters> 76306c3fb27SDimitry Andric struct zip_shortest 76406c3fb27SDimitry Andric : zip_common<zip_shortest<Iters...>, typename ZipTupleType<Iters...>::type, 76506c3fb27SDimitry Andric Iters...> { 76606c3fb27SDimitry Andric using zip_common<zip_shortest, typename ZipTupleType<Iters...>::type, 76706c3fb27SDimitry Andric Iters...>::zip_common; 76806c3fb27SDimitry Andric 76906c3fb27SDimitry Andric bool operator==(const zip_shortest &other) const { 77006c3fb27SDimitry Andric return any_iterator_equals(other, std::index_sequence_for<Iters...>{}); 77106c3fb27SDimitry Andric } 77206c3fb27SDimitry Andric 77306c3fb27SDimitry Andric private: 7740b57cec5SDimitry Andric template <size_t... Ns> 77506c3fb27SDimitry Andric bool any_iterator_equals(const zip_shortest &other, 7768bcb0991SDimitry Andric std::index_sequence<Ns...>) const { 77706c3fb27SDimitry Andric return ((std::get<Ns>(this->iterators) == std::get<Ns>(other.iterators)) || 778bdd1243dSDimitry Andric ...); 7790b57cec5SDimitry Andric } 78006c3fb27SDimitry Andric }; 7810b57cec5SDimitry Andric 78206c3fb27SDimitry Andric /// Helper to obtain the iterator types for the tuple storage within `zippy`. 78306c3fb27SDimitry Andric template <template <typename...> class ItType, typename TupleStorageType, 78406c3fb27SDimitry Andric typename IndexSequence> 78506c3fb27SDimitry Andric struct ZippyIteratorTuple; 7860b57cec5SDimitry Andric 78706c3fb27SDimitry Andric /// Partial specialization for non-const tuple storage. 78806c3fb27SDimitry Andric template <template <typename...> class ItType, typename... Args, 78906c3fb27SDimitry Andric std::size_t... Ns> 79006c3fb27SDimitry Andric struct ZippyIteratorTuple<ItType, std::tuple<Args...>, 79106c3fb27SDimitry Andric std::index_sequence<Ns...>> { 79206c3fb27SDimitry Andric using type = ItType<decltype(adl_begin( 79306c3fb27SDimitry Andric std::get<Ns>(declval<std::tuple<Args...> &>())))...>; 79406c3fb27SDimitry Andric }; 7950b57cec5SDimitry Andric 79606c3fb27SDimitry Andric /// Partial specialization for const tuple storage. 79706c3fb27SDimitry Andric template <template <typename...> class ItType, typename... Args, 79806c3fb27SDimitry Andric std::size_t... Ns> 79906c3fb27SDimitry Andric struct ZippyIteratorTuple<ItType, const std::tuple<Args...>, 80006c3fb27SDimitry Andric std::index_sequence<Ns...>> { 80106c3fb27SDimitry Andric using type = ItType<decltype(adl_begin( 80206c3fb27SDimitry Andric std::get<Ns>(declval<const std::tuple<Args...> &>())))...>; 8030b57cec5SDimitry Andric }; 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric template <template <typename...> class ItType, typename... Args> class zippy { 80606c3fb27SDimitry Andric private: 80706c3fb27SDimitry Andric std::tuple<Args...> storage; 80806c3fb27SDimitry Andric using IndexSequence = std::index_sequence_for<Args...>; 80906c3fb27SDimitry Andric 8100b57cec5SDimitry Andric public: 81106c3fb27SDimitry Andric using iterator = typename ZippyIteratorTuple<ItType, decltype(storage), 81206c3fb27SDimitry Andric IndexSequence>::type; 81306c3fb27SDimitry Andric using const_iterator = 81406c3fb27SDimitry Andric typename ZippyIteratorTuple<ItType, const decltype(storage), 81506c3fb27SDimitry Andric IndexSequence>::type; 8160b57cec5SDimitry Andric using iterator_category = typename iterator::iterator_category; 8170b57cec5SDimitry Andric using value_type = typename iterator::value_type; 8180b57cec5SDimitry Andric using difference_type = typename iterator::difference_type; 8190b57cec5SDimitry Andric using pointer = typename iterator::pointer; 8200b57cec5SDimitry Andric using reference = typename iterator::reference; 82106c3fb27SDimitry Andric using const_reference = typename const_iterator::reference; 82206c3fb27SDimitry Andric 82306c3fb27SDimitry Andric zippy(Args &&...args) : storage(std::forward<Args>(args)...) {} 82406c3fb27SDimitry Andric 82506c3fb27SDimitry Andric const_iterator begin() const { return begin_impl(IndexSequence{}); } 82606c3fb27SDimitry Andric iterator begin() { return begin_impl(IndexSequence{}); } 82706c3fb27SDimitry Andric const_iterator end() const { return end_impl(IndexSequence{}); } 82806c3fb27SDimitry Andric iterator end() { return end_impl(IndexSequence{}); } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric private: 83106c3fb27SDimitry Andric template <size_t... Ns> 83206c3fb27SDimitry Andric const_iterator begin_impl(std::index_sequence<Ns...>) const { 83306c3fb27SDimitry Andric return const_iterator(adl_begin(std::get<Ns>(storage))...); 83406c3fb27SDimitry Andric } 83506c3fb27SDimitry Andric template <size_t... Ns> iterator begin_impl(std::index_sequence<Ns...>) { 83606c3fb27SDimitry Andric return iterator(adl_begin(std::get<Ns>(storage))...); 83706c3fb27SDimitry Andric } 8380b57cec5SDimitry Andric 8398bcb0991SDimitry Andric template <size_t... Ns> 84006c3fb27SDimitry Andric const_iterator end_impl(std::index_sequence<Ns...>) const { 84106c3fb27SDimitry Andric return const_iterator(adl_end(std::get<Ns>(storage))...); 8420b57cec5SDimitry Andric } 84306c3fb27SDimitry Andric template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) { 84406c3fb27SDimitry Andric return iterator(adl_end(std::get<Ns>(storage))...); 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric }; 8470b57cec5SDimitry Andric 8480b57cec5SDimitry Andric } // end namespace detail 8490b57cec5SDimitry Andric 850bdd1243dSDimitry Andric /// zip iterator for two or more iteratable types. Iteration continues until the 851bdd1243dSDimitry Andric /// end of the *shortest* iteratee is reached. 8520b57cec5SDimitry Andric template <typename T, typename U, typename... Args> 8530b57cec5SDimitry Andric detail::zippy<detail::zip_shortest, T, U, Args...> zip(T &&t, U &&u, 8540b57cec5SDimitry Andric Args &&...args) { 8550b57cec5SDimitry Andric return detail::zippy<detail::zip_shortest, T, U, Args...>( 8560b57cec5SDimitry Andric std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); 8570b57cec5SDimitry Andric } 8580b57cec5SDimitry Andric 859bdd1243dSDimitry Andric /// zip iterator that assumes that all iteratees have the same length. 860bdd1243dSDimitry Andric /// In builds with assertions on, this assumption is checked before the 861bdd1243dSDimitry Andric /// iteration starts. 862bdd1243dSDimitry Andric template <typename T, typename U, typename... Args> 863bdd1243dSDimitry Andric detail::zippy<detail::zip_first, T, U, Args...> zip_equal(T &&t, U &&u, 864bdd1243dSDimitry Andric Args &&...args) { 86506c3fb27SDimitry Andric assert(all_equal({range_size(t), range_size(u), range_size(args)...}) && 866bdd1243dSDimitry Andric "Iteratees do not have equal length"); 867bdd1243dSDimitry Andric return detail::zippy<detail::zip_first, T, U, Args...>( 868bdd1243dSDimitry Andric std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); 869bdd1243dSDimitry Andric } 870bdd1243dSDimitry Andric 8710b57cec5SDimitry Andric /// zip iterator that, for the sake of efficiency, assumes the first iteratee to 872bdd1243dSDimitry Andric /// be the shortest. Iteration continues until the end of the first iteratee is 873bdd1243dSDimitry Andric /// reached. In builds with assertions on, we check that the assumption about 874bdd1243dSDimitry Andric /// the first iteratee being the shortest holds. 8750b57cec5SDimitry Andric template <typename T, typename U, typename... Args> 8760b57cec5SDimitry Andric detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u, 8770b57cec5SDimitry Andric Args &&...args) { 87806c3fb27SDimitry Andric assert(range_size(t) <= std::min({range_size(u), range_size(args)...}) && 879bdd1243dSDimitry Andric "First iteratee is not the shortest"); 880bdd1243dSDimitry Andric 8810b57cec5SDimitry Andric return detail::zippy<detail::zip_first, T, U, Args...>( 8820b57cec5SDimitry Andric std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric namespace detail { 8860b57cec5SDimitry Andric template <typename Iter> 8875ffd83dbSDimitry Andric Iter next_or_end(const Iter &I, const Iter &End) { 8880b57cec5SDimitry Andric if (I == End) 8890b57cec5SDimitry Andric return End; 8900b57cec5SDimitry Andric return std::next(I); 8910b57cec5SDimitry Andric } 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric template <typename Iter> 894bdd1243dSDimitry Andric auto deref_or_none(const Iter &I, const Iter &End) -> std::optional< 8955ffd83dbSDimitry Andric std::remove_const_t<std::remove_reference_t<decltype(*I)>>> { 8960b57cec5SDimitry Andric if (I == End) 897bdd1243dSDimitry Andric return std::nullopt; 8980b57cec5SDimitry Andric return *I; 8990b57cec5SDimitry Andric } 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric template <typename Iter> struct ZipLongestItemType { 902bdd1243dSDimitry Andric using type = std::optional<std::remove_const_t< 903bdd1243dSDimitry Andric std::remove_reference_t<decltype(*std::declval<Iter>())>>>; 9040b57cec5SDimitry Andric }; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric template <typename... Iters> struct ZipLongestTupleType { 9070b57cec5SDimitry Andric using type = std::tuple<typename ZipLongestItemType<Iters>::type...>; 9080b57cec5SDimitry Andric }; 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric template <typename... Iters> 9110b57cec5SDimitry Andric class zip_longest_iterator 9120b57cec5SDimitry Andric : public iterator_facade_base< 9130b57cec5SDimitry Andric zip_longest_iterator<Iters...>, 914bdd1243dSDimitry Andric std::common_type_t< 9150b57cec5SDimitry Andric std::forward_iterator_tag, 916bdd1243dSDimitry Andric typename std::iterator_traits<Iters>::iterator_category...>, 9170b57cec5SDimitry Andric typename ZipLongestTupleType<Iters...>::type, 918bdd1243dSDimitry Andric typename std::iterator_traits< 919bdd1243dSDimitry Andric std::tuple_element_t<0, std::tuple<Iters...>>>::difference_type, 9200b57cec5SDimitry Andric typename ZipLongestTupleType<Iters...>::type *, 9210b57cec5SDimitry Andric typename ZipLongestTupleType<Iters...>::type> { 9220b57cec5SDimitry Andric public: 9230b57cec5SDimitry Andric using value_type = typename ZipLongestTupleType<Iters...>::type; 9240b57cec5SDimitry Andric 9250b57cec5SDimitry Andric private: 9260b57cec5SDimitry Andric std::tuple<Iters...> iterators; 9270b57cec5SDimitry Andric std::tuple<Iters...> end_iterators; 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric template <size_t... Ns> 9300b57cec5SDimitry Andric bool test(const zip_longest_iterator<Iters...> &other, 9318bcb0991SDimitry Andric std::index_sequence<Ns...>) const { 932bdd1243dSDimitry Andric return ((std::get<Ns>(this->iterators) != std::get<Ns>(other.iterators)) || 933bdd1243dSDimitry Andric ...); 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric 9368bcb0991SDimitry Andric template <size_t... Ns> value_type deref(std::index_sequence<Ns...>) const { 9370b57cec5SDimitry Andric return value_type( 9380b57cec5SDimitry Andric deref_or_none(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...); 9390b57cec5SDimitry Andric } 9400b57cec5SDimitry Andric 9410b57cec5SDimitry Andric template <size_t... Ns> 9428bcb0991SDimitry Andric decltype(iterators) tup_inc(std::index_sequence<Ns...>) const { 9430b57cec5SDimitry Andric return std::tuple<Iters...>( 9440b57cec5SDimitry Andric next_or_end(std::get<Ns>(iterators), std::get<Ns>(end_iterators))...); 9450b57cec5SDimitry Andric } 9460b57cec5SDimitry Andric 9470b57cec5SDimitry Andric public: 9480b57cec5SDimitry Andric zip_longest_iterator(std::pair<Iters &&, Iters &&>... ts) 9490b57cec5SDimitry Andric : iterators(std::forward<Iters>(ts.first)...), 9500b57cec5SDimitry Andric end_iterators(std::forward<Iters>(ts.second)...) {} 9510b57cec5SDimitry Andric 9528bcb0991SDimitry Andric value_type operator*() const { 9538bcb0991SDimitry Andric return deref(std::index_sequence_for<Iters...>{}); 9548bcb0991SDimitry Andric } 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric zip_longest_iterator<Iters...> &operator++() { 9578bcb0991SDimitry Andric iterators = tup_inc(std::index_sequence_for<Iters...>{}); 9580b57cec5SDimitry Andric return *this; 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric 9610b57cec5SDimitry Andric bool operator==(const zip_longest_iterator<Iters...> &other) const { 9628bcb0991SDimitry Andric return !test(other, std::index_sequence_for<Iters...>{}); 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric }; 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric template <typename... Args> class zip_longest_range { 9670b57cec5SDimitry Andric public: 9680b57cec5SDimitry Andric using iterator = 9690b57cec5SDimitry Andric zip_longest_iterator<decltype(adl_begin(std::declval<Args>()))...>; 9700b57cec5SDimitry Andric using iterator_category = typename iterator::iterator_category; 9710b57cec5SDimitry Andric using value_type = typename iterator::value_type; 9720b57cec5SDimitry Andric using difference_type = typename iterator::difference_type; 9730b57cec5SDimitry Andric using pointer = typename iterator::pointer; 9740b57cec5SDimitry Andric using reference = typename iterator::reference; 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric private: 9770b57cec5SDimitry Andric std::tuple<Args...> ts; 9780b57cec5SDimitry Andric 9798bcb0991SDimitry Andric template <size_t... Ns> 9808bcb0991SDimitry Andric iterator begin_impl(std::index_sequence<Ns...>) const { 9810b57cec5SDimitry Andric return iterator(std::make_pair(adl_begin(std::get<Ns>(ts)), 9820b57cec5SDimitry Andric adl_end(std::get<Ns>(ts)))...); 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9858bcb0991SDimitry Andric template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const { 9860b57cec5SDimitry Andric return iterator(std::make_pair(adl_end(std::get<Ns>(ts)), 9870b57cec5SDimitry Andric adl_end(std::get<Ns>(ts)))...); 9880b57cec5SDimitry Andric } 9890b57cec5SDimitry Andric 9900b57cec5SDimitry Andric public: 9910b57cec5SDimitry Andric zip_longest_range(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {} 9920b57cec5SDimitry Andric 9938bcb0991SDimitry Andric iterator begin() const { 9948bcb0991SDimitry Andric return begin_impl(std::index_sequence_for<Args...>{}); 9958bcb0991SDimitry Andric } 9968bcb0991SDimitry Andric iterator end() const { return end_impl(std::index_sequence_for<Args...>{}); } 9970b57cec5SDimitry Andric }; 9980b57cec5SDimitry Andric } // namespace detail 9990b57cec5SDimitry Andric 10000b57cec5SDimitry Andric /// Iterate over two or more iterators at the same time. Iteration continues 1001bdd1243dSDimitry Andric /// until all iterators reach the end. The std::optional only contains a value 10020b57cec5SDimitry Andric /// if the iterator has not reached the end. 10030b57cec5SDimitry Andric template <typename T, typename U, typename... Args> 10040b57cec5SDimitry Andric detail::zip_longest_range<T, U, Args...> zip_longest(T &&t, U &&u, 10050b57cec5SDimitry Andric Args &&... args) { 10060b57cec5SDimitry Andric return detail::zip_longest_range<T, U, Args...>( 10070b57cec5SDimitry Andric std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...); 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric 10100b57cec5SDimitry Andric /// Iterator wrapper that concatenates sequences together. 10110b57cec5SDimitry Andric /// 10120b57cec5SDimitry Andric /// This can concatenate different iterators, even with different types, into 10130b57cec5SDimitry Andric /// a single iterator provided the value types of all the concatenated 10140b57cec5SDimitry Andric /// iterators expose `reference` and `pointer` types that can be converted to 10150b57cec5SDimitry Andric /// `ValueT &` and `ValueT *` respectively. It doesn't support more 10160b57cec5SDimitry Andric /// interesting/customized pointer or reference types. 10170b57cec5SDimitry Andric /// 10180b57cec5SDimitry Andric /// Currently this only supports forward or higher iterator categories as 10190b57cec5SDimitry Andric /// inputs and always exposes a forward iterator interface. 10200b57cec5SDimitry Andric template <typename ValueT, typename... IterTs> 10210b57cec5SDimitry Andric class concat_iterator 10220b57cec5SDimitry Andric : public iterator_facade_base<concat_iterator<ValueT, IterTs...>, 10230b57cec5SDimitry Andric std::forward_iterator_tag, ValueT> { 10240b57cec5SDimitry Andric using BaseT = typename concat_iterator::iterator_facade_base; 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric /// We store both the current and end iterators for each concatenated 10270b57cec5SDimitry Andric /// sequence in a tuple of pairs. 10280b57cec5SDimitry Andric /// 10290b57cec5SDimitry Andric /// Note that something like iterator_range seems nice at first here, but the 10300b57cec5SDimitry Andric /// range properties are of little benefit and end up getting in the way 10310b57cec5SDimitry Andric /// because we need to do mutation on the current iterators. 10320b57cec5SDimitry Andric std::tuple<IterTs...> Begins; 10330b57cec5SDimitry Andric std::tuple<IterTs...> Ends; 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric /// Attempts to increment a specific iterator. 10360b57cec5SDimitry Andric /// 10370b57cec5SDimitry Andric /// Returns true if it was able to increment the iterator. Returns false if 10380b57cec5SDimitry Andric /// the iterator is already at the end iterator. 10390b57cec5SDimitry Andric template <size_t Index> bool incrementHelper() { 10400b57cec5SDimitry Andric auto &Begin = std::get<Index>(Begins); 10410b57cec5SDimitry Andric auto &End = std::get<Index>(Ends); 10420b57cec5SDimitry Andric if (Begin == End) 10430b57cec5SDimitry Andric return false; 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric ++Begin; 10460b57cec5SDimitry Andric return true; 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric /// Increments the first non-end iterator. 10500b57cec5SDimitry Andric /// 10510b57cec5SDimitry Andric /// It is an error to call this with all iterators at the end. 10528bcb0991SDimitry Andric template <size_t... Ns> void increment(std::index_sequence<Ns...>) { 10530b57cec5SDimitry Andric // Build a sequence of functions to increment each iterator if possible. 10540b57cec5SDimitry Andric bool (concat_iterator::*IncrementHelperFns[])() = { 10550b57cec5SDimitry Andric &concat_iterator::incrementHelper<Ns>...}; 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric // Loop over them, and stop as soon as we succeed at incrementing one. 10580b57cec5SDimitry Andric for (auto &IncrementHelperFn : IncrementHelperFns) 10590b57cec5SDimitry Andric if ((this->*IncrementHelperFn)()) 10600b57cec5SDimitry Andric return; 10610b57cec5SDimitry Andric 10620b57cec5SDimitry Andric llvm_unreachable("Attempted to increment an end concat iterator!"); 10630b57cec5SDimitry Andric } 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric /// Returns null if the specified iterator is at the end. Otherwise, 10660b57cec5SDimitry Andric /// dereferences the iterator and returns the address of the resulting 10670b57cec5SDimitry Andric /// reference. 10680b57cec5SDimitry Andric template <size_t Index> ValueT *getHelper() const { 10690b57cec5SDimitry Andric auto &Begin = std::get<Index>(Begins); 10700b57cec5SDimitry Andric auto &End = std::get<Index>(Ends); 10710b57cec5SDimitry Andric if (Begin == End) 10720b57cec5SDimitry Andric return nullptr; 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric return &*Begin; 10750b57cec5SDimitry Andric } 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric /// Finds the first non-end iterator, dereferences, and returns the resulting 10780b57cec5SDimitry Andric /// reference. 10790b57cec5SDimitry Andric /// 10800b57cec5SDimitry Andric /// It is an error to call this with all iterators at the end. 10818bcb0991SDimitry Andric template <size_t... Ns> ValueT &get(std::index_sequence<Ns...>) const { 10820b57cec5SDimitry Andric // Build a sequence of functions to get from iterator if possible. 10830b57cec5SDimitry Andric ValueT *(concat_iterator::*GetHelperFns[])() const = { 10840b57cec5SDimitry Andric &concat_iterator::getHelper<Ns>...}; 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric // Loop over them, and return the first result we find. 10870b57cec5SDimitry Andric for (auto &GetHelperFn : GetHelperFns) 10880b57cec5SDimitry Andric if (ValueT *P = (this->*GetHelperFn)()) 10890b57cec5SDimitry Andric return *P; 10900b57cec5SDimitry Andric 10910b57cec5SDimitry Andric llvm_unreachable("Attempted to get a pointer from an end concat iterator!"); 10920b57cec5SDimitry Andric } 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric public: 10955ffd83dbSDimitry Andric /// Constructs an iterator from a sequence of ranges. 10960b57cec5SDimitry Andric /// 10970b57cec5SDimitry Andric /// We need the full range to know how to switch between each of the 10980b57cec5SDimitry Andric /// iterators. 10990b57cec5SDimitry Andric template <typename... RangeTs> 11000b57cec5SDimitry Andric explicit concat_iterator(RangeTs &&... Ranges) 11010b57cec5SDimitry Andric : Begins(std::begin(Ranges)...), Ends(std::end(Ranges)...) {} 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric using BaseT::operator++; 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric concat_iterator &operator++() { 11068bcb0991SDimitry Andric increment(std::index_sequence_for<IterTs...>()); 11070b57cec5SDimitry Andric return *this; 11080b57cec5SDimitry Andric } 11090b57cec5SDimitry Andric 11108bcb0991SDimitry Andric ValueT &operator*() const { 11118bcb0991SDimitry Andric return get(std::index_sequence_for<IterTs...>()); 11128bcb0991SDimitry Andric } 11130b57cec5SDimitry Andric 11140b57cec5SDimitry Andric bool operator==(const concat_iterator &RHS) const { 11150b57cec5SDimitry Andric return Begins == RHS.Begins && Ends == RHS.Ends; 11160b57cec5SDimitry Andric } 11170b57cec5SDimitry Andric }; 11180b57cec5SDimitry Andric 11190b57cec5SDimitry Andric namespace detail { 11200b57cec5SDimitry Andric 11210b57cec5SDimitry Andric /// Helper to store a sequence of ranges being concatenated and access them. 11220b57cec5SDimitry Andric /// 11230b57cec5SDimitry Andric /// This is designed to facilitate providing actual storage when temporaries 11240b57cec5SDimitry Andric /// are passed into the constructor such that we can use it as part of range 11250b57cec5SDimitry Andric /// based for loops. 11260b57cec5SDimitry Andric template <typename ValueT, typename... RangeTs> class concat_range { 11270b57cec5SDimitry Andric public: 11280b57cec5SDimitry Andric using iterator = 11290b57cec5SDimitry Andric concat_iterator<ValueT, 11300b57cec5SDimitry Andric decltype(std::begin(std::declval<RangeTs &>()))...>; 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric private: 11330b57cec5SDimitry Andric std::tuple<RangeTs...> Ranges; 11340b57cec5SDimitry Andric 11354824e7fdSDimitry Andric template <size_t... Ns> 11364824e7fdSDimitry Andric iterator begin_impl(std::index_sequence<Ns...>) { 11374824e7fdSDimitry Andric return iterator(std::get<Ns>(Ranges)...); 11384824e7fdSDimitry Andric } 11394824e7fdSDimitry Andric template <size_t... Ns> 11404824e7fdSDimitry Andric iterator begin_impl(std::index_sequence<Ns...>) const { 11410b57cec5SDimitry Andric return iterator(std::get<Ns>(Ranges)...); 11420b57cec5SDimitry Andric } 11438bcb0991SDimitry Andric template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) { 11440b57cec5SDimitry Andric return iterator(make_range(std::end(std::get<Ns>(Ranges)), 11450b57cec5SDimitry Andric std::end(std::get<Ns>(Ranges)))...); 11460b57cec5SDimitry Andric } 11474824e7fdSDimitry Andric template <size_t... Ns> iterator end_impl(std::index_sequence<Ns...>) const { 11484824e7fdSDimitry Andric return iterator(make_range(std::end(std::get<Ns>(Ranges)), 11494824e7fdSDimitry Andric std::end(std::get<Ns>(Ranges)))...); 11504824e7fdSDimitry Andric } 11510b57cec5SDimitry Andric 11520b57cec5SDimitry Andric public: 11530b57cec5SDimitry Andric concat_range(RangeTs &&... Ranges) 11540b57cec5SDimitry Andric : Ranges(std::forward<RangeTs>(Ranges)...) {} 11550b57cec5SDimitry Andric 11564824e7fdSDimitry Andric iterator begin() { 11574824e7fdSDimitry Andric return begin_impl(std::index_sequence_for<RangeTs...>{}); 11584824e7fdSDimitry Andric } 11594824e7fdSDimitry Andric iterator begin() const { 11604824e7fdSDimitry Andric return begin_impl(std::index_sequence_for<RangeTs...>{}); 11614824e7fdSDimitry Andric } 11624824e7fdSDimitry Andric iterator end() { 11634824e7fdSDimitry Andric return end_impl(std::index_sequence_for<RangeTs...>{}); 11644824e7fdSDimitry Andric } 11654824e7fdSDimitry Andric iterator end() const { 11664824e7fdSDimitry Andric return end_impl(std::index_sequence_for<RangeTs...>{}); 11674824e7fdSDimitry Andric } 11680b57cec5SDimitry Andric }; 11690b57cec5SDimitry Andric 11700b57cec5SDimitry Andric } // end namespace detail 11710b57cec5SDimitry Andric 11720b57cec5SDimitry Andric /// Concatenated range across two or more ranges. 11730b57cec5SDimitry Andric /// 11740b57cec5SDimitry Andric /// The desired value type must be explicitly specified. 11750b57cec5SDimitry Andric template <typename ValueT, typename... RangeTs> 11760b57cec5SDimitry Andric detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) { 11770b57cec5SDimitry Andric static_assert(sizeof...(RangeTs) > 1, 11780b57cec5SDimitry Andric "Need more than one range to concatenate!"); 11790b57cec5SDimitry Andric return detail::concat_range<ValueT, RangeTs...>( 11800b57cec5SDimitry Andric std::forward<RangeTs>(Ranges)...); 11810b57cec5SDimitry Andric } 11820b57cec5SDimitry Andric 11835ffd83dbSDimitry Andric /// A utility class used to implement an iterator that contains some base object 11845ffd83dbSDimitry Andric /// and an index. The iterator moves the index but keeps the base constant. 11855ffd83dbSDimitry Andric template <typename DerivedT, typename BaseT, typename T, 11865ffd83dbSDimitry Andric typename PointerT = T *, typename ReferenceT = T &> 11875ffd83dbSDimitry Andric class indexed_accessor_iterator 11885ffd83dbSDimitry Andric : public llvm::iterator_facade_base<DerivedT, 11895ffd83dbSDimitry Andric std::random_access_iterator_tag, T, 11905ffd83dbSDimitry Andric std::ptrdiff_t, PointerT, ReferenceT> { 11915ffd83dbSDimitry Andric public: 11925ffd83dbSDimitry Andric ptrdiff_t operator-(const indexed_accessor_iterator &rhs) const { 11935ffd83dbSDimitry Andric assert(base == rhs.base && "incompatible iterators"); 11945ffd83dbSDimitry Andric return index - rhs.index; 11955ffd83dbSDimitry Andric } 11965ffd83dbSDimitry Andric bool operator==(const indexed_accessor_iterator &rhs) const { 11975ffd83dbSDimitry Andric return base == rhs.base && index == rhs.index; 11985ffd83dbSDimitry Andric } 11995ffd83dbSDimitry Andric bool operator<(const indexed_accessor_iterator &rhs) const { 12005ffd83dbSDimitry Andric assert(base == rhs.base && "incompatible iterators"); 12015ffd83dbSDimitry Andric return index < rhs.index; 12025ffd83dbSDimitry Andric } 12035ffd83dbSDimitry Andric 12045ffd83dbSDimitry Andric DerivedT &operator+=(ptrdiff_t offset) { 12055ffd83dbSDimitry Andric this->index += offset; 12065ffd83dbSDimitry Andric return static_cast<DerivedT &>(*this); 12075ffd83dbSDimitry Andric } 12085ffd83dbSDimitry Andric DerivedT &operator-=(ptrdiff_t offset) { 12095ffd83dbSDimitry Andric this->index -= offset; 12105ffd83dbSDimitry Andric return static_cast<DerivedT &>(*this); 12115ffd83dbSDimitry Andric } 12125ffd83dbSDimitry Andric 12135ffd83dbSDimitry Andric /// Returns the current index of the iterator. 12145ffd83dbSDimitry Andric ptrdiff_t getIndex() const { return index; } 12155ffd83dbSDimitry Andric 12165ffd83dbSDimitry Andric /// Returns the current base of the iterator. 12175ffd83dbSDimitry Andric const BaseT &getBase() const { return base; } 12185ffd83dbSDimitry Andric 12195ffd83dbSDimitry Andric protected: 12205ffd83dbSDimitry Andric indexed_accessor_iterator(BaseT base, ptrdiff_t index) 12215ffd83dbSDimitry Andric : base(base), index(index) {} 12225ffd83dbSDimitry Andric BaseT base; 12235ffd83dbSDimitry Andric ptrdiff_t index; 12245ffd83dbSDimitry Andric }; 12255ffd83dbSDimitry Andric 12265ffd83dbSDimitry Andric namespace detail { 12275ffd83dbSDimitry Andric /// The class represents the base of a range of indexed_accessor_iterators. It 12285ffd83dbSDimitry Andric /// provides support for many different range functionalities, e.g. 12295ffd83dbSDimitry Andric /// drop_front/slice/etc.. Derived range classes must implement the following 12305ffd83dbSDimitry Andric /// static methods: 12315ffd83dbSDimitry Andric /// * ReferenceT dereference_iterator(const BaseT &base, ptrdiff_t index) 12325ffd83dbSDimitry Andric /// - Dereference an iterator pointing to the base object at the given 12335ffd83dbSDimitry Andric /// index. 12345ffd83dbSDimitry Andric /// * BaseT offset_base(const BaseT &base, ptrdiff_t index) 12355ffd83dbSDimitry Andric /// - Return a new base that is offset from the provide base by 'index' 12365ffd83dbSDimitry Andric /// elements. 12375ffd83dbSDimitry Andric template <typename DerivedT, typename BaseT, typename T, 12385ffd83dbSDimitry Andric typename PointerT = T *, typename ReferenceT = T &> 12395ffd83dbSDimitry Andric class indexed_accessor_range_base { 12405ffd83dbSDimitry Andric public: 1241349cc55cSDimitry Andric using RangeBaseT = indexed_accessor_range_base; 12425ffd83dbSDimitry Andric 12435ffd83dbSDimitry Andric /// An iterator element of this range. 12445ffd83dbSDimitry Andric class iterator : public indexed_accessor_iterator<iterator, BaseT, T, 12455ffd83dbSDimitry Andric PointerT, ReferenceT> { 12465ffd83dbSDimitry Andric public: 12475ffd83dbSDimitry Andric // Index into this iterator, invoking a static method on the derived type. 12485ffd83dbSDimitry Andric ReferenceT operator*() const { 12495ffd83dbSDimitry Andric return DerivedT::dereference_iterator(this->getBase(), this->getIndex()); 12505ffd83dbSDimitry Andric } 12515ffd83dbSDimitry Andric 12525ffd83dbSDimitry Andric private: 12535ffd83dbSDimitry Andric iterator(BaseT owner, ptrdiff_t curIndex) 1254349cc55cSDimitry Andric : iterator::indexed_accessor_iterator(owner, curIndex) {} 12555ffd83dbSDimitry Andric 12565ffd83dbSDimitry Andric /// Allow access to the constructor. 12575ffd83dbSDimitry Andric friend indexed_accessor_range_base<DerivedT, BaseT, T, PointerT, 12585ffd83dbSDimitry Andric ReferenceT>; 12595ffd83dbSDimitry Andric }; 12605ffd83dbSDimitry Andric 12615ffd83dbSDimitry Andric indexed_accessor_range_base(iterator begin, iterator end) 12625ffd83dbSDimitry Andric : base(offset_base(begin.getBase(), begin.getIndex())), 12635ffd83dbSDimitry Andric count(end.getIndex() - begin.getIndex()) {} 12645ffd83dbSDimitry Andric indexed_accessor_range_base(const iterator_range<iterator> &range) 12655ffd83dbSDimitry Andric : indexed_accessor_range_base(range.begin(), range.end()) {} 12665ffd83dbSDimitry Andric indexed_accessor_range_base(BaseT base, ptrdiff_t count) 12675ffd83dbSDimitry Andric : base(base), count(count) {} 12685ffd83dbSDimitry Andric 12695ffd83dbSDimitry Andric iterator begin() const { return iterator(base, 0); } 12705ffd83dbSDimitry Andric iterator end() const { return iterator(base, count); } 1271fe6060f1SDimitry Andric ReferenceT operator[](size_t Index) const { 1272fe6060f1SDimitry Andric assert(Index < size() && "invalid index for value range"); 1273fe6060f1SDimitry Andric return DerivedT::dereference_iterator(base, static_cast<ptrdiff_t>(Index)); 12745ffd83dbSDimitry Andric } 12755ffd83dbSDimitry Andric ReferenceT front() const { 12765ffd83dbSDimitry Andric assert(!empty() && "expected non-empty range"); 12775ffd83dbSDimitry Andric return (*this)[0]; 12785ffd83dbSDimitry Andric } 12795ffd83dbSDimitry Andric ReferenceT back() const { 12805ffd83dbSDimitry Andric assert(!empty() && "expected non-empty range"); 12815ffd83dbSDimitry Andric return (*this)[size() - 1]; 12825ffd83dbSDimitry Andric } 12835ffd83dbSDimitry Andric 12845ffd83dbSDimitry Andric /// Return the size of this range. 12855ffd83dbSDimitry Andric size_t size() const { return count; } 12865ffd83dbSDimitry Andric 12875ffd83dbSDimitry Andric /// Return if the range is empty. 12885ffd83dbSDimitry Andric bool empty() const { return size() == 0; } 12895ffd83dbSDimitry Andric 12905ffd83dbSDimitry Andric /// Drop the first N elements, and keep M elements. 12915ffd83dbSDimitry Andric DerivedT slice(size_t n, size_t m) const { 12925ffd83dbSDimitry Andric assert(n + m <= size() && "invalid size specifiers"); 12935ffd83dbSDimitry Andric return DerivedT(offset_base(base, n), m); 12945ffd83dbSDimitry Andric } 12955ffd83dbSDimitry Andric 12965ffd83dbSDimitry Andric /// Drop the first n elements. 12975ffd83dbSDimitry Andric DerivedT drop_front(size_t n = 1) const { 12985ffd83dbSDimitry Andric assert(size() >= n && "Dropping more elements than exist"); 12995ffd83dbSDimitry Andric return slice(n, size() - n); 13005ffd83dbSDimitry Andric } 13015ffd83dbSDimitry Andric /// Drop the last n elements. 13025ffd83dbSDimitry Andric DerivedT drop_back(size_t n = 1) const { 13035ffd83dbSDimitry Andric assert(size() >= n && "Dropping more elements than exist"); 13045ffd83dbSDimitry Andric return DerivedT(base, size() - n); 13055ffd83dbSDimitry Andric } 13065ffd83dbSDimitry Andric 13075ffd83dbSDimitry Andric /// Take the first n elements. 13085ffd83dbSDimitry Andric DerivedT take_front(size_t n = 1) const { 13095ffd83dbSDimitry Andric return n < size() ? drop_back(size() - n) 13105ffd83dbSDimitry Andric : static_cast<const DerivedT &>(*this); 13115ffd83dbSDimitry Andric } 13125ffd83dbSDimitry Andric 13135ffd83dbSDimitry Andric /// Take the last n elements. 13145ffd83dbSDimitry Andric DerivedT take_back(size_t n = 1) const { 13155ffd83dbSDimitry Andric return n < size() ? drop_front(size() - n) 13165ffd83dbSDimitry Andric : static_cast<const DerivedT &>(*this); 13175ffd83dbSDimitry Andric } 13185ffd83dbSDimitry Andric 13195ffd83dbSDimitry Andric /// Allow conversion to any type accepting an iterator_range. 13205ffd83dbSDimitry Andric template <typename RangeT, typename = std::enable_if_t<std::is_constructible< 13215ffd83dbSDimitry Andric RangeT, iterator_range<iterator>>::value>> 13225ffd83dbSDimitry Andric operator RangeT() const { 13235ffd83dbSDimitry Andric return RangeT(iterator_range<iterator>(*this)); 13245ffd83dbSDimitry Andric } 13255ffd83dbSDimitry Andric 13265ffd83dbSDimitry Andric /// Returns the base of this range. 13275ffd83dbSDimitry Andric const BaseT &getBase() const { return base; } 13285ffd83dbSDimitry Andric 13295ffd83dbSDimitry Andric private: 13305ffd83dbSDimitry Andric /// Offset the given base by the given amount. 13315ffd83dbSDimitry Andric static BaseT offset_base(const BaseT &base, size_t n) { 13325ffd83dbSDimitry Andric return n == 0 ? base : DerivedT::offset_base(base, n); 13335ffd83dbSDimitry Andric } 13345ffd83dbSDimitry Andric 13355ffd83dbSDimitry Andric protected: 13365ffd83dbSDimitry Andric indexed_accessor_range_base(const indexed_accessor_range_base &) = default; 13375ffd83dbSDimitry Andric indexed_accessor_range_base(indexed_accessor_range_base &&) = default; 13385ffd83dbSDimitry Andric indexed_accessor_range_base & 13395ffd83dbSDimitry Andric operator=(const indexed_accessor_range_base &) = default; 13405ffd83dbSDimitry Andric 13415ffd83dbSDimitry Andric /// The base that owns the provided range of values. 13425ffd83dbSDimitry Andric BaseT base; 13435ffd83dbSDimitry Andric /// The size from the owning range. 13445ffd83dbSDimitry Andric ptrdiff_t count; 13455ffd83dbSDimitry Andric }; 1346297eecfbSDimitry Andric /// Compare this range with another. 1347297eecfbSDimitry Andric /// FIXME: Make me a member function instead of friend when it works in C++20. 1348297eecfbSDimitry Andric template <typename OtherT, typename DerivedT, typename BaseT, typename T, 1349297eecfbSDimitry Andric typename PointerT, typename ReferenceT> 1350297eecfbSDimitry Andric bool operator==(const indexed_accessor_range_base<DerivedT, BaseT, T, PointerT, 1351297eecfbSDimitry Andric ReferenceT> &lhs, 1352297eecfbSDimitry Andric const OtherT &rhs) { 1353297eecfbSDimitry Andric return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); 1354297eecfbSDimitry Andric } 1355297eecfbSDimitry Andric 1356297eecfbSDimitry Andric template <typename OtherT, typename DerivedT, typename BaseT, typename T, 1357297eecfbSDimitry Andric typename PointerT, typename ReferenceT> 1358297eecfbSDimitry Andric bool operator!=(const indexed_accessor_range_base<DerivedT, BaseT, T, PointerT, 1359297eecfbSDimitry Andric ReferenceT> &lhs, 1360297eecfbSDimitry Andric const OtherT &rhs) { 1361297eecfbSDimitry Andric return !(lhs == rhs); 1362297eecfbSDimitry Andric } 13635ffd83dbSDimitry Andric } // end namespace detail 13645ffd83dbSDimitry Andric 13655ffd83dbSDimitry Andric /// This class provides an implementation of a range of 13665ffd83dbSDimitry Andric /// indexed_accessor_iterators where the base is not indexable. Ranges with 13675ffd83dbSDimitry Andric /// bases that are offsetable should derive from indexed_accessor_range_base 13685ffd83dbSDimitry Andric /// instead. Derived range classes are expected to implement the following 13695ffd83dbSDimitry Andric /// static method: 13705ffd83dbSDimitry Andric /// * ReferenceT dereference(const BaseT &base, ptrdiff_t index) 13715ffd83dbSDimitry Andric /// - Dereference an iterator pointing to a parent base at the given index. 13725ffd83dbSDimitry Andric template <typename DerivedT, typename BaseT, typename T, 13735ffd83dbSDimitry Andric typename PointerT = T *, typename ReferenceT = T &> 13745ffd83dbSDimitry Andric class indexed_accessor_range 13755ffd83dbSDimitry Andric : public detail::indexed_accessor_range_base< 13765ffd83dbSDimitry Andric DerivedT, std::pair<BaseT, ptrdiff_t>, T, PointerT, ReferenceT> { 13775ffd83dbSDimitry Andric public: 13785ffd83dbSDimitry Andric indexed_accessor_range(BaseT base, ptrdiff_t startIndex, ptrdiff_t count) 13795ffd83dbSDimitry Andric : detail::indexed_accessor_range_base< 13805ffd83dbSDimitry Andric DerivedT, std::pair<BaseT, ptrdiff_t>, T, PointerT, ReferenceT>( 13815ffd83dbSDimitry Andric std::make_pair(base, startIndex), count) {} 13825ffd83dbSDimitry Andric using detail::indexed_accessor_range_base< 13835ffd83dbSDimitry Andric DerivedT, std::pair<BaseT, ptrdiff_t>, T, PointerT, 13845ffd83dbSDimitry Andric ReferenceT>::indexed_accessor_range_base; 13855ffd83dbSDimitry Andric 13865ffd83dbSDimitry Andric /// Returns the current base of the range. 13875ffd83dbSDimitry Andric const BaseT &getBase() const { return this->base.first; } 13885ffd83dbSDimitry Andric 13895ffd83dbSDimitry Andric /// Returns the current start index of the range. 13905ffd83dbSDimitry Andric ptrdiff_t getStartIndex() const { return this->base.second; } 13915ffd83dbSDimitry Andric 13925ffd83dbSDimitry Andric /// See `detail::indexed_accessor_range_base` for details. 13935ffd83dbSDimitry Andric static std::pair<BaseT, ptrdiff_t> 13945ffd83dbSDimitry Andric offset_base(const std::pair<BaseT, ptrdiff_t> &base, ptrdiff_t index) { 13955ffd83dbSDimitry Andric // We encode the internal base as a pair of the derived base and a start 13965ffd83dbSDimitry Andric // index into the derived base. 13975ffd83dbSDimitry Andric return std::make_pair(base.first, base.second + index); 13985ffd83dbSDimitry Andric } 13995ffd83dbSDimitry Andric /// See `detail::indexed_accessor_range_base` for details. 14005ffd83dbSDimitry Andric static ReferenceT 14015ffd83dbSDimitry Andric dereference_iterator(const std::pair<BaseT, ptrdiff_t> &base, 14025ffd83dbSDimitry Andric ptrdiff_t index) { 14035ffd83dbSDimitry Andric return DerivedT::dereference(base.first, base.second + index); 14045ffd83dbSDimitry Andric } 14055ffd83dbSDimitry Andric }; 14065ffd83dbSDimitry Andric 1407349cc55cSDimitry Andric namespace detail { 1408349cc55cSDimitry Andric /// Return a reference to the first or second member of a reference. Otherwise, 1409349cc55cSDimitry Andric /// return a copy of the member of a temporary. 1410349cc55cSDimitry Andric /// 1411349cc55cSDimitry Andric /// When passing a range whose iterators return values instead of references, 1412349cc55cSDimitry Andric /// the reference must be dropped from `decltype((elt.first))`, which will 1413349cc55cSDimitry Andric /// always be a reference, to avoid returning a reference to a temporary. 1414349cc55cSDimitry Andric template <typename EltTy, typename FirstTy> class first_or_second_type { 1415349cc55cSDimitry Andric public: 1416bdd1243dSDimitry Andric using type = std::conditional_t<std::is_reference<EltTy>::value, FirstTy, 1417349cc55cSDimitry Andric std::remove_reference_t<FirstTy>>; 1418349cc55cSDimitry Andric }; 1419349cc55cSDimitry Andric } // end namespace detail 1420349cc55cSDimitry Andric 1421e8d8bef9SDimitry Andric /// Given a container of pairs, return a range over the first elements. 1422e8d8bef9SDimitry Andric template <typename ContainerTy> auto make_first_range(ContainerTy &&c) { 1423349cc55cSDimitry Andric using EltTy = decltype((*std::begin(c))); 1424349cc55cSDimitry Andric return llvm::map_range(std::forward<ContainerTy>(c), 1425349cc55cSDimitry Andric [](EltTy elt) -> typename detail::first_or_second_type< 1426349cc55cSDimitry Andric EltTy, decltype((elt.first))>::type { 1427e8d8bef9SDimitry Andric return elt.first; 1428e8d8bef9SDimitry Andric }); 1429e8d8bef9SDimitry Andric } 1430e8d8bef9SDimitry Andric 14315ffd83dbSDimitry Andric /// Given a container of pairs, return a range over the second elements. 14325ffd83dbSDimitry Andric template <typename ContainerTy> auto make_second_range(ContainerTy &&c) { 1433349cc55cSDimitry Andric using EltTy = decltype((*std::begin(c))); 14345ffd83dbSDimitry Andric return llvm::map_range( 14355ffd83dbSDimitry Andric std::forward<ContainerTy>(c), 1436349cc55cSDimitry Andric [](EltTy elt) -> 1437349cc55cSDimitry Andric typename detail::first_or_second_type<EltTy, 1438349cc55cSDimitry Andric decltype((elt.second))>::type { 14395ffd83dbSDimitry Andric return elt.second; 14405ffd83dbSDimitry Andric }); 14415ffd83dbSDimitry Andric } 14425ffd83dbSDimitry Andric 14430b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14440b57cec5SDimitry Andric // Extra additions to <utility> 14450b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14460b57cec5SDimitry Andric 144706c3fb27SDimitry Andric /// Function object to check whether the first component of a container 144806c3fb27SDimitry Andric /// supported by std::get (like std::pair and std::tuple) compares less than the 144906c3fb27SDimitry Andric /// first component of another container. 14500b57cec5SDimitry Andric struct less_first { 14510b57cec5SDimitry Andric template <typename T> bool operator()(const T &lhs, const T &rhs) const { 145206c3fb27SDimitry Andric return std::less<>()(std::get<0>(lhs), std::get<0>(rhs)); 14530b57cec5SDimitry Andric } 14540b57cec5SDimitry Andric }; 14550b57cec5SDimitry Andric 145606c3fb27SDimitry Andric /// Function object to check whether the second component of a container 145706c3fb27SDimitry Andric /// supported by std::get (like std::pair and std::tuple) compares less than the 145806c3fb27SDimitry Andric /// second component of another container. 14590b57cec5SDimitry Andric struct less_second { 14600b57cec5SDimitry Andric template <typename T> bool operator()(const T &lhs, const T &rhs) const { 146106c3fb27SDimitry Andric return std::less<>()(std::get<1>(lhs), std::get<1>(rhs)); 14620b57cec5SDimitry Andric } 14630b57cec5SDimitry Andric }; 14640b57cec5SDimitry Andric 14650b57cec5SDimitry Andric /// \brief Function object to apply a binary function to the first component of 14660b57cec5SDimitry Andric /// a std::pair. 14670b57cec5SDimitry Andric template<typename FuncTy> 14680b57cec5SDimitry Andric struct on_first { 14690b57cec5SDimitry Andric FuncTy func; 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric template <typename T> 14725ffd83dbSDimitry Andric decltype(auto) operator()(const T &lhs, const T &rhs) const { 14730b57cec5SDimitry Andric return func(lhs.first, rhs.first); 14740b57cec5SDimitry Andric } 14750b57cec5SDimitry Andric }; 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric /// Utility type to build an inheritance chain that makes it easy to rank 14780b57cec5SDimitry Andric /// overload candidates. 14790b57cec5SDimitry Andric template <int N> struct rank : rank<N - 1> {}; 14800b57cec5SDimitry Andric template <> struct rank<0> {}; 14810b57cec5SDimitry Andric 1482fe6060f1SDimitry Andric namespace detail { 1483fe6060f1SDimitry Andric template <typename... Ts> struct Visitor; 1484fe6060f1SDimitry Andric 1485fe6060f1SDimitry Andric template <typename HeadT, typename... TailTs> 1486fe6060f1SDimitry Andric struct Visitor<HeadT, TailTs...> : remove_cvref_t<HeadT>, Visitor<TailTs...> { 1487fe6060f1SDimitry Andric explicit constexpr Visitor(HeadT &&Head, TailTs &&...Tail) 1488fe6060f1SDimitry Andric : remove_cvref_t<HeadT>(std::forward<HeadT>(Head)), 1489fe6060f1SDimitry Andric Visitor<TailTs...>(std::forward<TailTs>(Tail)...) {} 1490fe6060f1SDimitry Andric using remove_cvref_t<HeadT>::operator(); 1491fe6060f1SDimitry Andric using Visitor<TailTs...>::operator(); 14920b57cec5SDimitry Andric }; 14930b57cec5SDimitry Andric 1494fe6060f1SDimitry Andric template <typename HeadT> struct Visitor<HeadT> : remove_cvref_t<HeadT> { 1495fe6060f1SDimitry Andric explicit constexpr Visitor(HeadT &&Head) 1496fe6060f1SDimitry Andric : remove_cvref_t<HeadT>(std::forward<HeadT>(Head)) {} 1497fe6060f1SDimitry Andric using remove_cvref_t<HeadT>::operator(); 14980b57cec5SDimitry Andric }; 1499fe6060f1SDimitry Andric } // namespace detail 1500fe6060f1SDimitry Andric 1501fe6060f1SDimitry Andric /// Returns an opaquely-typed Callable object whose operator() overload set is 1502fe6060f1SDimitry Andric /// the sum of the operator() overload sets of each CallableT in CallableTs. 1503fe6060f1SDimitry Andric /// 1504fe6060f1SDimitry Andric /// The type of the returned object derives from each CallableT in CallableTs. 1505fe6060f1SDimitry Andric /// The returned object is constructed by invoking the appropriate copy or move 1506fe6060f1SDimitry Andric /// constructor of each CallableT, as selected by overload resolution on the 1507fe6060f1SDimitry Andric /// corresponding argument to makeVisitor. 1508fe6060f1SDimitry Andric /// 1509fe6060f1SDimitry Andric /// Example: 1510fe6060f1SDimitry Andric /// 1511fe6060f1SDimitry Andric /// \code 1512fe6060f1SDimitry Andric /// auto visitor = makeVisitor([](auto) { return "unhandled type"; }, 1513fe6060f1SDimitry Andric /// [](int i) { return "int"; }, 1514fe6060f1SDimitry Andric /// [](std::string s) { return "str"; }); 1515fe6060f1SDimitry Andric /// auto a = visitor(42); // `a` is now "int". 1516fe6060f1SDimitry Andric /// auto b = visitor("foo"); // `b` is now "str". 1517fe6060f1SDimitry Andric /// auto c = visitor(3.14f); // `c` is now "unhandled type". 1518fe6060f1SDimitry Andric /// \endcode 1519fe6060f1SDimitry Andric /// 1520fe6060f1SDimitry Andric /// Example of making a visitor with a lambda which captures a move-only type: 1521fe6060f1SDimitry Andric /// 1522fe6060f1SDimitry Andric /// \code 1523fe6060f1SDimitry Andric /// std::unique_ptr<FooHandler> FH = /* ... */; 1524fe6060f1SDimitry Andric /// auto visitor = makeVisitor( 1525fe6060f1SDimitry Andric /// [FH{std::move(FH)}](Foo F) { return FH->handle(F); }, 1526fe6060f1SDimitry Andric /// [](int i) { return i; }, 1527fe6060f1SDimitry Andric /// [](std::string s) { return atoi(s); }); 1528fe6060f1SDimitry Andric /// \endcode 1529fe6060f1SDimitry Andric template <typename... CallableTs> 1530fe6060f1SDimitry Andric constexpr decltype(auto) makeVisitor(CallableTs &&...Callables) { 1531fe6060f1SDimitry Andric return detail::Visitor<CallableTs...>(std::forward<CallableTs>(Callables)...); 1532fe6060f1SDimitry Andric } 15330b57cec5SDimitry Andric 15340b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 15351fd87a68SDimitry Andric // Extra additions to <algorithm> 15360b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 15370b57cec5SDimitry Andric 15385ffd83dbSDimitry Andric // We have a copy here so that LLVM behaves the same when using different 15395ffd83dbSDimitry Andric // standard libraries. 15405ffd83dbSDimitry Andric template <class Iterator, class RNG> 15415ffd83dbSDimitry Andric void shuffle(Iterator first, Iterator last, RNG &&g) { 15425ffd83dbSDimitry Andric // It would be better to use a std::uniform_int_distribution, 15435ffd83dbSDimitry Andric // but that would be stdlib dependent. 1544fe6060f1SDimitry Andric typedef 1545fe6060f1SDimitry Andric typename std::iterator_traits<Iterator>::difference_type difference_type; 1546fe6060f1SDimitry Andric for (auto size = last - first; size > 1; ++first, (void)--size) { 1547fe6060f1SDimitry Andric difference_type offset = g() % size; 1548fe6060f1SDimitry Andric // Avoid self-assignment due to incorrect assertions in libstdc++ 1549fe6060f1SDimitry Andric // containers (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85828). 1550fe6060f1SDimitry Andric if (offset != difference_type(0)) 1551fe6060f1SDimitry Andric std::iter_swap(first, first + offset); 1552fe6060f1SDimitry Andric } 15535ffd83dbSDimitry Andric } 15545ffd83dbSDimitry Andric 15550b57cec5SDimitry Andric /// Adapt std::less<T> for array_pod_sort. 15560b57cec5SDimitry Andric template<typename T> 15570b57cec5SDimitry Andric inline int array_pod_sort_comparator(const void *P1, const void *P2) { 15580b57cec5SDimitry Andric if (std::less<T>()(*reinterpret_cast<const T*>(P1), 15590b57cec5SDimitry Andric *reinterpret_cast<const T*>(P2))) 15600b57cec5SDimitry Andric return -1; 15610b57cec5SDimitry Andric if (std::less<T>()(*reinterpret_cast<const T*>(P2), 15620b57cec5SDimitry Andric *reinterpret_cast<const T*>(P1))) 15630b57cec5SDimitry Andric return 1; 15640b57cec5SDimitry Andric return 0; 15650b57cec5SDimitry Andric } 15660b57cec5SDimitry Andric 15670b57cec5SDimitry Andric /// get_array_pod_sort_comparator - This is an internal helper function used to 15680b57cec5SDimitry Andric /// get type deduction of T right. 15690b57cec5SDimitry Andric template<typename T> 15700b57cec5SDimitry Andric inline int (*get_array_pod_sort_comparator(const T &)) 15710b57cec5SDimitry Andric (const void*, const void*) { 15720b57cec5SDimitry Andric return array_pod_sort_comparator<T>; 15730b57cec5SDimitry Andric } 15740b57cec5SDimitry Andric 1575480093f4SDimitry Andric #ifdef EXPENSIVE_CHECKS 1576480093f4SDimitry Andric namespace detail { 1577480093f4SDimitry Andric 1578480093f4SDimitry Andric inline unsigned presortShuffleEntropy() { 1579480093f4SDimitry Andric static unsigned Result(std::random_device{}()); 1580480093f4SDimitry Andric return Result; 1581480093f4SDimitry Andric } 1582480093f4SDimitry Andric 1583480093f4SDimitry Andric template <class IteratorTy> 1584480093f4SDimitry Andric inline void presortShuffle(IteratorTy Start, IteratorTy End) { 1585480093f4SDimitry Andric std::mt19937 Generator(presortShuffleEntropy()); 1586fe6060f1SDimitry Andric llvm::shuffle(Start, End, Generator); 1587480093f4SDimitry Andric } 1588480093f4SDimitry Andric 1589480093f4SDimitry Andric } // end namespace detail 1590480093f4SDimitry Andric #endif 1591480093f4SDimitry Andric 15920b57cec5SDimitry Andric /// array_pod_sort - This sorts an array with the specified start and end 15930b57cec5SDimitry Andric /// extent. This is just like std::sort, except that it calls qsort instead of 15940b57cec5SDimitry Andric /// using an inlined template. qsort is slightly slower than std::sort, but 15950b57cec5SDimitry Andric /// most sorts are not performance critical in LLVM and std::sort has to be 15960b57cec5SDimitry Andric /// template instantiated for each type, leading to significant measured code 15970b57cec5SDimitry Andric /// bloat. This function should generally be used instead of std::sort where 15980b57cec5SDimitry Andric /// possible. 15990b57cec5SDimitry Andric /// 16000b57cec5SDimitry Andric /// This function assumes that you have simple POD-like types that can be 16010b57cec5SDimitry Andric /// compared with std::less and can be moved with memcpy. If this isn't true, 16020b57cec5SDimitry Andric /// you should use std::sort. 16030b57cec5SDimitry Andric /// 16040b57cec5SDimitry Andric /// NOTE: If qsort_r were portable, we could allow a custom comparator and 16050b57cec5SDimitry Andric /// default to std::less. 16060b57cec5SDimitry Andric template<class IteratorTy> 16070b57cec5SDimitry Andric inline void array_pod_sort(IteratorTy Start, IteratorTy End) { 16080b57cec5SDimitry Andric // Don't inefficiently call qsort with one element or trigger undefined 16090b57cec5SDimitry Andric // behavior with an empty sequence. 16100b57cec5SDimitry Andric auto NElts = End - Start; 16110b57cec5SDimitry Andric if (NElts <= 1) return; 16120b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 1613480093f4SDimitry Andric detail::presortShuffle<IteratorTy>(Start, End); 16140b57cec5SDimitry Andric #endif 16150b57cec5SDimitry Andric qsort(&*Start, NElts, sizeof(*Start), get_array_pod_sort_comparator(*Start)); 16160b57cec5SDimitry Andric } 16170b57cec5SDimitry Andric 16180b57cec5SDimitry Andric template <class IteratorTy> 16190b57cec5SDimitry Andric inline void array_pod_sort( 16200b57cec5SDimitry Andric IteratorTy Start, IteratorTy End, 16210b57cec5SDimitry Andric int (*Compare)( 16220b57cec5SDimitry Andric const typename std::iterator_traits<IteratorTy>::value_type *, 16230b57cec5SDimitry Andric const typename std::iterator_traits<IteratorTy>::value_type *)) { 16240b57cec5SDimitry Andric // Don't inefficiently call qsort with one element or trigger undefined 16250b57cec5SDimitry Andric // behavior with an empty sequence. 16260b57cec5SDimitry Andric auto NElts = End - Start; 16270b57cec5SDimitry Andric if (NElts <= 1) return; 16280b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 1629480093f4SDimitry Andric detail::presortShuffle<IteratorTy>(Start, End); 16300b57cec5SDimitry Andric #endif 16310b57cec5SDimitry Andric qsort(&*Start, NElts, sizeof(*Start), 16320b57cec5SDimitry Andric reinterpret_cast<int (*)(const void *, const void *)>(Compare)); 16330b57cec5SDimitry Andric } 16340b57cec5SDimitry Andric 16355ffd83dbSDimitry Andric namespace detail { 16365ffd83dbSDimitry Andric template <typename T> 16375ffd83dbSDimitry Andric // We can use qsort if the iterator type is a pointer and the underlying value 16385ffd83dbSDimitry Andric // is trivially copyable. 1639bdd1243dSDimitry Andric using sort_trivially_copyable = std::conjunction< 16405ffd83dbSDimitry Andric std::is_pointer<T>, 1641e8d8bef9SDimitry Andric std::is_trivially_copyable<typename std::iterator_traits<T>::value_type>>; 16425ffd83dbSDimitry Andric } // namespace detail 16435ffd83dbSDimitry Andric 16440b57cec5SDimitry Andric // Provide wrappers to std::sort which shuffle the elements before sorting 16450b57cec5SDimitry Andric // to help uncover non-deterministic behavior (PR35135). 1646bdd1243dSDimitry Andric template <typename IteratorTy> 16470b57cec5SDimitry Andric inline void sort(IteratorTy Start, IteratorTy End) { 1648bdd1243dSDimitry Andric if constexpr (detail::sort_trivially_copyable<IteratorTy>::value) { 1649bdd1243dSDimitry Andric // Forward trivially copyable types to array_pod_sort. This avoids a large 1650bdd1243dSDimitry Andric // amount of code bloat for a minor performance hit. 1651bdd1243dSDimitry Andric array_pod_sort(Start, End); 1652bdd1243dSDimitry Andric } else { 16530b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 1654480093f4SDimitry Andric detail::presortShuffle<IteratorTy>(Start, End); 16550b57cec5SDimitry Andric #endif 16560b57cec5SDimitry Andric std::sort(Start, End); 16570b57cec5SDimitry Andric } 16585ffd83dbSDimitry Andric } 16595ffd83dbSDimitry Andric 16600b57cec5SDimitry Andric template <typename Container> inline void sort(Container &&C) { 16610b57cec5SDimitry Andric llvm::sort(adl_begin(C), adl_end(C)); 16620b57cec5SDimitry Andric } 16630b57cec5SDimitry Andric 16640b57cec5SDimitry Andric template <typename IteratorTy, typename Compare> 16650b57cec5SDimitry Andric inline void sort(IteratorTy Start, IteratorTy End, Compare Comp) { 16660b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 1667480093f4SDimitry Andric detail::presortShuffle<IteratorTy>(Start, End); 16680b57cec5SDimitry Andric #endif 16690b57cec5SDimitry Andric std::sort(Start, End, Comp); 16700b57cec5SDimitry Andric } 16710b57cec5SDimitry Andric 16720b57cec5SDimitry Andric template <typename Container, typename Compare> 16730b57cec5SDimitry Andric inline void sort(Container &&C, Compare Comp) { 16740b57cec5SDimitry Andric llvm::sort(adl_begin(C), adl_end(C), Comp); 16750b57cec5SDimitry Andric } 16760b57cec5SDimitry Andric 16770b57cec5SDimitry Andric /// Get the size of a range. This is a wrapper function around std::distance 16780b57cec5SDimitry Andric /// which is only enabled when the operation is O(1). 16790b57cec5SDimitry Andric template <typename R> 16805ffd83dbSDimitry Andric auto size(R &&Range, 1681e8d8bef9SDimitry Andric std::enable_if_t< 1682e8d8bef9SDimitry Andric std::is_base_of<std::random_access_iterator_tag, 1683e8d8bef9SDimitry Andric typename std::iterator_traits<decltype( 1684e8d8bef9SDimitry Andric Range.begin())>::iterator_category>::value, 16855ffd83dbSDimitry Andric void> * = nullptr) { 16860b57cec5SDimitry Andric return std::distance(Range.begin(), Range.end()); 16870b57cec5SDimitry Andric } 16880b57cec5SDimitry Andric 168906c3fb27SDimitry Andric namespace detail { 169006c3fb27SDimitry Andric template <typename Range> 169106c3fb27SDimitry Andric using check_has_free_function_size = 169206c3fb27SDimitry Andric decltype(adl_size(std::declval<Range &>())); 169306c3fb27SDimitry Andric 169406c3fb27SDimitry Andric template <typename Range> 169506c3fb27SDimitry Andric static constexpr bool HasFreeFunctionSize = 169606c3fb27SDimitry Andric is_detected<check_has_free_function_size, Range>::value; 169706c3fb27SDimitry Andric } // namespace detail 169806c3fb27SDimitry Andric 169906c3fb27SDimitry Andric /// Returns the size of the \p Range, i.e., the number of elements. This 170006c3fb27SDimitry Andric /// implementation takes inspiration from `std::ranges::size` from C++20 and 170106c3fb27SDimitry Andric /// delegates the size check to `adl_size` or `std::distance`, in this order of 170206c3fb27SDimitry Andric /// preference. Unlike `llvm::size`, this function does *not* guarantee O(1) 170306c3fb27SDimitry Andric /// running time, and is intended to be used in generic code that does not know 170406c3fb27SDimitry Andric /// the exact range type. 170506c3fb27SDimitry Andric template <typename R> constexpr size_t range_size(R &&Range) { 170606c3fb27SDimitry Andric if constexpr (detail::HasFreeFunctionSize<R>) 170706c3fb27SDimitry Andric return adl_size(Range); 170806c3fb27SDimitry Andric else 170906c3fb27SDimitry Andric return static_cast<size_t>(std::distance(adl_begin(Range), adl_end(Range))); 171006c3fb27SDimitry Andric } 171106c3fb27SDimitry Andric 17120b57cec5SDimitry Andric /// Provide wrappers to std::for_each which take ranges instead of having to 17130b57cec5SDimitry Andric /// pass begin/end explicitly. 1714e8d8bef9SDimitry Andric template <typename R, typename UnaryFunction> 1715e8d8bef9SDimitry Andric UnaryFunction for_each(R &&Range, UnaryFunction F) { 1716e8d8bef9SDimitry Andric return std::for_each(adl_begin(Range), adl_end(Range), F); 17170b57cec5SDimitry Andric } 17180b57cec5SDimitry Andric 17190b57cec5SDimitry Andric /// Provide wrappers to std::all_of which take ranges instead of having to pass 17200b57cec5SDimitry Andric /// begin/end explicitly. 17210b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17220b57cec5SDimitry Andric bool all_of(R &&Range, UnaryPredicate P) { 17230b57cec5SDimitry Andric return std::all_of(adl_begin(Range), adl_end(Range), P); 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric /// Provide wrappers to std::any_of which take ranges instead of having to pass 17270b57cec5SDimitry Andric /// begin/end explicitly. 17280b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17290b57cec5SDimitry Andric bool any_of(R &&Range, UnaryPredicate P) { 17300b57cec5SDimitry Andric return std::any_of(adl_begin(Range), adl_end(Range), P); 17310b57cec5SDimitry Andric } 17320b57cec5SDimitry Andric 17330b57cec5SDimitry Andric /// Provide wrappers to std::none_of which take ranges instead of having to pass 17340b57cec5SDimitry Andric /// begin/end explicitly. 17350b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17360b57cec5SDimitry Andric bool none_of(R &&Range, UnaryPredicate P) { 17370b57cec5SDimitry Andric return std::none_of(adl_begin(Range), adl_end(Range), P); 17380b57cec5SDimitry Andric } 17390b57cec5SDimitry Andric 17400b57cec5SDimitry Andric /// Provide wrappers to std::find which take ranges instead of having to pass 17410b57cec5SDimitry Andric /// begin/end explicitly. 17425ffd83dbSDimitry Andric template <typename R, typename T> auto find(R &&Range, const T &Val) { 17430b57cec5SDimitry Andric return std::find(adl_begin(Range), adl_end(Range), Val); 17440b57cec5SDimitry Andric } 17450b57cec5SDimitry Andric 17460b57cec5SDimitry Andric /// Provide wrappers to std::find_if which take ranges instead of having to pass 17470b57cec5SDimitry Andric /// begin/end explicitly. 17480b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17495ffd83dbSDimitry Andric auto find_if(R &&Range, UnaryPredicate P) { 17500b57cec5SDimitry Andric return std::find_if(adl_begin(Range), adl_end(Range), P); 17510b57cec5SDimitry Andric } 17520b57cec5SDimitry Andric 17530b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17545ffd83dbSDimitry Andric auto find_if_not(R &&Range, UnaryPredicate P) { 17550b57cec5SDimitry Andric return std::find_if_not(adl_begin(Range), adl_end(Range), P); 17560b57cec5SDimitry Andric } 17570b57cec5SDimitry Andric 17580b57cec5SDimitry Andric /// Provide wrappers to std::remove_if which take ranges instead of having to 17590b57cec5SDimitry Andric /// pass begin/end explicitly. 17600b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 17615ffd83dbSDimitry Andric auto remove_if(R &&Range, UnaryPredicate P) { 17620b57cec5SDimitry Andric return std::remove_if(adl_begin(Range), adl_end(Range), P); 17630b57cec5SDimitry Andric } 17640b57cec5SDimitry Andric 17650b57cec5SDimitry Andric /// Provide wrappers to std::copy_if which take ranges instead of having to 17660b57cec5SDimitry Andric /// pass begin/end explicitly. 17670b57cec5SDimitry Andric template <typename R, typename OutputIt, typename UnaryPredicate> 17680b57cec5SDimitry Andric OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) { 17690b57cec5SDimitry Andric return std::copy_if(adl_begin(Range), adl_end(Range), Out, P); 17700b57cec5SDimitry Andric } 17710b57cec5SDimitry Andric 1772bdd1243dSDimitry Andric /// Return the single value in \p Range that satisfies 1773bdd1243dSDimitry Andric /// \p P(<member of \p Range> *, AllowRepeats)->T * returning nullptr 1774bdd1243dSDimitry Andric /// when no values or multiple values were found. 1775bdd1243dSDimitry Andric /// When \p AllowRepeats is true, multiple values that compare equal 1776bdd1243dSDimitry Andric /// are allowed. 1777bdd1243dSDimitry Andric template <typename T, typename R, typename Predicate> 1778bdd1243dSDimitry Andric T *find_singleton(R &&Range, Predicate P, bool AllowRepeats = false) { 1779bdd1243dSDimitry Andric T *RC = nullptr; 17805f757f3fSDimitry Andric for (auto &&A : Range) { 1781bdd1243dSDimitry Andric if (T *PRC = P(A, AllowRepeats)) { 1782bdd1243dSDimitry Andric if (RC) { 1783bdd1243dSDimitry Andric if (!AllowRepeats || PRC != RC) 1784bdd1243dSDimitry Andric return nullptr; 1785bdd1243dSDimitry Andric } else 1786bdd1243dSDimitry Andric RC = PRC; 1787bdd1243dSDimitry Andric } 1788bdd1243dSDimitry Andric } 1789bdd1243dSDimitry Andric return RC; 1790bdd1243dSDimitry Andric } 1791bdd1243dSDimitry Andric 1792bdd1243dSDimitry Andric /// Return a pair consisting of the single value in \p Range that satisfies 1793bdd1243dSDimitry Andric /// \p P(<member of \p Range> *, AllowRepeats)->std::pair<T*, bool> returning 1794bdd1243dSDimitry Andric /// nullptr when no values or multiple values were found, and a bool indicating 1795bdd1243dSDimitry Andric /// whether multiple values were found to cause the nullptr. 1796bdd1243dSDimitry Andric /// When \p AllowRepeats is true, multiple values that compare equal are 1797bdd1243dSDimitry Andric /// allowed. The predicate \p P returns a pair<T *, bool> where T is the 1798bdd1243dSDimitry Andric /// singleton while the bool indicates whether multiples have already been 1799bdd1243dSDimitry Andric /// found. It is expected that first will be nullptr when second is true. 1800bdd1243dSDimitry Andric /// This allows using find_singleton_nested within the predicate \P. 1801bdd1243dSDimitry Andric template <typename T, typename R, typename Predicate> 1802bdd1243dSDimitry Andric std::pair<T *, bool> find_singleton_nested(R &&Range, Predicate P, 1803bdd1243dSDimitry Andric bool AllowRepeats = false) { 1804bdd1243dSDimitry Andric T *RC = nullptr; 1805bdd1243dSDimitry Andric for (auto *A : Range) { 1806bdd1243dSDimitry Andric std::pair<T *, bool> PRC = P(A, AllowRepeats); 1807bdd1243dSDimitry Andric if (PRC.second) { 1808bdd1243dSDimitry Andric assert(PRC.first == nullptr && 1809bdd1243dSDimitry Andric "Inconsistent return values in find_singleton_nested."); 1810bdd1243dSDimitry Andric return PRC; 1811bdd1243dSDimitry Andric } 1812bdd1243dSDimitry Andric if (PRC.first) { 1813bdd1243dSDimitry Andric if (RC) { 1814bdd1243dSDimitry Andric if (!AllowRepeats || PRC.first != RC) 1815bdd1243dSDimitry Andric return {nullptr, true}; 1816bdd1243dSDimitry Andric } else 1817bdd1243dSDimitry Andric RC = PRC.first; 1818bdd1243dSDimitry Andric } 1819bdd1243dSDimitry Andric } 1820bdd1243dSDimitry Andric return {RC, false}; 1821bdd1243dSDimitry Andric } 1822bdd1243dSDimitry Andric 18230b57cec5SDimitry Andric template <typename R, typename OutputIt> 18240b57cec5SDimitry Andric OutputIt copy(R &&Range, OutputIt Out) { 18250b57cec5SDimitry Andric return std::copy(adl_begin(Range), adl_end(Range), Out); 18260b57cec5SDimitry Andric } 18270b57cec5SDimitry Andric 1828bdd1243dSDimitry Andric /// Provide wrappers to std::replace_copy_if which take ranges instead of having 1829bdd1243dSDimitry Andric /// to pass begin/end explicitly. 1830bdd1243dSDimitry Andric template <typename R, typename OutputIt, typename UnaryPredicate, typename T> 1831bdd1243dSDimitry Andric OutputIt replace_copy_if(R &&Range, OutputIt Out, UnaryPredicate P, 1832bdd1243dSDimitry Andric const T &NewValue) { 1833bdd1243dSDimitry Andric return std::replace_copy_if(adl_begin(Range), adl_end(Range), Out, P, 1834bdd1243dSDimitry Andric NewValue); 1835bdd1243dSDimitry Andric } 1836bdd1243dSDimitry Andric 1837bdd1243dSDimitry Andric /// Provide wrappers to std::replace_copy which take ranges instead of having to 1838bdd1243dSDimitry Andric /// pass begin/end explicitly. 1839bdd1243dSDimitry Andric template <typename R, typename OutputIt, typename T> 1840bdd1243dSDimitry Andric OutputIt replace_copy(R &&Range, OutputIt Out, const T &OldValue, 1841bdd1243dSDimitry Andric const T &NewValue) { 1842bdd1243dSDimitry Andric return std::replace_copy(adl_begin(Range), adl_end(Range), Out, OldValue, 1843bdd1243dSDimitry Andric NewValue); 1844bdd1243dSDimitry Andric } 1845bdd1243dSDimitry Andric 1846e8d8bef9SDimitry Andric /// Provide wrappers to std::move which take ranges instead of having to 1847e8d8bef9SDimitry Andric /// pass begin/end explicitly. 1848e8d8bef9SDimitry Andric template <typename R, typename OutputIt> 1849e8d8bef9SDimitry Andric OutputIt move(R &&Range, OutputIt Out) { 1850e8d8bef9SDimitry Andric return std::move(adl_begin(Range), adl_end(Range), Out); 1851e8d8bef9SDimitry Andric } 1852e8d8bef9SDimitry Andric 185306c3fb27SDimitry Andric namespace detail { 185406c3fb27SDimitry Andric template <typename Range, typename Element> 185506c3fb27SDimitry Andric using check_has_member_contains_t = 185606c3fb27SDimitry Andric decltype(std::declval<Range &>().contains(std::declval<const Element &>())); 185706c3fb27SDimitry Andric 185806c3fb27SDimitry Andric template <typename Range, typename Element> 185906c3fb27SDimitry Andric static constexpr bool HasMemberContains = 186006c3fb27SDimitry Andric is_detected<check_has_member_contains_t, Range, Element>::value; 186106c3fb27SDimitry Andric 186206c3fb27SDimitry Andric template <typename Range, typename Element> 186306c3fb27SDimitry Andric using check_has_member_find_t = 186406c3fb27SDimitry Andric decltype(std::declval<Range &>().find(std::declval<const Element &>()) != 186506c3fb27SDimitry Andric std::declval<Range &>().end()); 186606c3fb27SDimitry Andric 186706c3fb27SDimitry Andric template <typename Range, typename Element> 186806c3fb27SDimitry Andric static constexpr bool HasMemberFind = 186906c3fb27SDimitry Andric is_detected<check_has_member_find_t, Range, Element>::value; 187006c3fb27SDimitry Andric 187106c3fb27SDimitry Andric } // namespace detail 187206c3fb27SDimitry Andric 187306c3fb27SDimitry Andric /// Returns true if \p Element is found in \p Range. Delegates the check to 187406c3fb27SDimitry Andric /// either `.contains(Element)`, `.find(Element)`, or `std::find`, in this 187506c3fb27SDimitry Andric /// order of preference. This is intended as the canonical way to check if an 187606c3fb27SDimitry Andric /// element exists in a range in generic code or range type that does not 187706c3fb27SDimitry Andric /// expose a `.contains(Element)` member. 18780b57cec5SDimitry Andric template <typename R, typename E> 18790b57cec5SDimitry Andric bool is_contained(R &&Range, const E &Element) { 188006c3fb27SDimitry Andric if constexpr (detail::HasMemberContains<R, E>) 188106c3fb27SDimitry Andric return Range.contains(Element); 188206c3fb27SDimitry Andric else if constexpr (detail::HasMemberFind<R, E>) 188306c3fb27SDimitry Andric return Range.find(Element) != Range.end(); 188406c3fb27SDimitry Andric else 188506c3fb27SDimitry Andric return std::find(adl_begin(Range), adl_end(Range), Element) != 188606c3fb27SDimitry Andric adl_end(Range); 18870b57cec5SDimitry Andric } 18880b57cec5SDimitry Andric 188906c3fb27SDimitry Andric /// Returns true iff \p Element exists in \p Set. This overload takes \p Set as 189006c3fb27SDimitry Andric /// an initializer list and is `constexpr`-friendly. 189106c3fb27SDimitry Andric template <typename T, typename E> 189206c3fb27SDimitry Andric constexpr bool is_contained(std::initializer_list<T> Set, const E &Element) { 189381ad6265SDimitry Andric // TODO: Use std::find when we switch to C++20. 189406c3fb27SDimitry Andric for (const T &V : Set) 189506c3fb27SDimitry Andric if (V == Element) 189681ad6265SDimitry Andric return true; 189781ad6265SDimitry Andric return false; 189881ad6265SDimitry Andric } 189981ad6265SDimitry Andric 19005ffd83dbSDimitry Andric /// Wrapper function around std::is_sorted to check if elements in a range \p R 19015ffd83dbSDimitry Andric /// are sorted with respect to a comparator \p C. 19025ffd83dbSDimitry Andric template <typename R, typename Compare> bool is_sorted(R &&Range, Compare C) { 19035ffd83dbSDimitry Andric return std::is_sorted(adl_begin(Range), adl_end(Range), C); 19045ffd83dbSDimitry Andric } 19055ffd83dbSDimitry Andric 19065ffd83dbSDimitry Andric /// Wrapper function around std::is_sorted to check if elements in a range \p R 19075ffd83dbSDimitry Andric /// are sorted in non-descending order. 19085ffd83dbSDimitry Andric template <typename R> bool is_sorted(R &&Range) { 19095ffd83dbSDimitry Andric return std::is_sorted(adl_begin(Range), adl_end(Range)); 19105ffd83dbSDimitry Andric } 19115ffd83dbSDimitry Andric 19120b57cec5SDimitry Andric /// Wrapper function around std::count to count the number of times an element 19130b57cec5SDimitry Andric /// \p Element occurs in the given range \p Range. 19145ffd83dbSDimitry Andric template <typename R, typename E> auto count(R &&Range, const E &Element) { 19150b57cec5SDimitry Andric return std::count(adl_begin(Range), adl_end(Range), Element); 19160b57cec5SDimitry Andric } 19170b57cec5SDimitry Andric 19180b57cec5SDimitry Andric /// Wrapper function around std::count_if to count the number of times an 19190b57cec5SDimitry Andric /// element satisfying a given predicate occurs in a range. 19200b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 19215ffd83dbSDimitry Andric auto count_if(R &&Range, UnaryPredicate P) { 19220b57cec5SDimitry Andric return std::count_if(adl_begin(Range), adl_end(Range), P); 19230b57cec5SDimitry Andric } 19240b57cec5SDimitry Andric 19250b57cec5SDimitry Andric /// Wrapper function around std::transform to apply a function to a range and 19260b57cec5SDimitry Andric /// store the result elsewhere. 1927e8d8bef9SDimitry Andric template <typename R, typename OutputIt, typename UnaryFunction> 1928e8d8bef9SDimitry Andric OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F) { 1929e8d8bef9SDimitry Andric return std::transform(adl_begin(Range), adl_end(Range), d_first, F); 19300b57cec5SDimitry Andric } 19310b57cec5SDimitry Andric 19320b57cec5SDimitry Andric /// Provide wrappers to std::partition which take ranges instead of having to 19330b57cec5SDimitry Andric /// pass begin/end explicitly. 19340b57cec5SDimitry Andric template <typename R, typename UnaryPredicate> 19355ffd83dbSDimitry Andric auto partition(R &&Range, UnaryPredicate P) { 19360b57cec5SDimitry Andric return std::partition(adl_begin(Range), adl_end(Range), P); 19370b57cec5SDimitry Andric } 19380b57cec5SDimitry Andric 19390fca6ea1SDimitry Andric /// Provide wrappers to std::binary_search which take ranges instead of having 19400fca6ea1SDimitry Andric /// to pass begin/end explicitly. 19410fca6ea1SDimitry Andric template <typename R, typename T> auto binary_search(R &&Range, T &&Value) { 19420fca6ea1SDimitry Andric return std::binary_search(adl_begin(Range), adl_end(Range), 19430fca6ea1SDimitry Andric std::forward<T>(Value)); 19440fca6ea1SDimitry Andric } 19450fca6ea1SDimitry Andric 19460fca6ea1SDimitry Andric template <typename R, typename T, typename Compare> 19470fca6ea1SDimitry Andric auto binary_search(R &&Range, T &&Value, Compare C) { 19480fca6ea1SDimitry Andric return std::binary_search(adl_begin(Range), adl_end(Range), 19490fca6ea1SDimitry Andric std::forward<T>(Value), C); 19500fca6ea1SDimitry Andric } 19510fca6ea1SDimitry Andric 19520b57cec5SDimitry Andric /// Provide wrappers to std::lower_bound which take ranges instead of having to 19530b57cec5SDimitry Andric /// pass begin/end explicitly. 19545ffd83dbSDimitry Andric template <typename R, typename T> auto lower_bound(R &&Range, T &&Value) { 19550b57cec5SDimitry Andric return std::lower_bound(adl_begin(Range), adl_end(Range), 19560b57cec5SDimitry Andric std::forward<T>(Value)); 19570b57cec5SDimitry Andric } 19580b57cec5SDimitry Andric 19590b57cec5SDimitry Andric template <typename R, typename T, typename Compare> 19605ffd83dbSDimitry Andric auto lower_bound(R &&Range, T &&Value, Compare C) { 19610b57cec5SDimitry Andric return std::lower_bound(adl_begin(Range), adl_end(Range), 19620b57cec5SDimitry Andric std::forward<T>(Value), C); 19630b57cec5SDimitry Andric } 19640b57cec5SDimitry Andric 19650b57cec5SDimitry Andric /// Provide wrappers to std::upper_bound which take ranges instead of having to 19660b57cec5SDimitry Andric /// pass begin/end explicitly. 19675ffd83dbSDimitry Andric template <typename R, typename T> auto upper_bound(R &&Range, T &&Value) { 19680b57cec5SDimitry Andric return std::upper_bound(adl_begin(Range), adl_end(Range), 19690b57cec5SDimitry Andric std::forward<T>(Value)); 19700b57cec5SDimitry Andric } 19710b57cec5SDimitry Andric 19720b57cec5SDimitry Andric template <typename R, typename T, typename Compare> 19735ffd83dbSDimitry Andric auto upper_bound(R &&Range, T &&Value, Compare C) { 19740b57cec5SDimitry Andric return std::upper_bound(adl_begin(Range), adl_end(Range), 19750b57cec5SDimitry Andric std::forward<T>(Value), C); 19760b57cec5SDimitry Andric } 19770b57cec5SDimitry Andric 19780fca6ea1SDimitry Andric template <typename R> auto min_element(R &&Range) { 19790fca6ea1SDimitry Andric return std::min_element(adl_begin(Range), adl_end(Range)); 19800fca6ea1SDimitry Andric } 19810fca6ea1SDimitry Andric 19820fca6ea1SDimitry Andric template <typename R, typename Compare> auto min_element(R &&Range, Compare C) { 19830fca6ea1SDimitry Andric return std::min_element(adl_begin(Range), adl_end(Range), C); 19840fca6ea1SDimitry Andric } 19850fca6ea1SDimitry Andric 19860fca6ea1SDimitry Andric template <typename R> auto max_element(R &&Range) { 19870fca6ea1SDimitry Andric return std::max_element(adl_begin(Range), adl_end(Range)); 19880fca6ea1SDimitry Andric } 19890fca6ea1SDimitry Andric 19900fca6ea1SDimitry Andric template <typename R, typename Compare> auto max_element(R &&Range, Compare C) { 19910fca6ea1SDimitry Andric return std::max_element(adl_begin(Range), adl_end(Range), C); 19920fca6ea1SDimitry Andric } 19930fca6ea1SDimitry Andric 19940b57cec5SDimitry Andric template <typename R> 19950b57cec5SDimitry Andric void stable_sort(R &&Range) { 19960b57cec5SDimitry Andric std::stable_sort(adl_begin(Range), adl_end(Range)); 19970b57cec5SDimitry Andric } 19980b57cec5SDimitry Andric 19990b57cec5SDimitry Andric template <typename R, typename Compare> 20000b57cec5SDimitry Andric void stable_sort(R &&Range, Compare C) { 20010b57cec5SDimitry Andric std::stable_sort(adl_begin(Range), adl_end(Range), C); 20020b57cec5SDimitry Andric } 20030b57cec5SDimitry Andric 20040b57cec5SDimitry Andric /// Binary search for the first iterator in a range where a predicate is false. 20050b57cec5SDimitry Andric /// Requires that C is always true below some limit, and always false above it. 20060b57cec5SDimitry Andric template <typename R, typename Predicate, 20070b57cec5SDimitry Andric typename Val = decltype(*adl_begin(std::declval<R>()))> 20085ffd83dbSDimitry Andric auto partition_point(R &&Range, Predicate P) { 20090b57cec5SDimitry Andric return std::partition_point(adl_begin(Range), adl_end(Range), P); 20100b57cec5SDimitry Andric } 20110b57cec5SDimitry Andric 2012fe6060f1SDimitry Andric template<typename Range, typename Predicate> 2013fe6060f1SDimitry Andric auto unique(Range &&R, Predicate P) { 2014fe6060f1SDimitry Andric return std::unique(adl_begin(R), adl_end(R), P); 2015fe6060f1SDimitry Andric } 2016fe6060f1SDimitry Andric 20170fca6ea1SDimitry Andric /// Wrapper function around std::unique to allow calling unique on a 20180fca6ea1SDimitry Andric /// container without having to specify the begin/end iterators. 20190fca6ea1SDimitry Andric template <typename Range> auto unique(Range &&R) { 20200fca6ea1SDimitry Andric return std::unique(adl_begin(R), adl_end(R)); 20210fca6ea1SDimitry Andric } 20220fca6ea1SDimitry Andric 2023fe6060f1SDimitry Andric /// Wrapper function around std::equal to detect if pair-wise elements between 2024fe6060f1SDimitry Andric /// two ranges are the same. 2025fe6060f1SDimitry Andric template <typename L, typename R> bool equal(L &&LRange, R &&RRange) { 2026fe6060f1SDimitry Andric return std::equal(adl_begin(LRange), adl_end(LRange), adl_begin(RRange), 2027fe6060f1SDimitry Andric adl_end(RRange)); 2028fe6060f1SDimitry Andric } 2029fe6060f1SDimitry Andric 2030*52418fc2SDimitry Andric template <typename L, typename R, typename BinaryPredicate> 2031*52418fc2SDimitry Andric bool equal(L &&LRange, R &&RRange, BinaryPredicate P) { 2032*52418fc2SDimitry Andric return std::equal(adl_begin(LRange), adl_end(LRange), adl_begin(RRange), 2033*52418fc2SDimitry Andric adl_end(RRange), P); 2034*52418fc2SDimitry Andric } 2035*52418fc2SDimitry Andric 2036bdd1243dSDimitry Andric /// Returns true if all elements in Range are equal or when the Range is empty. 2037bdd1243dSDimitry Andric template <typename R> bool all_equal(R &&Range) { 2038bdd1243dSDimitry Andric auto Begin = adl_begin(Range); 2039bdd1243dSDimitry Andric auto End = adl_end(Range); 2040bdd1243dSDimitry Andric return Begin == End || std::equal(Begin + 1, End, Begin); 2041bdd1243dSDimitry Andric } 2042bdd1243dSDimitry Andric 2043bdd1243dSDimitry Andric /// Returns true if all Values in the initializer lists are equal or the list 2044bdd1243dSDimitry Andric // is empty. 2045bdd1243dSDimitry Andric template <typename T> bool all_equal(std::initializer_list<T> Values) { 2046bdd1243dSDimitry Andric return all_equal<std::initializer_list<T>>(std::move(Values)); 20470b57cec5SDimitry Andric } 20480b57cec5SDimitry Andric 20490b57cec5SDimitry Andric /// Provide a container algorithm similar to C++ Library Fundamentals v2's 20500b57cec5SDimitry Andric /// `erase_if` which is equivalent to: 20510b57cec5SDimitry Andric /// 20520b57cec5SDimitry Andric /// C.erase(remove_if(C, pred), C.end()); 20530b57cec5SDimitry Andric /// 20540b57cec5SDimitry Andric /// This version works for any container with an erase method call accepting 20550b57cec5SDimitry Andric /// two iterators. 20560b57cec5SDimitry Andric template <typename Container, typename UnaryPredicate> 20570b57cec5SDimitry Andric void erase_if(Container &C, UnaryPredicate P) { 20580b57cec5SDimitry Andric C.erase(remove_if(C, P), C.end()); 20590b57cec5SDimitry Andric } 20600b57cec5SDimitry Andric 2061e8d8bef9SDimitry Andric /// Wrapper function to remove a value from a container: 2062e8d8bef9SDimitry Andric /// 2063e8d8bef9SDimitry Andric /// C.erase(remove(C.begin(), C.end(), V), C.end()); 2064e8d8bef9SDimitry Andric template <typename Container, typename ValueType> 20655f757f3fSDimitry Andric void erase(Container &C, ValueType V) { 2066e8d8bef9SDimitry Andric C.erase(std::remove(C.begin(), C.end(), V), C.end()); 2067e8d8bef9SDimitry Andric } 2068e8d8bef9SDimitry Andric 20695f757f3fSDimitry Andric /// Wrapper function to append range `R` to container `C`. 2070e8d8bef9SDimitry Andric /// 2071e8d8bef9SDimitry Andric /// C.insert(C.end(), R.begin(), R.end()); 2072e8d8bef9SDimitry Andric template <typename Container, typename Range> 20735f757f3fSDimitry Andric void append_range(Container &C, Range &&R) { 207406c3fb27SDimitry Andric C.insert(C.end(), adl_begin(R), adl_end(R)); 2075e8d8bef9SDimitry Andric } 2076e8d8bef9SDimitry Andric 20775f757f3fSDimitry Andric /// Appends all `Values` to container `C`. 20785f757f3fSDimitry Andric template <typename Container, typename... Args> 20795f757f3fSDimitry Andric void append_values(Container &C, Args &&...Values) { 20805f757f3fSDimitry Andric C.reserve(range_size(C) + sizeof...(Args)); 20815f757f3fSDimitry Andric // Append all values one by one. 20825f757f3fSDimitry Andric ((void)C.insert(C.end(), std::forward<Args>(Values)), ...); 20835f757f3fSDimitry Andric } 20845f757f3fSDimitry Andric 20850b57cec5SDimitry Andric /// Given a sequence container Cont, replace the range [ContIt, ContEnd) with 20860b57cec5SDimitry Andric /// the range [ValIt, ValEnd) (which is not from the same container). 20870b57cec5SDimitry Andric template<typename Container, typename RandomAccessIterator> 20880b57cec5SDimitry Andric void replace(Container &Cont, typename Container::iterator ContIt, 20890b57cec5SDimitry Andric typename Container::iterator ContEnd, RandomAccessIterator ValIt, 20900b57cec5SDimitry Andric RandomAccessIterator ValEnd) { 20910b57cec5SDimitry Andric while (true) { 20920b57cec5SDimitry Andric if (ValIt == ValEnd) { 20930b57cec5SDimitry Andric Cont.erase(ContIt, ContEnd); 20940b57cec5SDimitry Andric return; 20950b57cec5SDimitry Andric } else if (ContIt == ContEnd) { 20960b57cec5SDimitry Andric Cont.insert(ContIt, ValIt, ValEnd); 20970b57cec5SDimitry Andric return; 20980b57cec5SDimitry Andric } 20990b57cec5SDimitry Andric *ContIt++ = *ValIt++; 21000b57cec5SDimitry Andric } 21010b57cec5SDimitry Andric } 21020b57cec5SDimitry Andric 21030b57cec5SDimitry Andric /// Given a sequence container Cont, replace the range [ContIt, ContEnd) with 21040b57cec5SDimitry Andric /// the range R. 21050b57cec5SDimitry Andric template<typename Container, typename Range = std::initializer_list< 21060b57cec5SDimitry Andric typename Container::value_type>> 21070b57cec5SDimitry Andric void replace(Container &Cont, typename Container::iterator ContIt, 21080b57cec5SDimitry Andric typename Container::iterator ContEnd, Range R) { 21090b57cec5SDimitry Andric replace(Cont, ContIt, ContEnd, R.begin(), R.end()); 21100b57cec5SDimitry Andric } 21110b57cec5SDimitry Andric 21125ffd83dbSDimitry Andric /// An STL-style algorithm similar to std::for_each that applies a second 21135ffd83dbSDimitry Andric /// functor between every pair of elements. 21145ffd83dbSDimitry Andric /// 21155ffd83dbSDimitry Andric /// This provides the control flow logic to, for example, print a 21165ffd83dbSDimitry Andric /// comma-separated list: 21175ffd83dbSDimitry Andric /// \code 21185ffd83dbSDimitry Andric /// interleave(names.begin(), names.end(), 21195ffd83dbSDimitry Andric /// [&](StringRef name) { os << name; }, 21205ffd83dbSDimitry Andric /// [&] { os << ", "; }); 21215ffd83dbSDimitry Andric /// \endcode 21225ffd83dbSDimitry Andric template <typename ForwardIterator, typename UnaryFunctor, 21235ffd83dbSDimitry Andric typename NullaryFunctor, 2124bdd1243dSDimitry Andric typename = std::enable_if_t< 21255ffd83dbSDimitry Andric !std::is_constructible<StringRef, UnaryFunctor>::value && 2126bdd1243dSDimitry Andric !std::is_constructible<StringRef, NullaryFunctor>::value>> 21275ffd83dbSDimitry Andric inline void interleave(ForwardIterator begin, ForwardIterator end, 21285ffd83dbSDimitry Andric UnaryFunctor each_fn, NullaryFunctor between_fn) { 21295ffd83dbSDimitry Andric if (begin == end) 21305ffd83dbSDimitry Andric return; 21315ffd83dbSDimitry Andric each_fn(*begin); 21325ffd83dbSDimitry Andric ++begin; 21335ffd83dbSDimitry Andric for (; begin != end; ++begin) { 21345ffd83dbSDimitry Andric between_fn(); 21355ffd83dbSDimitry Andric each_fn(*begin); 21365ffd83dbSDimitry Andric } 21375ffd83dbSDimitry Andric } 21385ffd83dbSDimitry Andric 21395ffd83dbSDimitry Andric template <typename Container, typename UnaryFunctor, typename NullaryFunctor, 2140bdd1243dSDimitry Andric typename = std::enable_if_t< 21415ffd83dbSDimitry Andric !std::is_constructible<StringRef, UnaryFunctor>::value && 2142bdd1243dSDimitry Andric !std::is_constructible<StringRef, NullaryFunctor>::value>> 21435ffd83dbSDimitry Andric inline void interleave(const Container &c, UnaryFunctor each_fn, 21445ffd83dbSDimitry Andric NullaryFunctor between_fn) { 21450fca6ea1SDimitry Andric interleave(adl_begin(c), adl_end(c), each_fn, between_fn); 21465ffd83dbSDimitry Andric } 21475ffd83dbSDimitry Andric 21485ffd83dbSDimitry Andric /// Overload of interleave for the common case of string separator. 21495ffd83dbSDimitry Andric template <typename Container, typename UnaryFunctor, typename StreamT, 21505ffd83dbSDimitry Andric typename T = detail::ValueOfRange<Container>> 21515ffd83dbSDimitry Andric inline void interleave(const Container &c, StreamT &os, UnaryFunctor each_fn, 21525ffd83dbSDimitry Andric const StringRef &separator) { 21530fca6ea1SDimitry Andric interleave(adl_begin(c), adl_end(c), each_fn, [&] { os << separator; }); 21545ffd83dbSDimitry Andric } 21555ffd83dbSDimitry Andric template <typename Container, typename StreamT, 21565ffd83dbSDimitry Andric typename T = detail::ValueOfRange<Container>> 21575ffd83dbSDimitry Andric inline void interleave(const Container &c, StreamT &os, 21585ffd83dbSDimitry Andric const StringRef &separator) { 21595ffd83dbSDimitry Andric interleave( 21605ffd83dbSDimitry Andric c, os, [&](const T &a) { os << a; }, separator); 21615ffd83dbSDimitry Andric } 21625ffd83dbSDimitry Andric 21635ffd83dbSDimitry Andric template <typename Container, typename UnaryFunctor, typename StreamT, 21645ffd83dbSDimitry Andric typename T = detail::ValueOfRange<Container>> 21655ffd83dbSDimitry Andric inline void interleaveComma(const Container &c, StreamT &os, 21665ffd83dbSDimitry Andric UnaryFunctor each_fn) { 21675ffd83dbSDimitry Andric interleave(c, os, each_fn, ", "); 21685ffd83dbSDimitry Andric } 21695ffd83dbSDimitry Andric template <typename Container, typename StreamT, 21705ffd83dbSDimitry Andric typename T = detail::ValueOfRange<Container>> 21715ffd83dbSDimitry Andric inline void interleaveComma(const Container &c, StreamT &os) { 21725ffd83dbSDimitry Andric interleaveComma(c, os, [&](const T &a) { os << a; }); 21735ffd83dbSDimitry Andric } 21745ffd83dbSDimitry Andric 21750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 21760b57cec5SDimitry Andric // Extra additions to <memory> 21770b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 21780b57cec5SDimitry Andric 21790b57cec5SDimitry Andric struct FreeDeleter { 21800b57cec5SDimitry Andric void operator()(void* v) { 21810b57cec5SDimitry Andric ::free(v); 21820b57cec5SDimitry Andric } 21830b57cec5SDimitry Andric }; 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric template<typename First, typename Second> 21860b57cec5SDimitry Andric struct pair_hash { 21870b57cec5SDimitry Andric size_t operator()(const std::pair<First, Second> &P) const { 21880b57cec5SDimitry Andric return std::hash<First>()(P.first) * 31 + std::hash<Second>()(P.second); 21890b57cec5SDimitry Andric } 21900b57cec5SDimitry Andric }; 21910b57cec5SDimitry Andric 21920b57cec5SDimitry Andric /// Binary functor that adapts to any other binary functor after dereferencing 21930b57cec5SDimitry Andric /// operands. 21940b57cec5SDimitry Andric template <typename T> struct deref { 21950b57cec5SDimitry Andric T func; 21960b57cec5SDimitry Andric 21970b57cec5SDimitry Andric // Could be further improved to cope with non-derivable functors and 21980b57cec5SDimitry Andric // non-binary functors (should be a variadic template member function 21990b57cec5SDimitry Andric // operator()). 22005ffd83dbSDimitry Andric template <typename A, typename B> auto operator()(A &lhs, B &rhs) const { 22010b57cec5SDimitry Andric assert(lhs); 22020b57cec5SDimitry Andric assert(rhs); 22030b57cec5SDimitry Andric return func(*lhs, *rhs); 22040b57cec5SDimitry Andric } 22050b57cec5SDimitry Andric }; 22060b57cec5SDimitry Andric 22070b57cec5SDimitry Andric namespace detail { 22080b57cec5SDimitry Andric 220906c3fb27SDimitry Andric /// Tuple-like type for `zip_enumerator` dereference. 221006c3fb27SDimitry Andric template <typename... Refs> struct enumerator_result; 22110b57cec5SDimitry Andric 221206c3fb27SDimitry Andric template <typename... Iters> 221306c3fb27SDimitry Andric using EnumeratorTupleType = enumerator_result<decltype(*declval<Iters>())...>; 22140b57cec5SDimitry Andric 221506c3fb27SDimitry Andric /// Zippy iterator that uses the second iterator for comparisons. For the 221606c3fb27SDimitry Andric /// increment to be safe, the second range has to be the shortest. 221706c3fb27SDimitry Andric /// Returns `enumerator_result` on dereference to provide `.index()` and 221806c3fb27SDimitry Andric /// `.value()` member functions. 221906c3fb27SDimitry Andric /// Note: Because the dereference operator returns `enumerator_result` as a 222006c3fb27SDimitry Andric /// value instead of a reference and does not strictly conform to the C++17's 222106c3fb27SDimitry Andric /// definition of forward iterator. However, it satisfies all the 222206c3fb27SDimitry Andric /// forward_iterator requirements that the `zip_common` and `zippy` depend on 222306c3fb27SDimitry Andric /// and fully conforms to the C++20 definition of forward iterator. 222406c3fb27SDimitry Andric /// This is similar to `std::vector<bool>::iterator` that returns bit reference 222506c3fb27SDimitry Andric /// wrappers on dereference. 222606c3fb27SDimitry Andric template <typename... Iters> 222706c3fb27SDimitry Andric struct zip_enumerator : zip_common<zip_enumerator<Iters...>, 222806c3fb27SDimitry Andric EnumeratorTupleType<Iters...>, Iters...> { 222906c3fb27SDimitry Andric static_assert(sizeof...(Iters) >= 2, "Expected at least two iteratees"); 223006c3fb27SDimitry Andric using zip_common<zip_enumerator<Iters...>, EnumeratorTupleType<Iters...>, 223106c3fb27SDimitry Andric Iters...>::zip_common; 22320b57cec5SDimitry Andric 223306c3fb27SDimitry Andric bool operator==(const zip_enumerator &Other) const { 223406c3fb27SDimitry Andric return std::get<1>(this->iterators) == std::get<1>(Other.iterators); 22350b57cec5SDimitry Andric } 22360b57cec5SDimitry Andric }; 22370b57cec5SDimitry Andric 223806c3fb27SDimitry Andric template <typename... Refs> struct enumerator_result<std::size_t, Refs...> { 223906c3fb27SDimitry Andric static constexpr std::size_t NumRefs = sizeof...(Refs); 224006c3fb27SDimitry Andric static_assert(NumRefs != 0); 224106c3fb27SDimitry Andric // `NumValues` includes the index. 224206c3fb27SDimitry Andric static constexpr std::size_t NumValues = NumRefs + 1; 224306c3fb27SDimitry Andric 224406c3fb27SDimitry Andric // Tuple type whose element types are references for each `Ref`. 224506c3fb27SDimitry Andric using range_reference_tuple = std::tuple<Refs...>; 224606c3fb27SDimitry Andric // Tuple type who elements are references to all values, including both 224706c3fb27SDimitry Andric // the index and `Refs` reference types. 224806c3fb27SDimitry Andric using value_reference_tuple = std::tuple<std::size_t, Refs...>; 224906c3fb27SDimitry Andric 225006c3fb27SDimitry Andric enumerator_result(std::size_t Index, Refs &&...Rs) 225106c3fb27SDimitry Andric : Idx(Index), Storage(std::forward<Refs>(Rs)...) {} 225206c3fb27SDimitry Andric 225306c3fb27SDimitry Andric /// Returns the 0-based index of the current position within the original 225406c3fb27SDimitry Andric /// input range(s). 225506c3fb27SDimitry Andric std::size_t index() const { return Idx; } 225606c3fb27SDimitry Andric 225706c3fb27SDimitry Andric /// Returns the value(s) for the current iterator. This does not include the 225806c3fb27SDimitry Andric /// index. 225906c3fb27SDimitry Andric decltype(auto) value() const { 226006c3fb27SDimitry Andric if constexpr (NumRefs == 1) 226106c3fb27SDimitry Andric return std::get<0>(Storage); 226206c3fb27SDimitry Andric else 226306c3fb27SDimitry Andric return Storage; 2264bdd1243dSDimitry Andric } 2265bdd1243dSDimitry Andric 226606c3fb27SDimitry Andric /// Returns the value at index `I`. This case covers the index. 226706c3fb27SDimitry Andric template <std::size_t I, typename = std::enable_if_t<I == 0>> 226806c3fb27SDimitry Andric friend std::size_t get(const enumerator_result &Result) { 226906c3fb27SDimitry Andric return Result.Idx; 22700b57cec5SDimitry Andric } 22710b57cec5SDimitry Andric 227206c3fb27SDimitry Andric /// Returns the value at index `I`. This case covers references to the 227306c3fb27SDimitry Andric /// iteratees. 227406c3fb27SDimitry Andric template <std::size_t I, typename = std::enable_if_t<I != 0>> 227506c3fb27SDimitry Andric friend decltype(auto) get(const enumerator_result &Result) { 227606c3fb27SDimitry Andric // Note: This is a separate function from the other `get`, instead of an 227706c3fb27SDimitry Andric // `if constexpr` case, to work around an MSVC 19.31.31XXX compiler 227806c3fb27SDimitry Andric // (Visual Studio 2022 17.1) return type deduction bug. 227906c3fb27SDimitry Andric return std::get<I - 1>(Result.Storage); 22800b57cec5SDimitry Andric } 22810b57cec5SDimitry Andric 228206c3fb27SDimitry Andric template <typename... Ts> 228306c3fb27SDimitry Andric friend bool operator==(const enumerator_result &Result, 228406c3fb27SDimitry Andric const std::tuple<std::size_t, Ts...> &Other) { 228506c3fb27SDimitry Andric static_assert(NumRefs == sizeof...(Ts), "Size mismatch"); 228606c3fb27SDimitry Andric if (Result.Idx != std::get<0>(Other)) 228706c3fb27SDimitry Andric return false; 228806c3fb27SDimitry Andric return Result.is_value_equal(Other, std::make_index_sequence<NumRefs>{}); 22890b57cec5SDimitry Andric } 22900b57cec5SDimitry Andric 22910b57cec5SDimitry Andric private: 229206c3fb27SDimitry Andric template <typename Tuple, std::size_t... Idx> 229306c3fb27SDimitry Andric bool is_value_equal(const Tuple &Other, std::index_sequence<Idx...>) const { 229406c3fb27SDimitry Andric return ((std::get<Idx>(Storage) == std::get<Idx + 1>(Other)) && ...); 229506c3fb27SDimitry Andric } 229606c3fb27SDimitry Andric 229706c3fb27SDimitry Andric std::size_t Idx; 229806c3fb27SDimitry Andric // Make this tuple mutable to avoid casts that obfuscate const-correctness 229906c3fb27SDimitry Andric // issues. Const-correctness of references is taken care of by `zippy` that 230006c3fb27SDimitry Andric // defines const-non and const iterator types that will propagate down to 230106c3fb27SDimitry Andric // `enumerator_result`'s `Refs`. 230206c3fb27SDimitry Andric // Note that unlike the results of `zip*` functions, `enumerate`'s result are 230306c3fb27SDimitry Andric // supposed to be modifiable even when defined as 230406c3fb27SDimitry Andric // `const`. 230506c3fb27SDimitry Andric mutable range_reference_tuple Storage; 23060b57cec5SDimitry Andric }; 23070b57cec5SDimitry Andric 23085f757f3fSDimitry Andric struct index_iterator 23095f757f3fSDimitry Andric : llvm::iterator_facade_base<index_iterator, 23105f757f3fSDimitry Andric std::random_access_iterator_tag, std::size_t> { 23115f757f3fSDimitry Andric index_iterator(std::size_t Index) : Index(Index) {} 23125f757f3fSDimitry Andric 23135f757f3fSDimitry Andric index_iterator &operator+=(std::ptrdiff_t N) { 23145f757f3fSDimitry Andric Index += N; 231506c3fb27SDimitry Andric return *this; 23164824e7fdSDimitry Andric } 23170b57cec5SDimitry Andric 23185f757f3fSDimitry Andric index_iterator &operator-=(std::ptrdiff_t N) { 23195f757f3fSDimitry Andric Index -= N; 23205f757f3fSDimitry Andric return *this; 23215f757f3fSDimitry Andric } 23225f757f3fSDimitry Andric 23235f757f3fSDimitry Andric std::ptrdiff_t operator-(const index_iterator &R) const { 23245f757f3fSDimitry Andric return Index - R.Index; 23255f757f3fSDimitry Andric } 23265f757f3fSDimitry Andric 232706c3fb27SDimitry Andric // Note: This dereference operator returns a value instead of a reference 232806c3fb27SDimitry Andric // and does not strictly conform to the C++17's definition of forward 232906c3fb27SDimitry Andric // iterator. However, it satisfies all the forward_iterator requirements 233006c3fb27SDimitry Andric // that the `zip_common` depends on and fully conforms to the C++20 233106c3fb27SDimitry Andric // definition of forward iterator. 233206c3fb27SDimitry Andric std::size_t operator*() const { return Index; } 233306c3fb27SDimitry Andric 23345f757f3fSDimitry Andric friend bool operator==(const index_iterator &Lhs, const index_iterator &Rhs) { 233506c3fb27SDimitry Andric return Lhs.Index == Rhs.Index; 23364824e7fdSDimitry Andric } 23370b57cec5SDimitry Andric 23385f757f3fSDimitry Andric friend bool operator<(const index_iterator &Lhs, const index_iterator &Rhs) { 23395f757f3fSDimitry Andric return Lhs.Index < Rhs.Index; 23405f757f3fSDimitry Andric } 23415f757f3fSDimitry Andric 23425f757f3fSDimitry Andric private: 23435f757f3fSDimitry Andric std::size_t Index; 234406c3fb27SDimitry Andric }; 234506c3fb27SDimitry Andric 23465f757f3fSDimitry Andric /// Infinite stream of increasing 0-based `size_t` indices. 23475f757f3fSDimitry Andric struct index_stream { 23485f757f3fSDimitry Andric index_iterator begin() const { return {0}; } 23495f757f3fSDimitry Andric index_iterator end() const { 235006c3fb27SDimitry Andric // We approximate 'infinity' with the max size_t value, which should be good 235106c3fb27SDimitry Andric // enough to index over any container. 23525f757f3fSDimitry Andric return index_iterator{std::numeric_limits<std::size_t>::max()}; 235306c3fb27SDimitry Andric } 23540b57cec5SDimitry Andric }; 23550b57cec5SDimitry Andric 23560b57cec5SDimitry Andric } // end namespace detail 23570b57cec5SDimitry Andric 23585f757f3fSDimitry Andric /// Increasing range of `size_t` indices. 23595f757f3fSDimitry Andric class index_range { 23605f757f3fSDimitry Andric std::size_t Begin; 23615f757f3fSDimitry Andric std::size_t End; 23625f757f3fSDimitry Andric 23635f757f3fSDimitry Andric public: 23645f757f3fSDimitry Andric index_range(std::size_t Begin, std::size_t End) : Begin(Begin), End(End) {} 23655f757f3fSDimitry Andric detail::index_iterator begin() const { return {Begin}; } 23665f757f3fSDimitry Andric detail::index_iterator end() const { return {End}; } 23675f757f3fSDimitry Andric }; 23685f757f3fSDimitry Andric 236906c3fb27SDimitry Andric /// Given two or more input ranges, returns a new range whose values are are 237006c3fb27SDimitry Andric /// tuples (A, B, C, ...), such that A is the 0-based index of the item in the 237106c3fb27SDimitry Andric /// sequence, and B, C, ..., are the values from the original input ranges. All 237206c3fb27SDimitry Andric /// input ranges are required to have equal lengths. Note that the returned 237306c3fb27SDimitry Andric /// iterator allows for the values (B, C, ...) to be modified. Example: 23740b57cec5SDimitry Andric /// 237506c3fb27SDimitry Andric /// ```c++ 237606c3fb27SDimitry Andric /// std::vector<char> Letters = {'A', 'B', 'C', 'D'}; 237706c3fb27SDimitry Andric /// std::vector<int> Vals = {10, 11, 12, 13}; 237806c3fb27SDimitry Andric /// 237906c3fb27SDimitry Andric /// for (auto [Index, Letter, Value] : enumerate(Letters, Vals)) { 238006c3fb27SDimitry Andric /// printf("Item %zu - %c: %d\n", Index, Letter, Value); 238106c3fb27SDimitry Andric /// Value -= 10; 23820b57cec5SDimitry Andric /// } 238306c3fb27SDimitry Andric /// ``` 2384bdd1243dSDimitry Andric /// 23850b57cec5SDimitry Andric /// Output: 238606c3fb27SDimitry Andric /// Item 0 - A: 10 238706c3fb27SDimitry Andric /// Item 1 - B: 11 238806c3fb27SDimitry Andric /// Item 2 - C: 12 238906c3fb27SDimitry Andric /// Item 3 - D: 13 23900b57cec5SDimitry Andric /// 239106c3fb27SDimitry Andric /// or using an iterator: 239206c3fb27SDimitry Andric /// ```c++ 239306c3fb27SDimitry Andric /// for (auto it : enumerate(Vals)) { 239406c3fb27SDimitry Andric /// it.value() += 10; 239506c3fb27SDimitry Andric /// printf("Item %zu: %d\n", it.index(), it.value()); 239606c3fb27SDimitry Andric /// } 239706c3fb27SDimitry Andric /// ``` 239806c3fb27SDimitry Andric /// 239906c3fb27SDimitry Andric /// Output: 240006c3fb27SDimitry Andric /// Item 0: 20 240106c3fb27SDimitry Andric /// Item 1: 21 240206c3fb27SDimitry Andric /// Item 2: 22 240306c3fb27SDimitry Andric /// Item 3: 23 240406c3fb27SDimitry Andric /// 240506c3fb27SDimitry Andric template <typename FirstRange, typename... RestRanges> 240606c3fb27SDimitry Andric auto enumerate(FirstRange &&First, RestRanges &&...Rest) { 240706c3fb27SDimitry Andric if constexpr (sizeof...(Rest) != 0) { 240806c3fb27SDimitry Andric #ifndef NDEBUG 240906c3fb27SDimitry Andric // Note: Create an array instead of an initializer list to work around an 241006c3fb27SDimitry Andric // Apple clang 14 compiler bug. 241106c3fb27SDimitry Andric size_t sizes[] = {range_size(First), range_size(Rest)...}; 241206c3fb27SDimitry Andric assert(all_equal(sizes) && "Ranges have different length"); 241306c3fb27SDimitry Andric #endif 241406c3fb27SDimitry Andric } 241506c3fb27SDimitry Andric using enumerator = detail::zippy<detail::zip_enumerator, detail::index_stream, 241606c3fb27SDimitry Andric FirstRange, RestRanges...>; 241706c3fb27SDimitry Andric return enumerator(detail::index_stream{}, std::forward<FirstRange>(First), 241806c3fb27SDimitry Andric std::forward<RestRanges>(Rest)...); 24190b57cec5SDimitry Andric } 24200b57cec5SDimitry Andric 24210b57cec5SDimitry Andric namespace detail { 24220b57cec5SDimitry Andric 2423349cc55cSDimitry Andric template <typename Predicate, typename... Args> 2424349cc55cSDimitry Andric bool all_of_zip_predicate_first(Predicate &&P, Args &&...args) { 2425349cc55cSDimitry Andric auto z = zip(args...); 2426349cc55cSDimitry Andric auto it = z.begin(); 2427349cc55cSDimitry Andric auto end = z.end(); 2428349cc55cSDimitry Andric while (it != end) { 2429bdd1243dSDimitry Andric if (!std::apply([&](auto &&...args) { return P(args...); }, *it)) 2430349cc55cSDimitry Andric return false; 2431349cc55cSDimitry Andric ++it; 2432349cc55cSDimitry Andric } 2433349cc55cSDimitry Andric return it.all_equals(end); 2434349cc55cSDimitry Andric } 2435349cc55cSDimitry Andric 2436349cc55cSDimitry Andric // Just an adaptor to switch the order of argument and have the predicate before 2437349cc55cSDimitry Andric // the zipped inputs. 2438349cc55cSDimitry Andric template <typename... ArgsThenPredicate, size_t... InputIndexes> 2439349cc55cSDimitry Andric bool all_of_zip_predicate_last( 2440349cc55cSDimitry Andric std::tuple<ArgsThenPredicate...> argsThenPredicate, 2441349cc55cSDimitry Andric std::index_sequence<InputIndexes...>) { 2442349cc55cSDimitry Andric auto constexpr OutputIndex = 2443349cc55cSDimitry Andric std::tuple_size<decltype(argsThenPredicate)>::value - 1; 2444349cc55cSDimitry Andric return all_of_zip_predicate_first(std::get<OutputIndex>(argsThenPredicate), 2445349cc55cSDimitry Andric std::get<InputIndexes>(argsThenPredicate)...); 2446349cc55cSDimitry Andric } 2447349cc55cSDimitry Andric 2448349cc55cSDimitry Andric } // end namespace detail 2449349cc55cSDimitry Andric 2450349cc55cSDimitry Andric /// Compare two zipped ranges using the provided predicate (as last argument). 2451349cc55cSDimitry Andric /// Return true if all elements satisfy the predicate and false otherwise. 2452349cc55cSDimitry Andric // Return false if the zipped iterator aren't all at end (size mismatch). 2453349cc55cSDimitry Andric template <typename... ArgsAndPredicate> 2454349cc55cSDimitry Andric bool all_of_zip(ArgsAndPredicate &&...argsAndPredicate) { 2455349cc55cSDimitry Andric return detail::all_of_zip_predicate_last( 2456349cc55cSDimitry Andric std::forward_as_tuple(argsAndPredicate...), 2457349cc55cSDimitry Andric std::make_index_sequence<sizeof...(argsAndPredicate) - 1>{}); 2458349cc55cSDimitry Andric } 2459349cc55cSDimitry Andric 24600b57cec5SDimitry Andric /// Return true if the sequence [Begin, End) has exactly N items. Runs in O(N) 24610b57cec5SDimitry Andric /// time. Not meant for use with random-access iterators. 24625ffd83dbSDimitry Andric /// Can optionally take a predicate to filter lazily some items. 24635ffd83dbSDimitry Andric template <typename IterTy, 24645ffd83dbSDimitry Andric typename Pred = bool (*)(const decltype(*std::declval<IterTy>()) &)> 24650b57cec5SDimitry Andric bool hasNItems( 24660b57cec5SDimitry Andric IterTy &&Begin, IterTy &&End, unsigned N, 24675ffd83dbSDimitry Andric Pred &&ShouldBeCounted = 24685ffd83dbSDimitry Andric [](const decltype(*std::declval<IterTy>()) &) { return true; }, 24695ffd83dbSDimitry Andric std::enable_if_t< 2470e8d8bef9SDimitry Andric !std::is_base_of<std::random_access_iterator_tag, 2471e8d8bef9SDimitry Andric typename std::iterator_traits<std::remove_reference_t< 2472e8d8bef9SDimitry Andric decltype(Begin)>>::iterator_category>::value, 24735ffd83dbSDimitry Andric void> * = nullptr) { 24745ffd83dbSDimitry Andric for (; N; ++Begin) { 24750b57cec5SDimitry Andric if (Begin == End) 24760b57cec5SDimitry Andric return false; // Too few. 24775ffd83dbSDimitry Andric N -= ShouldBeCounted(*Begin); 24785ffd83dbSDimitry Andric } 24795ffd83dbSDimitry Andric for (; Begin != End; ++Begin) 24805ffd83dbSDimitry Andric if (ShouldBeCounted(*Begin)) 24815ffd83dbSDimitry Andric return false; // Too many. 24825ffd83dbSDimitry Andric return true; 24830b57cec5SDimitry Andric } 24840b57cec5SDimitry Andric 24850b57cec5SDimitry Andric /// Return true if the sequence [Begin, End) has N or more items. Runs in O(N) 24860b57cec5SDimitry Andric /// time. Not meant for use with random-access iterators. 24875ffd83dbSDimitry Andric /// Can optionally take a predicate to lazily filter some items. 24885ffd83dbSDimitry Andric template <typename IterTy, 24895ffd83dbSDimitry Andric typename Pred = bool (*)(const decltype(*std::declval<IterTy>()) &)> 24900b57cec5SDimitry Andric bool hasNItemsOrMore( 24910b57cec5SDimitry Andric IterTy &&Begin, IterTy &&End, unsigned N, 24925ffd83dbSDimitry Andric Pred &&ShouldBeCounted = 24935ffd83dbSDimitry Andric [](const decltype(*std::declval<IterTy>()) &) { return true; }, 24945ffd83dbSDimitry Andric std::enable_if_t< 2495e8d8bef9SDimitry Andric !std::is_base_of<std::random_access_iterator_tag, 2496e8d8bef9SDimitry Andric typename std::iterator_traits<std::remove_reference_t< 2497e8d8bef9SDimitry Andric decltype(Begin)>>::iterator_category>::value, 24985ffd83dbSDimitry Andric void> * = nullptr) { 24995ffd83dbSDimitry Andric for (; N; ++Begin) { 25000b57cec5SDimitry Andric if (Begin == End) 25010b57cec5SDimitry Andric return false; // Too few. 25025ffd83dbSDimitry Andric N -= ShouldBeCounted(*Begin); 25035ffd83dbSDimitry Andric } 25040b57cec5SDimitry Andric return true; 25050b57cec5SDimitry Andric } 25060b57cec5SDimitry Andric 25075ffd83dbSDimitry Andric /// Returns true if the sequence [Begin, End) has N or less items. Can 25085ffd83dbSDimitry Andric /// optionally take a predicate to lazily filter some items. 25095ffd83dbSDimitry Andric template <typename IterTy, 25105ffd83dbSDimitry Andric typename Pred = bool (*)(const decltype(*std::declval<IterTy>()) &)> 25115ffd83dbSDimitry Andric bool hasNItemsOrLess( 25125ffd83dbSDimitry Andric IterTy &&Begin, IterTy &&End, unsigned N, 25135ffd83dbSDimitry Andric Pred &&ShouldBeCounted = [](const decltype(*std::declval<IterTy>()) &) { 25145ffd83dbSDimitry Andric return true; 25155ffd83dbSDimitry Andric }) { 25165ffd83dbSDimitry Andric assert(N != std::numeric_limits<unsigned>::max()); 25175ffd83dbSDimitry Andric return !hasNItemsOrMore(Begin, End, N + 1, ShouldBeCounted); 25185ffd83dbSDimitry Andric } 25195ffd83dbSDimitry Andric 25205ffd83dbSDimitry Andric /// Returns true if the given container has exactly N items 25215ffd83dbSDimitry Andric template <typename ContainerTy> bool hasNItems(ContainerTy &&C, unsigned N) { 25225ffd83dbSDimitry Andric return hasNItems(std::begin(C), std::end(C), N); 25235ffd83dbSDimitry Andric } 25245ffd83dbSDimitry Andric 25255ffd83dbSDimitry Andric /// Returns true if the given container has N or more items 25265ffd83dbSDimitry Andric template <typename ContainerTy> 25275ffd83dbSDimitry Andric bool hasNItemsOrMore(ContainerTy &&C, unsigned N) { 25285ffd83dbSDimitry Andric return hasNItemsOrMore(std::begin(C), std::end(C), N); 25295ffd83dbSDimitry Andric } 25305ffd83dbSDimitry Andric 25315ffd83dbSDimitry Andric /// Returns true if the given container has N or less items 25325ffd83dbSDimitry Andric template <typename ContainerTy> 25335ffd83dbSDimitry Andric bool hasNItemsOrLess(ContainerTy &&C, unsigned N) { 25345ffd83dbSDimitry Andric return hasNItemsOrLess(std::begin(C), std::end(C), N); 25355ffd83dbSDimitry Andric } 25365ffd83dbSDimitry Andric 25370b57cec5SDimitry Andric /// Returns a raw pointer that represents the same address as the argument. 25380b57cec5SDimitry Andric /// 25395ffd83dbSDimitry Andric /// This implementation can be removed once we move to C++20 where it's defined 25405ffd83dbSDimitry Andric /// as std::to_address(). 25410b57cec5SDimitry Andric /// 25420b57cec5SDimitry Andric /// The std::pointer_traits<>::to_address(p) variations of these overloads has 25430b57cec5SDimitry Andric /// not been implemented. 25445ffd83dbSDimitry Andric template <class Ptr> auto to_address(const Ptr &P) { return P.operator->(); } 25450b57cec5SDimitry Andric template <class T> constexpr T *to_address(T *P) { return P; } 25460b57cec5SDimitry Andric 25475f757f3fSDimitry Andric // Detect incomplete types, relying on the fact that their size is unknown. 25485f757f3fSDimitry Andric namespace detail { 25495f757f3fSDimitry Andric template <typename T> using has_sizeof = decltype(sizeof(T)); 25505f757f3fSDimitry Andric } // namespace detail 25515f757f3fSDimitry Andric 25525f757f3fSDimitry Andric /// Detects when type `T` is incomplete. This is true for forward declarations 25535f757f3fSDimitry Andric /// and false for types with a full definition. 25545f757f3fSDimitry Andric template <typename T> 25555f757f3fSDimitry Andric constexpr bool is_incomplete_v = !is_detected<detail::has_sizeof, T>::value; 25565f757f3fSDimitry Andric 25570b57cec5SDimitry Andric } // end namespace llvm 25580b57cec5SDimitry Andric 2559bdd1243dSDimitry Andric namespace std { 256006c3fb27SDimitry Andric template <typename... Refs> 256106c3fb27SDimitry Andric struct tuple_size<llvm::detail::enumerator_result<Refs...>> 256206c3fb27SDimitry Andric : std::integral_constant<std::size_t, sizeof...(Refs)> {}; 2563bdd1243dSDimitry Andric 256406c3fb27SDimitry Andric template <std::size_t I, typename... Refs> 256506c3fb27SDimitry Andric struct tuple_element<I, llvm::detail::enumerator_result<Refs...>> 256606c3fb27SDimitry Andric : std::tuple_element<I, std::tuple<Refs...>> {}; 256706c3fb27SDimitry Andric 256806c3fb27SDimitry Andric template <std::size_t I, typename... Refs> 256906c3fb27SDimitry Andric struct tuple_element<I, const llvm::detail::enumerator_result<Refs...>> 257006c3fb27SDimitry Andric : std::tuple_element<I, std::tuple<Refs...>> {}; 2571bdd1243dSDimitry Andric 2572bdd1243dSDimitry Andric } // namespace std 2573bdd1243dSDimitry Andric 25740b57cec5SDimitry Andric #endif // LLVM_ADT_STLEXTRAS_H 2575