diff --git a/src/strings.cpp b/src/strings.cpp index 99210bee55..9e4cdfdb1d 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -303,11 +303,10 @@ std::string GetString(StringID string) */ std::string GetStringWithArgs(StringID string, StringParameters *args) { - char buffer[DRAW_STRING_BUFFER]; - char *state = buffer; - StringBuilder builder(&state, lastof(buffer)); + std::string result; + StringBuilder builder(result); GetStringWithArgs(builder, string, args); - return std::string(buffer, builder.GetEnd()); + return result; } /** @@ -838,9 +837,8 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara * the parameters. So, we need to gather the type information via the * dry run first, before we can continue formatting the string. */ - char buffer[DRAW_STRING_BUFFER]; - char *state = buffer; - StringBuilder dry_run_builder(&state, lastof(buffer)); + std::string buffer; + StringBuilder dry_run_builder(buffer); if (UsingNewGRFTextStack()) { /* Values from the NewGRF text stack are only copied to the normal * argv array at the time they are encountered. That means that if @@ -1004,21 +1002,17 @@ static void FormatString(StringBuilder &builder, const char *str_arg, StringPara char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset)); *p = '\0'; - /* The gender is stored at the start of the formatted string. - * So to determine the gender after formatting we only need - * enough space for the gender index token, one character - * for the actual gender and one character for '\0'. */ - char buf[MAX_CHAR_LENGTH + 1 + 1]; - char *state = buf; + /* The gender is stored at the start of the formatted string. */ bool old_sgd = _scan_for_gender_data; _scan_for_gender_data = true; - StringBuilder tmp_builder(&state, lastof(buf)); + std::string buffer; + StringBuilder tmp_builder(buffer); StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, nullptr); FormatString(tmp_builder, input, &tmp_params); _scan_for_gender_data = old_sgd; /* And determine the string. */ - const char *s = buf; + const char *s = buffer.c_str(); WChar c = Utf8Consume(&s); /* Does this string have a gender, if so, set it */ if (c == SCC_GENDER_INDEX) gender = (byte)s[0]; diff --git a/src/strings_internal.h b/src/strings_internal.h index a29c6e5486..da2cffe173 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -20,9 +20,7 @@ * extra functions to ease the migration from char buffers to std::string. */ class StringBuilder { - char **current; ///< The current location to add strings. - char *start; ///< The begin of the string. - const char *last; ///< The last element of the buffer. + std::string *string; public: /* Required type for this to be an output_iterator; mimics std::back_insert_iterator. */ @@ -37,7 +35,7 @@ public: * @param start The start location to write to. * @param last The last location to write to. */ - StringBuilder(char **start, const char *last) : current(start), start(*start), last(last) {} + StringBuilder(std::string &string) : string(&string) {} /* Required operators for this to be an output_iterator; mimics std::back_insert_iterator, which has no-ops. */ StringBuilder &operator++() { return *this; } @@ -63,7 +61,7 @@ public: */ StringBuilder &operator+=(const char value) { - if (*this->current != this->last) *(*this->current)++ = value; + this->string->push_back(value); return *this; } @@ -72,54 +70,31 @@ public: * @param str The string to add. * @return Reference to this inserter. */ - StringBuilder &operator+=(const char *str) + StringBuilder &operator+=(std::string_view str) { - *this->current = strecpy(*this->current, str, this->last); + *this->string += str; return *this; } - /** - * Operator to append the given string to the output buffer. - * @param str The string to add. - * @return Reference to this inserter. - */ - StringBuilder &operator+=(const std::string &str) - { - return this->operator+=(str.c_str()); - } - /** * Encode the given Utf8 character into the output buffer. * @param c The character to encode. - * @return true iff there was enough space and the character got added. */ bool Utf8Encode(WChar c) { - if (this->Remaining() < Utf8CharLen(c)) return false; - - (*this->current) += ::Utf8Encode(*this->current, c); + auto iterator = std::back_inserter(*this->string); + ::Utf8Encode(iterator, c); return true; } /** * Remove the given amount of characters from the back of the string. * @param amount The amount of characters to remove. + * @return true iff there was enough space and the character got added. */ void RemoveElementsFromBack(size_t amount) { - *this->current = std::max(this->start, *this->current - amount); - } - - /** - * Get the pointer to the this->last written element in the buffer. - * This call does '\0' terminate the string, whereas other calls do not - * (necessarily) do this. - * @return The this->current end of the string. - */ - char *GetEnd() - { - **this->current = '\0'; - return *this->current; + this->string->erase(this->string->size() - std::min(amount, this->string->size())); } /** @@ -128,7 +103,7 @@ public: */ ptrdiff_t Remaining() { - return (ptrdiff_t)(this->last - *this->current); + return 42; // Just something big-ish, as there's always space (until allocation fails) } /** @@ -137,7 +112,7 @@ public: */ size_t CurrentIndex() { - return *this->current - this->start; + return this->string->size(); } /** @@ -146,7 +121,7 @@ public: */ char &operator[](size_t index) { - return this->start[index]; + return (*this->string)[index]; } }; diff --git a/src/townname.cpp b/src/townname.cpp index 557ed9c497..20dc112560 100644 --- a/src/townname.cpp +++ b/src/townname.cpp @@ -65,11 +65,10 @@ static void GetTownName(StringBuilder &builder, const TownNameParams *par, uint3 */ std::string GetTownName(const TownNameParams *par, uint32 townnameparts) { - char buffer[DRAW_STRING_BUFFER]; - char *state = buffer; - StringBuilder builder(&state, lastof(buffer)); + std::string result; + StringBuilder builder(result); GetTownName(builder, par, townnameparts); - return std::string(buffer, builder.GetEnd()); + return result; } /** @@ -1024,19 +1023,6 @@ void GenerateTownNameString(StringBuilder &builder, size_t lang, uint32 seed) { assert(lang < lengthof(_town_name_generators)); - /* Some generators need at least 9 bytes in buffer. English generators need 5 for - * string replacing, others use constructions like strlen(buf)-3 and so on. - * Finnish generator needs to fit all strings from _name_finnish_1. - * Czech generator needs to fit almost whole town name... - * These would break. Using another temporary buffer results in ~40% slower code, - * so use it only when really needed. */ const TownNameGeneratorParams *par = &_town_name_generators[lang]; - if (builder.Remaining() >= par->min) return par->proc(builder, seed); - - std::string buffer(par->min + 1, '\0'); - char *state = buffer.data(); - StringBuilder buffer_builder(&state, buffer.data() + par->min); - par->proc(buffer_builder, seed); - - builder += buffer; + return par->proc(builder, seed); }