Skip to content

Commit 55da316

Browse files
committed
Making it possible to add any compatible range to sys_string
1 parent 3547396 commit 55da316

File tree

3 files changed

+112
-47
lines changed

3 files changed

+112
-47
lines changed

lib/inc/sys_string/impl/addition.h

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ namespace sysstr::util
1919
class addend<Storage, sys_string_t<Storage>>
2020
{
2121
public:
22-
addend(sys_string_t<Storage> && str) noexcept:
23-
m_val(std::move(str))
22+
addend(const sys_string_t<Storage> & str) noexcept:
23+
m_val(str)
2424
{}
2525

2626
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
27-
{ return m_val.storage_size(); }
27+
{ return this->m_val.storage_size(); }
2828

2929
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
30-
{ builder.append(m_val); }
30+
{ builder.append(this->m_val); }
3131
private:
32-
sys_string_t<Storage> m_val;
32+
const sys_string_t<Storage> & m_val;
3333
};
3434

3535
template<class Storage>
@@ -43,53 +43,98 @@ namespace sysstr::util
4343
}
4444

4545
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
46-
{ return typename sys_string_t<Storage>::size_type(m_encoded.end() - m_encoded.begin()); }
46+
{ return typename sys_string_t<Storage>::size_type(this->m_encoded.end() - this->m_encoded.begin()); }
4747

4848
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
49-
{ builder.chars().append(m_encoded.begin(), storage_size()); }
49+
{ builder.chars().append(this->m_encoded.begin(), storage_size()); }
5050
private:
5151
utf_codepoint_encoder<utf_encoding_of<typename sys_string_t<Storage>::storage_type>, true> m_encoded;
5252
};
5353

54+
template<class Storage, std::ranges::forward_range Range>
55+
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
56+
class addend<Storage, Range>
57+
{
58+
public:
59+
addend(const Range & range) noexcept:
60+
m_range(range)
61+
{}
62+
63+
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
64+
{
65+
if constexpr (std::is_same_v<std::ranges::range_value_t<Range>, typename sys_string_t<Storage>::storage_type>)
66+
{
67+
if constexpr (std::ranges::sized_range<Range>)
68+
{
69+
return std::ranges::size(this->m_range);
70+
}
71+
else
72+
{
73+
size_t count = 0;
74+
for(auto & x: this->m_range)
75+
++count;
76+
return count;
77+
}
78+
}
79+
else
80+
{
81+
using converter = utf_converter<utf_encoding_of<std::ranges::range_value_t<Range>>,
82+
utf_encoding_of<typename sys_string_t<Storage>::storage_type>>;
83+
return converter::converted_length(this->m_range);
84+
}
85+
}
86+
87+
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
88+
{ builder.append(this->m_range); }
89+
private:
90+
const Range & m_range;
91+
};
92+
5493
template<class Storage, class First, class Second>
5594
class addend<Storage, addition<Storage, First, Second>>
5695
{
5796
public:
58-
addend(addition<Storage, First, Second> && val) noexcept:
59-
m_val(std::move(val))
97+
addend(const addition<Storage, First, Second> & val) noexcept:
98+
m_val(val)
6099
{}
61100

62101
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
63-
{ return m_val.storage_size(); }
102+
{ return this->m_val.storage_size(); }
64103

65104
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
66-
{ m_val.append_to(builder); }
105+
{ this->m_val.append_to(builder); }
67106
private:
68-
addition<Storage, First, Second> m_val;
107+
const addition<Storage, First, Second> & m_val;
69108
};
70109

