OGLplus  (0.59.0) a C++ wrapper for rendering APIs

string_list.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_STRING_LIST_HPP
10 #define EAGINE_STRING_LIST_HPP
11 
12 #include "assert.hpp"
13 #include "maybe_unused.hpp"
14 #include "memory/span_algo.hpp"
15 #include "multi_byte_seq.hpp"
16 #include "string_span.hpp"
17 #include <iterator>
18 #include <string>
19 #include <tuple>
20 
21 namespace eagine {
22 namespace string_list {
23 //------------------------------------------------------------------------------
24 static inline auto encode_length(span_size_t len) -> std::string {
25  return extract(mbs::encode_code_point(mbs::code_point_t(len)));
26 }
27 //------------------------------------------------------------------------------
28 static inline auto element_header_size(string_view elem) noexcept
29  -> span_size_t {
30  return extract_or(
31  mbs::decode_sequence_length(mbs::make_cbyte_span(elem)), 0);
32 }
33 //------------------------------------------------------------------------------
34 static inline auto element_value_size(string_view elem, span_size_t l) noexcept
35  -> span_size_t {
36  return extract_or(
37  mbs::do_decode_code_point(mbs::make_cbyte_span(elem), l), 0U);
38 }
39 //------------------------------------------------------------------------------
40 static inline auto element_value_size(string_view elem) noexcept
41  -> span_size_t {
42  return element_value_size(elem, elem.size());
43 }
44 //------------------------------------------------------------------------------
45 static inline auto rev_seek_header_start(string_view elem) -> span_size_t {
46  for(auto i = elem.rbegin(); i != elem.rend(); ++i) {
47  if(mbs::is_valid_head_byte(byte(*i))) {
48  return elem.rend() - i - 1;
49  }
50  }
51  return 0;
52 }
53 //------------------------------------------------------------------------------
54 static inline auto front_value(string_view list) noexcept -> string_view {
55  const span_size_t k = element_header_size(list);
56  const span_size_t l = element_value_size(list, k);
57  return slice(list, k, l);
58 }
59 //------------------------------------------------------------------------------
60 static inline auto back_value(string_view list) noexcept -> string_view {
61  const span_size_t i = rev_seek_header_start(list);
62  string_view header = skip(list, i);
63  const span_size_t k = element_header_size(header);
64  const span_size_t l = element_value_size(header, k);
65  return slice(list, i - l, l);
66 }
67 //------------------------------------------------------------------------------
68 static inline auto pop_back(string_view list) noexcept -> string_view {
69  const span_size_t i = rev_seek_header_start(list);
70  string_view header = skip(list, i);
71  const span_size_t k = element_header_size(header);
72  const span_size_t l = element_value_size(header, k);
73  EAGINE_ASSERT(i >= k + l);
74  return head(list, i - k - l);
75 }
76 //------------------------------------------------------------------------------
77 static inline void push_back(std::string& list, string_view value) {
78  const span_size_t vl = value.size();
79  const std::string elen = encode_length(vl);
80  const std::size_t nl = list.size() + elen.size() * 2 + std_size(vl);
81  if(list.capacity() < nl) {
82  list.reserve(nl);
83  }
84  list.append(elen);
85  list.append(value.data(), std_size(vl));
86  list.append(elen);
87 }
88 //------------------------------------------------------------------------------
89 class element : public string_view {
90 private:
91  auto _base() -> string_view {
92  return *this;
93  }
94  auto _base() const -> string_view {
95  return *this;
96  }
97 
98  static inline auto _fit(string_view s) noexcept -> string_view {
99  span_size_t hs = element_header_size(s);
100  span_size_t vs = element_value_size(s, hs);
101  EAGINE_ASSERT(s.size() >= hs + vs + hs);
102  return {s.data(), hs + vs + hs};
103  }
104 
105  static inline auto _fit(const char* ptr, span_size_t max_size) noexcept
106  -> string_view {
107  return _fit(string_view(ptr, max_size));
108  }
109 
110  static inline auto _rev_fit(string_view s, span_size_t rev_sz) noexcept
111  -> string_view {
112  span_size_t hs = element_header_size(s);
113  span_size_t vs = element_value_size(s, hs);
114  EAGINE_ASSERT(rev_sz >= hs + vs);
115  EAGINE_MAYBE_UNUSED(rev_sz);
116  return {s.data() - hs - vs, hs + vs + hs};
117  }
118 
119  static inline auto
120  _rev_fit(const char* ptr, span_size_t rev_sz, span_size_t foot_sz) noexcept
121  -> string_view {
122  return _rev_fit(string_view(ptr, foot_sz), rev_sz);
123  }
124 
125 public:
126  element(const char* ptr, span_size_t max_size) noexcept
127  : string_view(_fit(ptr, max_size)) {}
128 
129  element(const char* ptr, span_size_t rev_sz, span_size_t foot_sz) noexcept
130  : string_view(_rev_fit(ptr, rev_sz, foot_sz)) {}
131 
132  auto header_size() const noexcept -> span_size_t {
133  return element_header_size(_base());
134  }
135 
136  auto header() const noexcept -> string_view {
137  return {data(), header_size()};
138  }
139 
140  auto value_size() const noexcept -> span_size_t {
141  return element_value_size(header());
142  }
143 
144  auto value_data() const noexcept -> const char* {
145  return data() + header_size();
146  }
147 
148  auto value() const noexcept -> string_view {
149  return {value_data(), value_size()};
150  }
151 
152  auto footer_size() const noexcept -> span_size_t {
153  return element_header_size(_base());
154  }
155 
156  auto footer() const noexcept -> string_view {
157  return {data() + header_size() + value_size(), header_size()};
158  }
159 };
160 //------------------------------------------------------------------------------
161 template <typename Func>
162 static inline void for_each_elem(string_view list, Func func) noexcept {
163  span_size_t i = 0;
164  bool first = true;
165  while(i < list.size()) {
166  element elem(list.data() + i, list.size() - i);
167  func(elem, first);
168  i += elem.size();
169  first = false;
170  }
171 }
172 //------------------------------------------------------------------------------
173 template <typename Func>
174 static inline void for_each(string_view list, Func func) noexcept {
175  auto adapted_func = [&func](const element& elem, bool) {
176  func(elem.value());
177  };
178  for_each_elem(list, adapted_func);
179 }
180 //------------------------------------------------------------------------------
181 template <typename Func>
182 static inline void rev_for_each_elem(string_view list, Func func) noexcept {
183  span_size_t i = list.size() - 1;
184  bool first = true;
185  while(i > 0) {
186  while(!mbs::is_valid_head_byte(byte(list[i]))) {
187  EAGINE_ASSERT(i > 0);
188  --i;
189  }
190  element elem(list.data() + i, i, list.size() - i);
191  func(elem, first);
192  i -= elem.header_size() + elem.value_size() + 1;
193  first = false;
194  }
195 }
196 //------------------------------------------------------------------------------
197 template <typename Func>
198 static inline void rev_for_each(string_view list, Func func) noexcept {
199  auto adapted_func = [&func](const element& elem, bool) {
200  func(elem.value());
201  };
202  rev_for_each_elem(list, adapted_func);
203 }
204 //------------------------------------------------------------------------------
205 static inline auto
206 split_into(std::string& dst, string_view str, string_view sep) -> span_size_t {
207  span_size_t cnt = 0;
208  for_each_delimited(str, sep, [&dst, &cnt](const auto& x) {
209  push_back(dst, x);
210  ++cnt;
211  });
212  return cnt;
213 }
214 //------------------------------------------------------------------------------
215 static inline auto split(string_view str, string_view sep)
216  -> std::tuple<std::string, span_size_t> {
217  std::string res;
218  const auto cnt = split_into(res, str, sep);
219  return std::make_tuple(std::move(res), cnt);
220 }
221 //------------------------------------------------------------------------------
222 template <typename Func>
223 static inline auto
224 for_each_separated_c_str(const char* str, const char sep, Func func)
225  -> span_size_t {
226  span_size_t cnt = 0;
227  const char* bgn = str;
228  const char* pos = bgn;
229  if(sep != '\0') {
230  while(bool(str) && (*pos != '\0')) {
231  if(*pos == sep) {
232  if(pos - bgn > 0) {
233  func(string_view(bgn, pos - bgn));
234  ++cnt;
235  bgn = ++pos;
236  } else {
237  break;
238  }
239  } else {
240  ++pos;
241  }
242  }
243  } else {
244  while(bool(str)) {
245  if((*pos == sep) || (*pos == char(0))) {
246  if(pos - bgn > 1) {
247  func(string_view(bgn, pos - bgn));
248  ++cnt;
249  bgn = ++pos;
250  } else {
251  break;
252  }
253  } else {
254  ++pos;
255  }
256  }
257  }
258  return cnt;
259 }
260 //------------------------------------------------------------------------------
261 static inline auto
262 split_c_str_into(std::string& dst, const char* str, const char sep)
263  -> span_size_t {
264  return for_each_separated_c_str(
265  str, sep, [&dst](auto elem) { push_back(dst, elem); });
266 }
267 //------------------------------------------------------------------------------
268 static inline auto split_c_str(const char* str, const char sep)
269  -> std::tuple<std::string, span_size_t> {
270  std::string res;
271  const auto cnt = split_c_str_into(res, str, sep);
272  return std::make_tuple(std::move(res), cnt);
273 }
274 //------------------------------------------------------------------------------
275 static inline auto join(string_view list, string_view sep, bool trail_sep)
276  -> std::string {
277  span_size_t slen = sep.size();
278  span_size_t len = trail_sep ? slen : 0;
279  auto get_len = [&len, slen](const element& elem, bool first) {
280  if(!first) {
281  len += slen;
282  }
283  len += elem.value_size();
284  };
285  for_each_elem(list, get_len);
286 
287  std::string res;
288  res.reserve(std_size(len));
289 
290  auto fill = [&res, sep](const element& elem, bool first) {
291  if(!first) {
292  append_to(res, sep);
293  }
294  res.append(elem.value_data(), std_size(elem.value_size()));
295  };
296  for_each_elem(list, fill);
297 
298  if(trail_sep) {
299  append_to(res, sep);
300  }
301  EAGINE_ASSERT(res.size() == std_size(len));
302 
303  return res;
304 }
305 //------------------------------------------------------------------------------
306 static inline auto join(string_view list, string_view sep) -> std::string {
307  return join(list, sep, false);
308 }
309 //------------------------------------------------------------------------------
310 template <typename Iter>
311 class iterator {
312 private:
313  Iter _pos;
314  mutable string_view _tmp;
315 
316  auto _b() const noexcept {
317  return byte(*_pos);
318  }
319 
320  auto _len_len() const noexcept -> span_size_t {
321  byte b = _b();
322  EAGINE_ASSERT(mbs::is_valid_head_byte(b));
323  return extract(mbs::do_decode_sequence_length(b));
324  }
325 
326  auto _val_len(span_size_t ll) const noexcept -> span_size_t {
327  string_view el{&*_pos, ll};
328  return extract_or(
329  mbs::do_decode_code_point(mbs::make_cbyte_span(el), ll), 0U);
330  }
331 
332  void _update() const {
333  if(_tmp.size() == 0) {
334  span_size_t ll = _len_len();
335  span_size_t vl = _val_len(ll);
336  _tmp = string_view{&*(_pos + ll), vl};
337  }
338  }
339 
340 public:
341  using difference_type = std::ptrdiff_t;
342  using value_type = string_view;
343  using reference = const value_type&;
344  using pointer = const value_type*;
345  using iterator_category = std::forward_iterator_tag;
346 
347  iterator(Iter pos) noexcept
348  : _pos(pos) {}
349 
350  friend auto operator==(iterator a, iterator b) noexcept {
351  return a._pos == b._pos;
352  }
353 
354  friend auto operator!=(iterator a, iterator b) noexcept {
355  return a._pos != b._pos;
356  }
357 
358  friend auto operator<(iterator a, iterator b) noexcept {
359  return a._pos < b._pos;
360  }
361 
362  auto operator*() const noexcept -> reference {
363  _update();
364  return _tmp;
365  }
366 
367  auto operator->() const noexcept -> pointer {
368  _update();
369  return &_tmp;
370  }
371 
372  auto operator++() noexcept -> auto& {
373  span_size_t ll = _len_len();
374  span_size_t vl = _val_len(ll);
375  _pos += ll + vl + ll;
376  _tmp = string_view();
377  return *this;
378  }
379 
380  auto operator++(int) noexcept -> iterator {
381  iterator result = *this;
382  ++(*this);
383  return result;
384  }
385 };
386 //------------------------------------------------------------------------------
387 template <typename Iter>
388 class rev_iterator {
389 private:
390  mutable Iter _pos;
391  mutable string_view _tmp;
392 
393  auto _b() const noexcept {
394  return byte(*_pos);
395  }
396 
397  void _rseek_head() const noexcept {
398  while(!mbs::is_valid_head_byte(_b())) {
399  --_pos;
400  }
401  }
402 
403  auto _len_len() const noexcept -> span_size_t {
404  byte b = _b();
405  EAGINE_ASSERT(mbs::is_valid_head_byte(b));
406  return extract(mbs::do_decode_sequence_length(b));
407  }
408 
409  auto _val_len(span_size_t ll) const noexcept -> span_size_t {
410  string_view el{&*_pos, ll};
411  return extract_or(
412  mbs::do_decode_code_point(mbs::make_cbyte_span(el), ll), 0U);
413  }
414 
415  void _update() const {
416  if(_tmp.size() == 0) {
417  _rseek_head();
418  span_size_t ll = _len_len();
419  span_size_t vl = _val_len(ll);
420  _tmp = string_view{&*(_pos - vl), vl};
421  }
422  }
423 
424 public:
425  using difference_type = std::ptrdiff_t;
426  using value_type = string_view;
427  using reference = const value_type&;
428  using pointer = const value_type*;
429  using iterator_category = std::forward_iterator_tag;
430 
431  rev_iterator(Iter pos) noexcept
432  : _pos(pos) {}
433 
434  friend auto operator==(rev_iterator a, rev_iterator b) noexcept {
435  return a._pos == b._pos;
436  }
437 
438  friend auto operator!=(rev_iterator a, rev_iterator b) noexcept {
439  return a._pos != b._pos;
440  }
441 
442  friend auto operator<(rev_iterator a, rev_iterator b) noexcept {
443  return a._pos > b._pos;
444  }
445 
446  auto operator*() const noexcept -> reference {
447  _update();
448  return _tmp;
449  }
450 
451  auto operator->() const noexcept -> pointer {
452  _update();
453  return &_tmp;
454  }
455 
456  auto operator++() noexcept -> auto& {
457  _rseek_head();
458  span_size_t ll = _len_len();
459  span_size_t vl = _val_len(ll);
460  _pos -= ll + vl + 1;
461  _tmp = string_view();
462  return *this;
463  }
464 
465  auto operator++(int) noexcept -> rev_iterator {
466  rev_iterator result = *this;
467  ++(*this);
468  return result;
469  }
470 };
471 //------------------------------------------------------------------------------
472 template <typename Range>
473 class range_view {
474 
475 public:
476  using iterator = eagine::string_list::iterator<typename Range::iterator>;
477 
478  range_view(Range& range) noexcept
479  : _range{range} {}
480 
481  auto begin() const noexcept -> iterator {
482  return {_range.begin()};
483  }
484 
485  auto end() const noexcept -> iterator {
486  return {_range.end()};
487  }
488 
489 private:
490  Range& _range;
491 };
492 //------------------------------------------------------------------------------
493 template <typename Range>
494 class rev_range_view {
495 
496 public:
497  using iterator =
498  eagine::string_list::rev_iterator<typename Range::iterator>;
499 
500  rev_range_view(Range& range) noexcept
501  : _range{range} {}
502 
503  auto begin() const noexcept -> iterator {
504  return {_range.end() - 1};
505  }
506 
507  auto end() const noexcept -> iterator {
508  return {_range.begin() - 1};
509  }
510 
511 private:
512  Range& _range;
513 };
514 //------------------------------------------------------------------------------
515 template <typename Range>
516 class basic_string_list {
517 public:
518  using value_type = string_view;
519  using iterator =
520  eagine::string_list::iterator<typename Range::const_iterator>;
521  using reverse_iterator =
522  eagine::string_list::rev_iterator<typename Range::const_iterator>;
523 
524  basic_string_list() noexcept = default;
525 
526  basic_string_list(Range range) noexcept
527  : _range{std::move(range)} {}
528 
529  auto begin() const noexcept -> iterator {
530  return {_range.begin()};
531  }
532 
533  auto end() const noexcept -> iterator {
534  return {_range.end()};
535  }
536 
537  auto rbegin() const noexcept -> reverse_iterator {
538  return {_range.end() - 1};
539  }
540 
541  auto rend() const noexcept -> reverse_iterator {
542  return {_range.begin() - 1};
543  }
544 
545 private:
546  Range _range{};
547 };
548 //------------------------------------------------------------------------------
549 } // namespace string_list
550 //------------------------------------------------------------------------------
551 static inline auto make_string_list(std::string str)
552  -> string_list::basic_string_list<std::string> {
553  return {std::move(str)};
554 }
555 //------------------------------------------------------------------------------
556 static inline auto split_into_string_list(string_view src, char sep) {
557  std::string temp;
558  string_list::split_into(temp, src, cover_one(sep));
559  return make_string_list(std::move(temp));
560 }
561 //------------------------------------------------------------------------------
562 static inline auto split_c_str_into_string_list(const char* src, char sep) {
563  std::string temp;
564  string_list::split_c_str_into(temp, src, sep);
565  return make_string_list(std::move(temp));
566 }
567 //------------------------------------------------------------------------------
568 } // namespace eagine
569 
570 #endif // EAGINE_STRING_LIST_HPP
value_type
Value tree value element data type enumeration.
Definition: interface.hpp:27
static constexpr auto slice(basic_span< T, P, S > s, I i, L l) noexcept -> basic_span< T, P, S >
Returns a slice of span starting at specified index with specified length.
Definition: span_algo.hpp:47
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
basic_string_span< const char > string_view
Alias for const string views.
Definition: string_span.hpp:116
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
constexpr auto begin() const noexcept -> iterator
Returns an interator to the start of the span.
Definition: span.hpp:259
static constexpr auto head(basic_span< T, P, S > s, L l) noexcept -> basic_span< T, P, S >
Returns the first l elements from the front of a span.
Definition: span_algo.hpp:99
static constexpr auto std_size(T v) noexcept
Converts argument to std size type.
Definition: types.hpp:52
constexpr auto element(Int index) const noexcept -> std::enable_if_t< std::is_integral_v< Int >, std::add_const_t< value_type > & >
Returns a const reference to value at the specified index.
Definition: span.hpp:366
static constexpr auto operator!=(const valid_if< T, P1 > &v1, const valid_if< T, P2 > &v2) noexcept -> tribool
Non-equality comparison of two conditionally valid values.
Definition: decl.hpp:169
static constexpr auto skip(basic_span< T, P, S > s, L l) noexcept -> basic_span< T, P, S >
Skips a specified count of elements from the front of a span.
Definition: span_algo.hpp:60
unsigned char byte
Byte type alias.
Definition: types.hpp:24
static auto fill(basic_span< T, P, S > spn, const V &v) -> basic_span< T, P, S >
Fills a span with copies of the specified value.
Definition: span_algo.hpp:536
static void for_each_delimited(basic_span< T1, P1, S1 > spn, basic_span< T2, P2, S2 > delim, UnaryOperation unary_op)
Scans span for parts split by delimiter, calls a function for each part.
Definition: span_algo.hpp:723
constexpr auto data() const noexcept -> pointer
Returns a pointer to the start of the span.
Definition: span.hpp:254
auto operator==(message_id l, static_message_id< ClassId, MethodId > r) noexcept
Equality comparison between message_id and static_message_id.
Definition: message_id.hpp:131
static constexpr auto operator<(const valid_if< T, P1 > &v1, const valid_if< T, P2 > &v2) noexcept -> tribool
Less-than comparison of two conditionally valid values.
Definition: decl.hpp:180
static constexpr auto append_to(std::basic_string< C, T, A > &str, memory::basic_span< const C, P, S > spn) -> auto &
Appends the contents of a span of characters to a standard string.
Definition: string_span.hpp:147

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).