AK: Add String::copy_characters_to_buffer()

This is a strcpy()-like method with actually sane semantics:

* It accepts a non-empty buffer along with its size in bytes.
* It copies as much of the string as fits into the buffer.
* It always null-terminates the result.
* It returns, as a non-discardable boolean, whether the whole string has been
copied.

Intended usage looks like this:

bool fits = string.copy_characters_to_buffer(buffer, sizeof(buffer));

and then either

if (!fits) {
    fprintf(stderr, "The name does not fit!!11");
    return nullptr;
}

or, if you're sure the buffer is large enough,

// I'm totally sure it fits because [reasons go here].
ASSERT(fits);

or if you're feeling extremely adventurous,

(void)fits;

but don't do that, please.
This commit is contained in:
Sergey Bugaev 2020-08-25 17:23:18 +03:00 committed by Andreas Kling
parent 17109a3a31
commit be6cce5530
2 changed files with 14 additions and 0 deletions

View file

@ -106,6 +106,18 @@ String String::empty()
return StringImpl::the_empty_stringimpl();
}
bool String::copy_characters_to_buffer(char* buffer, size_t buffer_size) const
{
// We must fit at least the NUL-terminator.
ASSERT(buffer_size > 0);
size_t characters_to_copy = min(length(), buffer_size - 1);
__builtin_memcpy(buffer, characters(), characters_to_copy);
buffer[characters_to_copy] = 0;
return characters_to_copy == length();
}
String String::isolated_copy() const
{
if (!m_impl)

View file

@ -146,6 +146,8 @@ public:
// Includes NUL-terminator, if non-nullptr.
ALWAYS_INLINE const char* characters() const { return m_impl ? m_impl->characters() : nullptr; }
[[nodiscard]] bool copy_characters_to_buffer(char* buffer, size_t buffer_size) const;
ALWAYS_INLINE ReadonlyBytes bytes() const { return m_impl ? m_impl->bytes() : nullptr; }
ALWAYS_INLINE const char& operator[](size_t i) const