Skip to content

Commit

Permalink
Add: shrink_to_fit
Browse files Browse the repository at this point in the history
Closes #100
  • Loading branch information
ashvardanian committed Mar 18, 2024
1 parent 45ea51c commit c573a05
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
35 changes: 32 additions & 3 deletions include/stringzilla/stringzilla.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,11 +651,12 @@ SZ_PUBLIC sz_size_t sz_string_erase(sz_string_t *string, sz_size_t offset, sz_si

/**
* @brief Shrinks the string to fit the current length, if it's allocated on the heap.
* Teh reverse operation of ::sz_string_reserve.
* It's the reverse operation of ::sz_string_reserve.
*
* @param string String to shrink.
* @param allocator Memory allocator to use for the allocation.
* @return Whether the operation was successful. The only failures can come from the allocator.
* On failure, the string will remain unchanged.
*/
SZ_PUBLIC sz_ptr_t sz_string_shrink_to_fit(sz_string_t *string, sz_memory_allocator_t *allocator);

Expand Down Expand Up @@ -3217,7 +3218,7 @@ SZ_PUBLIC sz_ptr_t sz_string_init_length(sz_string_t *string, sz_size_t length,

SZ_PUBLIC sz_ptr_t sz_string_reserve(sz_string_t *string, sz_size_t new_capacity, sz_memory_allocator_t *allocator) {

sz_assert(string && "String can't be SZ_NULL.");
sz_assert(string && allocator && "Strings and allocators can't be SZ_NULL.");

sz_size_t new_space = new_capacity + 1;
if (new_space <= SZ_STRING_INTERNAL_SPACE) return string->external.start;
Expand All @@ -3243,6 +3244,34 @@ SZ_PUBLIC sz_ptr_t sz_string_reserve(sz_string_t *string, sz_size_t new_capacity
return string->external.start;
}

SZ_PUBLIC sz_ptr_t sz_string_shrink_to_fit(sz_string_t *string, sz_memory_allocator_t *allocator) {

sz_assert(string && allocator && "Strings and allocators can't be SZ_NULL.");

sz_ptr_t string_start;
sz_size_t string_length;
sz_size_t string_space;
sz_bool_t string_is_external;
sz_string_unpack(string, &string_start, &string_length, &string_space, &string_is_external);

// We may already be space-optimal, and in that case we don't need to do anything.
sz_size_t new_space = string_length + 1;
if (string_space == new_space || string_is_external) return string->external.start;

sz_ptr_t new_start = (sz_ptr_t)allocator->allocate(new_space, allocator->handle);
if (!new_start) return SZ_NULL_CHAR;

sz_copy(new_start, string_start, string_length);
string->external.start = new_start;
string->external.space = new_space;
string->external.padding = 0;
string->external.length = string_length;

// Deallocate the old string.
if (string_is_external) allocator->free(string_start, string_space, allocator->handle);
return string->external.start;
}

SZ_PUBLIC sz_ptr_t sz_string_expand(sz_string_t *string, sz_size_t offset, sz_size_t added_length,
sz_memory_allocator_t *allocator) {

Expand Down Expand Up @@ -3333,7 +3362,7 @@ SZ_PUBLIC void sz_fill_serial(sz_ptr_t target, sz_size_t length, sz_u8_t value)

// In case of long strings, skip unaligned bytes, and then fill the rest in 64-bit chunks.
else {
sz_u64_t value64 = (sz_u64_t)(value) * 0x0101010101010101ull;
sz_u64_t value64 = (sz_u64_t)value * 0x0101010101010101ull;
while ((sz_size_t)target & 7ull) *(target++) = value;
while (target + 8 <= end) *(sz_u64_t *)target = value64, target += 8;
while (target != end) *(target++) = value;
Expand Down
62 changes: 62 additions & 0 deletions include/stringzilla/stringzilla.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2604,23 +2604,77 @@ class basic_string {
#pragma region Modifiers
#pragma region Non-STL API

/**
* @brief Resizes the string to a specified number of characters, padding with the specified character if needed.
* @param count The new size of the string.
* @param character The character to fill new elements with, if expanding. Defaults to null character.
* @return `true` if the resizing was successful, `false` otherwise.
*/
bool try_resize(size_type count, value_type character = '\0') noexcept;

/**
* @brief Attempts to reduce memory usage by freeing unused memory.
* @return `true` if the operation was successful and potentially reduced the memory footprint, `false` otherwise.
*/
bool try_shrink_to_fit() noexcept {
return _with_alloc([&](sz_alloc_type &alloc) { return sz_string_shrink_to_fit(&string_, &alloc); });
}

/**
* @brief Attempts to reserve enough space for a specified number of characters.
* @param capacity The new capacity to reserve.
* @return `true` if the reservation was successful, `false` otherwise.
*/
bool try_reserve(size_type capacity) noexcept {
return _with_alloc([&](sz_alloc_type &alloc) { return sz_string_reserve(&string_, capacity, &alloc); });
}

/**
* @brief Assigns a new value to the string, replacing its current contents.
* @param other The string view whose contents to assign.
* @return `true` if the assignment was successful, `false` otherwise.
*/
bool try_assign(string_view other) noexcept;

/**
* @brief Assigns a concatenated sequence to the string, replacing its current contents.
* @param other The concatenation object representing the sequence to assign.
* @return `true` if the assignment was successful, `false` otherwise.
*/
template <typename first_type, typename second_type>
bool try_assign(concatenation<first_type, second_type> const &other) noexcept;

/**
* @brief Attempts to add a single character to the end of the string.
* @param c The character to add.
* @return `true` if the character was successfully added, `false` otherwise.
*/
bool try_push_back(char_type c) noexcept;

/**
* @brief Attempts to append a given character array to the string.
* @param str The pointer to the array of characters to append.
* @param length The number of characters to append.
* @return `true` if the append operation was successful, `false` otherwise.
*/
bool try_append(const_pointer str, size_type length) noexcept;

/**
* @brief Attempts to append a string view to the string.
* @param str The string view to append.
* @return `true` if the append operation was successful, `false` otherwise.
*/
bool try_append(string_view str) noexcept { return try_append(str.data(), str.size()); }

/**
* @brief Clears the contents of the string and resets its length to 0.
* @return Always returns `true` as this operation cannot fail under normal conditions.
*/
bool try_clear() noexcept {
clear();
return true;
}

/**
* @brief Erases ( @b in-place ) a range of characters defined with signed offsets.
* @return Number of characters removed.
Expand Down Expand Up @@ -2683,6 +2737,14 @@ class basic_string {
if (!try_resize(count, character)) throw std::bad_alloc();
}

/**
* @brief Reclaims the unused memory, if any.
* @throw `std::bad_alloc` if the allocation fails.
*/
void shrink_to_fit() noexcept(false) {
if (!try_shrink_to_fit()) throw std::bad_alloc();
}

/**
* @brief Informs the string object of a planned change in size, so that it pre-allocate once.
* @throw `std::length_error` if the string is too long.
Expand Down

0 comments on commit c573a05

Please sign in to comment.