/src/poco/Foundation/include/Poco/Buffer.h
Line | Count | Source |
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 | | |
27 | | namespace Poco { |
28 | | |
29 | | |
30 | | template <class T> |
31 | | class 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 | | /// |
38 | | /// Note: A Buffer has both a size and a capacity, similar to |
39 | | /// std::vector and std::string. However, upon creation of the |
40 | | /// Buffer, the size always equals the capacity (provided via the |
41 | | /// length argument of the constructor), as the Buffer is meant |
42 | | /// to be filled by directly writing to its contents, |
43 | | /// i.e., by passing the pointer to the first element |
44 | | /// of the buffer obtained via begin() to a function expecting |
45 | | /// a pointer to a buffer. |
46 | | /// |
47 | | /// Therefore, calling append() on a newly created Buffer will |
48 | | /// always expand the buffer size and capacity. |
49 | | /// If you need to create a Buffer and want to write data to it |
50 | | /// by calling append(), the correct steps are to first create |
51 | | /// the Buffer, then call resize(0), and then call append(). |
52 | | { |
53 | | public: |
54 | | Buffer(std::size_t length): |
55 | 389k | _capacity(length), |
56 | 389k | _used(length), |
57 | 389k | _ptr(nullptr), |
58 | 389k | _ownMem(true) |
59 | | /// Creates and allocates the Buffer. |
60 | 389k | { |
61 | 389k | if (length > 0) |
62 | 389k | { |
63 | 389k | _ptr = new T[length]; |
64 | 389k | } |
65 | 389k | } Poco::Buffer<char>::Buffer(unsigned long) Line | Count | Source | 55 | 389k | _capacity(length), | 56 | 389k | _used(length), | 57 | 389k | _ptr(nullptr), | 58 | 389k | _ownMem(true) | 59 | | /// Creates and allocates the Buffer. | 60 | 389k | { | 61 | 389k | if (length > 0) | 62 | 389k | { | 63 | 389k | _ptr = new T[length]; | 64 | 389k | } | 65 | 389k | } |
Unexecuted instantiation: Poco::Buffer<int>::Buffer(unsigned long) |
66 | | |
67 | | Buffer(T* pMem, std::size_t length): |
68 | | _capacity(length), |
69 | | _used(length), |
70 | | _ptr(pMem), |
71 | | _ownMem(false) |
72 | | /// Creates the Buffer. Length argument specifies the length |
73 | | /// of the supplied memory pointed to by pMem in the number |
74 | | /// of elements of type T. Supplied pointer is considered |
75 | | /// blank and not owned by Buffer, so in this case Buffer |
76 | | /// only acts as a wrapper around externally supplied |
77 | | /// (and lifetime-managed) memory. |
78 | | { |
79 | | } |
80 | | |
81 | | Buffer(const T* pMem, std::size_t length): |
82 | | _capacity(length), |
83 | | _used(length), |
84 | | _ptr(nullptr), |
85 | | _ownMem(true) |
86 | | /// Creates and allocates the Buffer; copies the contents of |
87 | | /// the supplied memory into the buffer. Length argument specifies |
88 | | /// the length of the supplied memory pointed to by pMem in the |
89 | | /// number of elements of type T. |
90 | | { |
91 | | if (_capacity > 0) |
92 | | { |
93 | | _ptr = new T[_capacity]; |
94 | | std::memcpy(_ptr, pMem, _used * sizeof(T)); |
95 | | } |
96 | | } |
97 | | |
98 | | Buffer(const Buffer& other): |
99 | | /// Copy constructor. |
100 | | _capacity(other._used), |
101 | | _used(other._used), |
102 | | _ptr(nullptr), |
103 | | _ownMem(true) |
104 | | { |
105 | | if (_used) |
106 | | { |
107 | | _ptr = new T[_used]; |
108 | | std::memcpy(_ptr, other._ptr, _used * sizeof(T)); |
109 | | } |
110 | | } |
111 | | |
112 | | Buffer(Buffer&& other) noexcept: |
113 | | /// Move constructor. |
114 | | _capacity(other._capacity), |
115 | | _used(other._used), |
116 | | _ptr(other._ptr), |
117 | | _ownMem(other._ownMem) |
118 | | { |
119 | | other._capacity = 0; |
120 | | other._used = 0; |
121 | | other._ownMem = false; |
122 | | other._ptr = nullptr; |
123 | | } |
124 | | |
125 | | Buffer& operator = (const Buffer& other) |
126 | | /// Assignment operator. |
127 | | { |
128 | | if (this != &other) |
129 | | { |
130 | | Buffer tmp(other); |
131 | | swap(tmp); |
132 | | } |
133 | | |
134 | | return *this; |
135 | | } |
136 | | |
137 | | Buffer& operator = (Buffer&& other) noexcept |
138 | | /// Move assignment operator. |
139 | | { |
140 | | if (_ownMem) delete [] _ptr; |
141 | | |
142 | | _capacity = other._capacity; |
143 | | _used = other._used; |
144 | | _ptr = other._ptr; |
145 | | _ownMem = other._ownMem; |
146 | | |
147 | | other._capacity = 0; |
148 | | other._used = 0; |
149 | | other._ownMem = false; |
150 | | other._ptr = nullptr; |
151 | | |
152 | | return *this; |
153 | | } |
154 | | |
155 | | ~Buffer() |
156 | | /// Destroys the Buffer. |
157 | 389k | { |
158 | 389k | if (_ownMem) delete [] _ptr; |
159 | 389k | } Poco::Buffer<char>::~Buffer() Line | Count | Source | 157 | 389k | { | 158 | 389k | if (_ownMem) delete [] _ptr; | 159 | 389k | } |
Unexecuted instantiation: Poco::Buffer<int>::~Buffer() |
160 | | |
161 | | Buffer() = delete; |
162 | | |
163 | | void resize(std::size_t newCapacity, bool preserveContent = true) |
164 | | /// Resizes the buffer capacity and size. If preserveContent is true, |
165 | | /// the content of the old buffer is copied over to the |
166 | | /// new buffer. The new capacity can be larger or smaller than |
167 | | /// the current one; if it is smaller, capacity will remain intact. |
168 | | /// Size will always be set to the new capacity. |
169 | | /// |
170 | | /// Buffers only wrapping externally owned storage can not be |
171 | | /// resized. If resize is attempted on those, IllegalAccessException |
172 | | /// is thrown. |
173 | | { |
174 | | if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage."); |
175 | | |
176 | | if (newCapacity > _capacity) |
177 | | { |
178 | | T* ptr = new T[newCapacity]; |
179 | | if (preserveContent && _ptr) |
180 | | { |
181 | | std::memcpy(ptr, _ptr, _used * sizeof(T)); |
182 | | } |
183 | | delete [] _ptr; |
184 | | _ptr = ptr; |
185 | | _capacity = newCapacity; |
186 | | } |
187 | | |
188 | | _used = newCapacity; |
189 | | } |
190 | | |
191 | | void setCapacity(std::size_t newCapacity, bool preserveContent = true) |
192 | | /// Sets the buffer capacity. If preserveContent is true, |
193 | | /// the content of the old buffer is copied over to the |
194 | | /// new buffer. The new capacity can be larger or smaller than |
195 | | /// the current one; size will be set to the new capacity only if |
196 | | /// new capacity is smaller than the current size, otherwise it will |
197 | | /// remain intact. |
198 | | /// |
199 | | /// Buffers only wrapping externally owned storage can not be |
200 | | /// resized. If resize is attempted on those, IllegalAccessException |
201 | | /// is thrown. |
202 | | { |
203 | | if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage."); |
204 | | |
205 | | if (newCapacity != _capacity) |
206 | | { |
207 | | T* ptr = nullptr; |
208 | | if (newCapacity > 0) |
209 | | { |
210 | | ptr = new T[newCapacity]; |
211 | | if (preserveContent && _ptr) |
212 | | { |
213 | | std::size_t newSz = _used < newCapacity ? _used : newCapacity; |
214 | | std::memcpy(ptr, _ptr, newSz * sizeof(T)); |
215 | | } |
216 | | } |
217 | | delete [] _ptr; |
218 | | _ptr = ptr; |
219 | | _capacity = newCapacity; |
220 | | |
221 | | if (newCapacity < _used) _used = newCapacity; |
222 | | } |
223 | | } |
224 | | |
225 | | void assign(const T* buf, std::size_t sz) |
226 | | /// Assigns the argument buffer to this buffer. |
227 | | /// If necessary, resizes the buffer. |
228 | | { |
229 | | if (0 == sz) return; |
230 | | if (sz > _capacity) resize(sz, false); |
231 | | std::memcpy(_ptr, buf, sz * sizeof(T)); |
232 | | _used = sz; |
233 | | } |
234 | | |
235 | | void append(const T* buf, std::size_t sz) |
236 | | /// Resizes this buffer and appends the argument buffer. |
237 | | { |
238 | | if (0 == sz) return; |
239 | | resize(_used + sz, true); |
240 | | std::memcpy(_ptr + _used - sz, buf, sz * sizeof(T)); |
241 | | } |
242 | | |
243 | | void append(T val) |
244 | | /// Resizes this buffer by one element and appends the argument value. |
245 | | { |
246 | | resize(_used + 1, true); |
247 | | _ptr[_used - 1] = val; |
248 | | } |
249 | | |
250 | | void append(const Buffer& buf) |
251 | | /// Resizes this buffer and appends the argument buffer. |
252 | | { |
253 | | append(buf.begin(), buf.size()); |
254 | | } |
255 | | |
256 | | std::size_t capacity() const |
257 | | /// Returns the allocated memory size in elements. |
258 | | { |
259 | | return _capacity; |
260 | | } |
261 | | |
262 | | std::size_t capacityBytes() const |
263 | | /// Returns the allocated memory size in bytes. |
264 | | { |
265 | | return _capacity * sizeof(T); |
266 | | } |
267 | | |
268 | | void swap(Buffer& other) noexcept |
269 | | /// Swaps the buffer with another one. |
270 | | { |
271 | | using std::swap; |
272 | | |
273 | | swap(_ptr, other._ptr); |
274 | | swap(_capacity, other._capacity); |
275 | | swap(_used, other._used); |
276 | | swap(_ownMem, other._ownMem); |
277 | | } |
278 | | |
279 | | bool operator == (const Buffer& other) const |
280 | | /// Compare operator. |
281 | | { |
282 | | if (this != &other) |
283 | | { |
284 | | if (_used == other._used) |
285 | | { |
286 | | if (_ptr && other._ptr && std::memcmp(_ptr, other._ptr, _used * sizeof(T)) == 0) |
287 | | { |
288 | | return true; |
289 | | } |
290 | | else return _used == 0; |
291 | | } |
292 | | return false; |
293 | | } |
294 | | |
295 | | return true; |
296 | | } |
297 | | |
298 | | bool operator != (const Buffer& other) const |
299 | | /// Compare operator. |
300 | | { |
301 | | return !(*this == other); |
302 | | } |
303 | | |
304 | | void clear() |
305 | | /// Sets the contents of the buffer to zero. |
306 | | { |
307 | | std::memset(_ptr, 0, _used * sizeof(T)); |
308 | | } |
309 | | |
310 | | std::size_t size() const |
311 | | /// Returns the used size of the buffer in elements. |
312 | | { |
313 | | return _used; |
314 | | } |
315 | | |
316 | | std::size_t sizeBytes() const |
317 | | /// Returns the used size of the buffer in bytes. |
318 | | { |
319 | | return _used * sizeof(T); |
320 | | } |
321 | | |
322 | | T* begin() |
323 | | /// Returns a pointer to the beginning of the buffer. |
324 | 409k | { |
325 | 409k | return _ptr; |
326 | 409k | } Poco::Buffer<char>::begin() Line | Count | Source | 324 | 409k | { | 325 | 409k | return _ptr; | 326 | 409k | } |
Unexecuted instantiation: Poco::Buffer<int>::begin() |
327 | | |
328 | | const T* begin() const |
329 | | /// Returns a pointer to the beginning of the buffer. |
330 | | { |
331 | | return _ptr; |
332 | | } |
333 | | |
334 | | T* end() |
335 | | /// Returns a pointer to end of the buffer. |
336 | | { |
337 | | return _ptr + _used; |
338 | | } |
339 | | |
340 | | const T* end() const |
341 | | /// Returns a pointer to the end of the buffer. |
342 | | { |
343 | | return _ptr + _used; |
344 | | } |
345 | | |
346 | | bool empty() const |
347 | | /// Return true if buffer is empty. |
348 | | { |
349 | | return 0 == _used; |
350 | | } |
351 | | |
352 | | T& operator [] (std::size_t index) |
353 | | { |
354 | | poco_assert (index < _used); |
355 | | |
356 | | return _ptr[index]; |
357 | | } |
358 | | |
359 | | const T& operator [] (std::size_t index) const |
360 | | { |
361 | | poco_assert (index < _used); |
362 | | |
363 | | return _ptr[index]; |
364 | | } |
365 | | |
366 | | private: |
367 | | std::size_t _capacity; |
368 | | std::size_t _used; |
369 | | T* _ptr; |
370 | | bool _ownMem; |
371 | | }; |
372 | | |
373 | | |
374 | | } // namespace Poco |
375 | | |
376 | | |
377 | | #endif // Foundation_Buffer_INCLUDED |