-
Notifications
You must be signed in to change notification settings - Fork 0
/
vgl_queue.hpp
192 lines (165 loc) · 3.9 KB
/
vgl_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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#ifndef VGL_QUEUE_HPP
#define VGL_QUEUE_HPP
#include "vgl_algorithm.hpp"
#include "vgl_assert.hpp"
#include "vgl_realloc.hpp"
#include "vgl_utility.hpp"
namespace vgl
{
/// Limited implementation of queue.
template<typename T> class queue
{
private:
/// Internal array.
T* m_data = nullptr;
/// Insertion location.
unsigned m_first = 0;
/// Number of active elements.
unsigned m_size = 0;
/// Array capacity.
unsigned m_capacity = 0;
private:
/// Deleted copy constructor.
queue(const queue&) = delete;
/// Deleted assignment.
queue& operator=(const queue&) = delete;
public:
/// Default constructor.
constexpr explicit queue() = default;
/// Destructor.
~queue()
{
for(unsigned ii = 0, jj = m_first; ii < m_size; ++ii)
{
m_data[jj].~T();
if(++jj >= m_capacity)
{
jj = 0;
}
}
array_delete(m_data);
}
private:
/// Return bounds-checked index.
///
/// Only works reliably if given parameter is less than capacity * 2.
///
/// \param op Index to check.
/// \return Bounds-checked index.
unsigned boundsCheck(unsigned op)
{
return (op >= m_capacity) ? (op - m_capacity) : op;
}
/// Grow if necessary.
///
/// Increases size by one.
///
/// \return Pointer to the end of sequence.
T* growCheck()
{
if(m_size >= m_capacity)
{
const unsigned DEFAULT_CAPACITY = 4u;
resizeInternal(max(m_capacity * 2u, DEFAULT_CAPACITY));
}
unsigned ins = boundsCheck(m_first + m_size);
++m_size;
return m_data + ins;
}
/// Internal resize.
///
/// \param cnt New size.
void resizeInternal(unsigned cnt)
{
T* old_data = m_data;
m_data = array_new(static_cast<T*>(nullptr), cnt);
for(unsigned ii = 0, jj = m_first; ii < m_size; ++ii)
{
m_data[ii] = move(old_data[jj]);
if(++jj >= m_capacity)
{
jj = 0;
}
}
array_delete(old_data);
m_first = 0;
m_capacity = cnt;
}
public:
/// Access first element of array.
///
/// \return First element.
constexpr T& front()
{
return m_data[m_first];
}
/// Access first element of array.
///
/// \return Last element.
constexpr const T& front() const
{
return m_data[m_first];
}
/// Access last element of array.
///
/// \return First element.
constexpr T& back()
{
unsigned bk = boundsCheck(m_first + m_size - 1);
return m_data[bk];
}
/// Access last element of array.
///
/// \return Last element.
constexpr const T& back() const
{
unsigned bk = boundsCheck(m_first + m_size - 1);
return m_data[bk];
}
/// Tell if the sequence is empty.
///
/// \return True if yes, false if no.
constexpr bool empty() const
{
return (m_size == 0);
}
/// Accessor.
///
/// \return Current size.
constexpr unsigned size() const
{
return m_size;
}
/// Remove element from front of queue.
void pop()
{
VGL_ASSERT(m_size > 0);
m_data[m_first].~T();
m_first = boundsCheck(m_first + 1);
--m_size;
}
/// Push into the end of queue.
///
/// \param op Element to push.
void push(const T& op)
{
new(growCheck()) T(op);
}
/// Push into the end of queue.
///
/// \param op Element to push.
void push(T&& op)
{
new(growCheck()) T(move(op));
}
/// Emplace an element into end of queue.
///
/// \param args Arguments.
/// \return Reference to newly emplaced object.
template<typename...Args> void emplace(Args&&...args)
{
new(growCheck()) T(args...);
}
};
}
#endif