Alien-libpanda
view release on metacpan or search on metacpan
src/panda/basic_string.h view on Meta::CPAN
}
}
void _reserve_save_internal (size_type capacity) {
if (_storage.internal->refcnt > 1) _detach_cow(capacity);
else if (_storage.internal->capacity < capacity) _internal_realloc(capacity); // need to grow storage
else if (_capacity_internal() < capacity) { // may not to grow storage if str is moved to the beginning
traits_type::move(_storage.internal->start, _str, _length);
_str = _storage.internal->start;
}
}
void _internal_realloc (size_type capacity) {
// see if we can reallocate. if _str != start we should not reallocate because we would need
// either allocate more space than needed or move everything to the beginning before reallocation
if (_storage.dtor == &Alloc::deallocate && _str == _storage.internal->start) {
if (capacity > MAX_SIZE) throw std::length_error("basic_string::_internal_realloc");
_storage.internal = (Buffer*)Alloc::reallocate((CharT*)_storage.internal, capacity + BUF_CHARS, _storage.internal->capacity + BUF_CHARS);
_str = _storage.internal->start;
_storage.internal->capacity = capacity;
} else { // need to allocate/deallocate
auto old_buf = _storage.internal;
auto old_str = _str;
auto old_dtor = _storage.dtor;
_new_auto(capacity);
traits_type::copy(_str, old_str, _length);
_free_internal(old_buf, old_dtor);
}
}
void _reserve_save_external (size_type capacity) {
if (_storage.external->refcnt > 1) _detach_cow(capacity);
else if (_storage.external->capacity < capacity) _external_realloc(capacity); // need to grow storage, switch to INTERNAL/SSO
else if (_capacity_external() < capacity) { // may not to grow storage if str is moved to the beginning
traits_type::move(_storage.external->ptr, _str, _length);
_str = _storage.external->ptr;
}
}
void _external_realloc (size_type capacity) {
auto old_buf = _storage.external;
auto old_str = _str;
auto old_dtor = _storage.dtor;
_new_auto(capacity);
traits_type::copy(_str, old_str, _length);
_free_external(old_buf, old_dtor);
}
void _reserve_save_sso (size_type capacity) {
if (MAX_SSO_CHARS < capacity) {
_new_internal_from_sso(capacity);
return;
}
else if (_capacity_sso() < capacity) {
traits_type::move(_sso, _str, _length);
_str = _sso;
}
}
// splits string into pwo pieces at position 'pos' with insert_count distance between them replacing remove_count chars after pos.
// Tries its best not to allocate memory. set the length of string to old length + insert_count - remove_count.
// The content of part [pos, pos+insert_count) is undefined after operation
void _reserve_middle (size_type pos, size_type remove_count, size_type insert_count) {
size_type newlen = _length + insert_count - remove_count;
switch (_state) {
case State::INTERNAL:
if (_storage.internal->refcnt > 1) {
--_storage.internal->refcnt;
_reserve_middle_new(pos, remove_count, insert_count);
}
else if (newlen > _storage.internal->capacity) {
auto old_buf = _storage.internal;
auto old_dtor = _storage.dtor;
_reserve_middle_new(pos, remove_count, insert_count);
_release_internal(old_buf, old_dtor);
}
else _reserve_middle_move(pos, remove_count, insert_count, _storage.internal->start, _capacity_internal());
break;
case State::EXTERNAL:
if (_storage.external->refcnt > 1) {
--_storage.external->refcnt;
_reserve_middle_new(pos, remove_count, insert_count);
}
else if (newlen > _storage.external->capacity) {
auto old_buf = _storage.external;
auto old_dtor = _storage.dtor;
_reserve_middle_new(pos, remove_count, insert_count);
_release_external(old_buf, old_dtor);
}
else _reserve_middle_move(pos, remove_count, insert_count, _storage.external->ptr, _capacity_external());
break;
case State::LITERAL:
_reserve_middle_new(pos, remove_count, insert_count);
break;
case State::SSO:
if (newlen > MAX_SSO_CHARS) _new_internal_from_sso(newlen, pos, remove_count, insert_count);
else _reserve_middle_move(pos, remove_count, insert_count, _sso, _capacity_sso());
break;
}
_length = newlen;
}
void _reserve_middle_new (size_type pos, size_type remove_count, size_type insert_count) {
auto old_str = _str;
_new_auto(_length + insert_count - remove_count);
if (pos) traits_type::copy(_str, old_str, pos);
traits_type::copy(_str + pos + insert_count, old_str + pos + remove_count, _length - pos - remove_count);
}
void _reserve_middle_move (size_type pos, size_type remove_count, size_type insert_count, CharT* ptr_start, size_type capacity_tail) {
if (remove_count >= insert_count) {
traits_type::move(_str + pos + insert_count, _str + pos + remove_count, _length - pos - remove_count);
return;
}
auto extra_count = insert_count - remove_count;
bool has_head_space = _str >= ptr_start + extra_count;
bool has_tail_space = (capacity_tail - _length) >= extra_count;
if (has_head_space && has_tail_space) { // move what is shorter
( run in 0.900 second using v1.01-cache-2.11-cpan-adec679a428 )