libime
naivevector.h
1 /*
2  * SPDX-FileCopyrightText: 2015-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  */
6 
7 #ifndef NAIVEVECTOR_H
8 #define NAIVEVECTOR_H
9 
10 #include <cstddef>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iterator>
14 #include <new>
15 #include <stdexcept>
16 #include <type_traits>
17 
18 namespace libime {
19 
20 template <typename T>
21 struct naivevector {
22  static_assert(std::is_trivially_destructible<T>::value &&
23  std::is_standard_layout<T>::value,
24  "this class should only use with trivially copyable class, "
25  "but well, we only "
26  "care about fundamental type");
27 
28  using value_type = T;
29  using pointer = value_type *;
30  using const_pointer = const value_type *;
31  using reference = value_type &;
32  using const_reference = const value_type &;
33  using iterator = value_type *;
34  using const_iterator = const value_type *;
35  using size_type = std::size_t;
36  using difference_type = std::ptrdiff_t;
37  using reverse_iterator = std::reverse_iterator<iterator>;
38  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
39 
40  naivevector() noexcept : m_start(nullptr), m_end(nullptr), m_cap(nullptr) {}
41 
42  ~naivevector() noexcept { std::free(m_start); }
43  naivevector(const naivevector &other) : naivevector() {
44  reserve(other.size());
45  for (auto value : other) {
46  push_back(value);
47  }
48  }
49  naivevector(naivevector &&other) noexcept : naivevector() { swap(other); }
50 
51  naivevector &operator=(naivevector other) {
52  swap(other);
53  return *this;
54  }
55 
56  void swap(naivevector &__other) noexcept {
57  using std::swap;
58  swap(m_start, __other.m_start);
59  swap(m_end, __other.m_end);
60  swap(m_cap, __other.m_cap);
61  }
62 
63  // Iterators.
64  iterator begin() noexcept { return iterator(data()); }
65 
66  const_iterator begin() const noexcept { return const_iterator(data()); }
67 
68  iterator end() noexcept { return iterator(m_end); }
69 
70  const_iterator end() const noexcept { return const_iterator(m_end); }
71 
72  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
73 
74  const_reverse_iterator rbegin() const noexcept {
75  return const_reverse_iterator(end());
76  }
77 
78  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
79 
80  const_reverse_iterator rend() const noexcept {
81  return const_reverse_iterator(begin());
82  }
83 
84  const_iterator cbegin() const noexcept { return const_iterator(data()); }
85 
86  const_iterator cend() const noexcept { return const_iterator(m_end); }
87 
88  const_reverse_iterator crbegin() const noexcept {
89  return const_reverse_iterator(end());
90  }
91 
92  const_reverse_iterator crend() const noexcept {
93  return const_reverse_iterator(begin());
94  }
95 
96  // Capacity.
97  size_type size() const noexcept { return size_type(m_end - m_start); }
98 
99  constexpr size_type max_size() const noexcept {
100  return size_type(-1) / sizeof(value_type);
101  }
102 
103  void clear() { resize(0); }
104 
105  void resize(size_type new_size) {
106  if (new_size > size()) {
107  auto old_size = size();
108  auto cap = capacity();
109  while (new_size > cap) {
110  cap = cap ? (2 * cap) : 32;
111  }
112  reserve(cap);
113 
114  m_end = m_start + new_size;
115  if constexpr (!std::is_trivial_v<value_type>) {
116  for (auto *p = m_start + old_size; p != m_end; p++) {
117  new (p) value_type();
118  }
119  } else {
120  std::memset(m_start + old_size, 0,
121  sizeof(value_type) * (new_size - old_size));
122  }
123  } else {
124  m_end = m_start + new_size;
125  }
126  }
127 
128  void shrink_to_fit() {
129  if (m_cap > m_end) {
130  _realloc_array(size_type(reinterpret_cast<char *>(m_end) -
131  reinterpret_cast<char *>(m_start)));
132  }
133  }
134 
135  void reserve(size_type new_size) {
136  if (new_size > max_size()) {
137  throw std::length_error("larger than max_size");
138  }
139 
140  if (new_size > capacity()) {
141  _realloc_array(new_size * sizeof(value_type));
142  }
143  }
144 
145  size_type capacity() const noexcept { return size_type(m_cap - m_start); }
146 
147  bool empty() const noexcept { return size() == 0; }
148 
149  // Element access.
150  reference operator[](size_type __n) noexcept { return m_start[__n]; }
151 
152  const_reference operator[](size_type __n) const noexcept {
153  return m_start[__n];
154  }
155 
156  reference at(size_type __n) {
157  if (__n >= size()) {
158  throw std::out_of_range("out_of_range");
159  }
160  return m_start[__n];
161  }
162 
163  const_reference at(size_type __n) const {
164  if (__n >= size()) {
165  throw std::out_of_range("out_of_range");
166  }
167  return m_start[__n];
168  }
169 
170  reference front() noexcept { return *begin(); }
171 
172  const_reference front() const noexcept { return *cbegin(); }
173 
174  reference back() noexcept { return size() ? *(end() - 1) : *end(); }
175 
176  const_reference back() const noexcept {
177  return size() ? *(cend() - 1) : *cend();
178  }
179 
180  pointer data() noexcept { return m_start; }
181 
182  const_pointer data() const noexcept { return m_start; }
183 
184  void push_back(const value_type &__x) { emplace_back(__x); }
185 
186  void push_back(value_type &&__x) { emplace_back(std::move(__x)); }
187 
188  template <typename... _Args>
189  void emplace_back(_Args &&...__args) {
190  if (m_end == m_cap) {
191  reserve(capacity() ? (2 * capacity()) : 32);
192  }
193  new (m_end) value_type(std::forward<_Args>(__args)...);
194  m_end++;
195  }
196 
197  void pop_back() { m_end--; }
198 
199 private:
200  void _realloc_array(size_type bytes) {
201  if (bytes == 0) {
202  std::free(m_start);
203  m_start = m_end = m_cap = nullptr;
204  } else {
205  auto old_bytes = size_type(reinterpret_cast<char *>(m_end) -
206  reinterpret_cast<char *>(m_start));
207  auto *new_start =
208  reinterpret_cast<pointer>(std::realloc(m_start, bytes));
209  if (new_start) {
210  m_start = new_start;
211  m_cap = reinterpret_cast<pointer>(
212  reinterpret_cast<char *>(new_start) + bytes);
213  m_end = reinterpret_cast<pointer>(
214  reinterpret_cast<char *>(new_start) + old_bytes);
215  } else {
216  throw std::bad_alloc();
217  }
218  }
219  }
220 
221  value_type *m_start;
222  value_type *m_end;
223  value_type *m_cap;
224 };
225 
226 template <typename T>
227 void swap(naivevector<T> &lhs, naivevector<T> &rhs) noexcept {
228  lhs.swap(rhs);
229 }
230 } // namespace libime
231 
232 #endif // NAIVEVECTOR_H