DynExp
Highly flexible laboratory automation for dynamically changing experiments.
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 
6 namespace 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.
Definition: circularbuf.cpp:76
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,...
Definition: circularbuf.h:161
circularbuf(size_t size)
Constructs a new circularbuf instance with a buffer of size size. The put area will span the entire b...
Definition: circularbuf.cpp:8
pos_type gtellp() const noexcept
Indicates the get pointer's position within the get area.
Definition: circularbuf.cpp:34
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...
Definition: circularbuf.cpp:71
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...
Definition: circularbuf.cpp:52
size_t gsize()
Returns the size of the get area. Not const since sync() needs to be called to get correct size after...
Definition: circularbuf.cpp:22
void clear()
Resets the put areas to the entire area of buffer. The get area will be empty. The get and put pointe...
Definition: circularbuf.cpp:44
virtual int_type underflow() override
Refer to documentation of std::streambuf.
Definition: circularbuf.cpp:95
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.
Definition: circularbuf.cpp:29
pos_type to_pos_type(const T value)
Converts an unsigned, integral number type to pos_type.
Definition: circularbuf.h:143
bool empty()
Indicates whether characters can be read from the get area. Not const since sync() needs to be called...
Definition: circularbuf.cpp:15
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.
Definition: circularbuf.cpp:39
std::vector< CharT > buffer
The buffer itself.
Definition: circularbuf.h:154
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...
Definition: circularbuf.cpp:7
Accumulates include statements to provide a precompiled header.