Repository: godotengine/godot
File: core/string/ustring.cpp (C++)

Code before:
	return r;
}

String String::increment_numeric() const {
	String res = *this;
	bool carry = res.length() > 0;

	for (int i = res.length() - 1; i >= 0; i--) {
		if (!carry) {
			break;
		}
		char32_t n = operator[](i);
		if (n == '9') { // Keep carry as true: 9 + 1.
			res[i] = '0';
		} else {
			res[i] = operator[](i) + 1;
			carry = false;
		}
	}

	if (carry) {
		res = "1" + res;
	}

	return res;
}

int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
	if (p_len == 0 || !p_str[0]) {
		return 0;
	}
	///@todo make more exact so saving and loading does not lose precision

	int64_t integer = 0;
	int64_t sign = 1;
	int reading = READING_SIGN;

	const char32_t *str = p_str;
	const char32_t *limit = &p_str[p_len];

	while (*str && reading != READING_DONE && str != limit) {
		char32_t c = *(str++);
		switch (reading) {
			case READING_SIGN: {
				if (is_digit(c)) {
					reading = READING_INT;
					// let it fallthrough
				} else if (c == '-') {
					sign = -1;
					reading = READING_INT;
					break;

Review comment (suggestion):
I'm not sure this is a good design as for a public `String` method, since it implicitly assumes that the entire string is a numeric string and produces unexpected results if it isn't. I'd rather go further and do something like:

<details>
<summary>Code</summary>


```c++
String increment_numeric_suffix(const String &p_separator = "_", int p_start_from = 2) const;
```

```c++
String String::increment_numeric_suffix(const String &p_separator, int p_start_from) const {
	if (is_empty()) {
		return itos(p_start_from);
	}

	if (!is_digit(operator[](length() - 1))) {
		if (ends_with(p_separator)) {
			return *this + itos(p_start_from);
		}
		return *this + p_separator + itos(p_start_from);
	}

	String result = *this;
	int index = length() - 1;
	bool carry = true;

	while (carry && index >= 0 && is_digit(operator[](index))) {
		const char32_t n = operator[](index);
		if (n == '9') {
			result[index] = '0';
			// Keep `carry` as `true`: 9 + 1.
		} else {
			result[index] = operator[](index) + 1;
			carry = false;
		}
		index--;
	}

	if (carry) {
		result = result.left(index + 1) + "1" + result.substr(index + 1);
	}

	return result;
}
```

Test cases:

```
 -> 2
abc -> abc_2
abc_ -> abc_2
abc_0 -> abc_1
abc_1 -> abc_2
abc_2 -> abc_3
abc_9 -> abc_10
abc_91 -> abc_92
abc_92 -> abc_93
abc_99 -> abc_100
abc_001 -> abc_002
abc_009 -> abc_010
abc_090 -> abc_091
abc_091 -> abc_092
abc_099 -> abc_100
abc_999 -> abc_1000
abc_999_999 -> abc_999_1000
0 -> 1
1 -> 2
2 -> 3
9 -> 10
91 -> 92
92 -> 93
99 -> 100
001 -> 002
009 -> 010
090 -> 091
091 -> 092
099 -> 100
999 -> 1000
```

</details>

But I'm afraid that this will require changing and testing `Node::_generate_serial_child_name()`. Perhaps we should avoid touching `Node` and `String` and focus only on `SpriteFramesEditor` for this PR, even if it requires a little code duplication. Let's wait for other contributors' opinions and decide whether it's worth it or whether it's beyond the scope of this PR.

Code after:
	return r;
}

int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
	if (p_len == 0 || !p_str[0]) {
		return 0;
	}
	///@todo make more exact so saving and loading does not lose precision

	int64_t integer = 0;
	int64_t sign = 1;
	int reading = READING_SIGN;

	const char32_t *str = p_str;
	const char32_t *limit = &p_str[p_len];

	while (*str && reading != READING_DONE && str != limit) {
		char32_t c = *(str++);
		switch (reading) {
			case READING_SIGN: {
				if (is_digit(c)) {
					reading = READING_INT;
					// let it fallthrough
				} else if (c == '-') {
					sign = -1;
					reading = READING_INT;
					break;
				} else if (c == '+') {
					sign = 1;
					reading = READING_INT;
					break;
				} else {
					break;
				}
				[[fallthrough]];
			}
			case READING_INT: {
				if (is_digit(c)) {
					if (integer > INT64_MAX / 10) {
						String number("");
						str = p_str;
						while (*str && str != limit) {
							number += *(str++);
						}
						if (p_clamp) {
							if (sign == 1) {
								return INT64_MAX;
							} else {
								return INT64_MIN;
							}
						} else {