9#include "int_arith.hpp"
19namespace tcspc::internal {
32template <
typename T>
class vector_queue {
40 using alloctraits = std::allocator_traits<std::allocator<T>>;
42 [[nodiscard]]
constexpr auto is_full() const noexcept ->
bool {
43 return ptr ==
nullptr || tail + 1 == head ||
44 (tail + 1 == endptr && head == ptr);
47 static auto compute_enlarged_cap(std::size_t oldcap) -> std::size_t {
48 auto alloc = std::allocator<T>();
49 auto const max_size = alloctraits::max_size(alloc);
50 if (oldcap == max_size)
51 throw std::bad_alloc();
54 std::size_t newcap = oldcap / 2 * 3;
55 if (newcap < oldcap || newcap > max_size)
61 std::size_t
const siz = size();
62 std::size_t
const newcap =
63 compute_enlarged_cap(as_unsigned(std::distance(ptr, endptr)));
64 auto alloc = std::allocator<T>();
65 auto const dtor = [&](T &v) { alloctraits::destroy(alloc, &v); };
67 T *
const newptr = alloctraits::allocate(alloc, newcap);
70 std::uninitialized_move(head, endptr, newptr);
71 std::uninitialized_move(ptr, tail,
72 newptr + std::distance(head, endptr));
73 std::for_each(head, endptr, dtor);
74 std::for_each(ptr, tail, dtor);
76 std::uninitialized_move(head, tail, newptr);
77 std::for_each(head, tail, dtor);
79 alloctraits::deallocate(alloc, ptr,
80 as_unsigned(std::distance(ptr, endptr)));
83 endptr = newptr + newcap;
90 auto alloc = std::allocator<T>();
91 auto const dtor = [&](T &v) { alloctraits::destroy(alloc, &v); };
94 std::for_each(head, endptr, dtor);
95 std::for_each(ptr, tail, dtor);
97 std::for_each(head, tail, dtor);
100 alloctraits::deallocate(alloc, ptr,
101 as_unsigned(std::distance(ptr, endptr)));
104 vector_queue() noexcept
105 : ptr(
nullptr), endptr(
nullptr), head(
nullptr), tail(
nullptr) {}
107 vector_queue(vector_queue
const &other) {
108 std::size_t
const cap = other.size() > 0 ? other.size() + 1 : 0;
110 auto alloc = std::allocator<T>();
111 ptr = alloctraits::allocate(alloc, cap);
112 if (other.head > other.tail) {
113 std::uninitialized_copy(other.head, other.endptr, ptr);
114 std::uninitialized_copy(
115 other.ptr, other.tail,
116 ptr + std::distance(other.head, other.endptr));
118 std::uninitialized_copy(other.head, other.tail, ptr);
125 tail = ptr + other.size();
128 vector_queue(vector_queue &&other) noexcept
129 : ptr(std::exchange(other.ptr,
nullptr)),
130 endptr(std::exchange(other.endptr,
nullptr)),
131 head(std::exchange(other.head,
nullptr)),
132 tail(std::exchange(other.tail,
nullptr)) {}
134 auto operator=(vector_queue
const &rhs) -> vector_queue & {
140 auto operator=(vector_queue &&rhs)
noexcept -> vector_queue & {
141 vector_queue t(std::move(rhs));
146 [[nodiscard]]
constexpr auto empty() const noexcept ->
bool {
150 [[nodiscard]]
constexpr auto size() const noexcept -> std::
size_t {
152 return as_unsigned(std::distance(head, endptr) +
153 std::distance(ptr, tail));
154 return as_unsigned(std::distance(head, tail));
157 auto front() -> T & {
158 assert(head != tail);
162 auto front() const -> T const & {
163 assert(head != tail);
168 assert(head != tail);
170 return *(endptr - 1);
174 auto back() const -> T const & {
175 assert(head != tail);
177 return *(endptr - 1);
182 assert(head != tail);
183 auto alloc = std::allocator<T>();
184 alloctraits::destroy(alloc, head);
190 void push(T
const &value) {
193 auto alloc = std::allocator<T>();
194 alloctraits::construct(alloc, tail, value);
200 void push(T &&value) {
203 auto alloc = std::allocator<T>();
204 alloctraits::construct(alloc, tail, std::move(value));
210 void swap(vector_queue &other)
noexcept {
212 swap(ptr, other.ptr);
213 swap(endptr, other.endptr);
214 swap(head, other.head);
215 swap(tail, other.tail);
219 template <
typename F>
220 void for_each(F func)
noexcept(
noexcept(func(std::declval<T &>()))) {
222 std::for_each(head, tail, func);
224 std::for_each(head, endptr, func);
225 std::for_each(ptr, tail, func);
229 template <
typename F>
230 void for_each(F func)
const noexcept(
noexcept(func(std::declval<T &>()))) {
232 std::for_each(head, tail, func);
234 std::for_each(head, endptr, func);
235 std::for_each(ptr, tail, func);