containers.h
Go to the documentation of this file.
1 #ifndef GARLIC_CONTAINERS_H
2 #define GARLIC_CONTAINERS_H
3 
18 #include "garlic.h"
19 
20 namespace garlic {
21 
22  enum class text_type : uint8_t {
23  reference,
24  copy,
25  };
26 
27  template<typename Ch, typename SizeType = unsigned>
28  class basic_string_ref {
29  private:
30  const Ch* data_;
31  SizeType size_;
32 
33  public:
34  explicit constexpr basic_string_ref(const Ch* data) : data_(data) {
35  size_ = strlen(data);
36  }
37 
38  explicit constexpr basic_string_ref(const Ch* data, SizeType size) : data_(data), size_(size) {}
39 
40  explicit constexpr basic_string_ref(
41  const std::basic_string_view<Ch>& data) : data_(data.data()), size_(data.size()) {}
42 
43  explicit basic_string_ref(
44  const std::basic_string<Ch>& data) : data_(data.data()), size_(data.size()) {}
45 
46  constexpr basic_string_ref(const basic_string_ref& value) : data_(value.data_), size_(value.size_) {};
47  constexpr basic_string_ref(basic_string_ref&& value) : data_(value.data_), size_(value.size_) {};
48 
49  constexpr const Ch* data() const { return data_; }
50  constexpr SizeType size() const { return size_; }
51  };
52 
53  using string_ref = basic_string_ref<char>;
54 
56 
66  template<typename Ch, typename SizeType = unsigned>
67  class basic_text {
68  public:
69  constexpr basic_text() : size_(0), type_(text_type::reference) {}
70 
71  constexpr basic_text(const Ch* data, text_type type = text_type::reference) : type_(type) {
72  size_ = strlen(data);
73  if (type == text_type::copy && size_)
74  data_ = strcpy((Ch*)malloc((size_ + 1) * sizeof(Ch)), data);
75  else
76  data_ = data;
77  }
78 
79  constexpr basic_text(
80  const Ch* data, SizeType size,
81  text_type type = text_type::reference) : size_(size), type_(type) {
82  if (type == text_type::copy && size_) {
83  data_ = strncpy((Ch*)malloc((size_ + 1) * sizeof(Ch)), data, size_ + 1);
84  }
85  else
86  data_ = data;
87  }
88 
89  basic_text(
90  const std::basic_string<Ch>& value,
91  text_type type = text_type::reference) : basic_text(value.data(), value.size(), type) {}
92 
93  constexpr basic_text(
94  const std::basic_string_view<Ch>& value,
95  text_type type = text_type::reference) : basic_text(value.data(), value.size(), type) {}
96 
97  constexpr basic_text(
98  const basic_string_ref<Ch>& value,
99  text_type type = text_type::reference) : basic_text(value.data(), value.size(), type) {}
100 
101  constexpr basic_text(
102  const basic_text& other
103  ) : data_(other.data_), size_(other.size_), type_(text_type::reference) {};
104 
105  basic_text(basic_text&& old) : data_(old.data_), size_(old.size_), type_(old.type_) {
106  old.size_ = 0;
107  }
108 
109  static inline basic_text copy(const Ch* data) { return basic_text(data, text_type::copy); }
110  static inline basic_text copy(const Ch* data, SizeType size) { return basic_text(data, size, text_type::copy); }
111  static inline basic_text copy(const std::basic_string<Ch>& value) { return basic_text(value, text_type::copy); }
112  static inline basic_text copy(const std::basic_string_view<Ch>& value) { return basic_text(value, text_type::copy); }
113  static inline basic_text copy(const basic_text& another) {
114  return basic_text(another.data(), another.size(), text_type::copy);
115  }
116 
117  inline constexpr basic_text& operator =(const basic_text& other) {
118  destroy();
119  data_ = other.data_;
120  size_ = other.size_;
121  type_ = text_type::reference;
122  return *this;
123  }
124 
125  inline constexpr basic_text& operator =(basic_text&& other) {
126  destroy();
127  data_ = other.data_;
128  size_ = other.size_;
129  type_ = other.type_;
130  other.size_ = 0;
131  return *this;
132  }
133 
134  inline basic_text clone() const noexcept {
135  return basic_text(data_, size_, text_type::copy);
136  }
137  inline basic_text view() const noexcept {
138  return basic_text(data_, size_, text_type::reference);
139  }
140  inline basic_string_ref<Ch> string_ref() const noexcept {
141  return basic_string_ref<Ch>(data_, size_);
142  }
143 
144  constexpr ~basic_text() { destroy(); }
145 
146  inline constexpr bool operator ==(const basic_text& another) const noexcept {
147  return (another.data_ == data_ && another.size_ == size_) || !strncmp(data_, another.data_, size_);
148  }
149  inline bool operator ==(const std::basic_string<Ch>& value) const noexcept {
150  return !strncmp(data_, value.data(), size_);
151  }
152  inline constexpr bool operator ==(const std::basic_string_view<Ch>& value) const noexcept {
153  return !strncmp(data_, value.data(), size_);
154  }
155 
156  const Ch* data() const { return data_; }
157 
158  inline void pop_back() noexcept {
159  if (size_)
160  --size_;
161  }
162 
163  inline constexpr char back() const { return data_[size_ - 1]; }
164 
165  inline constexpr const Ch* begin() const { return data_; }
166  inline constexpr const Ch* end() const { return data_ + size_; }
167 
168  inline constexpr SizeType size() const noexcept { return size_; }
169  inline constexpr bool empty() const noexcept { return !size_; }
170  inline constexpr bool is_view() const noexcept { return type_ == text_type::reference; }
171 
172  inline int compare(const char* value) {
173  return strncmp(value, data_, size_);
174  }
175 
176  inline int compare(const basic_text& value) {
177  return strncmp(value.data_, data_, size_);
178  }
179 
180  constexpr static inline basic_text no_text() noexcept {
181  return basic_text("");
182  }
183 
184  friend inline std::ostream& operator << (std::ostream& output, const basic_text& text) {
185  output.write(text.data(), text.size());
186  return output;
187  }
188 
189  private:
190  const Ch* data_;
191  SizeType size_;
192  text_type type_;
193 
194  constexpr inline void destroy() noexcept {
195  if (type_ == text_type::copy && size_)
196  std::free((void*)data_);
197  }
198  };
199 
200  using text = basic_text<char>;
201 
203 
206  template<typename ValueType, typename SizeType = unsigned>
207  class sequence {
208  public:
209  using value_type = ValueType;
210  using const_reference = const ValueType&;
211  using reference = ValueType&;
212  using pointer = ValueType*;
213  using iterator = ValueType*;
214  using const_iterator = const ValueType*;
215 
216  sequence(SizeType initial_capacity = 8) : capacity_(initial_capacity), size_(0) {
217  if (capacity_)
218  items_ = reinterpret_cast<pointer>(std::malloc(capacity_ * sizeof(ValueType)));
219  }
220 
221  sequence(std::initializer_list<value_type> list) : sequence(list.size()) {
222  push_front(list.begin(), list.end());
223  }
224 
225  sequence(const sequence&) = delete;
226  sequence(sequence&& old) : items_(old.items_), capacity_(old.capacity_), size_(old.size_) {
227  old.capacity_ = 0;
228  }
229 
230  ~sequence() { destroy(); }
231 
232  void push_back(value_type&& value) {
233  reserve_item();
234  new (items_ + size_++) ValueType(std::forward<ValueType>(value));
235  }
236 
237  void push_back(const_reference value) {
238  reserve_item();
239  new (items_ + size_++) ValueType(value);
240  }
241 
242  void push_front(const_iterator begin, const_iterator end) noexcept {
243  auto count = end - begin;
244  if (count > capacity_ - size_) {
245  capacity_ += count;
246  items_ = reinterpret_cast<pointer>(std::realloc(items_, capacity_ * sizeof(ValueType)));
247  }
248  if (size_)
249  memmove(items_ + count, items_, count * sizeof(ValueType));
250  for (auto i = 0; i < count; ++i) new (items_ + i) ValueType(begin[i]);
251  size_ += count;
252  }
253 
254  inline constexpr sequence& operator =(sequence&& old) {
255  destroy();
256  size_ = old.size_;
257  items_ = old.items_;
258  capacity_ = old.capacity_;
259  old.capacity_ = 0;
260  return *this;
261  };
262 
263  reference operator [](SizeType index) { return items_[index]; }
264  const_reference operator [](SizeType index) const { return items_[index]; }
265 
267  inline iterator begin() { return items_; }
268 
270  inline iterator end() { return items_ + size_; }
271 
273  inline const_iterator begin() const { return items_; }
274 
276  inline const_iterator end() const { return items_ + size_; }
277 
279  inline SizeType size() const noexcept { return size_; }
280 
282  inline SizeType capacity() const noexcept { return capacity_; }
283 
285  inline bool empty() const noexcept { return !size_; }
286 
287  constexpr static inline sequence no_sequence() noexcept {
288  return sequence(0);
289  }
290 
291  protected:
292  pointer items_;
293  SizeType capacity_;
294  SizeType size_;
295 
296  private:
297  inline void reserve_item() noexcept {
298  if (capacity_ == 0) {
299  capacity_ = 8;
300  items_ = reinterpret_cast<pointer>(std::malloc(capacity_ * sizeof(ValueType)));
301  return;
302  }
303  if (size_ == capacity_) {
304  capacity_ += (capacity_ + 1) / 2;
305  items_ = reinterpret_cast<pointer>(std::realloc(items_, capacity_ * sizeof(ValueType)));
306  }
307  }
308 
309  inline void destroy() noexcept {
310  if (capacity_) {
311  for (auto it = items_; it < (items_ + size_); ++it) it->~ValueType();
312  free(items_);
313  }
314  }
315  };
316 
317 }
318 
319 namespace std {
320  template<typename Ch, typename SizeType>
321  struct hash<garlic::basic_text<Ch, SizeType>> {
322  size_t operator() (const garlic::basic_text<Ch, SizeType>& value) const {
323  return hash<std::string_view>()(std::string_view(value.data(), value.size()));
324  }
325  };
326 }
327 
328 #endif /* end of include guard: GARLIC_CONTAINERS_H */
garlic::Constraint
Smallest unit of data validation.
Definition: constraints.h:275
garlic::basic_text
A container for storing small strings that can either act as a view or as an owner.
Definition: containers.h:67
garlic::sequence::capacity
SizeType capacity() const noexcept
Definition: containers.h:282
garlic::sequence::end
iterator end()
Definition: containers.h:270
garlic::sequence::end
const_iterator end() const
Definition: containers.h:276
garlic::sequence::empty
bool empty() const noexcept
Definition: containers.h:285
garlic::sequence::begin
iterator begin()
Definition: containers.h:267
garlic::sequence::size
SizeType size() const noexcept
Definition: containers.h:279
garlic::sequence::begin
const_iterator begin() const
Definition: containers.h:273
garlic::sequence
A container to store a list of items, similar to std::vector but far more limited.
Definition: containers.h:207
garlic::ConstraintResult
Result of a constriant test.
Definition: constraints.h:18