9 #ifndef EAGINE_STRING_LIST_HPP
10 #define EAGINE_STRING_LIST_HPP
22 namespace string_list {
24 static inline auto encode_length(
span_size_t len) -> std::string {
25 return extract(mbs::encode_code_point(mbs::code_point_t(len)));
28 static inline auto element_header_size(
string_view elem) noexcept
31 mbs::decode_sequence_length(mbs::make_cbyte_span(elem)), 0);
37 mbs::do_decode_code_point(mbs::make_cbyte_span(elem), l), 0U);
40 static inline auto element_value_size(
string_view elem) noexcept
42 return element_value_size(elem, elem.size());
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;
57 return slice(list, k, l);
64 const span_size_t l = element_value_size(header, k);
65 return slice(list, i - l, l);
72 const span_size_t l = element_value_size(header, k);
73 EAGINE_ASSERT(i >= k + l);
74 return head(list, i - k - l);
77 static inline void push_back(std::string& list,
string_view value) {
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) {
85 list.append(value.data(),
std_size(vl));
101 EAGINE_ASSERT(s.size() >= hs + vs + hs);
102 return {s.data(), hs + vs + hs};
105 static inline auto _fit(
const char* ptr,
span_size_t max_size) noexcept
114 EAGINE_ASSERT(rev_sz >= hs + vs);
115 EAGINE_MAYBE_UNUSED(rev_sz);
116 return {s.data() - hs - vs, hs + vs + hs};
122 return _rev_fit(
string_view(ptr, foot_sz), rev_sz);
133 return element_header_size(_base());
137 return {
data(), header_size()};
141 return element_value_size(header());
144 auto value_data() const noexcept -> const
char* {
145 return data() + header_size();
149 return {value_data(), value_size()};
153 return element_header_size(_base());
157 return {
data() + header_size() + value_size(), header_size()};
161 template <
typename Func>
162 static inline void for_each_elem(
string_view list, Func func) noexcept {
165 while(i < list.size()) {
166 element elem(list.data() + i, list.size() - i);
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) {
178 for_each_elem(list, adapted_func);
181 template <
typename Func>
182 static inline void rev_for_each_elem(
string_view list, Func func) noexcept {
186 while(!mbs::is_valid_head_byte(
byte(list[i]))) {
187 EAGINE_ASSERT(i > 0);
190 element elem(list.data() + i, i, list.size() - i);
192 i -= elem.header_size() + elem.value_size() + 1;
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) {
202 rev_for_each_elem(list, adapted_func);
216 -> std::tuple<std::string, span_size_t> {
218 const auto cnt = split_into(res, str, sep);
219 return std::make_tuple(std::move(res), cnt);
222 template <
typename Func>
224 for_each_separated_c_str(
const char* str,
const char sep, Func func)
227 const char* bgn = str;
228 const char* pos = bgn;
230 while(
bool(str) && (*pos !=
'\0')) {
245 if((*pos == sep) || (*pos ==
char(0))) {
262 split_c_str_into(std::string& dst,
const char* str,
const char sep)
264 return for_each_separated_c_str(
265 str, sep, [&dst](
auto elem) { push_back(dst, elem); });
268 static inline auto split_c_str(
const char* str,
const char sep)
269 -> std::tuple<std::string, span_size_t> {
271 const auto cnt = split_c_str_into(res, str, sep);
272 return std::make_tuple(std::move(res), cnt);
279 auto get_len = [&len, slen](
const element& elem,
bool first) {
283 len += elem.value_size();
285 for_each_elem(list, get_len);
290 auto fill = [&res, sep](
const element& elem,
bool first) {
294 res.append(elem.value_data(),
std_size(elem.value_size()));
296 for_each_elem(list,
fill);
301 EAGINE_ASSERT(res.size() ==
std_size(len));
307 return join(list, sep,
false);
310 template <
typename Iter>
316 auto _b() const noexcept {
322 EAGINE_ASSERT(mbs::is_valid_head_byte(b));
323 return extract(mbs::do_decode_sequence_length(b));
329 mbs::do_decode_code_point(mbs::make_cbyte_span(el), ll), 0U);
332 void _update()
const {
333 if(_tmp.size() == 0) {
341 using difference_type = std::ptrdiff_t;
345 using iterator_category = std::forward_iterator_tag;
347 iterator(Iter pos) noexcept
350 friend auto operator==(iterator a, iterator b) noexcept {
351 return a._pos == b._pos;
354 friend auto operator!=(iterator a, iterator b) noexcept {
355 return a._pos != b._pos;
358 friend auto operator<(iterator a, iterator b) noexcept {
359 return a._pos < b._pos;
362 auto operator*() const noexcept -> reference {
367 auto operator->() const noexcept -> pointer {
372 auto operator++() noexcept -> auto& {
375 _pos += ll + vl + ll;
380 auto operator++(
int) noexcept -> iterator {
381 iterator result = *
this;
387 template <
typename Iter>
393 auto _b() const noexcept {
397 void _rseek_head() const noexcept {
398 while(!mbs::is_valid_head_byte(_b())) {
405 EAGINE_ASSERT(mbs::is_valid_head_byte(b));
406 return extract(mbs::do_decode_sequence_length(b));
412 mbs::do_decode_code_point(mbs::make_cbyte_span(el), ll), 0U);
415 void _update()
const {
416 if(_tmp.size() == 0) {
425 using difference_type = std::ptrdiff_t;
429 using iterator_category = std::forward_iterator_tag;
431 rev_iterator(Iter pos) noexcept
434 friend auto operator==(rev_iterator a, rev_iterator b) noexcept {
435 return a._pos == b._pos;
438 friend auto operator!=(rev_iterator a, rev_iterator b) noexcept {
439 return a._pos != b._pos;
442 friend auto operator<(rev_iterator a, rev_iterator b) noexcept {
443 return a._pos > b._pos;
446 auto operator*() const noexcept -> reference {
451 auto operator->() const noexcept -> pointer {
456 auto operator++() noexcept -> auto& {
465 auto operator++(
int) noexcept -> rev_iterator {
466 rev_iterator result = *
this;
472 template <
typename Range>
476 using iterator = eagine::string_list::iterator<typename Range::iterator>;
478 range_view(Range& range) noexcept
481 auto begin() const noexcept -> iterator {
482 return {_range.begin()};
485 auto end() const noexcept -> iterator {
486 return {_range.end()};
493 template <
typename Range>
494 class rev_range_view {
498 eagine::string_list::rev_iterator<typename Range::iterator>;
500 rev_range_view(Range& range) noexcept
503 auto begin() const noexcept -> iterator {
504 return {_range.end() - 1};
507 auto end() const noexcept -> iterator {
508 return {_range.begin() - 1};
515 template <
typename Range>
516 class basic_string_list {
520 eagine::string_list::iterator<typename Range::const_iterator>;
521 using reverse_iterator =
522 eagine::string_list::rev_iterator<typename Range::const_iterator>;
524 basic_string_list() noexcept = default;
526 basic_string_list(Range range) noexcept
527 : _range{std::move(range)} {}
529 auto begin() const noexcept -> iterator {
530 return {_range.
begin()};
533 auto end() const noexcept -> iterator {
534 return {_range.end()};
537 auto rbegin() const noexcept -> reverse_iterator {
538 return {_range.end() - 1};
541 auto rend() const noexcept -> reverse_iterator {
542 return {_range.begin() - 1};
551 static inline auto make_string_list(std::string str)
552 -> string_list::basic_string_list<std::string> {
553 return {std::move(str)};
556 static inline auto split_into_string_list(
string_view src,
char sep) {
558 string_list::split_into(temp, src, cover_one(sep));
559 return make_string_list(std::move(temp));
562 static inline auto split_c_str_into_string_list(
const char* src,
char sep) {
564 string_list::split_c_str_into(temp, src, sep);
565 return make_string_list(std::move(temp));
570 #endif // EAGINE_STRING_LIST_HPP