AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
AByteBuffer.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include "AUI/Util/Assert.h"
15#include "SharedPtr.h"
16
17#include <cstddef>
18#include <cstring>
19#include <string>
20#include <stdexcept>
21#include <cassert>
22#include "AUI/Core.h"
23#include <AUI/Traits/serializable.h>
24#include "AByteBufferView.h"
25
26
31class API_AUI_CORE AByteBuffer final: public IOutputStream {
32private:
33 char* mBuffer = nullptr;
34 size_t mCapacity = 0;
35 size_t mSize = 0;
36
37public:
38 using iterator = char*;
39
41 AByteBuffer(const char* buffer, size_t size);
42 explicit AByteBuffer(size_t initialCapacity);
43 AByteBuffer(const unsigned char* buffer, size_t size);
45 reserve(other.size());
46 memcpy(mBuffer, other.data(), other.size());
47 mSize = other.size();
48 }
49
50 AByteBuffer(const AByteBuffer& other): AByteBuffer(AByteBufferView(other)) {}
51 AByteBuffer(AByteBuffer&& other) noexcept;
52
54
55 void write(const char* src, size_t size) override;
56
57
58 [[nodiscard]]
59 AByteBufferView slice(std::size_t offset, std::size_t size) const noexcept {
60 return operator AByteBufferView().slice(offset, size);
61 }
62
63 [[nodiscard]]
64 AByteBufferView slice(std::size_t offset /* to end */) const noexcept {
65 return operator AByteBufferView().slice(offset);
66 }
67
73 void write(IInputStream& stream, size_t size);
74
75 operator AByteBufferView() const noexcept {
76 return { mBuffer, mSize };
77 }
78
79 void clear() {
80 delete[] mBuffer;
81 mBuffer = nullptr;
82 mSize = mCapacity = 0;
83 }
84
88 void reserve(size_t size);
89
93 void increaseInternalBuffer(size_t size) {
94 reserve(mCapacity + size);
95 }
96
101 void grow(size_t size) {
102 auto availableToWrite = getAvailableToWrite();
103 if (availableToWrite < size) {
104 increaseInternalBuffer((glm::max)(getReserved() * 2, size_t(size - availableToWrite)));
105 }
106 }
107
111 size_t getAvailableToWrite() const {
112 return getReserved() - getSize();
113 }
114
115
119 char* data() const
120 {
121 return mBuffer;
122 }
123
130 template <typename T>
131 T& at(size_t byteIndex)
132 {
133 return *reinterpret_cast<T*>(mBuffer + byteIndex);
134 }
135
136
143 template <typename T>
144 const T& at(size_t byteIndex) const
145 {
146 return *reinterpret_cast<T*>(mBuffer + byteIndex);
147 }
148
160 void setSize(size_t s) {
161 AUI_ASSERTX(s <= mCapacity, "size cannot be greater than reserved buffer size; did you mean AByteBuffer::resize?");
162 mSize = s;
163 }
175 void increaseSize(size_t s) {
176 mSize += s;
177 AUI_ASSERTX(mSize <= mCapacity, "size cannot be greater than reserved buffer size; did you mean AByteBuffer::resize?");
178 }
179
185 void resize(size_t s) {
186 if (mCapacity < s) {
187 reserve(s);
188 }
189 mSize = s;
190 }
191
197 void reallocate(size_t s) {
198 if (mCapacity != s) {
199 delete[] mBuffer;
200 if (s == 0) {
201 mBuffer = nullptr;
202 } else {
203 mBuffer = new char[s];
204 }
205 mCapacity = s;
206 }
207 mSize = s;
208 }
209
213 size_t getSize() const noexcept {
214 return mSize;
215 }
216
220 bool empty() const noexcept {
221 return mSize == 0;
222 }
223
227 size_t size() const noexcept {
228 return mSize;
229 }
230
234 size_t capacity() const noexcept {
235 return mCapacity;
236 }
237
241 size_t getReserved() const noexcept {
242 return mCapacity;
243 }
244
245 AByteBuffer& operator=(AByteBuffer&& other) noexcept {
246 if (&other == this) {
247 return *this;
248 }
249
250 delete[] mBuffer;
251 mBuffer = other.mBuffer;
252 mCapacity = other.mCapacity;
253 mSize = other.mSize;
254
255 other.mBuffer = nullptr;
256 other.mCapacity = 0;
257 other.mSize = 0;
258
259 return *this;
260 }
261 AByteBuffer& operator=(const AByteBuffer& other) {
262 if (&other == this) {
263 return *this;
264 }
265
266 if (mCapacity < other.size()) {
267 reallocate(other.size());
268 }
269 std::memcpy(mBuffer, other.data(), other.size());
270 mSize = other.mSize;
271
272 return *this;
273 }
274
275 bool operator==(const AByteBuffer& r) const;
276 bool operator!=(const AByteBuffer& r) const;
277
278 char* begin()
279 {
280 return mBuffer;
281 }
282 char* end()
283 {
284 return mBuffer + mSize;
285 }
286 char* endReserved()
287 {
288 return mBuffer + mCapacity;
289 }
290 const char* begin() const
291 {
292 return mBuffer;
293 }
294 const char* end() const
295 {
296 return mBuffer + mSize;
297 }
298
299
300 template<typename T>
301 T as() const {
302 return AByteBufferView(*this).template as<T>();
303 }
304
305 [[nodiscard]]
306 AString toHexString() const {
307 return AByteBufferView(*this).toHexString();
308 }
309
310 [[nodiscard]]
311 AString toBase64String() const {
312 return AByteBufferView(*this).toBase64String();
313 }
314
315 iterator erase(iterator begin, iterator end) noexcept {
316 AUI_ASSERT(ownsIterator(begin));
317 AUI_ASSERT(ownsIterator(end));
318 std::memmove(begin, end, std::distance(end, AByteBuffer::end()));
319 setSize(size() - std::distance(begin, end));
320 return begin;
321 }
322
323 [[nodiscard]]
324 bool ownsIterator(iterator i) const noexcept {
325 return i >= begin() && i <= end();
326 }
327
328 static AByteBuffer fromStream(aui::no_escape<IInputStream> is);
329 static AByteBuffer fromStream(aui::no_escape<IInputStream> is, size_t sizeRestriction);
330
331 static AByteBuffer fromString(const AString& string);
332 static AByteBuffer fromHexString(const AString& string);
333 static AByteBuffer fromBase64String(const AString& encodedString);
334};
335
336API_AUI_CORE std::ostream& operator<<(std::ostream& o, AByteBufferView buffer);
337
338template<>
340 static void write(IOutputStream& os, const AByteBuffer& value) {
341 os.write(value.data(), value.size());
342 }
343};
Acts like std::string_view but for AByteBuffer.
Definition: AByteBufferView.h:24
std::vector-like growing array for byte storage.
Definition: AByteBuffer.h:31
void reallocate(size_t s)
Definition: AByteBuffer.h:197
void increaseSize(size_t s)
Definition: AByteBuffer.h:175
size_t getAvailableToWrite() const
Definition: AByteBuffer.h:111
void increaseInternalBuffer(size_t size)
Increases internal buffer.
Definition: AByteBuffer.h:93
T & at(size_t byteIndex)
Gets value of specified type by byte index relative to the beginning of internal buffer.
Definition: AByteBuffer.h:131
size_t size() const noexcept
Definition: AByteBuffer.h:227
size_t capacity() const noexcept
Definition: AByteBuffer.h:234
const T & at(size_t byteIndex) const
Gets value of specified type by byte index relative to the beginning of internal buffer.
Definition: AByteBuffer.h:144
void grow(size_t size)
If getReserved() - getSize() is less than size increases internal buffer size enough to store size by...
Definition: AByteBuffer.h:101
void resize(size_t s)
Definition: AByteBuffer.h:185
void setSize(size_t s)
Definition: AByteBuffer.h:160
size_t getReserved() const noexcept
Definition: AByteBuffer.h:241
size_t getSize() const noexcept
Definition: AByteBuffer.h:213
bool empty() const noexcept
Definition: AByteBuffer.h:220
char * data() const
Definition: AByteBuffer.h:119
Represents a Unicode character string.
Definition: AString.h:37
Represents an input stream.
Definition: IInputStream.h:26
Definition: IOutputStream.h:20
virtual void write(const char *src, size_t size)=0
Writes exact size bytes to stream. Blocking (waiting for write all data) is allowed.
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition: Assert.h:55
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition: Assert.h:74
Definition: serializable.h:26
Does not allow escaping, allowing to accept lvalue ref, rvalue ref, shared_ptr and etc without overhe...
Definition: values.h:127