11#include <userver/utils/assert.hpp>
13USERVER_NAMESPACE_BEGIN
19struct GenerateTag
final {
20 explicit GenerateTag() =
default;
33class FixedArray
final {
36 using const_iterator =
const T*;
42 template <
class... Args>
45 FixedArray(FixedArray&& other)
noexcept;
46 FixedArray& operator=(FixedArray&& other)
noexcept;
48 FixedArray(
const FixedArray&) =
delete;
49 FixedArray& operator=(
const FixedArray&) =
delete;
53 std::size_t size()
const noexcept {
return size_; }
54 bool empty()
const noexcept {
return size_ == 0; }
56 const T& operator[](std::size_t i)
const noexcept {
61 T& operator[](std::size_t i)
noexcept {
66 T& front()
noexcept {
return *NonEmptyData(); }
67 const T& front()
const noexcept {
return *NonEmptyData(); }
69 T& back()
noexcept {
return *(NonEmptyData() + size_ - 1); }
70 const T& back()
const noexcept {
return *(NonEmptyData() + size_ - 1); }
72 T* data()
noexcept {
return storage_; }
73 const T* data()
const noexcept {
return storage_; }
75 T* begin()
noexcept {
return data(); }
76 T* end()
noexcept {
return data() + size_; }
77 const T* begin()
const noexcept {
return data(); }
78 const T* end()
const noexcept {
return data() + size_; }
79 const T* cbegin()
const noexcept {
return data(); }
80 const T* cend()
const noexcept {
return data() + size_; }
83 template <
class GeneratorFunc>
84 FixedArray(impl::GenerateTag tag, std::size_t size, GeneratorFunc&& generator);
88 T* NonEmptyData()
noexcept {
93 const T* NonEmptyData()
const noexcept {
109template <
class GeneratorFunc>
113template <
class... Args>
114FixedArray<T>::
FixedArray(std::size_t size, Args&&... args) : size_(size) {
115 if (size_ == 0)
return;
116 storage_ = std::allocator<T>{}.allocate(size_);
118 auto* begin = data();
120 for (
auto* end = begin + size - 1; begin != end; ++begin) {
121 new (begin) T(args...);
123 new (begin) T(std::forward<Args>(args)...);
125 std::destroy(data(), begin);
126 std::allocator<T>{}.deallocate(storage_, size);
132template <
class GeneratorFunc>
133FixedArray<T>::FixedArray(impl::GenerateTag , std::size_t size, GeneratorFunc&& generator) : size_(size) {
134 if (size_ == 0)
return;
135 storage_ = std::allocator<T>{}.allocate(size_);
137 auto* our_begin = begin();
138 auto*
const our_end = end();
139 std::size_t index = 0;
142 for (; our_begin != our_end; ++our_begin) {
143 new (our_begin) T(generator(index));
147 std::destroy(begin(), our_begin);
148 std::allocator<T>{}.deallocate(storage_, size_);
154FixedArray<T>::FixedArray(FixedArray&& other)
noexcept
155 : storage_(std::exchange(other.storage_,
nullptr)), size_(std::exchange(other.size_, 0)) {}
158FixedArray<T>& FixedArray<T>::operator=(FixedArray&& other)
noexcept {
159 std::swap(storage_, other.storage_);
160 std::swap(size_, other.size_);
165FixedArray<T>::~FixedArray() {
166 std::destroy(begin(), end());
167 std::allocator<T>{}.deallocate(storage_, size_);
170template <
class GeneratorFunc>
172 using ResultType = std::remove_reference_t<std::invoke_result_t<GeneratorFunc&, std::size_t>>;
173 return FixedArray<ResultType>(impl::GenerateTag{}, size, std::forward<GeneratorFunc>(generator));