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