From fd073a281082cd984890bad22fae2e39088f3b9e Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Tue, 16 Jan 2024 22:46:00 +0100 Subject: [PATCH 01/14] Remove: replace custom span with std::span --- src/cargotype.cpp | 2 +- src/cargotype.h | 3 +- src/core/CMakeLists.txt | 1 - src/core/span_type.hpp | 110 ------------------------------------- src/misc/endian_buffer.hpp | 7 +-- src/news_gui.cpp | 2 +- src/saveload/saveload.h | 7 +-- src/settings_internal.h | 2 +- src/stdafx.h | 1 + src/string.cpp | 2 +- src/string_func.h | 3 +- src/strings.cpp | 2 +- src/strings_func.h | 3 +- src/strings_internal.h | 9 ++- src/survey.cpp | 6 +- 15 files changed, 22 insertions(+), 138 deletions(-) delete mode 100644 src/core/span_type.hpp diff --git a/src/cargotype.cpp b/src/cargotype.cpp index 925b8a98f4..dafb4e1164 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -158,7 +158,7 @@ SpriteID CargoSpec::GetCargoIcon() const std::array _sorted_cargo_types; ///< Sort order of cargoes by cargo ID. std::vector _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name. -span _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name. +std::span _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name. /** Sort cargo specifications by their name. */ static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b) diff --git a/src/cargotype.h b/src/cargotype.h index bc8f6f4043..50c89b237d 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -16,7 +16,6 @@ #include "strings_type.h" #include "landscape_type.h" #include "core/bitmath_func.hpp" -#include "core/span_type.hpp" /** Globally unique label of a cargo type. */ typedef uint32_t CargoLabel; @@ -190,7 +189,7 @@ Dimension GetLargestCargoIconSize(); void InitializeSortedCargoSpecs(); extern std::array _sorted_cargo_types; extern std::vector _sorted_cargo_specs; -extern span _sorted_standard_cargo_specs; +extern std::span _sorted_standard_cargo_specs; /** * Does cargo \a c have cargo class \a cc? diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6dd7bbd69b..dc233bdd73 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -25,6 +25,5 @@ add_files( random_func.hpp smallstack_type.hpp container_func.hpp - span_type.hpp strong_typedef_type.hpp ) diff --git a/src/core/span_type.hpp b/src/core/span_type.hpp deleted file mode 100644 index 9a39bdb529..0000000000 --- a/src/core/span_type.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file span_type.hpp Minimized implementation of C++20 std::span. */ - -#ifndef CORE_SPAN_TYPE_HPP -#define CORE_SPAN_TYPE_HPP - -/* This is a partial copy/paste from https://github.com/gsl-lite/gsl-lite/blob/master/include/gsl/gsl-lite.hpp */ - -/* Template to check if a template variable defines size() and data(). */ -template -struct has_size_and_data : std::false_type{}; -template -struct has_size_and_data -< - C, std::void_t< - decltype(std::size(std::declval())), - decltype(std::data(std::declval()))> -> : std::true_type{}; - -/* Template to check if two elements are compatible. */ -template -struct is_compatible_element : std::false_type {}; -template -struct is_compatible_element -< - C, E, std::void_t< - decltype(std::data(std::declval())), - typename std::remove_pointer_t()))>(*)[]> -> : std::is_convertible()))>(*)[], E(*)[]>{}; - -/* Template to check if a container is compatible. gsl-lite also includes is_array and is_std_array, but as we don't use them, they are omitted. */ -template -struct is_compatible_container : std::bool_constant -< - has_size_and_data::value - && is_compatible_element::value ->{}; - -/** - * A trimmed down version of what std::span will be in C++20. - * - * It is fully forwards compatible, so if this codebase switches to C++20, - * all "span" instances can be replaced by "std::span" without loss of - * functionality. - * - * Currently it only supports basic functionality: - * - size() and friends - * - begin() and friends - * - * It is meant to simplify function parameters, where we only want to walk - * a continuous list. - */ -template -class span { -public: - typedef T element_type; - typedef typename std::remove_cv< T >::type value_type; - - typedef T &reference; - typedef T *pointer; - typedef const T &const_reference; - typedef const T *const_pointer; - - typedef pointer iterator; - typedef const_pointer const_iterator; - - typedef size_t size_type; - typedef std::ptrdiff_t difference_type; - - constexpr span() noexcept : first(nullptr), last(nullptr) {} - - constexpr span(pointer data_in, size_t size_in) : first(data_in), last(data_in + size_in) {} - - template::value), int>::type = 0> - constexpr span(Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {} - template::value && is_compatible_container::value), int>::type = 0> - constexpr span(const Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {} - - constexpr size_t size() const noexcept { return static_cast( last - first ); } - constexpr std::ptrdiff_t ssize() const noexcept { return static_cast( last - first ); } - constexpr bool empty() const noexcept { return this->size() == 0; } - - constexpr iterator begin() const noexcept { return iterator(first); } - constexpr iterator end() const noexcept { return iterator(last); } - - constexpr const_iterator cbegin() const noexcept { return const_iterator(first); } - constexpr const_iterator cend() const noexcept { return const_iterator(last); } - - constexpr reference operator[](size_type idx) const { return first[idx]; } - - constexpr pointer data() const noexcept { return first; } - - constexpr span subspan(size_t offset, size_t count) - { - assert(offset + count <= size()); - return span(this->data() + offset, count); - } - -private: - pointer first; - pointer last; -}; - -#endif /* CORE_SPAN_TYPE_HPP */ diff --git a/src/misc/endian_buffer.hpp b/src/misc/endian_buffer.hpp index 749657786c..3229029c53 100644 --- a/src/misc/endian_buffer.hpp +++ b/src/misc/endian_buffer.hpp @@ -11,7 +11,6 @@ #define ENDIAN_BUFFER_HPP #include -#include "../core/span_type.hpp" #include "../core/bitmath_func.hpp" #include "../core/overflowsafe_type.hpp" @@ -119,12 +118,12 @@ private: */ class EndianBufferReader { /** Reference to storage buffer. */ - span buffer; + std::span buffer; /** Current read position. */ size_t read_pos = 0; public: - EndianBufferReader(span buffer) : buffer(buffer) {} + EndianBufferReader(std::span buffer) : buffer(buffer) {} void rewind() { this->read_pos = 0; } @@ -155,7 +154,7 @@ public: } template - static Tvalue ToValue(span buffer) + static Tvalue ToValue(std::span buffer) { Tvalue result{}; EndianBufferReader reader{ buffer }; diff --git a/src/news_gui.cpp b/src/news_gui.cpp index a6952600d2..afd894fee4 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -586,7 +586,7 @@ private: StringID GetCompanyMessageString() const { /* Company news with a face have a separate headline, so the normal message is shifted by two params */ - CopyInDParam(span(this->ni->params.data() + 2, this->ni->params.size() - 2)); + CopyInDParam(std::span(this->ni->params.data() + 2, this->ni->params.size() - 2)); return this->ni->params[1].data; } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index b3bd344cd9..be139df5ab 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -13,7 +13,6 @@ #include "saveload_error.hpp" #include "../fileio_type.h" #include "../fios.h" -#include "../core/span_type.hpp" /** SaveLoad versions * Previous savegame versions, the trunk revision where they were @@ -480,13 +479,13 @@ struct ChunkHandler { using ChunkHandlerRef = std::reference_wrapper; /** A table of ChunkHandler entries. */ -using ChunkHandlerTable = span; +using ChunkHandlerTable = std::span; /** A table of SaveLoad entries. */ -using SaveLoadTable = span; +using SaveLoadTable = std::span; /** A table of SaveLoadCompat entries. */ -using SaveLoadCompatTable = span; +using SaveLoadCompatTable = std::span; /** Handler for saving/loading an object to/from disk. */ class SaveLoadHandler { diff --git a/src/settings_internal.h b/src/settings_internal.h index 914071909b..aada1a1379 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -360,7 +360,7 @@ static constexpr const SettingDesc *GetSettingDesc(const SettingVariant &desc) return std::visit([](auto&& arg) -> const SettingDesc * { return &arg; }, desc); } -typedef span SettingTable; +typedef std::span SettingTable; const SettingDesc *GetSettingFromName(const std::string_view name); void GetSaveLoadFromSettingTable(SettingTable settings, std::vector &saveloads); diff --git a/src/stdafx.h b/src/stdafx.h index edfd4f02a9..ab96be4e5a 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include diff --git a/src/string.cpp b/src/string.cpp index 4eb45c2886..c6b1a154a6 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -85,7 +85,7 @@ char *strecpy(char *dst, const char *src, const char *last) * @param data Array to format * @return Converted string. */ -std::string FormatArrayAsHex(span data) +std::string FormatArrayAsHex(std::span data) { std::string str; str.reserve(data.size() * 2 + 1); diff --git a/src/string_func.h b/src/string_func.h index ca23fdf189..bd0e547558 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -15,12 +15,11 @@ #include #include "core/bitmath_func.hpp" -#include "core/span_type.hpp" #include "string_type.h" char *strecpy(char *dst, const char *src, const char *last) NOACCESS(3); -std::string FormatArrayAsHex(span data); +std::string FormatArrayAsHex(std::span data); void StrMakeValidInPlace(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) NOACCESS(2); [[nodiscard]] std::string StrMakeValid(std::string_view str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); diff --git a/src/strings.cpp b/src/strings.cpp index c25e366a5b..6834135880 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -155,7 +155,7 @@ void SetDParamMaxDigits(size_t n, uint count, FontSize size) * Copy the parameters from the backup into the global string parameter array. * @param backup The backup to copy from. */ -void CopyInDParam(const span backup) +void CopyInDParam(const std::span backup) { for (size_t i = 0; i < backup.size(); i++) { auto &value = backup[i]; diff --git a/src/strings_func.h b/src/strings_func.h index 4fe2746e8a..21a77705d8 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -14,7 +14,6 @@ #include "string_type.h" #include "gfx_type.h" #include "core/bitmath_func.hpp" -#include "core/span_type.hpp" #include "core/strong_typedef_type.hpp" #include "vehicle_type.h" @@ -99,7 +98,7 @@ void SetDParamStr(size_t n, const char *str); void SetDParamStr(size_t n, const std::string &str); void SetDParamStr(size_t n, std::string &&str); -void CopyInDParam(const span backup); +void CopyInDParam(const std::span backup); void CopyOutDParam(std::vector &backup, size_t num); bool HaveDParamChanged(const std::vector &backup); diff --git a/src/strings_internal.h b/src/strings_internal.h index 6584827e78..fc28c34716 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -12,7 +12,6 @@ #include "strings_func.h" #include "string_func.h" -#include "core/span_type.hpp" /** The data required to format and validate a single parameter of a string. */ struct StringParameter { @@ -25,12 +24,12 @@ struct StringParameter { class StringParameters { protected: StringParameters *parent = nullptr; ///< If not nullptr, this instance references data from this parent instance. - span parameters = {}; ///< Array with the actual parameters. + std::span parameters = {}; ///< Array with the actual parameters. size_t offset = 0; ///< Current offset in the parameters span. char32_t next_type = 0; ///< The type of the next data that is retrieved. - StringParameters(span parameters = {}) : + StringParameters(std::span parameters = {}) : parameters(parameters) {} @@ -211,7 +210,7 @@ class ArrayStringParameters : public StringParameters { public: ArrayStringParameters() { - this->parameters = span(params.data(), params.size()); + this->parameters = std::span(params.data(), params.size()); } ArrayStringParameters(ArrayStringParameters&& other) noexcept @@ -224,7 +223,7 @@ public: this->offset = other.offset; this->next_type = other.next_type; this->params = std::move(other.params); - this->parameters = span(params.data(), params.size()); + this->parameters = std::span(params.data(), params.size()); return *this; } diff --git a/src/survey.cpp b/src/survey.cpp index 3f6b1a1593..7dc2d238f8 100644 --- a/src/survey.cpp +++ b/src/survey.cpp @@ -250,9 +250,9 @@ void SurveyConfiguration(nlohmann::json &survey) survey["graphics_set"] = fmt::format("{}.{}", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); const GRFConfig *extra_cfg = BaseGraphics::GetUsedSet()->GetExtraConfig(); if (extra_cfg != nullptr && extra_cfg->num_params > 0) { - survey["graphics_set_parameters"] = span(extra_cfg->param.data(), extra_cfg->num_params); + survey["graphics_set_parameters"] = std::span(extra_cfg->param.data(), extra_cfg->num_params); } else { - survey["graphics_set_parameters"] = span(); + survey["graphics_set_parameters"] = std::span(); } } if (BaseMusic::GetUsedSet() != nullptr) { @@ -344,7 +344,7 @@ void SurveyGrfs(nlohmann::json &survey) if ((c->palette & GRFP_BLT_MASK) == GRFP_BLT_32BPP) grf["blitter"] = "32bpp"; grf["is_static"] = HasBit(c->flags, GCF_STATIC); - grf["parameters"] = span(c->param.data(), c->num_params); + grf["parameters"] = std::span(c->param.data(), c->num_params); } } From 17d47ba06fd6a8e7f40dbc372f1bbdcf3c796c14 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jan 2024 00:55:09 +0000 Subject: [PATCH 02/14] Fix 661bdae2: cargo_payment not cleared when aircraft loading cancelled --- src/saveload/vehicle_sl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index cbec457e2d..0befccc1dc 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -23,6 +23,7 @@ #include "../company_base.h" #include "../company_func.h" #include "../disaster_vehicle.h" +#include "../economy_base.h" #include "../safeguards.h" @@ -205,6 +206,7 @@ void UpdateOldAircraft() Vehicle *v = *iter; if (v->type == VEH_AIRCRAFT && !v->current_order.IsType(OT_LOADING)) { iter = st->loading_vehicles.erase(iter); + delete v->cargo_payment; } else { ++iter; } From fd0528a9b4a695c601c7b0ae1ad897ed719800b1 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Tue, 16 Jan 2024 22:23:31 +0000 Subject: [PATCH 03/14] Fix: Excessive switching of horizontal scale for FPS graph 60 Hz categories --- src/framerate_gui.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index e058235058..114d5c2d89 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -801,15 +801,21 @@ struct FrametimeGraphWindow : Window { void SelectHorizontalScale(TimingMeasurement range) { + /* 60 Hz graphical drawing results in a value of approximately TIMESTAMP_PRECISION, + * this lands exactly on the scale = 2 vs scale = 4 boundary. + * To avoid excessive switching of the horizontal scale, bias these performance + * categories away from this scale boundary. */ + if (this->element == PFE_DRAWING || this->element == PFE_DRAWWORLD) range += (range / 2); + /* Determine horizontal scale based on period covered by 60 points * (slightly less than 2 seconds at full game speed) */ struct ScaleDef { TimingMeasurement range; int scale; }; static const ScaleDef hscales[] = { - { 120, 60 }, - { 10, 20 }, - { 5, 10 }, - { 3, 4 }, - { 1, 2 }, + { TIMESTAMP_PRECISION * 120, 60 }, + { TIMESTAMP_PRECISION * 10, 20 }, + { TIMESTAMP_PRECISION * 5, 10 }, + { TIMESTAMP_PRECISION * 3, 4 }, + { TIMESTAMP_PRECISION * 1, 2 }, }; for (const ScaleDef *sc = hscales; sc < hscales + lengthof(hscales); sc++) { if (range < sc->range) this->horizontal_scale = sc->scale; @@ -869,7 +875,7 @@ struct FrametimeGraphWindow : Window { lastts = timestamps[point]; /* Enough data to select a range and get decent data density */ - if (count == 60) this->SelectHorizontalScale(time_sum / TIMESTAMP_PRECISION); + if (count == 60) this->SelectHorizontalScale(time_sum); /* End when enough points have been collected and the horizontal scale has been exceeded */ if (count >= 60 && time_sum >= (this->horizontal_scale + 2) * TIMESTAMP_PRECISION / 2) break; From 341bdabc709d5103cdf9c7031d3b7aa9c79e86cc Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 Jan 2024 13:23:55 +0000 Subject: [PATCH 04/14] Fix #11815, bb491127: Missing brackets prevented vehicles turning properly. (#11816) --- src/direction_func.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/direction_func.h b/src/direction_func.h index 396943b024..c554873a0d 100644 --- a/src/direction_func.h +++ b/src/direction_func.h @@ -71,7 +71,7 @@ inline DirDiff DirDifference(Direction d0, Direction d1) assert(IsValidDirection(d1)); /* Cast to uint so compiler can use bitmask. If the difference is negative * and we used int instead of uint, further "+ 8" would have to be added. */ - return static_cast(static_cast(d0) - static_cast(d1) % 8); + return static_cast((static_cast(d0) - static_cast(d1)) % 8); } /** From 384b804f9c35e83f1840393431f98fabbe2f9368 Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 17 Jan 2024 18:39:56 +0000 Subject: [PATCH 05/14] Update: Translations from eints english (au): 1 change by krysclarke chinese (simplified): 21 changes by WenSimEHRP danish: 4 changes by bscargo french: 2 changes by ottdfevr portuguese (brazilian): 5 changes by pasantoro polish: 5 changes by pAter-exe --- src/lang/brazilian_portuguese.txt | 6 ++++- src/lang/danish.txt | 4 +++ src/lang/english_AU.txt | 2 +- src/lang/french.txt | 4 +-- src/lang/polish.txt | 6 ++++- src/lang/simplified_chinese.txt | 42 +++++++++++++++---------------- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 942f469e3f..741e69b569 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1045,6 +1045,10 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Marque e STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Escalar chanfros STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Marque esta caixa para dimensionar os chanfros por tamanho de interface +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Usar a fonte sprite tradicional +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Marque esta caixa se você prefere usar a fonte sprite tradicional de tamanho fixo. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Fontes com bordas suaves +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Marcar esta caixa para fontes redimensionáveis com bordas suaves. STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x @@ -3424,7 +3428,7 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Tipo de estrada STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}Variável NewGRF 60+ parâmetro x (hexadecimal) # Sprite aligner window -STR_SPRITE_ALIGNER_CAPTION :{WHITE}Alinhando "sprite" {COMMA} ({STRING}) +STR_SPRITE_ALIGNER_CAPTION :{WHITE}Alinhando sprite {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Próximo "sprite" STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Prossegue ao próximo "sprite" normal, pulando quaisquer "sprites" falsos, recoloridos ou de fontes, e junta tudo do último pro primeiro STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Ir para o "sprite" diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 487cc64845..defc099a3e 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -1044,6 +1044,10 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Marker d STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Skalere facetter STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Marker dette afkrydsningsfelt for at skalere facetter efter grænsefladestørrelse +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Brug traditionel sprite-skrifttype +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Marker dette felt, hvis du foretrækker at bruge den traditionelle sprite-skrifttype med fast størrelse. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Anti-alias skrifttyper +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Marker dette felt for at skrifttyper, der kan ændres størrelse, kan udlignes. STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index b2765387ff..c409709897 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -1045,7 +1045,7 @@ STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Scale be STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Check this box to scale bevels by interface size STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Use traditional sprite font -STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Check this box if you prefer to use the tradition fixed-size sprite font. +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Check this box if you prefer to use the traditional fixed-size sprite font. STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Anti-alias fonts STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Check this box to anti-alias resizable fonts. diff --git a/src/lang/french.txt b/src/lang/french.txt index 6d35650377..5bcef7310e 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -1045,8 +1045,8 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Cochez c STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Mettre à l’échelle les bordures STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Cochez cette case pour mettre les bordures à l'échelle avec la taille de l'interface -STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Utiliser la police d'écriture de sprite -STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Cochez cette case si vous préferez utiliser la police d'écriture à taille fixe de sprite. +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Utiliser la police d'écriture par défaut +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Cochez cette case si vous préferez utiliser la police d'écriture par défaut. STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Polices d'écriture supportant l'anti-crénelage STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Cochez cette case pour activer l'anti-crénelage sur les polices d'écriture à taille variable. diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 70e22af9b0..bd55c0da6c 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1424,6 +1424,10 @@ STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}Zaznacz STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}Skaluj fazy krawędzi STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}Zaznacz to pole, aby skalować fazy krawędzi zgodnie z rozmiarem interfejsu +STR_GAME_OPTIONS_GUI_FONT_SPRITE :{BLACK}Użyj tradycyjnego fonta typu sprite +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}Zaznacz to pole, jeśli wolisz używać tradycyjnego fonta typu sprite o stałym rozmiarze. +STR_GAME_OPTIONS_GUI_FONT_AA :{BLACK}Antyaliasing fontów +STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :{BLACK}Zaznacz to pole, aby wygładzać fonty o zmiennym rozmiarze. STR_GAME_OPTIONS_GUI_SCALE_1X :1x STR_GAME_OPTIONS_GUI_SCALE_2X :2x @@ -3398,7 +3402,7 @@ STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Właści STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokalne władze: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Brak STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Współrzędne: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) -STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Zbudowano: {LTBLUE}{DATE_LONG} +STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Zbudowano/odnowiono: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Rodzaj stacji: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Typ stacji: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Rodzaj lotniska: {LTBLUE}{STRING} diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 1ec4859649..7833fc2808 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -94,36 +94,36 @@ STR_CARGO_SINGULAR_FIZZY_DRINK :汽水 # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}位旅客 -STR_QUANTITY_COAL :{WEIGHT_LONG} 煤炭 +STR_QUANTITY_COAL :{WEIGHT_LONG}煤炭 STR_QUANTITY_MAIL :{COMMA}{NBSP}包邮件 -STR_QUANTITY_OIL :{VOLUME_LONG} 原油 +STR_QUANTITY_OIL :{VOLUME_LONG}原油 STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}头牲畜 STR_QUANTITY_GOODS :{COMMA}{NBSP}件货物 -STR_QUANTITY_GRAIN :{WEIGHT_LONG} 谷物 -STR_QUANTITY_WOOD :{WEIGHT_LONG} 木材 -STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} 铁矿石 -STR_QUANTITY_STEEL :{WEIGHT_LONG} 钢材 +STR_QUANTITY_GRAIN :{WEIGHT_LONG}谷物 +STR_QUANTITY_WOOD :{WEIGHT_LONG}木材 +STR_QUANTITY_IRON_ORE :{WEIGHT_LONG}铁矿石 +STR_QUANTITY_STEEL :{WEIGHT_LONG}钢材 STR_QUANTITY_VALUABLES :{COMMA}{NBSP}包贵重品 STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} 铜矿石 -STR_QUANTITY_MAIZE :{WEIGHT_LONG} 玉米 -STR_QUANTITY_FRUIT :{WEIGHT_LONG} 水果 +STR_QUANTITY_MAIZE :{WEIGHT_LONG}玉米 +STR_QUANTITY_FRUIT :{WEIGHT_LONG}水果 STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}包钻石 -STR_QUANTITY_FOOD :{WEIGHT_LONG} 食品 -STR_QUANTITY_PAPER :{WEIGHT_LONG} 纸张 +STR_QUANTITY_FOOD :{WEIGHT_LONG}食品 +STR_QUANTITY_PAPER :{WEIGHT_LONG}纸张 STR_QUANTITY_GOLD :{COMMA}{NBSP}包黄金 -STR_QUANTITY_WATER :{VOLUME_LONG} 饮用水 -STR_QUANTITY_WHEAT :{WEIGHT_LONG} 小麦 -STR_QUANTITY_RUBBER :{VOLUME_LONG} 橡胶 -STR_QUANTITY_SUGAR :{WEIGHT_LONG} 蔗糖 +STR_QUANTITY_WATER :{VOLUME_LONG}饮用水 +STR_QUANTITY_WHEAT :{WEIGHT_LONG}小麦 +STR_QUANTITY_RUBBER :{VOLUME_LONG}橡胶 +STR_QUANTITY_SUGAR :{WEIGHT_LONG}蔗糖 STR_QUANTITY_TOYS :{COMMA}{NBSP}件玩具 STR_QUANTITY_SWEETS :{COMMA}{NBSP}包糖果 -STR_QUANTITY_COLA :{VOLUME_LONG} 可乐 -STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} 棉花糖 +STR_QUANTITY_COLA :{VOLUME_LONG}可乐 +STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG}棉花糖 STR_QUANTITY_BUBBLES :{COMMA} 个泡泡 -STR_QUANTITY_TOFFEE :{WEIGHT_LONG} 太妃糖 +STR_QUANTITY_TOFFEE :{WEIGHT_LONG}太妃糖 STR_QUANTITY_BATTERIES :{COMMA} 箱电池 -STR_QUANTITY_PLASTIC :{VOLUME_LONG} 塑料 -STR_QUANTITY_FIZZY_DRINKS :{COMMA} 瓶汽水 +STR_QUANTITY_PLASTIC :{VOLUME_LONG}塑料 +STR_QUANTITY_FIZZY_DRINKS :{COMMA}瓶汽水 STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name @@ -1045,7 +1045,7 @@ STR_GAME_OPTIONS_GUI_SCALE_BEVELS :{BLACK}适应 STR_GAME_OPTIONS_GUI_SCALE_BEVELS_TOOLTIP :{BLACK}选中此框使边框大小随界面大小而缩放 STR_GAME_OPTIONS_GUI_FONT_SPRITE :使用位图字体 -STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :如果您想使用固定大小的传统位图字体,请勾选此框。 +STR_GAME_OPTIONS_GUI_FONT_SPRITE_TOOLTIP :{BLACK}如果您想使用固定大小的传统位图字体,请勾选此框。 STR_GAME_OPTIONS_GUI_FONT_AA :字体抗锯齿 STR_GAME_OPTIONS_GUI_FONT_AA_TOOLTIP :勾选此框以对游戏字体应用抗锯齿。 @@ -4658,7 +4658,7 @@ STR_DATE_YEAR_TOOLTIP :{BLACK}选择 # AI debug window -STR_AI_DEBUG :{WHITE}AI/脚本 调试 +STR_AI_DEBUG :{WHITE}AI/脚本调试 STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}AI名称 STR_AI_DEBUG_SETTINGS :{BLACK}AI 设置 From 2d77cf9c80f26e5064749114aac33be71f768ffd Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 17 Jan 2024 06:30:44 +0100 Subject: [PATCH 06/14] Codechange: replace StrStartsWith/StrEndsWith with starts_with and ends_with --- src/fileio.cpp | 2 +- src/fios.cpp | 2 +- src/network/core/address.cpp | 2 +- src/network/core/http_curl.cpp | 2 +- src/network/core/http_winhttp.cpp | 2 +- src/network/network_chat_gui.cpp | 2 +- src/network/network_coordinator.cpp | 2 +- src/network/network_gui.cpp | 2 +- src/openttd.cpp | 2 +- src/screenshot.cpp | 2 +- src/script/api/script_text.cpp | 2 +- src/settings.cpp | 4 +- src/string.cpp | 26 ---- src/string_func.h | 2 - src/tests/string_func.cpp | 182 ---------------------------- src/textfile_gui.cpp | 16 +-- 16 files changed, 21 insertions(+), 231 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index 215da0f36b..089e25e702 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -608,7 +608,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t, [[maybe_unused]] c /* Process relative path. * Note: The destination of links must not contain any directory-links. */ std::string dest = (std::filesystem::path(name).remove_filename() /= link).lexically_normal().string(); - if (dest[0] == PATHSEPCHAR || StrStartsWith(dest, "..")) { + if (dest[0] == PATHSEPCHAR || dest.starts_with("..")) { Debug(misc, 5, "Ignoring link pointing outside of data directory: {} -> {}", name, link); break; } diff --git a/src/fios.cpp b/src/fios.cpp index e7bdac1e08..3b7efd822e 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -729,7 +729,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p /* Callback for FiosFileScanner. */ static FiosGetTypeAndNameProc *proc = [](SaveLoadOperation, const std::string &file, const std::string_view ext) { - if (StrEqualsIgnoreCase(ext, ".sav") && StrStartsWith(file, _prefix)) return std::tuple(FIOS_TYPE_FILE, std::string{}); + if (StrEqualsIgnoreCase(ext, ".sav") && file.starts_with(_prefix)) return std::tuple(FIOS_TYPE_FILE, std::string{}); return std::tuple(FIOS_TYPE_INVALID, std::string{}); }; diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 525edd511d..62210f0668 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -449,7 +449,7 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets) */ /* static */ ServerAddress ServerAddress::Parse(const std::string &connection_string, uint16_t default_port, CompanyID *company_id) { - if (StrStartsWith(connection_string, "+")) { + if (connection_string.starts_with("+")) { std::string_view invite_code = ParseCompanyFromConnectionString(connection_string, company_id); return ServerAddress(SERVER_ADDRESS_INVITE_CODE, std::string(invite_code)); } diff --git a/src/network/core/http_curl.cpp b/src/network/core/http_curl.cpp index e238a81772..2a363559b0 100644 --- a/src/network/core/http_curl.cpp +++ b/src/network/core/http_curl.cpp @@ -176,7 +176,7 @@ void HttpThread() /* Prepare POST body and URI. */ if (!request->data.empty()) { /* When the payload starts with a '{', it is a JSON payload. */ - if (StrStartsWith(request->data, "{")) { + if (request->data.starts_with("{")) { headers = curl_slist_append(headers, "Content-Type: application/json"); } else { headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); diff --git a/src/network/core/http_winhttp.cpp b/src/network/core/http_winhttp.cpp index 7736dd60f8..9d365f6d17 100644 --- a/src/network/core/http_winhttp.cpp +++ b/src/network/core/http_winhttp.cpp @@ -252,7 +252,7 @@ void NetworkHTTPRequest::Connect() WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast(this)); } else { /* When the payload starts with a '{', it is a JSON payload. */ - LPCWSTR content_type = StrStartsWith(data, "{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n"; + LPCWSTR content_type = data.starts_with("{") ? L"Content-Type: application/json\r\n" : L"Content-Type: application/x-www-form-urlencoded\r\n"; WinHttpSendRequest(this->request, content_type, -1, const_cast(data.c_str()), static_cast(data.size()), static_cast(data.size()), reinterpret_cast(this)); } } diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 321cc4f9ec..c91a74bde6 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -408,7 +408,7 @@ struct NetworkChatWindow : public Window { /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ } - if (tb_buf.size() < cur_name.size() && StrStartsWith(cur_name, tb_buf)) { + if (tb_buf.size() < cur_name.size() && cur_name.starts_with(tb_buf)) { /* Save the data it was before completion */ if (!second_scan) _chat_tab_completion_buf = tb->buf; _chat_tab_completion_active = true; diff --git a/src/network/network_coordinator.cpp b/src/network/network_coordinator.cpp index 3aac31d00c..4298b382ef 100644 --- a/src/network/network_coordinator.cpp +++ b/src/network/network_coordinator.cpp @@ -514,7 +514,7 @@ void ClientNetworkCoordinatorSocketHandler::GetListing() */ void ClientNetworkCoordinatorSocketHandler::ConnectToServer(const std::string &invite_code, TCPServerConnecter *connecter) { - assert(StrStartsWith(invite_code, "+")); + assert(invite_code.starts_with("+")); if (this->connecter_pre.find(invite_code) != this->connecter_pre.end()) { /* If someone is hammering the refresh key, one can sent out two diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 40e2e966ae..8e92835663 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -649,7 +649,7 @@ public: tr.top = DrawStringMultiLine(tr, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version SetDParamStr(0, sel->connection_string); - StringID invite_or_address = StrStartsWith(sel->connection_string, "+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS; + StringID invite_or_address = sel->connection_string.starts_with("+") ? STR_NETWORK_SERVER_LIST_INVITE_CODE : STR_NETWORK_SERVER_LIST_SERVER_ADDRESS; tr.top = DrawStringMultiLine(tr, invite_or_address); // server address / invite code SetDParam(0, sel->info.start_date); diff --git a/src/openttd.cpp b/src/openttd.cpp index 6f4c35845f..37729c82ca 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -372,7 +372,7 @@ void MakeNewgameSettingsLive() void OpenBrowser(const std::string &url) { /* Make sure we only accept urls that are sure to open a browser. */ - if (StrStartsWith(url, "http://") || StrStartsWith(url, "https://")) { + if (url.starts_with("http://") || url.starts_with("https://")) { OSOpenBrowser(url); } } diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 5b9ce9388b..b57e484bfe 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -679,7 +679,7 @@ static const char *MakeScreenshotName(const char *default_fn, const char *ext, b } /* Handle user-specified filenames ending in # with automatic numbering */ - if (StrEndsWith(_screenshot_name, "#")) { + if (_screenshot_name.ends_with("#")) { generate = true; _screenshot_name.pop_back(); } diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index 834c77e137..d509ddd80c 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -140,7 +140,7 @@ SQInteger ScriptText::_set(HSQUIRRELVM vm) sq_getstring(vm, 2, &key_string); std::string str = StrMakeValid(key_string); - if (!StrStartsWith(str, "param_") || str.size() > 8) return SQ_ERROR; + if (!str.starts_with("param_") || str.size() > 8) return SQ_ERROR; k = stoi(str.substr(6)); } else if (sq_gettype(vm, 2) == OT_INTEGER) { diff --git a/src/settings.cpp b/src/settings.cpp index 01ad5bdbf6..0dd0a304b1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1604,7 +1604,7 @@ static const SettingDesc *GetSettingFromName(const std::string_view name, const for (auto &desc : settings) { const SettingDesc *sd = GetSettingDesc(desc); if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (StrEndsWith(sd->GetName(), short_name_suffix)) return sd; + if (sd->GetName().ends_with(short_name_suffix)) return sd; } return nullptr; @@ -1633,7 +1633,7 @@ void GetSaveLoadFromSettingTable(SettingTable settings, std::vector &s static const SettingDesc *GetCompanySettingFromName(std::string_view name) { static const std::string_view company_prefix = "company."; - if (StrStartsWith(name, company_prefix)) name.remove_prefix(company_prefix.size()); + if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size()); return GetSettingFromName(name, _company_settings); } diff --git a/src/string.cpp b/src/string.cpp index c6b1a154a6..3bc3e223f1 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -291,19 +291,6 @@ void StrTrimInPlace(std::string &str) StrRightTrimInPlace(str); } -/** - * Check whether the given string starts with the given prefix. - * @param str The string to look at. - * @param prefix The prefix to look for. - * @return True iff the begin of the string is the same as the prefix. - */ -bool StrStartsWith(const std::string_view str, const std::string_view prefix) -{ - size_t prefix_len = prefix.size(); - if (str.size() < prefix_len) return false; - return str.compare(0, prefix_len, prefix, 0, prefix_len) == 0; -} - /** * Check whether the given string starts with the given prefix, ignoring case. * @param str The string to look at. @@ -316,19 +303,6 @@ bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix return StrEqualsIgnoreCase(str.substr(0, prefix.size()), prefix); } -/** - * Check whether the given string ends with the given suffix. - * @param str The string to look at. - * @param suffix The suffix to look for. - * @return True iff the end of the string is the same as the suffix. - */ -bool StrEndsWith(const std::string_view str, const std::string_view suffix) -{ - size_t suffix_len = suffix.size(); - if (str.size() < suffix_len) return false; - return str.compare(str.size() - suffix_len, suffix_len, suffix, 0, suffix_len) == 0; -} - /** Case insensitive implementation of the standard character type traits. */ struct CaseInsensitiveCharTraits : public std::char_traits { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } diff --git a/src/string_func.h b/src/string_func.h index bd0e547558..470a8eca3d 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -30,9 +30,7 @@ bool strtolower(std::string &str, std::string::size_type offs = 0); [[nodiscard]] bool StrValid(const char *str, const char *last) NOACCESS(2); void StrTrimInPlace(std::string &str); -[[nodiscard]] bool StrStartsWith(const std::string_view str, const std::string_view prefix); [[nodiscard]] bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix); -[[nodiscard]] bool StrEndsWith(const std::string_view str, const std::string_view suffix); [[nodiscard]] bool StrEndsWithIgnoreCase(std::string_view str, const std::string_view suffix); [[nodiscard]] int StrCompareIgnoreCase(const std::string_view str1, const std::string_view str2); diff --git a/src/tests/string_func.cpp b/src/tests/string_func.cpp index 17c153cde9..eb61f0bac2 100644 --- a/src/tests/string_func.cpp +++ b/src/tests/string_func.cpp @@ -163,97 +163,6 @@ TEST_CASE("StrEqualsIgnoreCase - std::string_view") /**** String starts with *****/ -TEST_CASE("StrStartsWith - std::string") -{ - /* Everything starts with an empty prefix. */ - CHECK(StrStartsWith(std::string{""}, std::string{""})); - CHECK(StrStartsWith(std::string{"a"}, std::string{""})); - - /* Equal strings. */ - CHECK(StrStartsWith(std::string{"a"}, std::string{"a"})); - CHECK(StrStartsWith(std::string{"A"}, std::string{"A"})); - - /* Starts with same. */ - CHECK(StrStartsWith(std::string{"ab"}, std::string{"a"})); - CHECK(StrStartsWith(std::string{"Ab"}, std::string{"A"})); - - /* Different cases. */ - CHECK(!StrStartsWith(std::string{"a"}, std::string{"A"})); - CHECK(!StrStartsWith(std::string{"A"}, std::string{"a"})); - CHECK(!StrStartsWith(std::string{"ab"}, std::string{"A"})); - CHECK(!StrStartsWith(std::string{"Ab"}, std::string{"a"})); - - /* Does not start the same. */ - CHECK(!StrStartsWith(std::string{""}, std::string{"b"})); - CHECK(!StrStartsWith(std::string{"a"}, std::string{"b"})); - CHECK(!StrStartsWith(std::string{"b"}, std::string{"a"})); - CHECK(!StrStartsWith(std::string{"a"}, std::string{"aa"})); -} - -TEST_CASE("StrStartsWith - char pointer") -{ - CHECK(StrStartsWith("", "")); - CHECK(StrStartsWith("a", "")); - - /* Equal strings. */ - CHECK(StrStartsWith("a", "a")); - CHECK(StrStartsWith("A", "A")); - - /* Starts with same. */ - CHECK(StrStartsWith("ab", "a")); - CHECK(StrStartsWith("Ab", "A")); - - /* Different cases. */ - CHECK(!StrStartsWith("a", "A")); - CHECK(!StrStartsWith("A", "a")); - CHECK(!StrStartsWith("ab", "A")); - CHECK(!StrStartsWith("Ab", "a")); - - /* Does not start the same. */ - CHECK(!StrStartsWith("", "b")); - CHECK(!StrStartsWith("a", "b")); - CHECK(!StrStartsWith("b", "a")); - CHECK(!StrStartsWith("a", "aa")); -} - -TEST_CASE("StrStartsWith - std::string_view") -{ - /* - * With std::string_view the only way to access the data is via .data(), - * which does not guarantee the termination that would be required by - * things such as stricmp/strcasecmp. So, just passing .data() into stricmp - * or strcasecmp would fail if it does not account for the length of the - * view. Thus, contrary to the string/char* tests, this uses the same base - * string but gets different sections to trigger these corner cases. - */ - std::string_view base{"aabAb"}; - - /* Everything starts with an empty prefix. */ - CHECK(StrStartsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions - CHECK(StrStartsWith(base.substr(0, 1), base.substr(0, 0))); - - /* Equals string. */ - CHECK(StrStartsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions - CHECK(StrStartsWith(base.substr(3, 1), base.substr(3, 1))); - - /* Starts with same. */ - CHECK(StrStartsWith(base.substr(1, 2), base.substr(0, 1))); - CHECK(StrStartsWith(base.substr(3, 2), base.substr(3, 1))); - - /* Different cases. */ - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(3, 1))); - CHECK(!StrStartsWith(base.substr(3, 1), base.substr(0, 1))); - CHECK(!StrStartsWith(base.substr(1, 2), base.substr(3, 1))); - CHECK(!StrStartsWith(base.substr(3, 2), base.substr(0, 1))); - - /* Does not start the same. */ - CHECK(!StrStartsWith(base.substr(2, 0), base.substr(2, 1))); - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(2, 1))); - CHECK(!StrStartsWith(base.substr(2, 1), base.substr(0, 1))); - CHECK(!StrStartsWith(base.substr(0, 1), base.substr(0, 2))); -} - - TEST_CASE("StrStartsWithIgnoreCase - std::string") { /* Everything starts with an empty prefix. */ @@ -341,97 +250,6 @@ TEST_CASE("StrStartsWithIgnoreCase - std::string_view") /**** String ends with *****/ -TEST_CASE("StrEndsWith - std::string") -{ - /* Everything ends with an empty prefix. */ - CHECK(StrEndsWith(std::string{""}, std::string{""})); - CHECK(StrEndsWith(std::string{"a"}, std::string{""})); - - /* Equal strings. */ - CHECK(StrEndsWith(std::string{"a"}, std::string{"a"})); - CHECK(StrEndsWith(std::string{"A"}, std::string{"A"})); - - /* Ends with same. */ - CHECK(StrEndsWith(std::string{"ba"}, std::string{"a"})); - CHECK(StrEndsWith(std::string{"bA"}, std::string{"A"})); - - /* Different cases. */ - CHECK(!StrEndsWith(std::string{"a"}, std::string{"A"})); - CHECK(!StrEndsWith(std::string{"A"}, std::string{"a"})); - CHECK(!StrEndsWith(std::string{"ba"}, std::string{"A"})); - CHECK(!StrEndsWith(std::string{"bA"}, std::string{"a"})); - - /* Does not end the same. */ - CHECK(!StrEndsWith(std::string{""}, std::string{"b"})); - CHECK(!StrEndsWith(std::string{"a"}, std::string{"b"})); - CHECK(!StrEndsWith(std::string{"b"}, std::string{"a"})); - CHECK(!StrEndsWith(std::string{"a"}, std::string{"aa"})); -} - -TEST_CASE("StrEndsWith - char pointer") -{ - CHECK(StrEndsWith("", "")); - CHECK(StrEndsWith("a", "")); - - /* Equal strings. */ - CHECK(StrEndsWith("a", "a")); - CHECK(StrEndsWith("A", "A")); - - /* Ends with same. */ - CHECK(StrEndsWith("ba", "a")); - CHECK(StrEndsWith("bA", "A")); - - /* Different cases. */ - CHECK(!StrEndsWith("a", "A")); - CHECK(!StrEndsWith("A", "a")); - CHECK(!StrEndsWith("ba", "A")); - CHECK(!StrEndsWith("bA", "a")); - - /* Does not end the same. */ - CHECK(!StrEndsWith("", "b")); - CHECK(!StrEndsWith("a", "b")); - CHECK(!StrEndsWith("b", "a")); - CHECK(!StrEndsWith("a", "aa")); -} - -TEST_CASE("StrEndsWith - std::string_view") -{ - /* - * With std::string_view the only way to access the data is via .data(), - * which does not guarantee the termination that would be required by - * things such as stricmp/strcasecmp. So, just passing .data() into stricmp - * or strcasecmp would fail if it does not account for the length of the - * view. Thus, contrary to the string/char* tests, this uses the same base - * string but gets different sections to trigger these corner cases. - */ - std::string_view base{"aabAba"}; - - /* Everything ends with an empty prefix. */ - CHECK(StrEndsWith(base.substr(0, 0), base.substr(1, 0))); // Different positions - CHECK(StrEndsWith(base.substr(0, 1), base.substr(0, 0))); - - /* Equals string. */ - CHECK(StrEndsWith(base.substr(0, 1), base.substr(1, 1))); // Different positions - CHECK(StrEndsWith(base.substr(3, 1), base.substr(3, 1))); - - /* Ends with same. */ - CHECK(StrEndsWith(base.substr(4, 2), base.substr(0, 1))); - CHECK(StrEndsWith(base.substr(2, 2), base.substr(3, 1))); - - /* Different cases. */ - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(3, 1))); - CHECK(!StrEndsWith(base.substr(3, 1), base.substr(0, 1))); - CHECK(!StrEndsWith(base.substr(4, 2), base.substr(3, 1))); - CHECK(!StrEndsWith(base.substr(2, 2), base.substr(0, 1))); - - /* Does not end the same. */ - CHECK(!StrEndsWith(base.substr(2, 0), base.substr(2, 1))); - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(2, 1))); - CHECK(!StrEndsWith(base.substr(2, 1), base.substr(0, 1))); - CHECK(!StrEndsWith(base.substr(0, 1), base.substr(0, 2))); -} - - TEST_CASE("StrEndsWithIgnoreCase - std::string") { /* Everything ends with an empty prefix. */ diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index 029cd40ff8..1eff6f5fb6 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -177,14 +177,14 @@ enum class HyperlinkType { static HyperlinkType ClassifyHyperlink(const std::string &destination, bool trusted) { if (destination.empty()) return HyperlinkType::Unknown; - if (StrStartsWith(destination, "#")) return HyperlinkType::Internal; + if (destination.starts_with("#")) return HyperlinkType::Internal; /* Only allow external / internal links for sources we trust. */ if (!trusted) return HyperlinkType::Unknown; - if (StrStartsWith(destination, "http://")) return HyperlinkType::Web; - if (StrStartsWith(destination, "https://")) return HyperlinkType::Web; - if (StrStartsWith(destination, "./")) return HyperlinkType::File; + if (destination.starts_with("http://")) return HyperlinkType::Web; + if (destination.starts_with("https://")) return HyperlinkType::Web; + if (destination.starts_with("./")) return HyperlinkType::File; return HyperlinkType::Unknown; } @@ -428,7 +428,7 @@ void TextfileWindow::NavigateHistory(int delta) void TextfileWindow::NavigateToFile(std::string newfile, size_t line) { /* Double-check that the file link begins with ./ as a relative path. */ - if (!StrStartsWith(newfile, "./")) return; + if (!newfile.starts_with("./")) return; /* Get the path portion of the current file path. */ std::string newpath = this->filepath; @@ -783,12 +783,12 @@ static void Xunzip(byte **bufp, size_t *sizep) #if defined(WITH_ZLIB) /* In-place gunzip */ - if (StrEndsWith(textfile, ".gz")) Gunzip((byte**)&buf, &filesize); + if (textfile.ends_with(".gz")) Gunzip((byte**)&buf, &filesize); #endif #if defined(WITH_LIBLZMA) /* In-place xunzip */ - if (StrEndsWith(textfile, ".xz")) Xunzip((byte**)&buf, &filesize); + if (textfile.ends_with(".xz")) Xunzip((byte**)&buf, &filesize); #endif if (buf == nullptr) return; @@ -796,7 +796,7 @@ static void Xunzip(byte **bufp, size_t *sizep) std::string_view sv_buf(buf, filesize); /* Check for the byte-order-mark, and skip it if needed. */ - if (StrStartsWith(sv_buf, "\ufeff")) sv_buf.remove_prefix(3); + if (sv_buf.starts_with("\ufeff")) sv_buf.remove_prefix(3); /* Update the filename. */ this->filepath = textfile; From f457be5a27439f2cbb276b3d5c731941687d286a Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 17 Jan 2024 22:26:33 +0100 Subject: [PATCH 07/14] Fix #11819, aa5ba5b: Out-of-bounds access in linkgraph GUI. (#11821) --- src/linkgraph/linkgraph_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index b00f78ac9c..883484c26a 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -680,7 +680,7 @@ void LinkGraphLegendWindow::UpdateOverlayCompanies() void LinkGraphLegendWindow::UpdateOverlayCargoes() { CargoTypes mask = 0; - for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + for (uint c = 0; c < num_cargo; c++) { if (!this->IsWidgetLowered(WID_LGL_CARGO_FIRST + c)) continue; SetBit(mask, _sorted_cargo_specs[c]->Index()); } From 47c0184a0bc7d461d9502083d4bb5fef57a68d02 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 17 Jan 2024 20:58:06 +0100 Subject: [PATCH 08/14] Codechange: replace ROR/ROL with std::rotr/rotl --- src/3rdparty/md5/md5.cpp | 8 ++++---- src/core/bitmath_func.hpp | 32 -------------------------------- src/core/random_func.cpp | 4 ++-- src/newgrf_spritegroup.cpp | 2 +- src/saveload/oldloader.cpp | 2 +- src/stdafx.h | 1 + src/strgen/strgen_base.cpp | 2 +- 7 files changed, 10 insertions(+), 41 deletions(-) diff --git a/src/3rdparty/md5/md5.cpp b/src/3rdparty/md5/md5.cpp index 2e84d4c354..0e58d989b6 100644 --- a/src/3rdparty/md5/md5.cpp +++ b/src/3rdparty/md5/md5.cpp @@ -130,14 +130,14 @@ static inline void Md5Set1(const uint32_t *X, uint32_t *a, const uint32_t *b, co { uint32_t t = (*b & *c) | (~*b & *d); t += *a + X[k] + Ti; - *a = ROL(t, s) + *b; + *a = std::rotl(t, s) + *b; } static inline void Md5Set2(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti) { uint32_t t = (*b & *d) | (*c & ~*d); t += *a + X[k] + Ti; - *a = ROL(t, s) + *b; + *a = std::rotl(t, s) + *b; } @@ -145,14 +145,14 @@ static inline void Md5Set3(const uint32_t *X, uint32_t *a, const uint32_t *b, co { uint32_t t = *b ^ *c ^ *d; t += *a + X[k] + Ti; - *a = ROL(t, s) + *b; + *a = std::rotl(t, s) + *b; } static inline void Md5Set4(const uint32_t *X, uint32_t *a, const uint32_t *b, const uint32_t *c, const uint32_t *d, const uint8_t k, const uint8_t s, const uint32_t Ti) { uint32_t t = *c ^ (*b | ~*d); t += *a + X[k] + Ti; - *a = ROL(t, s) + *b; + *a = std::rotl(t, s) + *b; } Md5::Md5() diff --git a/src/core/bitmath_func.hpp b/src/core/bitmath_func.hpp index 51b7e13967..578714e211 100644 --- a/src/core/bitmath_func.hpp +++ b/src/core/bitmath_func.hpp @@ -288,38 +288,6 @@ inline bool HasAtMostOneBit(T value) return (value & (value - 1)) == 0; } -/** - * ROtate \a x Left by \a n - * - * @note Assumes a byte has 8 bits - * @param x The value which we want to rotate - * @param n The number how many we want to rotate - * @pre n < sizeof(T) * 8 - * @return A bit rotated number - */ -template -inline T ROL(const T x, const uint8_t n) -{ - if (n == 0) return x; - return (T)(x << n | x >> (sizeof(x) * 8 - n)); -} - -/** - * ROtate \a x Right by \a n - * - * @note Assumes a byte has 8 bits - * @param x The value which we want to rotate - * @param n The number how many we want to rotate - * @pre n < sizeof(T) * 8 - * @return A bit rotated number - */ -template -inline T ROR(const T x, const uint8_t n) -{ - if (n == 0) return x; - return (T)(x >> n | x << (sizeof(x) * 8 - n)); -} - /** * Iterable ensemble of each set bit in a value. * @tparam Tbitpos Type of the position variable. diff --git a/src/core/random_func.cpp b/src/core/random_func.cpp index cba6dbe376..2221af0be2 100644 --- a/src/core/random_func.cpp +++ b/src/core/random_func.cpp @@ -33,8 +33,8 @@ uint32_t Randomizer::Next() const uint32_t s = this->state[0]; const uint32_t t = this->state[1]; - this->state[0] = s + ROR(t ^ 0x1234567F, 7) + 1; - return this->state[1] = ROR(s, 3) - 1; + this->state[0] = s + std::rotr(t ^ 0x1234567F, 7) + 1; + return this->state[1] = std::rotr(s, 3) - 1; } /** diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index fcdd12bb91..daa65ca0d7 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -169,7 +169,7 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver case DSGA_OP_STO: _temp_store.StoreValue((U)value, (S)last_value); return last_value; case DSGA_OP_RST: return value; case DSGA_OP_STOP: scope->StorePSA((U)value, (S)last_value); return last_value; - case DSGA_OP_ROR: return ROR((U)last_value, (U)value & 0x1F); // mask 'value' to 5 bits, which should behave the same on all architectures. + case DSGA_OP_ROR: return std::rotr((U)last_value, (U)value & 0x1F); // mask 'value' to 5 bits, which should behave the same on all architectures. case DSGA_OP_SCMP: return ((S)last_value == (S)value) ? 1 : ((S)last_value < (S)value ? 0 : 2); case DSGA_OP_UCMP: return ((U)last_value == (U)value) ? 1 : ((U)last_value < (U)value ? 0 : 2); case DSGA_OP_SHL: return (uint32_t)(U)last_value << ((U)value & 0x1F); // Same behaviour as in ParamSet, mask 'value' to 5 bits, which should behave the same on all architectures. diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index 4f1954cc11..324866cf29 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -212,7 +212,7 @@ static bool VerifyOldNameChecksum(char *title, uint len) uint16_t sum = 0; for (uint i = 0; i < len - HEADER_CHECKSUM_SIZE; i++) { sum += title[i]; - sum = ROL(sum, 1); + sum = std::rotl(sum, 1); } sum ^= 0xAAAA; // computed checksum diff --git a/src/stdafx.h b/src/stdafx.h index ab96be4e5a..aec18c2b2e 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -48,6 +48,7 @@ #include #include +#include #include #include #include diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index fc5e471f90..8edcfb3d52 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -115,7 +115,7 @@ LangString *StringData::Find(const std::string_view s) uint StringData::VersionHashStr(uint hash, const char *s) const { for (; *s != '\0'; s++) { - hash = ROL(hash, 3) ^ *s; + hash = std::rotl(hash, 3) ^ *s; hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1); } return hash; From 0be26f5856a2a937e7ec61841dbe63efc479792b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 Jan 2024 22:17:14 +0000 Subject: [PATCH 09/14] Change: Remove extra padding from query text. (#11823) This window uses 'modalpopup' padding so does not need extra padding on its text. --- src/misc_gui.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 9abc483fa1..64e1d02840 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -1138,18 +1138,14 @@ struct QueryWindow : public Window { { if (widget != WID_Q_TEXT) return; - Dimension d = GetStringMultiLineBoundingBox(this->message, *size); - d.width += WidgetDimensions::scaled.frametext.Horizontal(); - d.height += WidgetDimensions::scaled.framerect.Vertical(); - *size = d; + *size = GetStringMultiLineBoundingBox(this->message, *size); } void DrawWidget(const Rect &r, WidgetID widget) const override { if (widget != WID_Q_TEXT) return; - DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect), - this->message, TC_FROMSTRING, SA_CENTER); + DrawStringMultiLine(r, this->message, TC_FROMSTRING, SA_CENTER); } void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override From 4cc97e04e63884e8e37058153a76b8e8adb1dd76 Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 17 Jan 2024 22:45:33 +0100 Subject: [PATCH 10/14] Fix #11801, 51f1e93: CalcClosestTownFromTile needs the kd-tree to be valid --- src/saveload/oldloader_sl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index e784eb8ca9..06c0af9084 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -499,7 +499,12 @@ static Town *RemapTown(TileIndex fallback) { /* In some cases depots, industries and stations could refer to a missing town. */ Town *t = Town::GetIfValid(RemapTownIndex(_old_town_index)); - if (t == nullptr) t = CalcClosestTownFromTile(fallback); + if (t == nullptr) { + /* In case the town that was refered to does not exist, find the closest. + * However, this needs the kd-tree to be present. */ + RebuildTownKdtree(); + t = CalcClosestTownFromTile(fallback); + } return t; } From 7faa3848debf0d59fc79b5f9078b375369e3224e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 17 Jan 2024 23:04:07 +0000 Subject: [PATCH 11/14] Change: Mark whole screen dirty when toggling font AA. (#11825) --- src/settings_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 07cdb6b808..15519b62f5 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -584,7 +584,7 @@ struct GameOptionsWindow : Window { _fcsettings.global_aa = !_fcsettings.global_aa; this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa); - this->SetDirty(); + MarkWholeScreenDirty(); ClearFontCache(); break; From a24c2bf10aebcfd63446e49b41873e84964a6b30 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 18 Jan 2024 09:36:48 +0100 Subject: [PATCH 12/14] Codechange: [HarfBuzz] hb-ft will set the scaling on its own --- src/gfx_layout_icu.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index 9cd0fbcdc1..c40c5c0156 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -26,7 +26,7 @@ #include "safeguards.h" -/** harfbuzz doesn't use floats, so we need a value to scale position with to get sub-pixel precision. */ +/** HarfBuzz FreeType integration sets the font scaling, which is always in 1/64th of a pixel. */ constexpr float FONT_SCALE = 64.0; /** @@ -157,7 +157,6 @@ ICUParagraphLayout::ICUVisualRun::ICUVisualRun(const ICURun &run, int x) : void ICURun::Shape(UChar *buff, size_t buff_length) { auto hbfont = hb_ft_font_create_referenced(*(static_cast(font->fc->GetOSHandle()))); - hb_font_set_scale(hbfont, this->font->fc->GetFontSize() * FONT_SCALE, this->font->fc->GetFontSize() * FONT_SCALE); /* ICU buffer is in UTF-16. */ auto hbbuf = hb_buffer_create(); From 2b599c9d00f970074085e1025fa90cec2a6aa81c Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Thu, 18 Jan 2024 09:34:56 +0100 Subject: [PATCH 13/14] Fix: [HarfBuzz] make HarfBuzz use the same glyphs as we render --- src/gfx_layout_icu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index c40c5c0156..c73e84866c 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -157,6 +157,8 @@ ICUParagraphLayout::ICUVisualRun::ICUVisualRun(const ICURun &run, int x) : void ICURun::Shape(UChar *buff, size_t buff_length) { auto hbfont = hb_ft_font_create_referenced(*(static_cast(font->fc->GetOSHandle()))); + /* Match the flags with how we render the glyphs. */ + hb_ft_font_set_load_flags(hbfont, GetFontAAState(this->font->fc->GetSize()) ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO); /* ICU buffer is in UTF-16. */ auto hbbuf = hb_buffer_create(); From 28ef5146ba4e366bf1d8be664c3cd0fa71f42d56 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 30 Dec 2023 00:07:51 +0000 Subject: [PATCH 14/14] Fix #11646: Non-thread safe shared buffer returned from GetLogPrefix(). Return string from GetLogPrefix instead of shared string's buffer. --- src/console.cpp | 7 +++---- src/debug.cpp | 14 ++++++-------- src/debug.h | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index becbcd644f..baeb893e83 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -51,10 +51,9 @@ static void IConsoleWriteToLogFile(const std::string &string) { if (_iconsole_output_file != nullptr) { /* if there is an console output file ... also print it there */ - const char *header = GetLogPrefix(); - if ((strlen(header) != 0 && fwrite(header, strlen(header), 1, _iconsole_output_file) != 1) || - fwrite(string.c_str(), string.size(), 1, _iconsole_output_file) != 1 || - fwrite("\n", 1, 1, _iconsole_output_file) != 1) { + try { + fmt::print(_iconsole_output_file, "{}{}\n", GetLogPrefix(), string); + } catch (const std::system_error &) { fclose(_iconsole_output_file); _iconsole_output_file = nullptr; IConsolePrint(CC_ERROR, "Cannot write to console log file; closing the log file."); diff --git a/src/debug.cpp b/src/debug.cpp index 6bc66532da..fba8111dd6 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -219,18 +219,16 @@ std::string GetDebugString() /** * Get the prefix for logs; if show_date_in_logs is enabled it returns - * the date, otherwise it returns nothing. - * @return the prefix for logs (do not free), never nullptr + * the date, otherwise it returns an empty string. + * @return the prefix for logs. */ -const char *GetLogPrefix() +std::string GetLogPrefix() { - static std::string _log_prefix; + std::string log_prefix; if (_settings_client.gui.show_date_in_logs) { - _log_prefix = fmt::format("[{:%Y-%m-%d %H:%M:%S}] ", fmt::localtime(time(nullptr))); - } else { - _log_prefix.clear(); + log_prefix = fmt::format("[{:%Y-%m-%d %H:%M:%S}] ", fmt::localtime(time(nullptr))); } - return _log_prefix.c_str(); + return log_prefix; } /** diff --git a/src/debug.h b/src/debug.h index 60725df8e5..a7e6300683 100644 --- a/src/debug.h +++ b/src/debug.h @@ -120,7 +120,7 @@ std::string GetDebugString(); void ShowInfoI(const std::string &str); #define ShowInfo(format_string, ...) ShowInfoI(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__)) -const char *GetLogPrefix(); +std::string GetLogPrefix(); void DebugSendRemoteMessages(); void DebugReconsiderSendRemoteMessages();