helics  3.0.1
SmallBuffer.hpp
1 /*
2 Copyright (c) 2017-2021,
3 Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable
4 Energy, LLC. See the top-level NOTICE for additional details. All rights reserved.
5 SPDX-License-Identifier: BSD-3-Clause
6 */
7 #pragma once
8 
9 #include <array>
10 #include <cstddef>
11 #include <cstring>
12 #include <new>
13 #include <stdexcept>
14 #include <string>
15 #include <string_view>
16 #include <utility>
17 
18 #if defined(__clang__)
19 # pragma clang diagnostic push
20 # pragma clang diagnostic ignored "-Wuninitialized"
21 #endif
22 
23 namespace helics {
24 class SmallBuffer {
25  public:
26  SmallBuffer() noexcept: heap(buffer.data()) {}
27 
28  SmallBuffer(const SmallBuffer& sb): heap(buffer.data())
29  {
30  resize(sb.size());
31  std::memcpy(heap, sb.heap, sb.size());
32  }
33 
34  SmallBuffer(SmallBuffer&& sb) noexcept
35  {
36  if (sb.usingAllocatedBuffer) {
37  heap = sb.heap;
38  bufferCapacity = sb.bufferCapacity;
39  usingAllocatedBuffer = sb.usingAllocatedBuffer;
40  nonOwning = sb.nonOwning;
41  sb.usingAllocatedBuffer = false;
42  } else {
43  std::memcpy(buffer.data(), sb.heap, sb.bufferSize);
44  heap = buffer.data();
45  }
46  bufferSize = sb.bufferSize;
47  sb.heap = sb.buffer.data();
48  sb.bufferCapacity = 64;
49  sb.bufferSize = 0;
50  }
51 
52  template<typename U,
53  typename T = std::enable_if_t<std::is_constructible_v<std::string_view, U>>>
54  SmallBuffer(U&& u): heap(buffer.data())
55  {
56  std::string_view val(std::forward<U>(u));
57  resize(val.size());
58  std::memcpy(heap, val.data(), val.size());
59  }
60 
61  SmallBuffer(const void* data, size_t size): heap(buffer.data())
62  {
63  resize(size);
64  std::memcpy(heap, data, size);
65  }
67  SmallBuffer(std::size_t size): heap(buffer.data()) { resize(size); }
68 
70  SmallBuffer(std::size_t size, std::byte val): heap(buffer.data()) { resize(size, val); }
72  SmallBuffer(std::size_t size, unsigned char val): heap(buffer.data())
73  {
74  resize(size, std::byte{val});
75  }
78  {
79  if (usingAllocatedBuffer && !nonOwning) {
80  delete[] heap;
81  }
82  }
83  SmallBuffer& operator=(const SmallBuffer& sb)
84  {
85  if (this == &sb) {
86  return *this;
87  }
88  resize(sb.size());
89  std::memcpy(heap, sb.heap, sb.size());
90  return *this;
91  }
92  SmallBuffer& operator=(SmallBuffer&& sb) noexcept
93  {
94  if (usingAllocatedBuffer) {
95  if (nonOwning) {
96  if (sb.heap == heap) {
97  bufferSize = sb.bufferSize;
98  bufferCapacity = sb.bufferCapacity;
99  return *this;
100  }
101  } else {
102  if (sb.heap == heap) {
103  bufferSize = sb.bufferSize;
104  return *this;
105  }
106  delete[] heap;
107  }
108  }
109  if (sb.usingAllocatedBuffer) {
110  heap = sb.heap;
111  bufferCapacity = sb.bufferCapacity;
112  usingAllocatedBuffer = true;
113  nonOwning = sb.nonOwning;
114  } else {
115  std::memcpy(buffer.data(), sb.heap, sb.bufferSize);
116  usingAllocatedBuffer = false;
117  nonOwning = false;
118  heap = buffer.data();
119  bufferCapacity = 64;
120  }
121  bufferSize = sb.bufferSize;
122  sb.heap = sb.buffer.data();
123  sb.bufferCapacity = 64;
124  sb.bufferSize = 0;
125  sb.usingAllocatedBuffer = false;
126  return *this;
127  }
128  template<typename U,
129  typename T = std::enable_if_t<std::is_constructible_v<std::string_view, U>>>
130  SmallBuffer& operator=(U&& u)
131  {
132  std::string_view val(std::forward<U>(u));
133  if (reinterpret_cast<const std::byte*>(val.data()) == heap) {
134  bufferSize = val.size();
135  return *this;
136  }
137  resize(val.size());
138  if (val.size() > 0) {
139  std::memcpy(heap, val.data(), val.size());
140  }
141  return *this;
142  }
144  std::byte* data() const { return heap; }
146  std::byte* begin() { return heap; }
148  std::byte* end() { return heap + bufferSize; }
150  const std::byte* begin() const { return heap; }
152  const std::byte* end() const { return heap + bufferSize; }
154  std::byte operator[](size_t index) const { return heap[index]; }
156  std::byte& operator[](size_t index) { return heap[index]; }
158  std::byte at(size_t index) const
159  {
160  if (index >= bufferSize) {
161  throw(std::out_of_range("specified index is not valid"));
162  }
163  return heap[index];
164  }
166  std::byte& at(size_t index)
167  {
168  if (index >= bufferSize) {
169  throw(std::out_of_range("specified index is not valid"));
170  }
171  return heap[index];
172  }
174  void assign(const void* start, const void* end)
175  {
176  if (start > end) {
177  throw(
178  std::invalid_argument("invalid range specified, end pointer before start pointer"));
179  }
180  const auto* st1 = reinterpret_cast<const std::byte*>(start);
181  const auto* end1 = reinterpret_cast<const std::byte*>(end);
182  resize(end1 - st1);
183  std::memcpy(heap, st1, end1 - st1);
184  }
185  void assign(const void* start, std::size_t size)
186  {
187  const auto* st1 = reinterpret_cast<const std::byte*>(start);
188  resize(size);
189  std::memcpy(heap, st1, size);
190  }
191  void append(const void* start, const void* end)
192  {
193  if (start > end) {
194  throw(
195  std::invalid_argument("invalid range specified, end pointer before start pointer"));
196  }
197  const auto* st1 = reinterpret_cast<const std::byte*>(start);
198  const auto* end1 = reinterpret_cast<const std::byte*>(end);
199  auto csize = bufferSize;
200  resize(bufferSize + (end1 - st1));
201  std::memcpy(heap + csize, st1, end1 - st1);
202  }
203  void append(const void* start, std::size_t size)
204  {
205  const auto* st1 = reinterpret_cast<const std::byte*>(start);
206  auto csize = bufferSize;
207  resize(bufferSize + size);
208  std::memcpy(heap + csize, st1, size);
209  }
210  void append(std::string_view data)
211  {
212  const auto* st1 = reinterpret_cast<const std::byte*>(data.data());
213  auto csize = bufferSize;
214  resize(bufferSize + data.size());
215  std::memcpy(heap + csize, st1, data.size());
216  }
217 
218  void push_back(char c) { append(&c, 1); }
219 
220  void pop_back() { bufferSize > 0 ? --bufferSize : 0; }
222  std::string_view to_string() const
223  {
224  return std::string_view{reinterpret_cast<const char*>(heap), bufferSize};
225  }
226 
229  {
230  if (bufferCapacity > bufferSize) {
231  heap[bufferSize] = std::byte(0);
232  } else {
233  push_back('\0');
234  pop_back();
235  }
236  }
238  const char* char_data() const { return reinterpret_cast<const char*>(heap); }
240  void moveAssign(void* data, std::size_t size, std::size_t capacity)
241  {
242  auto* newHeap = reinterpret_cast<std::byte*>(data);
243  if (usingAllocatedBuffer && !nonOwning) {
244  if (newHeap != heap) {
245  delete[] heap;
246  }
247  }
248  heap = newHeap;
249  bufferCapacity = capacity;
250  bufferSize = size;
251  nonOwning = false;
252  usingAllocatedBuffer = true;
253  }
255  void spanAssign(void* data, std::size_t size, std::size_t capacity)
256  {
257  auto* newHeap = reinterpret_cast<std::byte*>(data);
258  if (usingAllocatedBuffer && !nonOwning) {
259  if (newHeap == heap) {
260  // if the heaps are the same the only thing to change is the size and capacity
261  // don't change the other characteristics
262  bufferSize = size;
263  bufferCapacity = capacity;
264  return;
265  }
266  delete[] heap;
267  }
268  heap = newHeap;
269  bufferCapacity = capacity;
270  bufferSize = size;
271  nonOwning = true;
272  usingAllocatedBuffer = true;
273  }
274  void resize(size_t size)
275  {
276  reserve(size);
277  bufferSize = size;
278  }
279  void resize(size_t size, std::byte val)
280  {
281  reserve(size);
282  if (size > bufferSize) {
283  std::memset(heap + bufferSize, std::to_integer<int>(val), size - bufferSize);
284  }
285  bufferSize = size;
286  }
287  void reserve(size_t size)
288  {
289  static constexpr size_t bigSize{sizeof(size_t) == 8 ? 0x010'0000'0000U : 0xFFFF'0000U};
290  if (size > bufferCapacity) {
291  if (size > bigSize) {
292  throw(std::bad_alloc());
293  }
294  auto* ndata = new std::byte[size + 8];
295  std::memcpy(ndata, heap, bufferSize);
296  if (usingAllocatedBuffer && !nonOwning) {
297  delete[] heap;
298  }
299  heap = ndata;
300  nonOwning = false;
301  usingAllocatedBuffer = true;
302  bufferCapacity = size + 8;
303  }
304  }
306  bool empty() const { return (bufferSize == 0); }
308  std::size_t size() const { return bufferSize; }
310  std::size_t capacity() const { return bufferCapacity; }
312  void clear() { bufferSize = 0; }
313 
315  void swap(SmallBuffer& sb2) noexcept
316  {
317  if (sb2.usingAllocatedBuffer && usingAllocatedBuffer) {
318  std::swap(heap, sb2.heap);
319  std::swap(nonOwning, sb2.nonOwning);
320  std::swap(bufferCapacity, sb2.bufferCapacity);
321  std::swap(bufferSize, sb2.bufferSize);
322  } else if (usingAllocatedBuffer) {
323  sb2.heap = heap;
324  sb2.bufferCapacity = bufferCapacity;
325  sb2.usingAllocatedBuffer = true;
326  sb2.nonOwning = nonOwning;
327  usingAllocatedBuffer = false;
328  nonOwning = false;
329  heap = buffer.data();
330  bufferCapacity = 64;
331 
332  std::memcpy(heap, sb2.buffer.data(), sb2.size());
333  std::swap(sb2.bufferSize, bufferSize);
334  } else if (sb2.usingAllocatedBuffer) {
335  heap = sb2.heap;
336  bufferCapacity = sb2.bufferCapacity;
337  usingAllocatedBuffer = true;
338  nonOwning = sb2.nonOwning;
339  sb2.usingAllocatedBuffer = false;
340  sb2.nonOwning = false;
341  sb2.heap = buffer.data();
342  sb2.bufferCapacity = 64;
343 
344  std::memcpy(sb2.heap, buffer.data(), bufferSize);
345  std::swap(sb2.bufferSize, bufferSize);
346  } else {
347  std::swap(sb2.buffer, buffer);
348  std::swap(sb2.bufferSize, bufferSize);
349  }
350  }
352  std::byte* release()
353  {
354  if (!usingAllocatedBuffer) {
355  return nullptr;
356  }
357  auto* released = heap;
358  heap = buffer.data();
359  usingAllocatedBuffer = false;
360  nonOwning = false;
361  bufferCapacity = 64;
362  bufferSize = 0;
363  return released;
364  }
365 
366  private:
367  std::array<std::byte, 64> buffer{{std::byte{0}}};
368  std::size_t bufferSize{0};
369  std::size_t bufferCapacity{64};
370  std::byte* heap;
371  bool nonOwning{false};
372  bool usingAllocatedBuffer{false};
373 };
374 
376 inline bool operator==(const SmallBuffer& sb1, const SmallBuffer& sb2)
377 {
378  return (sb1.to_string() == sb2.to_string());
379 }
380 
382 inline bool operator!=(const SmallBuffer& sb1, const SmallBuffer& sb2)
383 {
384  return (sb1.to_string() != sb2.to_string());
385 }
386 
387 #if defined(__clang__)
388 # pragma clang diagnostic pop
389 #endif
390 
391 } // namespace helics
helics::SmallBuffer::~SmallBuffer
~SmallBuffer()
Definition: SmallBuffer.hpp:77
helics::SmallBuffer::SmallBuffer
SmallBuffer(std::size_t size)
Definition: SmallBuffer.hpp:67
helics::SmallBuffer::size
std::size_t size() const
Definition: SmallBuffer.hpp:308
helics::SmallBuffer::end
const std::byte * end() const
Definition: SmallBuffer.hpp:152
helics::SmallBuffer
Definition: SmallBuffer.hpp:24
helics::SmallBuffer::assign
void assign(const void *start, const void *end)
Definition: SmallBuffer.hpp:174
helics::SmallBuffer::char_data
const char * char_data() const
Definition: SmallBuffer.hpp:238
helics::SmallBuffer::to_string
std::string_view to_string() const
Definition: SmallBuffer.hpp:222
helics::SmallBuffer::null_terminate
void null_terminate()
Definition: SmallBuffer.hpp:228
helics::SmallBuffer::SmallBuffer
SmallBuffer(std::size_t size, std::byte val)
Definition: SmallBuffer.hpp:70
helics::SmallBuffer::at
std::byte at(size_t index) const
Definition: SmallBuffer.hpp:158
helics::SmallBuffer::operator[]
std::byte & operator[](size_t index)
Definition: SmallBuffer.hpp:156
helics::SmallBuffer::spanAssign
void spanAssign(void *data, std::size_t size, std::size_t capacity)
Definition: SmallBuffer.hpp:255
helics::SmallBuffer::begin
std::byte * begin()
Definition: SmallBuffer.hpp:146
helics::SmallBuffer::SmallBuffer
SmallBuffer(std::size_t size, unsigned char val)
Definition: SmallBuffer.hpp:72
helics::SmallBuffer::end
std::byte * end()
Definition: SmallBuffer.hpp:148
helics
the main namespace for the helics co-simulation library User functions will be in the helics namespac...
Definition: AsyncFedCallInfo.hpp:14
helics::SmallBuffer::data
std::byte * data() const
Definition: SmallBuffer.hpp:144
helics::SmallBuffer::operator[]
std::byte operator[](size_t index) const
Definition: SmallBuffer.hpp:154
helics::SmallBuffer::at
std::byte & at(size_t index)
Definition: SmallBuffer.hpp:166
helics::SmallBuffer::moveAssign
void moveAssign(void *data, std::size_t size, std::size_t capacity)
Definition: SmallBuffer.hpp:240
helics::SmallBuffer::begin
const std::byte * begin() const
Definition: SmallBuffer.hpp:150
helics::SmallBuffer::capacity
std::size_t capacity() const
Definition: SmallBuffer.hpp:310