quill
InlinedVector.h
1 
7 #pragma once
8 
9 #include <cstddef>
10 #include <cstdint>
11 #include <cstring>
12 #include <type_traits>
13 
14 #include "quill/core/Attributes.h"
15 #include "quill/core/Common.h"
16 #include "quill/core/QuillError.h"
17 
18 #if defined(__GNUC__) && !defined(__clang__)
19  #pragma GCC diagnostic push
20  #pragma GCC diagnostic ignored "-Warray-bounds"
21  #pragma GCC diagnostic ignored "-Wstringop-overflow"
22 #elif defined(__clang__)
23  #pragma GCC diagnostic push
24  #pragma GCC diagnostic ignored "-Warray-bounds"
25 #elif defined(_WIN32) && defined(_MSC_VER)
26  #pragma warning(push)
27  #pragma warning(disable : 4789)
28 #endif
29 
30 QUILL_BEGIN_NAMESPACE
31 
32 namespace detail
33 {
34 
35 template <typename T, size_t N>
37 {
38 public:
39  using value_type = T;
40  static_assert(std::is_trivially_copyable_v<value_type>, "value_type must be trivially copyable");
41 
42  InlinedVector() noexcept
43  {
44  for (size_t i = 0; i < _capacity; ++i)
45  {
46  _storage.inline_buffer[i] = value_type{};
47  }
48  }
49 
50  ~InlinedVector()
51  {
52  if (_capacity != N)
53  {
54  delete[] _storage.heap_buffer;
55  }
56  }
57 
61  InlinedVector(InlinedVector const& other) = delete;
62  InlinedVector& operator=(InlinedVector const& other) = delete;
63 
67  QUILL_ATTRIBUTE_HOT value_type push_back(value_type value)
68  {
69  if (_size == _capacity)
70  {
71  if (QUILL_UNLIKELY(_capacity > (SIZE_MAX / 2)))
72  {
73  QUILL_THROW(QuillError{"InlinedVector capacity overflow"});
74  }
75 
76  size_t const new_capacity = _capacity * 2;
77  auto* new_data = new value_type[new_capacity];
78 
79  if (_capacity == N)
80  {
81  // Entering here for the first time, then we copy the inline storage
82  // Use memcpy for trivially copyable types to avoid false positive warnings with LTO
83  std::memcpy(new_data, _storage.inline_buffer, _size * sizeof(value_type));
84  }
85  else
86  {
87  // Use memcpy for trivially copyable types to avoid false positive warnings with LTO
88  std::memcpy(new_data, _storage.heap_buffer, _size * sizeof(value_type));
89  delete[] _storage.heap_buffer;
90  }
91 
92  _storage.heap_buffer = new_data;
93  _capacity = new_capacity;
94  }
95 
96  if (_capacity == N)
97  {
98  _storage.inline_buffer[_size] = value;
99  }
100  else
101  {
102  _storage.heap_buffer[_size] = value;
103  }
104 
105  ++_size;
106 
107  return value;
108  }
109 
113  QUILL_ATTRIBUTE_HOT value_type operator[](size_t index) const
114  {
115  if (QUILL_UNLIKELY(index >= _size))
116  {
117  QUILL_THROW(QuillError{"index out of bounds"});
118  }
119 
120  if (_capacity == N)
121  {
122  return _storage.inline_buffer[index];
123  }
124  else
125  {
126  return _storage.heap_buffer[index];
127  }
128  }
129 
133  QUILL_ATTRIBUTE_HOT void assign(size_t index, value_type value)
134  {
135  if (QUILL_UNLIKELY(index >= _size))
136  {
137  QUILL_THROW(QuillError{"index out of bounds"});
138  }
139 
140  if (_capacity == N)
141  {
142  _storage.inline_buffer[index] = value;
143  }
144  else
145  {
146  _storage.heap_buffer[index] = value;
147  }
148  }
149 
150  QUILL_NODISCARD QUILL_ATTRIBUTE_HOT size_t size() const noexcept { return _size; }
151  QUILL_NODISCARD size_t capacity() const noexcept { return _capacity; }
152  QUILL_ATTRIBUTE_HOT void clear() noexcept { _size = 0; }
153 
154 private:
155  union Storage
156  {
157  value_type inline_buffer[N];
158  value_type* heap_buffer;
159  } _storage;
160 
161  size_t _size{0};
162  size_t _capacity{N};
163 };
164 
170 static_assert(sizeof(SizeCacheVector) <= QUILL_CACHE_LINE_SIZE,
171  "SizeCacheVector should not exceed a cache line");
172 } // namespace detail
173 
174 QUILL_END_NAMESPACE
175 
176 #if defined(__GNUC__) && !defined(__clang__)
177  #pragma GCC diagnostic pop
178 #elif defined(__clang__)
179  #pragma GCC diagnostic pop
180 #elif defined(_WIN32) && defined(_MSC_VER)
181  #pragma warning(pop)
182 #endif
QUILL_ATTRIBUTE_HOT value_type push_back(value_type value)
Push back a new element.
Definition: InlinedVector.h:67
QUILL_ATTRIBUTE_HOT value_type operator[](size_t index) const
Access element.
Definition: InlinedVector.h:113
QUILL_ATTRIBUTE_HOT void assign(size_t index, value_type value)
Assign value at index.
Definition: InlinedVector.h:133
Definition: InlinedVector.h:36
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:28
constexpr size_t QUILL_CACHE_LINE_SIZE
Cache line constants.
Definition: Common.h:67
Definition: base.h:2200
custom exception
Definition: QuillError.h:47