utility.h
Go to the documentation of this file.
1 
7 #ifndef GARLIC_UTILITY_H
8 #define GARLIC_UTILITY_H
9 
10 #include "garlic.h"
11 #include "meta.h"
12 #include "encoding.h"
13 
14 
15 namespace garlic {
16 
30  template<GARLIC_VIEW L1, GARLIC_VIEW L2>
31  static inline std::enable_if_t<!is_comparable<L1, L2>::value, bool>
32  cmp_layers(const L1& layer1, const L2& layer2) {
33  if (layer1.is_int() && layer2.is_int() && layer1.get_int() == layer2.get_int()) return true;
34  else if (layer1.is_string() && layer2.is_string() && std::strcmp(layer1.get_cstr(), layer2.get_cstr()) == 0) {
35  return true;
36  }
37  else if (layer1.is_double() && layer2.is_double() && layer1.get_double() == layer2.get_double()) return true;
38  else if (layer1.is_bool() && layer2.is_bool() && layer1.get_bool() == layer2.get_bool()) return true;
39  else if (layer1.is_null() && layer2.is_null()) return true;
40  else if (layer1.is_list() && layer2.is_list()) {
41  return std::equal(
42  layer1.begin_list(), layer1.end_list(),
43  layer2.begin_list(), layer2.end_list(),
44  [](const auto& item1, const auto& item2) { return cmp_layers(item1, item2); }
45  );
46  } else if (layer1.is_object() && layer2.is_object()) {
47  return std::equal(
48  layer1.begin_member(), layer1.end_member(),
49  layer2.begin_member(), layer2.end_member(),
50  [](const auto& item1, const auto& item2) {
51  return cmp_layers(item1.key, item2.key) && cmp_layers(item1.value, item2.value);
52  }
53  );
54  }
55  return false;
56  }
57 
58  template<GARLIC_VIEW Layer1, GARLIC_VIEW Layer2>
59  static inline std::enable_if_t<is_comparable<Layer1, Layer2>::value, bool>
60  cmp_layers(const Layer1& layer1, const Layer2& layer2) {
61  return layer1 == layer2;
62  }
63 
64 
66 
81  public:
82  using const_iterator = std::string_view::const_iterator;
83 
89  lazy_string_splitter(std::string_view text) : text_(text), cursor_(text.begin()) {}
90 
103  template<typename Callable>
104  void for_each(Callable&& cb) {
105  std::string_view part = this->next();
106  while (!part.empty()) {
107  cb(part);
108  part = this->next();
109  }
110  }
111 
115  std::string_view next() {
116  bool found_word = false;
117  auto it = cursor_;
118  for(; it < text_.end(); it++) {
119  if (*it == '.') {
120  if (found_word) return get_substr(it);
121  else cursor_ = it;
122  } else {
123  if (!found_word) cursor_ = it;
124  found_word = true;
125  }
126  }
127  if (found_word) return get_substr(it);
128  return {};
129  }
130 
131  private:
132  std::string_view text_;
133  const_iterator cursor_;
134 
135  std::string_view get_substr(const const_iterator& it) {
136  auto old_cursor = cursor_;
137  cursor_ = it;
138  return std::string_view{old_cursor, it};
139  }
140  };
141 
142 
149  template<GARLIC_VIEW LayerType, typename Callable>
150  static inline void
151  resolve_layer_cb(const LayerType& value, std::string_view path, Callable&& cb) {
152  using view_type = decltype(value.get_view());
153 
154  lazy_string_splitter parts{path};
155  view_type cursor = value.get_view();
156  while (true) {
157  auto part = parts.next();
158  if (part.empty()) {
159  cb(cursor);
160  return;
161  }
162  if (cursor.is_object()) {
163  bool found = false;
164  get_member(cursor, part, [&cursor, &found](const auto& result) {
165  cursor = result.get_view();
166  found = true;
167  });
168  if (!found) return;
169  } else if (cursor.is_list()) {
170  size_t position;
171  if (std::from_chars(part.begin(), part.end(), position).ec == std::errc::invalid_argument)
172  return;
173  bool found = false;
174  get_item(cursor, position, [&cursor, &found](const auto& result) {
175  cursor = result.get_view();
176  found = true;
177  });
178  if (!found) return;
179  } else return;
180  }
181  }
182 
183 
192  template<typename OutputType, GARLIC_VIEW Layer>
193  static inline OutputType
194  safe_resolve(const Layer& value, std::string_view key, OutputType default_value) {
195  resolve_layer_cb(value, key, [&default_value](const auto& result) {
196  safe_decode<OutputType>(result, [&default_value](auto&& result){
197  default_value = result;
198  });
199  });
200  return default_value;
201  }
202 
203 
212  template<typename OutputType, GARLIC_VIEW Layer, typename Callable>
213  static inline void
214  safe_resolve_cb(const Layer& value, std::string_view key, Callable&& cb) {
215  resolve_layer_cb(value, key, [&cb](const auto& result) {
216  safe_decode<OutputType>(result, cb);
217  });
218  }
219 
220 
228  template<typename OutputType, GARLIC_VIEW Layer>
229  static inline OutputType
230  resolve(const Layer& value, std::string_view key, OutputType default_value) {
231  resolve_layer_cb(value, key, [&default_value](const auto& result) {
232  default_value = decode<OutputType>(result);
233  });
234  return default_value;
235  }
236 
237 
246  template<typename OutputType, GARLIC_VIEW Layer, typename Callable>
247  static inline void
248  resolve_cb(const Layer& value, std::string_view key, Callable&& cb) {
249  resolve_layer_cb(value, key, [&cb](const auto& result) {
250  cb(decode<OutputType>(result, cb));
251  });
252  }
253 
254 
261  template<GARLIC_VIEW Layer, typename Callable>
262  static inline void
263  get_member(const Layer& value, const char* key, Callable&& cb) noexcept {
264  if(auto it = value.find_member(key); it != value.end_member()) cb((*it).value);
265  }
266 
268  template<GARLIC_VIEW Layer, typename Callable>
269  static inline void
270  get_member(const Layer& value, std::string_view key, Callable&& cb) noexcept {
271  if(auto it = value.find_member(key); it != value.end_member()) cb((*it).value);
272  }
273 
274 
282  template<GARLIC_VIEW Layer, std::integral IndexType, typename Callable>
283  static inline std::enable_if_t<std::__is_random_access_iter<ConstValueIteratorOf<Layer>>::value>
284  get_item(Layer&& layer, IndexType index, Callable&& cb) noexcept {
285  if (auto it = layer.begin_list() += index; it < layer.end_list()) cb(*it);
286  }
287 
288 
289  template<GARLIC_VIEW Layer, std::integral IndexType, typename Callable>
290  static inline std::enable_if_t<!std::__is_random_access_iter<ConstValueIteratorOf<Layer>>::value>
291  get_item(Layer&& layer, IndexType index, Callable&& cb) noexcept {
292  auto it = layer.begin_list();
293  IndexType counter = 0;
294  while (it != layer.end_list()) {
295  if (counter == index) {
296  cb(*it);
297  return;
298  }
299  ++counter;
300  ++it;
301  }
302  }
303 
304 
305  template<typename Container, typename ValueType, typename Callable>
306  static inline void
307  find(const Container& container, const ValueType& value, Callable&& cb) {
308  if (auto it = container.find(value); it != container.end()) cb(*it);
309  }
310 
311 
317  template<typename OutputType, GARLIC_VIEW Layer>
318  static inline OutputType
319  get(Layer&& layer, const char* key) {
320  return decode<OutputType>((*layer.find_member(key)).value);
321  }
322 
323 
331  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType>
332  static inline std::enable_if_t<std::__is_random_access_iter<ConstValueIteratorOf<Layer>>::value, OutputType>
333  get(Layer&& layer, IndexType index) {
334  return decode<OutputType>(layer.begin_list()[index]);
335  }
336 
337 
338  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType>
339  static inline std::enable_if_t<!std::__is_random_access_iter<ConstValueIteratorOf<Layer>>::value, OutputType>
340  get(Layer&& layer, IndexType index) {
341  auto it = layer.begin_list();
342  while (index > 0) {
343  --index;
344  ++it;
345  }
346  return decode<OutputType>(*it);
347  }
348 
349 
355  template<typename OutputType, GARLIC_VIEW Layer>
356  static inline OutputType
357  get(Layer&& layer, const char* key, OutputType default_value) {
358  if (auto it = layer.find_member(key); it != layer.end_member()) {
359  return decode<OutputType>((*it).value);
360  }
361  return default_value;
362  }
363 
364 
370  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType>
371  static inline OutputType
372  get(Layer&& layer, IndexType index, OutputType default_value) {
373  get_item(layer, index, [&default_value](const auto& result) {
374  default_value = decode<OutputType>(result);
375  });
376  return default_value;
377  }
378 
379 
387  template<typename OutputType, typename Callable, GARLIC_VIEW Layer>
388  static inline void
389  get_cb(Layer&& layer, const char* key, Callable&& cb) {
390  if (auto it = layer.find_member(key); it != layer.end_member()) {
391  cb(decode<OutputType>((*it).value));
392  }
393  }
394 
395 
402  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType, typename Callable>
403  static inline void
404  get_cb(Layer&& layer, IndexType index, Callable&& cb) {
405  get_item(layer, index, [&cb](const auto& result){
406  cb(decode<OutputType>(result));
407  });
408  }
409 
410 
416  template<typename OutputType, GARLIC_VIEW Layer>
417  static inline OutputType
418  safe_get(Layer&& layer, const char* key, OutputType default_value) {
419  if (auto it = layer.find_member(key); it != layer.end_member()) {
420  safe_decode<OutputType>(
421  (*it).value,
422  [&default_value](auto&& result) { default_value = result; });
423  }
424  return default_value;
425  }
426 
427 
433  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType>
434  static inline OutputType
435  safe_get(Layer&& layer, IndexType index, OutputType default_value) {
436  get_item(layer, index, [&default_value](const auto& result) {
437  safe_decode<OutputType>(result, [&default_value](auto&& value){
438  default_value = value;
439  });
440  });
441  return default_value;
442  }
443 
444 
452  template<typename OutputType, GARLIC_VIEW Layer, typename Callable>
453  static inline void
454  safe_get_cb(Layer&& layer, const char* key, Callable&& cb) {
455  if (auto it = layer.find_member(key); it != layer.end_member()) {
456  safe_decode<OutputType>((*it).value, cb);
457  }
458  }
459 
460 
467  template<typename OutputType, GARLIC_VIEW Layer, std::integral IndexType, typename Callable>
468  static inline void
469  safe_get_cb(Layer&& layer, IndexType index, Callable&& cb) {
470  get_item(layer, index, [&cb](const auto& result) {
471  safe_decode<OutputType>(result, cb);
472  });
473  }
474 
475 
483  template<GARLIC_VIEW Layer, GARLIC_REF Output>
484  static inline void
485  copy_layer(Layer&& layer, Output output) {
486  if (layer.is_double()) {
487  output.set_double(layer.get_double());
488  } else if (layer.is_int()) {
489  output.set_int(layer.get_int());
490  } else if (layer.is_bool()) {
491  output.set_bool(layer.get_bool());
492  } else if (layer.is_string()) {
493  output.set_string(layer.get_cstr());
494  } else if (layer.is_list()) {
495  output.set_list();
496  for (const auto& item : layer.get_list()) {
497  output.push_back_builder(
498  [&item](auto ref) { copy_layer(item, ref); }
499  );
500  }
501  } else if (layer.is_object()) {
502  output.set_object();
503  for (const auto& pair : layer.get_object()) {
504  output.add_member_builder(
505  pair.key.get_cstr(),
506  [&pair](auto ref) { copy_layer(pair.value, ref); }
507  );
508  }
509  } else {
510  output.set_null();
511  }
512  }
513 
514  namespace internal {
515 
516  template<GARLIC_VIEW Layer>
517  static constexpr bool has_random_access_list_iterator = std::__is_random_access_iter<ConstValueIteratorOf<Layer>>::value;
518 
519  template<GARLIC_VIEW, class = void>
520  static constexpr bool has_explicit_list_size_method = false;
521 
522  template<GARLIC_VIEW Layer>
523  static constexpr bool has_explicit_list_size_method<Layer, decltype(std::declval<Layer>().list_size())> = true;
524 
525  // Use explicit list_size method.
526  template<GARLIC_VIEW Layer>
527  static inline std::enable_if_t<has_explicit_list_size_method<Layer>, size_t>
528  list_size_impl(Layer&& layer) {
529  return layer.list_size();
530  }
531 
532  // Use random access iterators when available and there is no explicit list_size() method defined.
533  template<GARLIC_VIEW Layer>
534  static inline std::enable_if_t<has_random_access_list_iterator<Layer> && !has_explicit_list_size_method<Layer>, size_t>
535  list_size_impl(Layer&& layer) {
536  return layer.end_list() - layer.begin_list();
537  }
538 
539  // Worst outcome, use a loop!
540  template<GARLIC_VIEW Layer>
541  static inline std::enable_if_t<!has_random_access_list_iterator<Layer> && !has_explicit_list_size_method<Layer>, size_t>
542  list_size_impl(Layer&& layer) {
543  size_t count = 0;
544  for (auto it = layer.begin_list(); it != layer.end_list(); ++it)
545  ++count;
546  return count;
547  }
548 
549  template<GARLIC_VIEW, class = void>
550  static constexpr bool has_explicit_string_length_method = false;
551 
552  template<GARLIC_VIEW Layer>
553  static constexpr bool has_explicit_string_length_method<Layer, decltype(std::declval<Layer>().string_length())> = true;
554 
555  template<GARLIC_VIEW Layer>
556  static inline std::enable_if_t<has_explicit_string_length_method<Layer>, size_t>
557  string_length_impl(Layer&& layer) {
558  return layer.string_length();
559  }
560 
561  template<GARLIC_VIEW Layer>
562  static inline std::enable_if_t<!has_explicit_string_length_method<Layer>, size_t>
563  string_length_impl(Layer&& layer) {
564  return strlen(layer.get_cstr());
565  }
566  }
567 
569 
574  template<GARLIC_VIEW Layer>
575  static inline size_t list_size(Layer&& layer) {
576  return internal::list_size_impl(layer);
577  }
578 
580 
584  template<GARLIC_VIEW Layer>
585  static inline size_t string_length(Layer&& layer) {
586  return internal::string_length_impl(layer);
587  }
588 
589 
590  template<int BufferSize = 65536>
591  class FileStreamBuffer : public std::streambuf {
592  public:
593  FileStreamBuffer(FILE* file) : file_(file) {}
594 
595  std::streambuf::int_type underflow() override {
596  auto length = fread(read_buffer_, 1, sizeof(read_buffer_), file_);
597  if (!length) return traits_type::eof();
598  setg(read_buffer_, read_buffer_, read_buffer_ + length);
599  return traits_type::to_int_type(*gptr());
600  }
601 
602  private:
603  FILE* file_;
604  char read_buffer_[BufferSize];
605  };
606 
607 }
608 
609 #endif /* end of include guard: GARLIC_UTILITY_H */
garlic::basic_text< char >
garlic::string_length
static size_t string_length(Layer &&layer)
Get the length of a string from a layer.
Definition: utility.h:585
garlic::resolve_layer_cb
static void resolve_layer_cb(const LayerType &value, std::string_view path, Callable &&cb)
Definition: utility.h:151
encoding.h
Contains classes and methods for defining and using encoders/decoders for various types.
garlic::resolve_cb
static void resolve_cb(const Layer &value, std::string_view key, Callable &&cb)
Definition: utility.h:248
garlic::copy_layer
static void copy_layer(Layer &&layer, Output output)
Definition: utility.h:485
garlic::get_cb
static void get_cb(Layer &&layer, const char *key, Callable &&cb)
Definition: utility.h:389
garlic::resolve
static OutputType resolve(const Layer &value, std::string_view key, OutputType default_value)
Definition: utility.h:230
garlic::get
static OutputType get(Layer &&layer, const char *key)
Definition: utility.h:319
garlic::safe_resolve_cb
static void safe_resolve_cb(const Layer &value, std::string_view key, Callable &&cb)
Definition: utility.h:214
garlic::list_size
static size_t list_size(Layer &&layer)
Get the size of a list from a layer.
Definition: utility.h:575
garlic::cmp_layers
static std::enable_if_t<!is_comparable< L1, L2 >::value, bool > cmp_layers(const L1 &layer1, const L2 &layer2)
Checks the equality of two layers.
Definition: utility.h:32
garlic::get_member
static void get_member(const Layer &value, const char *key, Callable &&cb) noexcept
Definition: utility.h:263
garlic::get_item
static std::enable_if_t< std::__is_random_access_iter< ConstValueIteratorOf< Layer > >::value > get_item(Layer &&layer, IndexType index, Callable &&cb) noexcept
Definition: utility.h:284
garlic::safe_resolve
static OutputType safe_resolve(const Layer &value, std::string_view key, OutputType default_value)
Definition: utility.h:194
garlic::safe_get_cb
static void safe_get_cb(Layer &&layer, const char *key, Callable &&cb)
Definition: utility.h:454
garlic::lazy_string_splitter
Lazy string splitter for getting tokens one by one.
Definition: utility.h:80
garlic::lazy_string_splitter::for_each
void for_each(Callable &&cb)
If one needs to parse every single token, this is a good option as it will exhaust the splitter and k...
Definition: utility.h:104
garlic::safe_get
static OutputType safe_get(Layer &&layer, const char *key, OutputType default_value)
Definition: utility.h:418
garlic::lazy_string_splitter::next
std::string_view next()
Definition: utility.h:115
garlic::lazy_string_splitter::lazy_string_splitter
lazy_string_splitter(std::string_view text)
Takes a std::string_view object for reference while processing the text.
Definition: utility.h:89