Skip to content

Commit c573a05

Browse files
committed
Add: shrink_to_fit
Closes ashvardanian#100
1 parent 45ea51c commit c573a05

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

include/stringzilla/stringzilla.h

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -651,11 +651,12 @@ SZ_PUBLIC sz_size_t sz_string_erase(sz_string_t *string, sz_size_t offset, sz_si
651651

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

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

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

3220-
sz_assert(string && "String can't be SZ_NULL.");
3221+
sz_assert(string && allocator && "Strings and allocators can't be SZ_NULL.");
32213222

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

3247+
SZ_PUBLIC sz_ptr_t sz_string_shrink_to_fit(sz_string_t *string, sz_memory_allocator_t *allocator) {
3248+
3249+
sz_assert(string && allocator && "Strings and allocators can't be SZ_NULL.");
3250+
3251+
sz_ptr_t string_start;
3252+
sz_size_t string_length;
3253+
sz_size_t string_space;
3254+
sz_bool_t string_is_external;
3255+
sz_string_unpack(string, &string_start, &string_length, &string_space, &string_is_external);
3256+
3257+
// We may already be space-optimal, and in that case we don't need to do anything.
3258+
sz_size_t new_space = string_length + 1;
3259+
if (string_space == new_space || string_is_external) return string->external.start;
3260+
3261+
sz_ptr_t new_start = (sz_ptr_t)allocator->allocate(new_space, allocator->handle);
3262+
if (!new_start) return SZ_NULL_CHAR;
3263+
3264+
sz_copy(new_start, string_start, string_length);
3265+
string->external.start = new_start;
3266+
string->external.space = new_space;
3267+
string->external.padding = 0;
3268+
string->external.length = string_length;
3269+
3270+
// Deallocate the old string.
3271+
if (string_is_external) allocator->free(string_start, string_space, allocator->handle);
3272+
return string->external.start;
3273+
}
3274+
32463275
SZ_PUBLIC sz_ptr_t sz_string_expand(sz_string_t *string, sz_size_t offset, sz_size_t added_length,
32473276
sz_memory_allocator_t *allocator) {
32483277

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

33343363
// In case of long strings, skip unaligned bytes, and then fill the rest in 64-bit chunks.
33353364
else {
3336-
sz_u64_t value64 = (sz_u64_t)(value) * 0x0101010101010101ull;
3365+
sz_u64_t value64 = (sz_u64_t)value * 0x0101010101010101ull;
33373366
while ((sz_size_t)target & 7ull) *(target++) = value;
33383367
while (target + 8 <= end) *(sz_u64_t *)target = value64, target += 8;
33393368
while (target != end) *(target++) = value;

include/stringzilla/stringzilla.hpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,23 +2604,77 @@ class basic_string {
26042604
#pragma region Modifiers
26052605
#pragma region Non-STL API
26062606

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

2615+
/**
2616+
* @brief Attempts to reduce memory usage by freeing unused memory.
2617+
* @return `true` if the operation was successful and potentially reduced the memory footprint, `false` otherwise.
2618+
*/
2619+
bool try_shrink_to_fit() noexcept {
2620+
return _with_alloc([&](sz_alloc_type &alloc) { return sz_string_shrink_to_fit(&string_, &alloc); });
2621+
}
2622+
2623+
/**
2624+
* @brief Attempts to reserve enough space for a specified number of characters.
2625+
* @param capacity The new capacity to reserve.
2626+
* @return `true` if the reservation was successful, `false` otherwise.
2627+
*/
26092628
bool try_reserve(size_type capacity) noexcept {
26102629
return _with_alloc([&](sz_alloc_type &alloc) { return sz_string_reserve(&string_, capacity, &alloc); });
26112630
}
26122631

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

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

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

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

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

2669+
/**
2670+
* @brief Clears the contents of the string and resets its length to 0.
2671+
* @return Always returns `true` as this operation cannot fail under normal conditions.
2672+
*/
2673+
bool try_clear() noexcept {
2674+
clear();
2675+
return true;
2676+
}
2677+
26242678
/**
26252679
* @brief Erases ( @b in-place ) a range of characters defined with signed offsets.
26262680
* @return Number of characters removed.
@@ -2683,6 +2737,14 @@ class basic_string {
26832737
if (!try_resize(count, character)) throw std::bad_alloc();
26842738
}
26852739

2740+
/**
2741+
* @brief Reclaims the unused memory, if any.
2742+
* @throw `std::bad_alloc` if the allocation fails.
2743+
*/
2744+
void shrink_to_fit() noexcept(false) {
2745+
if (!try_shrink_to_fit()) throw std::bad_alloc();
2746+
}
2747+
26862748
/**
26872749
* @brief Informs the string object of a planned change in size, so that it pre-allocate once.
26882750
* @throw `std::length_error` if the string is too long.

0 commit comments

Comments
 (0)