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
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., if
20// 3 constructors are available, the `from_range_t` constructor is chosen in favor of the constructor taking two
21// 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 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

source code of libcxx/test/std/ranges/range.utility/range.utility.conv/container.h