Skip to content

Commit 12cc3cd

Browse files
committed
Reducing branching in addition
1 parent bd60cc5 commit 12cc3cd

1 file changed

Lines changed: 45 additions & 29 deletions

File tree

lib/inc/sys_string/impl/addition.h

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@
1212

1313
namespace sysstr::util
1414
{
15+
template<class Storage>
16+
class size_accumulator {
17+
public:
18+
19+
void add(size_t s) noexcept
20+
{
21+
m_overflow = m_overflow || (size_t(Storage::max_size) - m_size < s);
22+
m_size += s;
23+
}
24+
25+
bool overflow() const noexcept
26+
{ return m_overflow; }
27+
28+
auto value() const noexcept
29+
{ return typename sys_string_t<Storage>::size_type(m_size); }
30+
private:
31+
size_t m_size = 0;
32+
bool m_overflow = false;
33+
};
34+
1535
template<class Storage, class T>
1636
class addend;
1737

@@ -23,8 +43,8 @@ namespace sysstr::util
2343
m_val(str)
2444
{}
2545

26-
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
27-
{ return this->m_val.storage_size(); }
46+
void add_size(size_accumulator<Storage> & acc) const noexcept
47+
{ acc.add(size_t(this->m_val.storage_size())); }
2848

2949
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
3050
{ builder.append(this->m_val); }
@@ -42,11 +62,14 @@ namespace sysstr::util
4262
m_encoded.put(U'\uFFFD');
4363
}
4464

45-
auto storage_size() const noexcept -> typename sys_string_t<Storage>::size_type
46-
{ return typename sys_string_t<Storage>::size_type(this->m_encoded.end() - this->m_encoded.begin()); }
65+
void add_size(size_accumulator<Storage> & acc) const noexcept
66+
{ acc.add(size_t(this->m_encoded.end() - this->m_encoded.begin())); }
4767

4868
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
49-
{ builder.chars().append(this->m_encoded.begin(), storage_size()); }
69+
{
70+
builder.chars().append(this->m_encoded.begin(),
71+
typename sys_string_t<Storage>::size_type(this->m_encoded.end() - this->m_encoded.begin()));
72+
}
5073
private:
5174
utf_codepoint_encoder<utf_encoding_of<typename sys_string_t<Storage>::storage_type>, true> m_encoded;
5275
};
@@ -65,13 +88,8 @@ namespace sysstr::util
6588
m_view(ptr)
6689
{}
6790

68-
auto storage_size() const -> typename sys_string_t<Storage>::size_type
69-
{
70-
size_t count = m_view.size();
71-
if (count > size_t(Storage::max_size))
72-
throw std::bad_alloc();
73-
return static_cast<typename sys_string_t<Storage>::size_type>(count);
74-
}
91+
void add_size(size_accumulator<Storage> & acc) const noexcept
92+
{ acc.add(m_view.size()); }
7593

7694
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
7795
{ builder.append(m_view); }
@@ -90,31 +108,28 @@ namespace sysstr::util
90108
m_range(range)
91109
{}
92110

93-
auto storage_size() const -> typename sys_string_t<Storage>::size_type
111+
void add_size(size_accumulator<Storage> & acc) const
94112
{
95-
size_t count;
96113
if constexpr (std::is_same_v<std::ranges::range_value_t<Range>, typename sys_string_t<Storage>::storage_type>)
97114
{
98115
if constexpr (std::ranges::sized_range<Range>)
99116
{
100-
count = std::ranges::size(this->m_range);
117+
acc.add(std::ranges::size(this->m_range));
101118
}
102119
else
103120
{
104-
count = 0;
121+
size_t count = 0;
105122
for(auto & x: this->m_range)
106123
++count;
124+
acc.add(count);
107125
}
108126
}
109127
else
110128
{
111129
using converter = utf_converter<utf_encoding_of<std::ranges::range_value_t<Range>>,
112130
utf_encoding_of<typename sys_string_t<Storage>::storage_type>>;
113-
count = converter::converted_length(this->m_range);
131+
acc.add(converter::converted_length(this->m_range));
114132
}
115-
if (count > size_t(Storage::max_size))
116-
throw std::bad_alloc();
117-
return static_cast<typename sys_string_t<Storage>::size_type>(count);
118133
}
119134

120135
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
@@ -131,8 +146,8 @@ namespace sysstr::util
131146
m_val(std::move(val))
132147
{}
133148

134-
auto storage_size() const -> typename sys_string_t<Storage>::size_type
135-
{ return this->m_val.storage_size(); }
149+
void add_size(size_accumulator<Storage> & acc) const noexcept
150+
{ this->m_val.add_size(acc); }
136151

137152
auto append_to(sys_string_builder_t<Storage> & builder) const -> void
138153
{ this->m_val.append_to(builder); }
@@ -175,22 +190,23 @@ namespace sysstr::util
175190

176191
operator sys_string_t<Storage>() const &&
177192
{
193+
size_accumulator<Storage> acc;
194+
this->add_size(acc);
195+
if (acc.overflow())
196+
throw std::bad_alloc();
178197
sys_string_builder_t<Storage> builder;
179-
builder.reserve_storage(this->storage_size());
198+
builder.reserve_storage(acc.value());
180199
this->append_to(builder);
181200
return builder.build();
182201
}
183202

184203
operator sys_string_t<Storage>() const & = SYS_STRING_DELETE_REASON(
185204
"you must convert the result of sys_string_t addition to sys_string_t. Do not assign it to auto and carry around");
186205

187-
auto storage_size() const -> typename sys_string_t<Storage>::size_type
206+
void add_size(size_accumulator<Storage> & acc) const noexcept
188207
{
189-
auto s1 = this->m_first.storage_size();
190-
auto s2 = this->m_second.storage_size();
191-
if (Storage::max_size - s1 < s2)
192-
throw std::bad_alloc();
193-
return s1 + s2;
208+
this->m_first.add_size(acc);
209+
this->m_second.add_size(acc);
194210
}
195211

196212
void append_to(sys_string_builder_t<Storage> & builder) const

0 commit comments

Comments
 (0)