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