DynExp
Highly flexible laboratory automation for dynamically changing experiments.
Loading...
Searching...
No Matches
circularbuf.cpp
Go to the documentation of this file.
1// This file is part of DynExp.
2
3#include "stdafx.h"
4#include "circularbuf.h"
5
6namespace Util
7{
9 {
10 buffer.resize(size);
11
12 clear();
13 }
14
16 {
17 sync();
18
19 return !avail_get_count();
20 }
21
23 {
24 sync();
25
26 return avail_get_count();
27 }
28
29 size_t circularbuf::psize() const noexcept
30 {
31 return buffer.size();
32 }
33
34 circularbuf::pos_type circularbuf::gtellp() const noexcept
35 {
36 return gptr() - eback();
37 }
38
39 circularbuf::pos_type circularbuf::ptellp() const noexcept
40 {
41 return pptr() - pbase();
42 }
43
45 {
46 setp(buffer.data(), buffer.data() + buffer.size());
47 setg(buffer.data(), buffer.data(), buffer.data());
48
49 put_overflowed = false;
50 }
51
52 void circularbuf::resize(size_t size)
53 {
54 buffer.resize(size);
55
56 auto ppos = ptellp();
57 setp(buffer.data(), buffer.data() + buffer.size());
58
59 auto buffer_size = to_pos_type(buffer.size());
60 if (buffer_size > std::numeric_limits<int>::max())
61 throw std::overflow_error("Cannot convert a buffer size to int since this would cause an overflow in circularbuf::resize().");
62 pbump(ppos >= buffer_size ? buffer_size : ppos);
63
64 auto gpos = gtellp();
65 auto gsz = gsize();
66 setg(buffer.data(),
67 gpos >= buffer_size ? buffer.data() + buffer_size : buffer.data() + gpos,
68 gsz >= buffer.size() ? buffer.data() + buffer.size() : buffer.data() + gsz);
69 }
70
71 std::streamsize circularbuf::avail_get_count() const noexcept
72 {
73 return egptr() - eback();
74 }
75
76 circularbuf::int_type circularbuf::overflow(int_type c)
77 {
78 // Return eof if put buffer is empty or c is eof
79 if (!psize() || c == traits_type::eof())
80 return traits_type::eof();
81
82 // Restart from beginning if at buffer's end
83 if (pptr() == epptr())
84 setp(pbase(), epptr());
85
86 *pptr() = c;
87 pbump(1);
88
89 put_overflowed = true;
90 sync();
91
92 return int_type();
93 }
94
95 circularbuf::int_type circularbuf::underflow()
96 {
97 sync();
98
99 // Return eof if read buffer is empty
100 if (empty())
101 return traits_type::eof();
102
103 // Restart from beginning if at buffer's end
104 if (gptr() == egptr())
105 setg(eback(), eback(), egptr());
106
107 return traits_type::to_int_type(*gptr());
108 }
109
110 std::streamsize circularbuf::showmanyc()
111 {
112 // in_avail() returns egptr() - gptr() and if this is 0, showmanyc() is returned.
113 auto count = avail_get_count();
114
115 return count ? count : -1;
116 }
117
118 circularbuf::int_type circularbuf::pbackfail(int_type c)
119 {
120 sync();
121
122 // Return eof if buffer is empty
123 if (empty())
124 return traits_type::eof();
125
126 // At very beginning? Set to end, otherwise step back.
127 if (gptr() == eback())
128 setg(eback(), egptr() - 1, egptr());
129 else
130 gbump(-1);
131
132 // Replace character?
133 if (c != traits_type::eof())
134 *gptr() = c;
135
136 return traits_type::to_int_type(*gptr());
137 }
138
140 {
141 if (egptr() < (put_overflowed ? epptr() : pptr()))
142 setg(eback(), gptr(), put_overflowed ? epptr() : pptr());
143
144 put_overflowed = false;
145
146 return 0;
147 }
148
149 circularbuf::pos_type circularbuf::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which)
150 {
151 bool in = which & std::ios_base::in;
152 bool out = which & std::ios_base::out;
153 pos_type new_pos(pos_type(off_type(-1)));
154
155 if (in)
156 {
157 pos_type abs_pos_in = (dir == std::ios_base::end ? pos_type(avail_get_count()) :
158 (dir == std::ios_base::cur ? gtellp() : pos_type(0)));
159 if (!off)
160 return abs_pos_in;
161 if (avail_get_count())
162 abs_pos_in += std::abs(off % avail_get_count()) * (off >= 0 ? 1 : -1);
163 else
164 abs_pos_in += off;
165
166 // Check boundaries
167 if (abs_pos_in < 0 || avail_get_count() <= abs_pos_in)
168 abs_pos_in += avail_get_count() * (abs_pos_in < 0 ? 1 : -1);
169
170 new_pos = seekpos(abs_pos_in, std::ios_base::in);
171 }
172
173 // Only do something if there wasn't any error.
174 if (out && ((in && new_pos >= 0) || !in))
175 {
176 pos_type abs_pos_out = (dir == std::ios_base::end ? pos_type(buffer.size()) :
177 (dir == std::ios_base::cur ? ptellp() : pos_type(0)));
178 if (!off)
179 return abs_pos_out;
180 if (buffer.size())
181 abs_pos_out += std::abs(off % to_pos_type(buffer.size())) * (off >= 0 ? 1 : -1);
182 else
183 abs_pos_out += off;
184
185 // Check boundaries
186 if (abs_pos_out < 0 || to_pos_type(buffer.size()) <= abs_pos_out)
187 abs_pos_out += to_pos_type(buffer.size()) * (abs_pos_out < 0 ? 1 : -1);
188
189 auto new_pos_out = seekpos(abs_pos_out, std::ios_base::out);
190 if (new_pos_out < 0 || !in)
191 new_pos = new_pos_out;
192 }
193
194 if (in && out)
195 return pos_type(off_type(-1));
196 else
197 return new_pos;
198 }
199
200 circularbuf::pos_type circularbuf::seekpos(pos_type pos, std::ios_base::openmode which)
201 {
202 bool fail = false;
203
204 if (which & std::ios_base::in)
205 {
206 if (avail_get_count() <= pos || pos < 0)
207 fail = true;
208 else
209 setg(eback(), eback() + pos, egptr());
210 }
211
212 if (which & std::ios_base::out && !fail)
213 {
214 if (to_pos_type(buffer.size()) <= pos || pos < 0)
215 fail = true;
216 else
217 {
218 setp(pbase(), epptr());
219 pbump(pos);
220 }
221 }
222
223 return fail ? pos_type(off_type(-1)) : pos;
224 }
225}
Implements a circular stream buffer derived from std::streambuf to be used with standard library stre...
virtual int_type overflow(int_type c=traits_type::eof()) override
Refer to documentation of std::streambuf.
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which=std::ios_base::in|std::ios_base::out) override
Sets the position of the pointer(s) specified by which to the absolute position pos.
bool put_overflowed
Indicates wheter an overflow occurred writing to the buffer. If this was the case,...
circularbuf(size_t size)
Constructs a new circularbuf instance with a buffer of size size. The put area will span the entire b...
pos_type gtellp() const noexcept
Indicates the get pointer's position within the get area.
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which=std::ios_base::in|std::ios_base::out) override
Sets the position of the pointer(s) specified by which to the position pos relative to dir....
std::streamsize avail_get_count() const noexcept
Returns the amount of characters available to be read from the current get pointer position to the ge...
void resize(size_t size)
Resizes the size of buffer to size. The put area will span the entire buffer. If the buffer is enlarg...
size_t gsize()
Returns the size of the get area. Not const since sync() needs to be called to get correct size after...
void clear()
Resets the put areas to the entire area of buffer. The get area will be empty. The get and put pointe...
virtual int_type underflow() override
Refer to documentation of std::streambuf.
virtual int_type pbackfail(int_type c=traits_type::eof()) override
Refer to documentation of std::streambuf.
size_t psize() const noexcept
Returns the size of the put area.
pos_type to_pos_type(const T value)
Converts an unsigned, integral number type to pos_type.
bool empty()
Indicates whether characters can be read from the get area. Not const since sync() needs to be called...
virtual std::streamsize showmanyc() override
Refer to documentation of std::streambuf.
pos_type ptellp() const noexcept
Indicates the put pointer's position within the put area.
std::vector< CharT > buffer
The buffer itself.
virtual int sync() override
Expands the get area to the size of the put area. Resets put_overflowed.
DynExp's Util namespace contains commonly used functions and templates as well as extensions to Qt an...
Accumulates include statements to provide a precompiled header.