1212
1313namespace 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