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

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