167 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H10#define RANGES_RANGE_UTILITY_RANGE_UTILITY_CONV_CONTAINER_H11 12#include <algorithm>13#include <cstddef>14 15enum class CtrChoice { Invalid, DefaultCtrAndInsert, BeginEndPair, FromRangeT, DirectCtr };16 17enum 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., if20// 3 constructors are available, the `from_range_t` constructor is chosen in favor of the constructor taking two21// iterators, etc.22template <class ElementType, CtrChoice Rank, InserterChoice Inserter = InserterChoice::Insert, bool CanReserve = false>23struct 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 CanReserve147 {148 called_reserve = true;149 }150 151 constexpr std::size_t capacity() const152 requires CanReserve153 {154 return Capacity;155 }156 157 constexpr std::size_t max_size() const158 requires CanReserve159 {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_H167