15 #include <string_view>
18 #if defined(__clang__)
19 # pragma clang diagnostic push
20 # pragma clang diagnostic ignored "-Wuninitialized"
31 std::memcpy(heap, sb.heap, sb.
size());
36 if (sb.usingAllocatedBuffer) {
38 bufferCapacity = sb.bufferCapacity;
39 usingAllocatedBuffer = sb.usingAllocatedBuffer;
40 nonOwning = sb.nonOwning;
41 sb.usingAllocatedBuffer =
false;
43 std::memcpy(buffer.data(), sb.heap, sb.bufferSize);
46 bufferSize = sb.bufferSize;
47 sb.heap = sb.buffer.data();
48 sb.bufferCapacity = 64;
53 typename T = std::enable_if_t<std::is_constructible_v<std::string_view, U>>>
56 std::string_view val(std::forward<U>(u));
58 std::memcpy(heap, val.data(), val.size());
74 resize(
size, std::byte{val});
79 if (usingAllocatedBuffer && !nonOwning) {
89 std::memcpy(heap, sb.heap, sb.
size());
92 SmallBuffer& operator=(SmallBuffer&& sb) noexcept
94 if (usingAllocatedBuffer) {
96 if (sb.heap == heap) {
97 bufferSize = sb.bufferSize;
98 bufferCapacity = sb.bufferCapacity;
102 if (sb.heap == heap) {
103 bufferSize = sb.bufferSize;
109 if (sb.usingAllocatedBuffer) {
111 bufferCapacity = sb.bufferCapacity;
112 usingAllocatedBuffer =
true;
113 nonOwning = sb.nonOwning;
115 std::memcpy(buffer.data(), sb.heap, sb.bufferSize);
116 usingAllocatedBuffer =
false;
118 heap = buffer.data();
122 bufferSize = sb.bufferSize;
123 sb.heap = sb.buffer.data();
124 sb.bufferCapacity = 64;
126 sb.usingAllocatedBuffer =
false;
132 typename T = std::enable_if_t<std::is_constructible_v<std::string_view, U>>>
133 SmallBuffer& operator=(U&& u)
135 std::string_view val(std::forward<U>(u));
136 if (
reinterpret_cast<const std::byte*
>(val.data()) == heap) {
137 bufferSize = val.size();
141 if (val.size() > 0) {
142 std::memcpy(heap, val.data(), val.size());
147 std::byte*
data()
const {
return heap; }
151 std::byte*
end() {
return heap + bufferSize; }
153 const std::byte*
begin()
const {
return heap; }
155 const std::byte*
end()
const {
return heap + bufferSize; }
157 std::byte
operator[](
size_t index)
const {
return heap[index]; }
161 std::byte
at(
size_t index)
const
163 if (index >= bufferSize) {
164 throw(std::out_of_range(
"specified index is not valid"));
169 std::byte&
at(
size_t index)
171 if (index >= bufferSize) {
172 throw(std::out_of_range(
"specified index is not valid"));
181 std::invalid_argument(
"invalid range specified, end pointer before start pointer"));
183 const auto* st1 =
reinterpret_cast<const std::byte*
>(start);
184 const auto* end1 =
reinterpret_cast<const std::byte*
>(
end);
186 std::memcpy(heap, st1, end1 - st1);
188 void assign(
const void* start, std::size_t
size)
190 const auto* st1 =
reinterpret_cast<const std::byte*
>(start);
192 std::memcpy(heap, st1,
size);
194 void append(
const void* start,
const void*
end)
198 std::invalid_argument(
"invalid range specified, end pointer before start pointer"));
200 const auto* st1 =
reinterpret_cast<const std::byte*
>(start);
201 const auto* end1 =
reinterpret_cast<const std::byte*
>(
end);
202 auto csize = bufferSize;
203 resize(bufferSize + (end1 - st1));
204 std::memcpy(heap + csize, st1, end1 - st1);
206 void append(
const void* start, std::size_t
size)
208 const auto* st1 =
reinterpret_cast<const std::byte*
>(start);
209 auto csize = bufferSize;
210 resize(bufferSize +
size);
211 std::memcpy(heap + csize, st1,
size);
213 void append(std::string_view
data)
215 const auto* st1 =
reinterpret_cast<const std::byte*
>(
data.data());
216 auto csize = bufferSize;
217 resize(bufferSize +
data.size());
218 std::memcpy(heap + csize, st1,
data.size());
221 void push_back(
char c) { append(&c, 1); }
223 void pop_back() { bufferSize > 0 ? --bufferSize : 0; }
227 return std::string_view{
reinterpret_cast<const char*
>(heap), bufferSize};
233 if (bufferCapacity > bufferSize) {
234 heap[bufferSize] = std::byte(0);
241 const char*
char_data()
const {
return reinterpret_cast<const char*
>(heap); }
245 auto* newHeap =
reinterpret_cast<std::byte*
>(
data);
246 if (usingAllocatedBuffer && !nonOwning) {
247 if (newHeap != heap) {
255 usingAllocatedBuffer =
true;
261 auto* newHeap =
reinterpret_cast<std::byte*
>(
data);
262 if (usingAllocatedBuffer && !nonOwning) {
263 if (newHeap == heap) {
277 usingAllocatedBuffer =
true;
279 void resize(
size_t size)
284 void resize(
size_t size, std::byte val)
287 if (
size > bufferSize) {
288 std::memset(heap + bufferSize, std::to_integer<int>(val),
size - bufferSize);
292 void reserve(
size_t size)
294 static constexpr
size_t bigSize{
sizeof(size_t) == 8 ? 0x010
'0000'0000U : 0xFFFF
'0000U};
295 if (size > bufferCapacity) {
296 if (size > bigSize || locked) {
297 throw(std::bad_alloc());
299 auto* ndata = new std::byte[size + 8];
300 std::memcpy(ndata, heap, bufferSize);
301 if (usingAllocatedBuffer && !nonOwning) {
306 usingAllocatedBuffer = true;
307 bufferCapacity = size + 8;
310 void lock(bool lockStatus = true) { locked = lockStatus; }
312 bool isLocked() const { return locked; }
314 bool empty() const { return (bufferSize == 0); }
316 std::size_t size() const { return bufferSize; }
318 std::size_t capacity() const { return bufferCapacity; }
320 void clear() { bufferSize = 0; }
323 void swap(SmallBuffer& sb2) noexcept
325 if (sb2.usingAllocatedBuffer && usingAllocatedBuffer) {
326 std::swap(heap, sb2.heap);
327 std::swap(nonOwning, sb2.nonOwning);
328 std::swap(bufferCapacity, sb2.bufferCapacity);
329 std::swap(bufferSize, sb2.bufferSize);
330 } else if (usingAllocatedBuffer) {
332 sb2.bufferCapacity = bufferCapacity;
333 sb2.usingAllocatedBuffer = true;
334 sb2.nonOwning = nonOwning;
335 usingAllocatedBuffer = false;
337 heap = buffer.data();
340 std::memcpy(heap, sb2.buffer.data(), sb2.size());
341 std::swap(sb2.bufferSize, bufferSize);
342 } else if (sb2.usingAllocatedBuffer) {
344 bufferCapacity = sb2.bufferCapacity;
345 usingAllocatedBuffer = true;
346 nonOwning = sb2.nonOwning;
347 sb2.usingAllocatedBuffer = false;
348 sb2.nonOwning = false;
349 sb2.heap = buffer.data();
350 sb2.bufferCapacity = 64;
352 std::memcpy(sb2.heap, buffer.data(), bufferSize);
353 std::swap(sb2.bufferSize, bufferSize);
355 std::swap(sb2.buffer, buffer);
356 std::swap(sb2.bufferSize, bufferSize);
362 if (!usingAllocatedBuffer) {
365 auto* released = heap;
366 heap = buffer.data();
367 usingAllocatedBuffer = false;
376 std::array<std::byte, 64> buffer{{std::byte{0}}};
377 std::size_t bufferSize{0};
378 std::size_t bufferCapacity{64};
380 bool nonOwning{false};
382 bool usingAllocatedBuffer{false};
385 std::uint32_t userKey{0}; // 32 bits of user data for whatever purpose is desired has no impact
386 // on state or operations
390 inline bool operator==(const SmallBuffer& sb1, const SmallBuffer& sb2)
392 return (sb1.to_string() == sb2.to_string());
396 inline bool operator!=(const SmallBuffer& sb1, const SmallBuffer& sb2)
398 return (sb1.to_string() != sb2.to_string());
401 #if defined(__clang__)
402 # pragma clang diagnostic pop
405 } // namespace helics