FE 0.10.0
Header-only C++ frontend library
Loading...
Searching...
No Matches
ring.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstddef>
4
5#include <algorithm>
6#include <array>
7#include <initializer_list>
8
9#include <fe/assert.h>
10
11namespace fe {
12
13/// A ring buffer with @p N elements.
14template<class T, size_t N>
15class Ring {
16public:
17 /// @name Construction
18 ///@{
19 Ring(std::initializer_list<T> list) {
20 assert(list.size() == N);
21 std::copy(list.begin(), list.end(), array_.begin());
22 }
23 Ring() noexcept = default;
24 Ring(const Ring&) = default;
25 Ring(Ring&& other) noexcept
26 : Ring() {
27 swap(*this, other);
28 }
29 Ring& operator=(Ring other) noexcept { return swap(*this, other), *this; }
30 ///@}
31
32 /// @name Access
33 ///@{
34 T& front() { return array_[first_]; }
35 const T& front() const { return array_[first_]; }
36 T& operator[](size_t i) {
37 assert(i < N);
38 return array_[(first_ + i) % N];
39 }
40 const T& operator[](size_t i) const {
41 assert(i < N);
42 return array_[(first_ + i) % N];
43 }
44 ///@}
45
46 /// @name Modifiers
47 ///@{
48 void reset() { first_ = 0; }
49
50 /// Puts @p item into buffer.
51 /// @returns item that falls out.
52 T put(T item) {
53 auto res = array_[first_];
54 array_[first_] = item;
55 first_ = (first_ + 1) % N;
56 return res;
57 }
58 ///@}
59
60 friend void swap(Ring& r1, Ring& r2) noexcept {
61 using std::swap;
62 swap(r1.array_, r2.array_);
63 swap(r1.first_, r2.first_);
64 }
65
66private:
67 std::array<T, N> array_;
68 size_t first_ = 0;
69};
70
71/// Specialization if `N == 1` - doesn't need a ring.
72template<class T>
73class Ring<T, 1> {
74public:
75 /// @name Construction
76 ///@{
77 Ring(std::initializer_list<T> list)
78 : item_(*list.begin()) {}
79 Ring() = default; // no noexcept: we don't know whether T's default constructor throws
80 Ring(const Ring&) = default;
81 Ring(Ring&& other)
82 : Ring() {
83 swap(*this, other);
84 }
85 Ring& operator=(Ring other) noexcept { return swap(*this, other), *this; }
86 ///@}
87
88 /// @name Access
89 ///@{
90 T& front() { return item_; }
91 const T& front() const { return item_; }
92 T& operator[](size_t i) {
93 assert_unused(i == 0);
94 return item_;
95 }
96 const T& operator[](size_t i) const {
97 assert_unused(i == 0);
98 return item_;
99 }
100 ///@}
101
102 /// @name Modifiers
103 ///@{
104 void reset() {}
105 T put(T item) {
106 auto res = item_;
107 item_ = item;
108 return res;
109 }
110 ///@}
111
112 friend void swap(Ring& r1, Ring& r2) noexcept {
113 using std::swap;
114 swap(r1.item_, r2.item_);
115 }
116
117private:
118 T item_;
119};
120
121/// Specialization if `N == 2`; doesn't need a ring, we just copy.
122template<class T>
123class Ring<T, 2> {
124public:
125 /// @name Construction
126 ///@{
127 Ring(std::initializer_list<T> list) {
128 assert(list.size() == 2);
129 std::copy(list.begin(), list.end(), array_.begin());
130 }
131 Ring() noexcept = default;
132 Ring(const Ring&) = default;
133 Ring(Ring&& other) noexcept
134 : Ring() {
135 swap(*this, other);
136 }
137 Ring& operator=(Ring other) noexcept { return swap(*this, other), *this; }
138 ///@}
139
140 /// @name Access
141 ///@{
142 T& front() { return array_[0]; }
143 const T& front() const { return array_[0]; }
144 T& operator[](size_t i) {
145 assert_unused(i < 2);
146 return array_[i];
147 }
148 const T& operator[](size_t i) const {
149 assert_unused(i < 2);
150 return array_[i];
151 }
152 ///@}
153
154 /// @name Modifiers
155 ///@{
156 void reset() {}
157 T put(T item) {
158 auto res = array_[0];
159 array_[0] = array_[1];
160 array_[1] = item;
161 return res;
162 }
163 ///@}
164
165 friend void swap(Ring& r1, Ring& r2) noexcept {
166 using std::swap;
167 swap(r1.array_, r2.array_);
168 }
169
170private:
171 std::array<T, 2> array_;
172};
173
174} // namespace fe
#define assert_unused(x)
Definition assert.h:39
const T & front() const
Definition ring.h:91
Ring & operator=(Ring other) noexcept
Definition ring.h:85
Ring(const Ring &)=default
const T & operator[](size_t i) const
Definition ring.h:96
Ring(Ring &&other)
Definition ring.h:81
T & operator[](size_t i)
Definition ring.h:92
T put(T item)
Definition ring.h:105
T & front()
Definition ring.h:90
friend void swap(Ring &r1, Ring &r2) noexcept
Definition ring.h:112
Ring(std::initializer_list< T > list)
Definition ring.h:77
void reset()
Definition ring.h:104
T & front()
Definition ring.h:142
const T & front() const
Definition ring.h:143
const T & operator[](size_t i) const
Definition ring.h:148
Ring & operator=(Ring other) noexcept
Definition ring.h:137
Ring() noexcept=default
friend void swap(Ring &r1, Ring &r2) noexcept
Definition ring.h:165
void reset()
Definition ring.h:156
T & operator[](size_t i)
Definition ring.h:144
T put(T item)
Definition ring.h:157
Ring(std::initializer_list< T > list)
Definition ring.h:127
void reset()
Definition ring.h:48
Ring & operator=(Ring other) noexcept
Definition ring.h:29
const T & operator[](size_t i) const
Definition ring.h:40
Ring() noexcept=default
T put(T item)
Puts item into buffer.
Definition ring.h:52
friend void swap(Ring &r1, Ring &r2) noexcept
Definition ring.h:60
Ring(std::initializer_list< T > list)
Definition ring.h:19
T & front()
Definition ring.h:34
const T & front() const
Definition ring.h:35
T & operator[](size_t i)
Definition ring.h:36
Definition arena.h:13