1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H 10 #define RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H 11 12 #include <algorithm> 13 #include <cstddef> 14 15 enum class CtrChoice { Invalid, DefaultCtrAndInsert, BeginEndPair, FromRangeT, DirectCtr }; 16 17 enum class InserterChoice { Invalid, Insert, Emplace, PushBack, EmplaceBack }; 18 19 // Allows checking that `ranges::to` correctly follows the order of priority of different constructors -- e.g., if 20 // 3 constructors are available, the `from_range_t` constructor is chosen in favor of the constructor taking two 21 // iterators, etc. 22 template <class ElementType, CtrChoice Rank, InserterChoice Inserter = InserterChoice::Insert, bool CanReserve = false> 23 struct Container { 24 CtrChoice ctr_choice = CtrChoice::Invalid; 25 InserterChoice inserter_choice = InserterChoice::Invalid; 26 bool called_reserve = false; 27 28 int extra_arg1 = 0; 29 char extra_arg2 = 0; 30 31 using value_type = ElementType; 32 static constexpr int Capacity = 8; 33 int size_ = 0; 34 ElementType buffer_[Capacity] = {}; 35 36 // Case 1 -- construct directly from the range. 37 38 constexpr explicit Container(std::ranges::input_range auto&& in) 39 requires(Rank >= CtrChoice::DirectCtr) 40 : ctr_choice(CtrChoice::DirectCtr), size_(static_cast<int>(std::ranges::size(in))) { 41 std::ranges::copy(in, begin()); 42 } 43 44 // Check that `ranges::to` can also pass extra parameters. 45 constexpr explicit Container(std::ranges::input_range auto&& in, int arg1, char arg2) 46 requires(Rank >= CtrChoice::DirectCtr) 47 : Container(in) { 48 extra_arg1 = arg1; 49 extra_arg2 = arg2; 50 } 51 52 // Case 2 -- use `from_range_t` constructor. 53 54 constexpr Container(std::from_range_t, std::ranges::input_range auto&& in) 55 requires(Rank >= CtrChoice::FromRangeT) 56 : ctr_choice(CtrChoice::FromRangeT), size_(static_cast<int>(std::ranges::size(in))) { 57 std::ranges::copy(in, begin()); 58 } 59 60 constexpr Container(std::from_range_t, std::ranges::input_range auto&& in, int arg1, char arg2) 61 requires(Rank >= CtrChoice::FromRangeT) 62 : Container(std::from_range, in) { 63 extra_arg1 = arg1; 64 extra_arg2 = arg2; 65 } 66 67 // Case 3 -- use begin-end pair. 68 69 template <class Iter> 70 constexpr Container(Iter b, Iter e) 71 requires(Rank >= CtrChoice::BeginEndPair) 72 : ctr_choice(CtrChoice::BeginEndPair), size_(static_cast<int>(e - b)) { 73 std::ranges::copy(b, e, begin()); 74 } 75 76 template <class Iter> 77 constexpr Container(Iter b, Iter e, int arg1, char arg2) 78 requires(Rank >= CtrChoice::BeginEndPair) 79 : Container(b, e) { 80 extra_arg1 = arg1; 81 extra_arg2 = arg2; 82 } 83 84 // Case 4 -- default-construct and insert, reserving the size if possible. 85 86 constexpr Container() 87 requires(Rank >= CtrChoice::DefaultCtrAndInsert) 88 : ctr_choice(CtrChoice::DefaultCtrAndInsert) {} 89 90 constexpr Container(int arg1, char arg2) 91 requires(Rank >= CtrChoice::DefaultCtrAndInsert) 92 : ctr_choice(CtrChoice::DefaultCtrAndInsert), extra_arg1(arg1), extra_arg2(arg2) {} 93 94 constexpr ElementType* begin() { return buffer_; } 95 constexpr ElementType* end() { return buffer_ + size_; } 96 constexpr std::size_t size() const { return size_; } 97 98 template <class T> 99 constexpr void emplace_back(T val) 100 requires(Inserter >= InserterChoice::EmplaceBack) 101 { 102 inserter_choice = InserterChoice::EmplaceBack; 103 __push_back_impl(val); 104 } 105 106 template <class T> 107 constexpr void push_back(T val) 108 requires(Inserter >= InserterChoice::PushBack) 109 { 110 inserter_choice = InserterChoice::PushBack; 111 __push_back_impl(val); 112 } 113 114 template <class T> 115 constexpr void __push_back_impl(T val) { 116 buffer_[size_] = val; 117 ++size_; 118 } 119 120 template <class T> 121 constexpr ElementType* emplace(ElementType* where, T val) 122 requires(Inserter >= InserterChoice::Emplace) 123 { 124 inserter_choice = InserterChoice::Emplace; 125 return __insert_impl(where, val); 126 } 127 128 template <class T> 129 constexpr ElementType* insert(ElementType* where, T val) 130 requires(Inserter >= InserterChoice::Insert) 131 { 132 inserter_choice = InserterChoice::Insert; 133 return __insert_impl(where, val); 134 } 135 136 template <class T> 137 constexpr ElementType* __insert_impl(ElementType* where, T val) { 138 assert(size() + 1 <= Capacity); 139 std::shift_right(where, end(), 1); 140 *where = val; 141 ++size_; 142 return where; 143 } 144 145 constexpr void reserve(size_t) 146 requires CanReserve 147 { 148 called_reserve = true; 149 } 150 151 constexpr std::size_t capacity() const 152 requires CanReserve 153 { 154 return Capacity; 155 } 156 157 constexpr std::size_t max_size() const 158 requires CanReserve 159 { 160 return Capacity; 161 } 162 163 friend constexpr bool operator==(const Container&, const Container&) = default; 164 }; 165 166 #endif // RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H 167