-
Notifications
You must be signed in to change notification settings - Fork 6
/
cx_queue.hpp
115 lines (102 loc) · 3.26 KB
/
cx_queue.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#pragma once
#include <stdx/compiler.hpp>
#include <stdx/iterator.hpp>
#include <stdx/panic.hpp>
#include <array>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
namespace stdx {
inline namespace v1 {
struct unsafe_overflow_policy {
template <typename... Args> constexpr static auto check_push(Args &&...) {}
template <typename... Args> constexpr static auto check_pop(Args &&...) {}
};
struct safe_overflow_policy {
constexpr static auto check_push(std::size_t size, std::size_t capacity) {
if (size >= capacity) {
STDX_PANIC("cx_queue overflow!");
}
}
constexpr static auto check_pop(std::size_t size) {
if (size <= 0) {
STDX_PANIC("cx_queue underflow!");
}
}
};
template <typename T, std::size_t N,
typename OverflowPolicy = safe_overflow_policy>
class cx_queue {
std::array<T, N> storage{};
std::size_t push_index{N - 1};
std::size_t pop_index{};
std::size_t current_size{};
public:
using value_type = T;
using size_type = std::size_t;
using reference = value_type &;
using const_reference = value_type const &;
[[nodiscard]] constexpr auto size() const -> size_type {
return current_size;
}
constexpr static std::integral_constant<size_type, N> capacity{};
[[nodiscard]] constexpr auto full() const -> bool {
return current_size == N;
}
[[nodiscard]] constexpr auto empty() const -> bool {
return current_size == 0u;
}
constexpr auto clear() -> void {
pop_index = 0;
push_index = N - 1;
current_size = 0;
}
[[nodiscard]] constexpr auto front() & LIFETIMEBOUND -> reference {
OverflowPolicy::check_pop(current_size);
return storage[pop_index];
}
[[nodiscard]] constexpr auto front() const
& LIFETIMEBOUND -> const_reference {
OverflowPolicy::check_pop(current_size);
return storage[pop_index];
}
[[nodiscard]] constexpr auto back() & LIFETIMEBOUND -> reference {
OverflowPolicy::check_pop(current_size);
return storage[push_index];
}
[[nodiscard]] constexpr auto back() const
& LIFETIMEBOUND -> const_reference {
OverflowPolicy::check_pop(current_size);
return storage[push_index];
}
constexpr auto push(value_type const &value) LIFETIMEBOUND -> reference {
OverflowPolicy::check_push(current_size, N);
if (++push_index == N) {
push_index = 0;
}
++current_size;
return storage[push_index] = value;
}
constexpr auto push(value_type &&value) LIFETIMEBOUND -> reference {
OverflowPolicy::check_push(current_size, N);
if (++push_index == N) {
push_index = 0;
}
++current_size;
return storage[push_index] = std::move(value);
}
[[nodiscard]] constexpr auto pop() -> value_type {
OverflowPolicy::check_pop(current_size);
auto entry = std::move(storage[pop_index++]);
if (pop_index == N) {
pop_index = 0;
}
--current_size;
return entry;
}
};
template <typename T, std::size_t N, typename OP>
constexpr auto ct_capacity_v<cx_queue<T, N, OP>> = N;
} // namespace v1
} // namespace stdx