Skip to content

Rename String::size to String::buffer_size, to prevent misinterpretation. Use length() instead where appropriate. #105753

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Ivorforce
Copy link
Member

@Ivorforce Ivorforce commented Apr 25, 2025

Supersedes #105710.

String::size is error prone and misleading. I am proposing to rename it to buffer_size to make its purpose clearer.
String::size is luckily not exposed to GDExtension or GDScript.

This PR is likely to both fix subtle bugs and cause regressions (though less likely than #105710). I recommend merging it soon (early in the 4.5 release cycle).

Explanation

I was investigating why #102369 failed, when I realized that empty strings have a dichotomous state:

  • _cowdata is empty (_ptr == nullptr)
  • _cowdata is allocated and _size is 1. The only character is used for the trailing 0 (NUL terminator).

This peculiarity does not seem to be widely known. It is currently common to check for String emptiness like this:

if (p_version->uniforms.size()) {

This is incorrect because the String in question might be empty but allocated, whereupon size() would return 1. It should call if (p_version->uniforms.length()) instead (or better, if (!p_version->uniforms.is_empty())).

Additionally, size is currently often mistaken for length in the codebase. While making this PR, I found many subtle bugs of code that was iterating over the trailing NUL character and (potentially) inserting it into strings or other data.

By renaming to buffer_size, it's clearer that this should only be used when interacting with the buffer directly (such as when using resize and filling contents).

Changes

Interface:

  • size() is renamed to buffer_size() in ustring.h
  • A related unit test was edited to do more
  • get_data() is moved to the header to allow inlining.

Callers:

  • size() - 1 is almost always replaced by length()
  • if (size()) is replaced by if (length()) (could be !is_empty but that's out of scope)
  • size() is replaced by length() if it is obviously more correct
  • size() is replaced by buffer_size() in other cases.

Addendum

We should resolve the dichotomy mentioned above. Empty Strings should not allocate. Without the dichotomy, #102369 can also be merged for a pretty significant speed boost.
This will unfortunately require a little bit of a compatibility breakage, so I wanted to do this PR first.

…etation.

Change most callers to use `length` instead.
@Ivorforce Ivorforce added this to the 4.5 milestone Apr 25, 2025
@Ivorforce Ivorforce requested review from a team as code owners April 25, 2025 14:47
@Ivorforce Ivorforce removed request for a team April 25, 2025 14:47
@Ivorforce Ivorforce requested review from bruvzg and removed request for a team April 25, 2025 14:47
@@ -118,7 +118,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const c
template <int SHORT_BUFFER_SIZE>
StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_size) {
ERR_FAIL_COND_V_MSG(p_size < length(), *this, "reserve() called with a capacity smaller than the current size. This is likely a mistake.");
if (p_size <= SHORT_BUFFER_SIZE || p_size <= buffer.size()) {
if (p_size <= SHORT_BUFFER_SIZE || p_size <= buffer.length()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct?
Are we reserving by size or length?

If size, then the ERR_FAIL seems incorrect, if length, then the param name is incorrect.

If we are reserving by size (and size is counting the NULL terminator), then there should be no change if <= size rather than length?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it does reserve by size. I'm not sure if that's a good idea, but that's out of scope for this PR. I'll change this one back.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suspect the ERR_FAIL_CON_V_MSG should be for size() too rather than length() (if so it's pre-existing, but might be worth fixing).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants