@@ -24,30 +24,33 @@ class DynamicBuffer {
2424 DynamicBuffer () : _data(nullptr ), _len(0 ) {};
2525 explicit DynamicBuffer (size_t len) : _data(len ? reinterpret_cast <char *>(malloc(len)): nullptr), _len(_data ? len : 0 ) {};
2626 DynamicBuffer (const char * buf, size_t len) : DynamicBuffer(len) { if (_data) memcpy (_data, buf, len); };
27- explicit DynamicBuffer (const String& s) : DynamicBuffer(s.begin(), s.length()) {};
28- explicit DynamicBuffer (String&&); // Move string contents in to buffer if possible
29- DynamicBuffer (const SharedBuffer&);
30- DynamicBuffer (SharedBuffer&&);
27+
3128 ~DynamicBuffer () { clear (); };
3229
3330 // Move
3431 DynamicBuffer (DynamicBuffer&& d) : _data(d._data), _len(d._len) { d._data = nullptr ; d._len = 0 ; };
3532 DynamicBuffer& operator =(DynamicBuffer&& d) { std::swap (_data, d._data ); std::swap (_len, d._len ); return *this ; };
33+ DynamicBuffer (SharedBuffer&&); // Move data, leaving shared buffer empty
34+ explicit DynamicBuffer (String&&); // Move string contents in to buffer if possible
3635
3736 // Copy
3837 DynamicBuffer (const DynamicBuffer& d) : DynamicBuffer(d._data, d._len) {}; // copy
3938 DynamicBuffer& operator =(const DynamicBuffer& d) { *this = DynamicBuffer (d); return *this ; }; // use move to copy
40-
39+ DynamicBuffer (const SharedBuffer&); // Copy data
40+ explicit DynamicBuffer (const String& s) : DynamicBuffer(s.begin(), s.length()) {};
41+
4142 // Accessors
4243 char * data () const { return _data; };
4344 size_t size () const { return _len; };
45+ char & operator [](ptrdiff_t p) const { return *(_data + p); };
4446
4547 explicit operator bool () const { return (_data != nullptr ) && (_len > 0 ); }
4648
4749 // Release the buffer without freeing it
4850 char * release () { char * temp = _data; _data = nullptr ; _len = 0 ; return temp; }
4951
50- // TODO, if it ever matters - resizing
52+ // Resize the buffer. Returns new size on success, current size on failure.
53+ size_t resize (size_t );
5154};
5255
5356// Same interface as DynamicBuffer, but with shared_ptr semantics: buffer is held until last copy releases it.
@@ -67,6 +70,7 @@ class SharedBuffer {
6770
6871 char * data () const { return _buf ? _buf->data () : nullptr ; };
6972 size_t size () const { return _buf ? _buf->size () : 0U ; };
73+ char & operator [](ptrdiff_t p) const { return *(data () + p); };
7074 void clear () { _buf.reset (); };
7175
7276 explicit operator bool () const { return _buf && *_buf; };
@@ -150,3 +154,86 @@ class BufferListPrint : public Print {
150154typedef BufferListPrint<DynamicBufferList> DynamicBufferListPrint;
151155typedef BufferListPrint<SharedBufferList> SharedBufferListPrint;
152156
157+
158+ // Walkable buffer
159+ // A buffer class that permits "consuming" data from either end, adjusting data() and size() to match
160+ template <typename buffer_type>
161+ class Walkable
162+ {
163+ buffer_type _buf;
164+ size_t _left, _right;
165+
166+ public:
167+ Walkable () : _left(0 ), _right(0 ) {};
168+ explicit Walkable (size_t len) : _buf(len), _left(0 ), _right(0 ) {};
169+ Walkable (const char * buf, size_t len) : _buf(buf, len), _left(0 ), _right(0 ) {};
170+ Walkable (buffer_type&& buf) : _buf(std::move(buf)), _left(0 ), _right(0 ) {};
171+ explicit Walkable (const String& s) : _buf(s), _left(0 ), _right(0 ) {};
172+ explicit Walkable (String&& s) : _buf(std::move(s)), _left(0 ), _right(0 ) {};
173+
174+ // Accessors
175+ // Buffer interface
176+ char * data () const { return _buf.data () + _left; };
177+ size_t size () const { return _buf.size () - (_left + _right); };
178+ size_t capacity () const { return _buf.size (); }; // for similarity with STL types
179+ explicit operator bool () const { return (buffer_type::data () != nullptr ) && (size () > 0 ); }
180+ char & operator [](ptrdiff_t p) const { return *(data () + p); };
181+ void clear () { _buf.clear (); reset (); };
182+
183+ // Raw interface
184+ const buffer_type& buffer () const { return _buf; };
185+ size_t offset () const { return _left; }
186+ size_t roffset () const { return _right; }
187+
188+ // Modifiers
189+ void reset () { _left = _right = 0 ; }; // Reset the walking counters
190+ void advance (ptrdiff_t count) { // Consume some data from the left hand side
191+ if (count > 0 ) {
192+ _left = std::min (_left+count, _buf.size () - _right);
193+ } else {
194+ if (abs (count) <= _left) {
195+ _left += count;
196+ } else {
197+ _left = 0 ; // do not wrap
198+ }
199+ }
200+ }
201+ void radvance (ptrdiff_t count) { // Consume some data from the right hand side
202+ if (count > 0 ) {
203+ _right = std::min (_right+count, _buf.size () - _left);
204+ } else {
205+ if (abs (count) <= _right) {
206+ _right += count;
207+ } else {
208+ _right = 0 ; // do not wrap
209+ }
210+ }
211+ }
212+
213+ // Contract buffer to specified size
214+ size_t resize (size_t s) {
215+ auto bs = _buf.size () - _left;
216+ _right = s <= bs ? (bs - s) : 0U ;
217+ return size ();
218+ }
219+
220+ // Resize the underlying buffer storage, preserving contents
221+ // Returns new size on success, current size on failure.
222+ size_t reallocate (size_t s) {
223+ if (s <= size ()) {
224+ auto new_buf = buffer_type (data (), s);
225+ if (new_buf) {
226+ _buf = std::move (new_buf);
227+ reset ();
228+ }
229+ } else {
230+ auto new_buf = buffer_type (s);
231+ if (new_buf) {
232+ memcpy (new_buf.data (), data (), size ());
233+ _buf = std::move (new_buf);
234+ reset ();
235+ }
236+ }
237+ return _buf.size ();
238+ }
239+ };
0 commit comments