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,
85 GeneratorFunc&& generator);
89 T* NonEmptyData()
noexcept {
94 const T* NonEmptyData()
const noexcept {
100 std::size_t size_{0};
110template <
class GeneratorFunc>
114template <
class... Args>
115FixedArray<T>::
FixedArray(std::size_t size, Args&&... args) : size_(size) {
116 if (size_ == 0)
return;
117 storage_ = std::allocator<T>{}.allocate(size_);
119 auto* begin = data();
121 for (
auto* end = begin + size - 1; begin != end; ++begin) {
122 new (begin) T(args...);
124 new (begin) T(std::forward<Args>(args)...);
126 std::destroy(data(), begin);
127 std::allocator<T>{}.deallocate(storage_, size);
133template <
class GeneratorFunc>
134FixedArray<T>::FixedArray(impl::GenerateTag , std::size_t size,
135 GeneratorFunc&& generator)
137 if (size_ == 0)
return;
138 storage_ = std::allocator<T>{}.allocate(size_);
140 auto* our_begin = begin();
141 auto*
const our_end = end();
142 std::size_t index = 0;
145 for (; our_begin != our_end; ++our_begin) {
146 new (our_begin) T(generator(index));
150 std::destroy(begin(), our_begin);
151 std::allocator<T>{}.deallocate(storage_, size_);
157FixedArray<T>::FixedArray(FixedArray&& other)
noexcept
158 : storage_(std::exchange(other.storage_,
nullptr)),
159 size_(std::exchange(other.size_, 0)) {}
162FixedArray<T>& FixedArray<T>::operator=(FixedArray&& other)
noexcept {
163 std::swap(storage_, other.storage_);
164 std::swap(size_, other.size_);
169FixedArray<T>::~FixedArray() {
170 std::destroy(begin(), end());
171 std::allocator<T>{}.deallocate(storage_, size_);
174template <
class GeneratorFunc>
176 using ResultType = std::remove_reference_t<
177 std::invoke_result_t<GeneratorFunc&, std::size_t>>;
178 return FixedArray<ResultType>(impl::GenerateTag{}, size,
179 std::forward<GeneratorFunc>(generator));