Coverage Report

Created: 2025-11-13 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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