Flatten.h (3450B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_QUOTA_FLATTEN_H_ 8 #define DOM_QUOTA_FLATTEN_H_ 9 10 #include <iterator> 11 #include <type_traits> 12 #include <utility> 13 14 // XXX This should be moved to MFBT. 15 16 namespace mozilla::dom::quota { 17 18 namespace detail { 19 20 using std::begin; 21 using std::end; 22 23 template <typename T, typename NestedRange> 24 auto Flatten(NestedRange&& aRange) -> std::enable_if_t< 25 std::is_same_v<T, std::decay_t<typename decltype(begin( 26 std::declval<const NestedRange&>()))::value_type>>, 27 std::conditional_t<std::is_rvalue_reference_v<NestedRange>, 28 std::decay_t<NestedRange>, NestedRange>> { 29 return std::forward<NestedRange>(aRange); 30 } 31 32 template <typename T, typename NestedRange> 33 struct FlatIter { 34 using OuterIterator = 35 decltype(begin(std::declval<const std::decay_t<NestedRange>&>())); 36 using InnerIterator = 37 decltype(begin(*begin(std::declval<const std::decay_t<NestedRange>&>()))); 38 39 using iterator_category = std::input_iterator_tag; 40 using value_type = T; 41 using difference_type = std::ptrdiff_t; 42 using pointer = const T*; 43 using reference = const T&; 44 45 explicit FlatIter(const NestedRange& aRange, OuterIterator aIter) 46 : mOuterIter{std::move(aIter)}, mOuterEnd{end(aRange)} { 47 InitInner(); 48 } 49 50 const T& operator*() const { return *mInnerIter; } 51 52 FlatIter& operator++() { 53 ++mInnerIter; 54 if (mInnerIter == mInnerEnd) { 55 ++mOuterIter; 56 InitInner(); 57 } 58 return *this; 59 } 60 61 bool operator!=(const FlatIter& aOther) const { 62 return mOuterIter != aOther.mOuterIter || 63 (mOuterIter != mOuterEnd && mInnerIter != aOther.mInnerIter); 64 } 65 66 bool operator==(const FlatIter& aOther) const { return !(*this != aOther); } 67 68 private: 69 void InitInner() { 70 while (mOuterIter != mOuterEnd) { 71 const typename OuterIterator::value_type& innerRange = *mOuterIter; 72 73 mInnerIter = begin(innerRange); 74 mInnerEnd = end(innerRange); 75 76 if (mInnerIter != mInnerEnd) { 77 break; 78 } 79 80 ++mOuterIter; 81 } 82 } 83 84 OuterIterator mOuterIter; 85 const OuterIterator mOuterEnd; 86 87 InnerIterator mInnerIter; 88 InnerIterator mInnerEnd; 89 }; 90 91 template <typename T, typename NestedRange> 92 struct FlatRange { 93 explicit FlatRange(NestedRange aRange) : mRange{std::move(aRange)} {} 94 95 auto begin() const { 96 using std::begin; 97 return FlatIter<T, NestedRange>{mRange, begin(mRange)}; 98 } 99 auto end() const { 100 using std::end; 101 return FlatIter<T, NestedRange>{mRange, end(mRange)}; 102 } 103 104 private: 105 NestedRange mRange; 106 }; 107 108 template <typename T, typename NestedRange> 109 auto Flatten(NestedRange&& aRange) -> std::enable_if_t< 110 !std::is_same_v< 111 T, std::decay_t<typename decltype(begin( 112 std::declval<const std::decay_t<NestedRange>&>()))::value_type>>, 113 FlatRange<T, NestedRange>> { 114 return FlatRange<T, NestedRange>{std::forward<NestedRange>(aRange)}; 115 } 116 117 } // namespace detail 118 119 template <typename T, typename NestedRange> 120 auto Flatten(NestedRange&& aRange) -> decltype(auto) { 121 return detail::Flatten<T>(std::forward<NestedRange>(aRange)); 122 } 123 124 } // namespace mozilla::dom::quota 125 126 #endif