Coverage Report

Created: 2023-10-26 06:13

/src/poco/Foundation/include/Poco/Buffer.h
Line
Count
Source (jump to first uncovered line)
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
    _capacity(length),
56
    _used(length),
57
    _ptr(0),
58
    _ownMem(true)
59
    /// Creates and allocates the Buffer.
60
0
  {
61
0
    if (length > 0)
62
0
    {
63
0
      _ptr = new T[length];
64
0
    }
65
0
  }
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(0),
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(0),
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
0
  {
158
0
    if (_ownMem) delete [] _ptr;
159
0
  }
160
161
  void resize(std::size_t newCapacity, bool preserveContent = true)
162
    /// Resizes the buffer capacity and size. If preserveContent is true,
163
    /// the content of the old buffer is copied over to the
164
    /// new buffer. The new capacity can be larger or smaller than
165
    /// the current one; if it is smaller, capacity will remain intact.
166
    /// Size will always be set to the new capacity.
167
    ///
168
    /// Buffers only wrapping externally owned storage can not be
169
    /// resized. If resize is attempted on those, IllegalAccessException
170
    /// is thrown.
171
  {
172
    if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage.");
173
174
    if (newCapacity > _capacity)
175
    {
176
      T* ptr = new T[newCapacity];
177
      if (preserveContent && _ptr)
178
      {
179
        std::memcpy(ptr, _ptr, _used * sizeof(T));
180
      }
181
      delete [] _ptr;
182
      _ptr = ptr;
183
      _capacity = newCapacity;
184
    }
185
186
    _used = newCapacity;
187
  }
188
189
  void setCapacity(std::size_t newCapacity, bool preserveContent = true)
190
    /// Sets the buffer capacity. If preserveContent is true,
191
    /// the content of the old buffer is copied over to the
192
    /// new buffer. The new capacity can be larger or smaller than
193
    /// the current one; size will be set to the new capacity only if
194
    /// new capacity is smaller than the current size, otherwise it will
195
    /// remain intact.
196
    ///
197
    /// Buffers only wrapping externally owned storage can not be
198
    /// resized. If resize is attempted on those, IllegalAccessException
199
    /// is thrown.
200
  {
201
    if (!_ownMem) throw Poco::InvalidAccessException("Cannot resize buffer which does not own its storage.");
202
203
    if (newCapacity != _capacity)
204
    {
205
      T* ptr = 0;
206
      if (newCapacity > 0)
207
      {
208
        ptr = new T[newCapacity];
209
        if (preserveContent && _ptr)
210
        {
211
          std::size_t newSz = _used < newCapacity ? _used : newCapacity;
212
          std::memcpy(ptr, _ptr, newSz * sizeof(T));
213
        }
214
      }
215
      delete [] _ptr;
216
      _ptr = ptr;
217
      _capacity = newCapacity;
218
219
      if (newCapacity < _used) _used = newCapacity;
220
    }
221
  }
222
223
  void assign(const T* buf, std::size_t sz)
224
    /// Assigns the argument buffer to this buffer.
225
    /// If necessary, resizes the buffer.
226
  {
227
    if (0 == sz) return;
228
    if (sz > _capacity) resize(sz, false);
229
    std::memcpy(_ptr, buf, sz * sizeof(T));
230
    _used = sz;
231
  }
232
233
  void append(const T* buf, std::size_t sz)
234
    /// Resizes this buffer and appends the argument buffer.
235
  {
236
    if (0 == sz) return;
237
    resize(_used + sz, true);
238
    std::memcpy(_ptr + _used - sz, buf, sz * sizeof(T));
239
  }
240
241
  void append(T val)
242
    /// Resizes this buffer by one element and appends the argument value.
243
  {
244
    resize(_used + 1, true);
245
    _ptr[_used - 1] = val;
246
  }
247
248
  void append(const Buffer& buf)
249
    /// Resizes this buffer and appends the argument buffer.
250
  {
251
    append(buf.begin(), buf.size());
252
  }
253
254
  std::size_t capacity() const
255
    /// Returns the allocated memory size in elements.
256
  {
257
    return _capacity;
258
  }
259
260
  std::size_t capacityBytes() const
261
    /// Returns the allocated memory size in bytes.
262
  {
263
    return _capacity * sizeof(T);
264
  }
265
266
  void swap(Buffer& other) noexcept
267
  /// Swaps the buffer with another one.
268
  {
269
    using std::swap;
270
271
    swap(_ptr, other._ptr);
272
    swap(_capacity, other._capacity);
273
    swap(_used, other._used);
274
    swap(_ownMem, other._ownMem);
275
  }
276
277
  bool operator == (const Buffer& other) const
278
    /// Compare operator.
279
  {
280
    if (this != &other)
281
    {
282
      if (_used == other._used)
283
      {
284
        if (_ptr && other._ptr && std::memcmp(_ptr, other._ptr, _used * sizeof(T)) == 0)
285
        {
286
          return true;
287
        }
288
        else return _used == 0;
289
      }
290
      return false;
291
    }
292
293
    return true;
294
  }
295
296
  bool operator != (const Buffer& other) const
297
    /// Compare operator.
298
  {
299
    return !(*this == other);
300
  }
301
302
  void clear()
303
    /// Sets the contents of the buffer to zero.
304
  {
305
    std::memset(_ptr, 0, _used * sizeof(T));
306
  }
307
308
  std::size_t size() const
309
    /// Returns the used size of the buffer in elements.
310
  {
311
    return _used;
312
  }
313
314
  std::size_t sizeBytes() const
315
    /// Returns the used size of the buffer in bytes.
316
  {
317
    return _used * sizeof(T);
318
  }
319
320
  T* begin()
321
    /// Returns a pointer to the beginning of the buffer.
322
0
  {
323
0
    return _ptr;
324
0
  }
325
326
  const T* begin() const
327
    /// Returns a pointer to the beginning of the buffer.
328
  {
329
    return _ptr;
330
  }
331
332
  T* end()
333
    /// Returns a pointer to end of the buffer.
334
  {
335
    return _ptr + _used;
336
  }
337
338
  const T* end() const
339
    /// Returns a pointer to the end of the buffer.
340
  {
341
    return _ptr + _used;
342
  }
343
344
  bool empty() const
345
    /// Return true if buffer is empty.
346
  {
347
    return 0 == _used;
348
  }
349
350
  T& operator [] (std::size_t index)
351
  {
352
    poco_assert (index < _used);
353
354
    return _ptr[index];
355
  }
356
357
  const T& operator [] (std::size_t index) const
358
  {
359
    poco_assert (index < _used);
360
361
    return _ptr[index];
362
  }
363
364
private:
365
  Buffer();
366
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