71110
template<class Storage, class First, class Second>
72111
class addition
73112
{
74113
public:
75-
addition(First left, Second right) noexcept:
76-
m_first{std::move(left)},
77-
m_second{std::move(right)}
114+
addition(const First & left, const Second & right) noexcept:
115+
m_first{left},
116+
m_second{right}
78117
{}
79118

80-
friend auto operator+(addition lhs, sys_string_t<Storage> rhs) noexcept
81-
{ return addition<Storage, addition, sys_string_t<Storage>>(std::move(lhs), std::move(rhs)); }
82-
friend auto operator+(addition lhs, char32_t rhs) noexcept
83-
{ return addition<Storage, addition, char32_t>(std::move(lhs), rhs); }
119+
friend auto operator+(const addition & lhs, const sys_string_t<Storage> & rhs) noexcept
120+
{ return addition<Storage, addition, sys_string_t<Storage>>(lhs, rhs); }
121+
friend auto operator+(const addition & lhs, char32_t rhs) noexcept
122+
{ return addition<Storage, addition, char32_t>(lhs, rhs); }
123+
template <std::ranges::forward_range Range>
124+
friend auto operator+(const addition & lhs, const Range & rhs) noexcept
125+
{ return addition<Storage, addition, Range>(lhs, rhs); }
84126

85-
friend auto operator+(sys_string_t<Storage> lhs, addition rhs) noexcept
86-
{ return addition<Storage, sys_string_t<Storage>, addition>(std::move(lhs), std::move(rhs)); }
87-
friend auto operator+(char32_t lhs, addition rhs) noexcept
88-
{ return addition<Storage, char32_t, addition>(lhs, std::move(rhs)); }
127+
friend auto operator+(const sys_string_t<Storage> & lhs, const addition & rhs) noexcept
128+
{ return addition<Storage, sys_string_t<Storage>, addition>(lhs, rhs); }
129+
friend auto operator+(char32_t lhs, const addition & rhs) noexcept
130+
{ return addition<Storage, char32_t, addition>(lhs, rhs); }
131+
template <std::ranges::forward_range Range>
132+
friend auto operator+(const Range & lhs, const addition & rhs) noexcept
133+
{ return addition<Storage, Range, addition>(lhs, rhs); }
89134

90135
template<class RHSFirst, class RHSSecond>
91-
friend auto operator+(addition lhs, addition<Storage, RHSFirst, RHSSecond> rhs) noexcept
92-
{ return addition<Storage, addition, addition<Storage, RHSFirst, RHSSecond>>(std::move(lhs), std::move(rhs)); }
136+
friend auto operator+(const addition & lhs, const addition<Storage, RHSFirst, RHSSecond> & rhs) noexcept
137+
{ return addition<Storage, addition, addition<Storage, RHSFirst, RHSSecond>>(lhs, rhs); }
93138

94139
operator sys_string_t<Storage>() const
95140
{

lib/inc/sys_string/sys_string.h

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ namespace sysstr
5454
concept builder_appendable = requires(sys_string_builder_t<Storage> builder, T t) {
5555
builder.append(t);
5656
};
57+
58+
template<class T, class Storage>
59+
concept addable = sys_string_or_char<T, Storage> || (
60+
std::ranges::forward_range<T> &&
61+
has_utf_encoding<std::ranges::range_value_t<T>>
62+
);
5763
}
5864

5965
namespace sysstr::util
@@ -315,9 +321,9 @@ namespace sysstr
315321
friend auto compare_no_case(const sys_string_t lhs, const sys_string_t & rhs) noexcept -> std::strong_ordering
316322
{ return sys_string_t::compare_no_case(lhs, rhs); }
317323

318-
template<sys_string_or_char<Storage> StringOrChar1, sys_string_or_char<Storage> StringOrChar2>
319-
friend auto operator+(const StringOrChar1 lhs, const StringOrChar2 rhs) -> util::addition<Storage, StringOrChar1, StringOrChar2>
320-
{ return util::addition<Storage, StringOrChar1, StringOrChar2>(std::move(lhs), std::move(rhs)); }
324+
template<addable<Storage> Addend1, addable<Storage> Addend2>
325+
friend auto operator+(const Addend1 & lhs, const Addend2 & rhs) -> util::addition<Storage, Addend1, Addend2>
326+
{ return util::addition<Storage, Addend1, Addend2>(lhs, rhs); }
321327

322328
auto to_lower() const -> sys_string_t;
323329
auto to_upper() const -> sys_string_t;
@@ -567,44 +573,44 @@ namespace sysstr
567573
template<has_utf_encoding Char>
568574
iterator insert(iterator where, const Char * str)
569575
{
570-
auto res = insert_many(m_impl, where.storage_current(), str, std::char_traits<Char>::length(str));
576+
auto res = insert_many(m_impl, where.storage_current(), std::basic_string_view(str));
571577
return iterator(res, std::ranges::end(m_impl));
572578
}
573579

574580
template<has_utf_encoding Char>
575581
iterator insert(std::default_sentinel_t, const Char * str)
576582
{
577-
auto res = insert_many(m_impl, std::ranges::end(m_impl), str, std::char_traits<Char>::length(str));
583+
auto res = insert_many(m_impl, std::ranges::end(m_impl), std::basic_string_view(str));
578584
return iterator(res, std::ranges::end(m_impl));
579585
}
580586

581587
template<has_utf_encoding Char>
582588
iterator insert(iterator where, const Char * str, size_t len)
583589
{
584-
auto res = insert_many(m_impl, where.storage_current(), str, len);
590+
auto res = insert_many(m_impl, where.storage_current(), std::basic_string_view(str, len));
585591
return iterator(res, std::ranges::end(m_impl));
586592
}
587593

588594
template<has_utf_encoding Char>
589595
iterator insert(std::default_sentinel_t, const Char * str, size_t len)
590596
{
591-
auto res = insert_many(m_impl, std::ranges::end(m_impl), str, len);
597+
auto res = insert_many(m_impl, std::ranges::end(m_impl), std::basic_string_view(str, len));
592598
return iterator(res, std::ranges::end(m_impl));
593599
}
594600

595-
template<std::ranges::contiguous_range Range>
601+
template<std::ranges::input_range Range>
596602
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
597603
iterator insert(iterator where, const Range & range)
598604
{
599-
auto res = insert_many(m_impl, where.storage_current(), std::ranges::data(range), std::ranges::size(range));
605+
auto res = insert_many(m_impl, where.storage_current(), range);
600606
return iterator(res, std::ranges::end(m_impl));
601607
}
602608

603-
template<std::ranges::contiguous_range Range>
609+
template<std::ranges::input_range Range>
604610
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
605611
iterator insert(std::default_sentinel_t, const Range & range)
606612
{
607-
auto res = insert_many(m_impl, std::ranges::end(m_impl), std::ranges::data(range), std::ranges::size(range));
613+
auto res = insert_many(m_impl, std::ranges::end(m_impl), range);
608614
return iterator(res, std::ranges::end(m_impl));
609615
}
610616

@@ -631,19 +637,19 @@ namespace sysstr
631637

632638
template<has_utf_encoding Char>
633639
sys_string_builder_t & append(const Char * str, size_t len)
634-
{ append_many(m_impl, str, len); return *this; }
640+
{ append_many(m_impl, std::basic_string_view(str, len)); return *this; }
635641

636642
template<has_utf_encoding Char>
637643
sys_string_builder_t & append(const Char * str)
638-
{ append_many(m_impl, str, std::char_traits<Char>::length(str)); return *this; }
644+
{ append_many(m_impl, std::basic_string_view(str)); return *this; }
639645

640-
template<std::ranges::contiguous_range Range>
646+
template<std::ranges::input_range Range>
641647
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
642648
sys_string_builder_t & append(const Range & range)
643-
{ append_many(m_impl, std::ranges::data(range), std::ranges::size(range)); return *this; }
649+
{ append_many(m_impl, range); return *this; }
644650

645651
sys_string_builder_t & append(const sys_string_t<Storage> & str)
646-
{ append_range(typename sys_string_t<Storage>::char_access(str)); return *this; }
652+
{ append_many(m_impl, typename sys_string_t<Storage>::char_access(str)); return *this; }
647653

648654
sys_string_t<Storage> build() noexcept
649655
{ return util::build<Storage>(m_impl); }
@@ -664,14 +670,15 @@ namespace sysstr
664670

665671
static typename impl_type::iterator insert_one(impl_type & impl, typename impl_type::iterator where, char32_t c);
666672

667-
template<has_utf_encoding Char>
668-
static void append_many(impl_type & impl, const Char * str, size_t len);
669-
670-
template<has_utf_encoding Char>
671-
static typename impl_type::iterator insert_many(impl_type & impl, typename impl_type::iterator pos, const Char * str, size_t len);
673+
template<std::ranges::input_range Range>
674+
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
675+
static void append_many(impl_type & impl, const Range & range);
672676

673677
template<std::ranges::input_range Range>
674-
void append_range(const Range & range);
678+
requires(has_utf_encoding<std::ranges::range_value_t<Range>>)
679+
static typename impl_type::iterator insert_many(impl_type & impl, typename impl_type::iterator where, const Range & range);
680+
681+
675682

676683
private:
677684
impl_type m_impl;

test/test_general.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include <doctest/doctest.h>
1616

17+
#include <list>
18+
1719
using namespace sysstr;
1820

1921
static_assert(std::is_nothrow_default_constructible_v<sys_string>);
@@ -643,6 +645,8 @@ TEST_CASE( "Partition" ) {
643645
}
644646

645647
TEST_CASE( "Addition" ) {
648+
649+
using namespace std::literals;
646650

647651
CHECK(S("") + S("") == S(""));
648652

@@ -663,7 +667,16 @@ TEST_CASE( "Addition" ) {
663667
CHECK((S("💾") + U'💿') + S("") == S("💾💿⏰"));
664668

665669
CHECK((S("💾") + U'💿') + (U'🜇' + S("")) == S("💾💿🜇⏰"));
670+
CHECK((S("💾") + U'💿') + S("🧡") + (U'🜇' + S("")) == S("💾💿🧡🜇⏰"));
666671
CHECK(((U'a' + S("b")) + (S("💾") + U'💿')) + (U'🜇' + S("")) == S("ab💾💿🜇⏰"));
672+
673+
CHECK(S("💜") + "🧡" == S("💜🧡"));
674+
CHECK("💜" + S("🧡") == S("💜🧡"));
675+
CHECK(S("💜") + "🧡"s == S("💜🧡"));
676+
CHECK("💜"s + S("🧡") == S("💜🧡"));
677+
678+
std::list<char16_t> list{u'Ю'};
679+
CHECK(S("💜") + list == S("💜Ю"));
667680
}
668681

669682
TEST_CASE( "c_str" ) {

0 commit comments

Comments
 (0)