Skip to content

Commit 7b95761

Browse files
committed
Better resizing of char_vector in edge cases
1 parent b41fca1 commit 7b95761

File tree

2 files changed

+37
-12
lines changed

2 files changed

+37
-12
lines changed

lib/inc/sys_string/impl/util/char_vector.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,25 +183,28 @@ namespace sysstr::util
183183
}
184184

185185
private:
186+
186187

187188
void grow()
188189
{
189190
if (this->m_size < this->capacity())
190191
return;
191-
192+
192193
size_type desired;
193-
194-
if (this->capacity() == 0)
194+
if (this->capacity() < growth_increment) {
195195
desired = growth_increment;
196-
else if (this->capacity() / growth_div_factor < this->max_size() / growth_mul_factor)
197-
desired = (this->capacity() * growth_mul_factor) / growth_div_factor;
198-
else if (this->capacity() < this->max_size() - growth_increment)
199-
desired = this->capacity() + growth_increment;
200-
else if (this->capacity() == this->max_size())
201-
throw std::bad_alloc();
202-
else
203-
desired = this->max_size();
204-
196+
} else {
197+
desired = util::saturated_mul_div(this->capacity(), growth_mul_factor, growth_div_factor);
198+
if (desired == this->capacity() || desired >= this->max_size()) {
199+
if (this->capacity() < this->max_size() - growth_increment)
200+
desired = this->capacity() + growth_increment;
201+
else if (this->capacity() == this->max_size())
202+
throw std::bad_alloc();
203+
else
204+
desired = this->max_size();
205+
}
206+
}
207+
205208
this->m_storage.reallocate(desired, this->m_size);
206209
}
207210

lib/inc/sys_string/impl/util/util.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ namespace sysstr::util
108108

109109
#endif
110110

111+
template<std::unsigned_integral T>
112+
constexpr T saturated_mul_div(T val, std::convertible_to<T> auto numerator, std::convertible_to<T> auto denominator) {
113+
T num = T(numerator);
114+
T denom = T(denominator);
115+
T whole = num / denom;
116+
num = num % denom;
117+
118+
T quot = val / denom;
119+
T rem = val % denom;
120+
T increment = quot * num;
121+
122+
T extra = rem * num;
123+
quot = extra / denom;
124+
rem = extra % denom;
125+
increment += quot;
126+
increment += (2 * rem >= denom);
127+
128+
if (whole && (std::numeric_limits<T>::max() - increment) / whole < val)
129+
return std::numeric_limits<T>::max();
130+
return val * whole + increment;
131+
}
132+
111133
}
112134

113135
#endif

0 commit comments

Comments
 (0)