1//
2// Buffer.h
3//
4// Library: Foundation
5// Package: Core
6// Module: Buffer
7//
8// Definition of the Buffer class.
9//
10// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_Buffer_INCLUDED
18#define Foundation_Buffer_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/Exception.h"
23#include <cstring>
24#include <cstddef>
25
26
27namespace Poco {
28
29
30template <class T>
31class Buffer
32 /// A buffer class that allocates a buffer of a given type and size
33 /// in the constructor and deallocates the buffer in the destructor.
34 ///
35 /// This class is useful everywhere where a temporary buffer
36 /// is needed.
37{
38public:
39 Buffer(std::size_t length):
40 _capacity(length),
41 _used(length),
42 _ptr(0),
43 _ownMem(true)
44 /// Creates and allocates the Buffer.
45 {
46 if (length > 0)
47 {
48 _ptr = new T[length];
49 }
50 }
51
52 Buffer(T* pMem, std::size_t length):
53 _capacity(length),
54 _used(length),
55 _ptr(pMem),
56 _ownMem(false)
57 /// Creates the Buffer. Length argument specifies the length
58 /// of the supplied memory pointed to by pMem in the number
59 /// of elements of type T. Supplied pointer is considered
60 /// blank and not owned by Buffer, so in this case Buffer
61 /// only acts as a wrapper around externally supplied
62 /// (and lifetime-managed) memory.
63 {
64 }
65
66 Buffer(const T* pMem, std::size_t length):
67 _capacity(length),
68 _used(length),
69 _ptr(0),
70 _ownMem(true)
71 /// Creates and allocates the Buffer; copies the contents of
72 /// the supplied memory into the buffer. Length argument specifies
73 /// the length of the supplied memory pointed to by pMem in the
74 /// number of elements of type T.
75 {
76 if (_capacity > 0)
77 {
78 _ptr = new T[_capacity];
79 std::memcpy(_ptr, pMem, _used * sizeof(T));
80 }
81 }
82
83 Buffer(const Buffer& other):
84 /// Copy constructor.
85 _capacity(other._used),
86 _used(other._used),
87 _ptr(0),
88 _ownMem(true)
89 {
90 if (_used)
91 {
92 _ptr = new T[_used];
93 std::memcpy(_ptr, other._ptr, _used * sizeof(T));
94 }
95 }
96
97 Buffer& operator = (const Buffer& other)
98 /// Assignment operator.
99 {
100 if (this != &other)
101 {
102 Buffer tmp(other);
103 swap(tmp);
104 }
105
106 return *this;
107 }
108
109 Buffer(Buffer&& other) :
110 /// Copy constructor.
111 _capacity(other._capacity),
112 _used(other._used),
113 _ptr(other._ptr),
114 _ownMem(other._ownMem)
115 {
116 other._capacity = 0;
117 other._used = 0;
118 other._ownMem = false;
119 other._ptr = nullptr;
120 }
121
122 Buffer& operator =(Buffer&& other)
123 /// Assignment operator.
124 {
125 if (this != &other)
126 {
127 _capacity = other._capacity;
128 _used = other._used;
129 _ptr = other._ptr;
130 _ownMem = other._ownMem;
131
132 other._capacity = 0;
133 other._used = 0;
134 other._ownMem = false;
135 other._ptr = nullptr;
136 }
137
138 return *this;
139 }
140
141 ~Buffer()
142 /// Destroys the Buffer.
143 {
144 if (_ownMem) delete [] _ptr;
145 }
146
147 void resize(std::size_t newCapacity, bool preserveContent = true)
148 /// Resizes the buffer capacity and size. If preserveContent is true,
149 /// the content of the old buffer is copied over to the
150 /// new buffer. The new capacity can be larger or smaller than
151 /// the current one; if it is smaller, capacity will remain intact.
152 /// Size will always be set to the new capacity.
153 ///
154 /// Buffers only wrapping externally owned storage can not be
155 /// resized. If resize is attempted on those, IllegalAccessException
156 /// is thrown.
157 {
158 if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage.");
159
160 if (newCapacity > _capacity)
161 {
162 T* ptr = new T[newCapacity];
163 if (preserveContent)
164 {
165 std::memcpy(ptr, _ptr, _used * sizeof(T));
166 }
167 delete [] _ptr;
168 _ptr = ptr;
169 _capacity = newCapacity;
170 }
171
172 _used = newCapacity;
173 }
174
175 void setCapacity(std::size_t newCapacity, bool preserveContent = true)
176 /// Sets the buffer capacity. If preserveContent is true,
177 /// the content of the old buffer is copied over to the
178 /// new buffer. The new capacity can be larger or smaller than
179 /// the current one; size will be set to the new capacity only if
180 /// new capacity is smaller than the current size, otherwise it will
181 /// remain intact.
182 ///
183 /// Buffers only wrapping externally owned storage can not be
184 /// resized. If resize is attempted on those, IllegalAccessException
185 /// is thrown.
186 {
187 if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage.");
188
189 if (newCapacity != _capacity)
190 {
191 T* ptr = 0;
192 if (newCapacity > 0)
193 {
194 ptr = new T[newCapacity];
195 if (preserveContent)
196 {
197 std::size_t newSz = _used < newCapacity ? _used : newCapacity;
198 std::memcpy(ptr, _ptr, newSz * sizeof(T));
199 }
200 }
201 delete [] _ptr;
202 _ptr = ptr;
203 _capacity = newCapacity;
204
205 if (newCapacity < _used) _used = newCapacity;
206 }
207 }
208
209 void assign(const T* buf, std::size_t sz)
210 /// Assigns the argument buffer to this buffer.
211 /// If necessary, resizes the buffer.
212 {
213 if (0 == sz) return;
214 if (sz > _capacity) resize(sz, false);
215 std::memcpy(_ptr, buf, sz * sizeof(T));
216 _used = sz;
217 }
218
219 void append(const T* buf, std::size_t sz)
220 /// Resizes this buffer and appends the argument buffer.
221 {
222 if (0 == sz) return;
223 resize(_used + sz, true);
224 std::memcpy(_ptr + _used - sz, buf, sz * sizeof(T));
225 }
226
227 void append(T val)
228 /// Resizes this buffer by one element and appends the argument value.
229 {
230 resize(_used + 1, true);
231 _ptr[_used - 1] = val;
232 }
233
234 void append(const Buffer& buf)
235 /// Resizes this buffer and appends the argument buffer.
236 {
237 append(buf.begin(), buf.size());
238 }
239
240 std::size_t capacity() const
241 /// Returns the allocated memory size in elements.
242 {
243 return _capacity;
244 }
245
246 std::size_t capacityBytes() const
247 /// Returns the allocated memory size in bytes.
248 {
249 return _capacity * sizeof(T);
250 }
251
252 void swap(Buffer& other)
253 /// Swaps the buffer with another one.
254 {
255 using std::swap;
256
257 swap(_ptr, other._ptr);
258 swap(_capacity, other._capacity);
259 swap(_used, other._used);
260 swap(_ownMem, other._ownMem);
261 }
262
263 bool operator == (const Buffer& other) const
264 /// Compare operator.
265 {
266 if (this != &other)
267 {
268 if (_used == other._used)
269 {
270 if (std::memcmp(_ptr, other._ptr, _used * sizeof(T)) == 0)
271 {
272 return true;
273 }
274 }
275 return false;
276 }
277
278 return true;
279 }
280
281 bool operator != (const Buffer& other) const
282 /// Compare operator.
283 {
284 return !(*this == other);
285 }
286
287 void clear()
288 /// Sets the contents of the buffer to zero.
289 {
290 std::memset(_ptr, 0, _used * sizeof(T));
291 }
292
293 std::size_t size() const
294 /// Returns the used size of the buffer in elements.
295 {
296 return _used;
297 }
298
299 std::size_t sizeBytes() const
300 /// Returns the used size of the buffer in bytes.
301 {
302 return _used * sizeof(T);
303 }
304
305 T* begin()
306 /// Returns a pointer to the beginning of the buffer.
307 {
308 return _ptr;
309 }
310
311 const T* begin() const
312 /// Returns a pointer to the beginning of the buffer.
313 {
314 return _ptr;
315 }
316
317 T* end()
318 /// Returns a pointer to end of the buffer.
319 {
320 return _ptr + _used;
321 }
322
323 const T* end() const
324 /// Returns a pointer to the end of the buffer.
325 {
326 return _ptr + _used;
327 }
328
329 bool empty() const
330 /// Return true if buffer is empty.
331 {
332 return 0 == _used;
333 }
334
335 T& operator [] (std::size_t index)
336 {
337 poco_assert (index < _used);
338
339 return _ptr[index];
340 }
341
342 const T& operator [] (std::size_t index) const
343 {
344 poco_assert (index < _used);
345
346 return _ptr[index];
347 }
348
349private:
350 Buffer();
351
352 std::size_t _capacity;
353 std::size_t _used;
354 T* _ptr;
355 bool _ownMem;
356};
357
358
359} // namespace Poco
360
361
362#endif // Foundation_Buffer_INCLUDED
363