144 lines
4.4 KiB
C++
144 lines
4.4 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|