Merge branch 'master' into jgrpp
# Conflicts: # src/cargotype.h # src/core/CMakeLists.txt # src/core/span_type.hpp # src/fileio.cpp # src/fios.cpp # src/misc/endian_buffer.hpp # src/misc_gui.cpp # src/saveload/saveload.h # src/saveload/vehicle_sl.cpp # src/screenshot.cpp # src/settings.cpp # src/settings_internal.h # src/stdafx.h # src/string_func.h # src/strings.cpp # src/strings_func.h # src/strings_internal.h
This commit is contained in:
9
src/3rdparty/md5/md5.cpp
vendored
9
src/3rdparty/md5/md5.cpp
vendored
@@ -57,6 +57,7 @@
|
||||
#include "../../stdafx.h"
|
||||
#include "../../core/endian_func.hpp"
|
||||
#include "md5.h"
|
||||
#include <bit>
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
@@ -130,14 +131,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 +146,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()
|
||||
|
@@ -159,7 +159,7 @@ SpriteID CargoSpec::GetCargoIcon() const
|
||||
|
||||
std::array<uint8_t, NUM_CARGO> _sorted_cargo_types; ///< Sort order of cargoes by cargo ID.
|
||||
std::vector<const CargoSpec *> _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name.
|
||||
span<const CargoSpec *> _sorted_standard_cargo_specs; ///< Standard cargo specifications sorted alphabetically by name.
|
||||
std::span<const CargoSpec *> _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)
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include "strings_type.h"
|
||||
#include "landscape_type.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/span_type.hpp"
|
||||
#include <vector>
|
||||
|
||||
/** Globally unique label of a cargo type. */
|
||||
@@ -200,7 +199,7 @@ Dimension GetLargestCargoIconSize();
|
||||
void InitializeSortedCargoSpecs();
|
||||
extern std::array<uint8_t, NUM_CARGO> _sorted_cargo_types;
|
||||
extern std::vector<const CargoSpec *> _sorted_cargo_specs;
|
||||
extern span<const CargoSpec *> _sorted_standard_cargo_specs;
|
||||
extern std::span<const CargoSpec *> _sorted_standard_cargo_specs;
|
||||
|
||||
uint ConvertCargoQuantityToDisplayQuantity(CargoID cargo, uint quantity);
|
||||
uint ConvertDisplayQuantityToCargoQuantity(CargoID cargo, uint quantity);
|
||||
|
@@ -61,14 +61,14 @@ struct CommandAuxiliarySerialised : public CommandAuxiliaryBase {
|
||||
return new CommandAuxiliarySerialised(*this);
|
||||
}
|
||||
|
||||
virtual std::optional<span<const uint8_t>> GetDeserialisationSrc() const override { return span<const uint8_t>(this->serialised_data.data(), this->serialised_data.size()); }
|
||||
virtual std::optional<std::span<const uint8_t>> GetDeserialisationSrc() const override { return std::span<const uint8_t>(this->serialised_data.data(), this->serialised_data.size()); }
|
||||
|
||||
virtual void Serialise(CommandSerialisationBuffer &buffer) const override { buffer.Send_binary(this->serialised_data.data(), this->serialised_data.size()); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CommandAuxiliarySerialisable : public CommandAuxiliaryBase {
|
||||
virtual std::optional<span<const uint8_t>> GetDeserialisationSrc() const override { return {}; }
|
||||
virtual std::optional<std::span<const uint8_t>> GetDeserialisationSrc() const override { return {}; }
|
||||
|
||||
CommandAuxiliaryBase *Clone() const override
|
||||
{
|
||||
@@ -86,10 +86,10 @@ public:
|
||||
inline CommandCost Load(const CommandAuxiliaryBase *base)
|
||||
{
|
||||
if (base == nullptr) return CMD_ERROR;
|
||||
std::optional<span<const uint8_t>> deserialise_from = base->GetDeserialisationSrc();
|
||||
std::optional<std::span<const uint8_t>> deserialise_from = base->GetDeserialisationSrc();
|
||||
if (deserialise_from.has_value()) {
|
||||
this->store = T();
|
||||
CommandDeserialisationBuffer buffer(deserialise_from->begin(), deserialise_from->size());
|
||||
CommandDeserialisationBuffer buffer(deserialise_from->data(), deserialise_from->size());
|
||||
CommandCost res = this->store->Deserialise(buffer);
|
||||
if (res.Failed()) return res;
|
||||
if (buffer.error || buffer.pos != buffer.size) {
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include "economy_type.h"
|
||||
#include "strings_type.h"
|
||||
#include "tile_type.h"
|
||||
#include "core/span_type.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
@@ -714,7 +713,7 @@ struct CommandAuxiliaryBase {
|
||||
|
||||
virtual CommandAuxiliaryBase *Clone() const = 0;
|
||||
|
||||
virtual std::optional<span<const uint8_t>> GetDeserialisationSrc() const = 0;
|
||||
virtual std::optional<std::span<const uint8_t>> GetDeserialisationSrc() const = 0;
|
||||
|
||||
virtual void Serialise(CommandSerialisationBuffer &buffer) const = 0;
|
||||
};
|
||||
|
@@ -33,7 +33,6 @@ add_files(
|
||||
serialisation.cpp
|
||||
serialisation.hpp
|
||||
smallstack_type.hpp
|
||||
span_type.hpp
|
||||
strong_typedef_type.hpp
|
||||
tinystring_type.hpp
|
||||
y_combinator.hpp
|
||||
|
@@ -391,38 +391,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 <typename T>
|
||||
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 <typename T>
|
||||
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.
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "../fileio_func.h"
|
||||
#include "../date_func.h"
|
||||
#include "../debug.h"
|
||||
#include <bit>
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
struct SimpleChecksum64 {
|
||||
@@ -27,7 +28,7 @@ struct SimpleChecksum64 {
|
||||
|
||||
void Update(uint64_t input)
|
||||
{
|
||||
this->state = ROL(this->state, 1) ^ input ^ 0x123456789ABCDEF7ULL;
|
||||
this->state = std::rotl(this->state, 1) ^ input ^ 0x123456789ABCDEF7ULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "../stdafx.h"
|
||||
#include "random_func.hpp"
|
||||
#include "bitmath_func.hpp"
|
||||
#include <bit>
|
||||
|
||||
#ifdef RANDOM_DEBUG
|
||||
#include "../network/network.h"
|
||||
@@ -33,8 +34,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#define SERIALISATION_HPP
|
||||
|
||||
#include "bitmath_func.hpp"
|
||||
#include "span_type.hpp"
|
||||
#include "../string_type.h"
|
||||
#include "../string_func.h"
|
||||
|
||||
@@ -269,13 +268,13 @@ public:
|
||||
* @param size The size of the data.
|
||||
* @return The view of the data.
|
||||
*/
|
||||
span<const uint8_t> Recv_binary_view(size_t size)
|
||||
std::span<const uint8_t> Recv_binary_view(size_t size)
|
||||
{
|
||||
if (!this->CanRecvBytes(size, true)) return {};
|
||||
|
||||
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
|
||||
|
||||
span<const uint8_t> view { &this->GetBuffer()[pos], size };
|
||||
std::span<const uint8_t> view { &this->GetBuffer()[pos], size };
|
||||
pos += (decltype(pos)) size;
|
||||
|
||||
return view;
|
||||
@@ -288,7 +287,7 @@ public:
|
||||
*/
|
||||
std::vector<uint8_t> Recv_binary(size_t size)
|
||||
{
|
||||
span<const uint8_t> view = this->Recv_binary_view(size);
|
||||
std::span<const uint8_t> view = this->Recv_binary_view(size);
|
||||
|
||||
return { view.begin(), view.end() };
|
||||
}
|
||||
@@ -297,14 +296,14 @@ public:
|
||||
* Returns a view of a length-prefixed binary buffer from the packet.
|
||||
* @return The binary buffer.
|
||||
*/
|
||||
span<const uint8_t> Recv_buffer_view()
|
||||
std::span<const uint8_t> Recv_buffer_view()
|
||||
{
|
||||
uint16_t length = this->Recv_uint16();
|
||||
|
||||
if (!this->CanRecvBytes(length, true)) return {};
|
||||
|
||||
auto &pos = static_cast<T *>(this)->GetDeserialisationPosition();
|
||||
span<const uint8_t> buffer { &this->GetBuffer()[pos], length };
|
||||
std::span<const uint8_t> buffer { &this->GetBuffer()[pos], length };
|
||||
pos += length;
|
||||
|
||||
return buffer;
|
||||
@@ -316,7 +315,7 @@ public:
|
||||
*/
|
||||
std::vector<uint8_t> Recv_buffer()
|
||||
{
|
||||
span<const uint8_t> view = this->Recv_buffer_view();
|
||||
std::span<const uint8_t> view = this->Recv_buffer_view();
|
||||
|
||||
return { view.begin(), view.end() };
|
||||
}
|
||||
|
@@ -1,109 +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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @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 <class, class = void>
|
||||
struct has_size_and_data : std::false_type{};
|
||||
template <class C>
|
||||
struct has_size_and_data
|
||||
<
|
||||
C, std::void_t<
|
||||
decltype(std::size(std::declval<C>())),
|
||||
decltype(std::data(std::declval<C>()))>
|
||||
> : std::true_type{};
|
||||
|
||||
/* Template to check if two elements are compatible. */
|
||||
template <class, class, class = void>
|
||||
struct is_compatible_element : std::false_type {};
|
||||
template <class C, class E>
|
||||
struct is_compatible_element
|
||||
<
|
||||
C, E, std::void_t<
|
||||
decltype(std::data(std::declval<C>())),
|
||||
typename std::remove_pointer<decltype(std::data( std::declval<C&>()))>::type(*)[]>
|
||||
> : std::is_convertible<typename std::remove_pointer<decltype(std::data(std::declval<C&>()))>::type(*)[], 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 <class C, class E>
|
||||
struct is_compatible_container : std::bool_constant
|
||||
<
|
||||
has_size_and_data<C>::value
|
||||
&& is_compatible_element<C, E>::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 T>
|
||||
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<class Container, typename std::enable_if<(is_compatible_container<Container, element_type>::value), int>::type = 0>
|
||||
constexpr span(Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {}
|
||||
template<class Container, typename std::enable_if<(std::is_const<element_type>::value && is_compatible_container<Container, element_type>::value), int>::type = 0>
|
||||
constexpr span(const Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {}
|
||||
|
||||
constexpr pointer data() const noexcept { return first; }
|
||||
constexpr size_t size() const noexcept { return static_cast<size_t>( last - first ); }
|
||||
constexpr std::ptrdiff_t ssize() const noexcept { return static_cast<std::ptrdiff_t>( 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 span<element_type> 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 */
|
@@ -749,7 +749,7 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p
|
||||
|
||||
/* Callback for FiosFileScanner. */
|
||||
static fios_getlist_callback_proc *proc = [](SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) {
|
||||
if (StrEqualsIgnoreCase(ext, ".sav") && StrStartsWith(file, _prefix)) return FIOS_TYPE_FILE;
|
||||
if (StrEqualsIgnoreCase(ext, ".sav") && file.starts_with(_prefix)) return FIOS_TYPE_FILE;
|
||||
return FIOS_TYPE_INVALID;
|
||||
};
|
||||
|
||||
|
@@ -178,7 +178,7 @@ static void LoadSpriteTables()
|
||||
const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
|
||||
|
||||
SpriteFile &baseset_file = LoadGrfFile(used_set->files[GFT_BASE].filename, 0, PAL_DOS != used_set->palette);
|
||||
if (StrStartsWith(used_set->name, "original_")) {
|
||||
if (used_set->name.starts_with("original_")) {
|
||||
baseset_file.flags |= SFF_OPENTTDGRF;
|
||||
}
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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}
|
||||
|
@@ -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 :勾选此框以对游戏字体应用抗锯齿。
|
||||
|
||||
|
@@ -121,8 +121,8 @@ private:
|
||||
uint received_demand; ///< Received demand towards this node.
|
||||
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
||||
FlowStatMap flows; ///< Planned flows to other nodes.
|
||||
span<DemandAnnotation> demands; ///< Demand annotations belonging to this node.
|
||||
span<Edge> edges; ///< Edges with annotations belonging to this node.
|
||||
std::span<DemandAnnotation> demands; ///< Demand annotations belonging to this node.
|
||||
std::span<Edge> edges; ///< Edges with annotations belonging to this node.
|
||||
void Init(uint supply);
|
||||
};
|
||||
|
||||
@@ -232,12 +232,12 @@ public:
|
||||
this->node_anno.received_demand += amount;
|
||||
}
|
||||
|
||||
span<DemandAnnotation> GetDemandAnnotations() const
|
||||
std::span<DemandAnnotation> GetDemandAnnotations() const
|
||||
{
|
||||
return this->node_anno.demands;
|
||||
}
|
||||
|
||||
void SetDemandAnnotations(span<DemandAnnotation> demands)
|
||||
void SetDemandAnnotations(std::span<DemandAnnotation> demands)
|
||||
{
|
||||
this->node_anno.demands = demands;
|
||||
}
|
||||
@@ -252,7 +252,7 @@ public:
|
||||
return empty_edge;
|
||||
}
|
||||
|
||||
span<Edge> GetEdges()
|
||||
std::span<Edge> GetEdges()
|
||||
{
|
||||
return this->node_anno.edges;
|
||||
}
|
||||
|
@@ -134,8 +134,9 @@ public:
|
||||
void SetNode(NodeID, NodeID node)
|
||||
{
|
||||
Node node_anno = this->job[node];
|
||||
this->i = node_anno.GetEdges().begin();
|
||||
this->end = node_anno.GetEdges().end();
|
||||
std::span<Edge> edges = node_anno.GetEdges();
|
||||
this->i = edges.data();
|
||||
this->end = edges.data() + edges.size();
|
||||
this->node = node;
|
||||
}
|
||||
|
||||
|
@@ -1242,10 +1242,7 @@ struct QueryWindow : public Window {
|
||||
|
||||
if (!this->precomposed) this->message_str = GetString(this->message);
|
||||
|
||||
Dimension d = GetStringMultiLineBoundingBox(this->message_str.c_str(), *size);
|
||||
d.width += WidgetDimensions::scaled.frametext.Horizontal();
|
||||
d.height += WidgetDimensions::scaled.framerect.Vertical();
|
||||
*size = d;
|
||||
*size = GetStringMultiLineBoundingBox(this->message_str, *size);
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
@@ -1254,8 +1251,7 @@ struct QueryWindow : public Window {
|
||||
|
||||
if (!this->precomposed) this->message_str = GetString(this->message);
|
||||
|
||||
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect),
|
||||
this->message_str, TC_FROMSTRING, SA_CENTER);
|
||||
DrawStringMultiLine(r, this->message_str, TC_FROMSTRING, SA_CENTER);
|
||||
}
|
||||
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
|
@@ -473,7 +473,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));
|
||||
}
|
||||
|
@@ -177,7 +177,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");
|
||||
|
@@ -252,7 +252,7 @@ void NetworkHTTPRequest::Connect()
|
||||
WinHttpSendRequest(this->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, reinterpret_cast<DWORD_PTR>(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<char *>(data.c_str()), static_cast<DWORD>(data.size()), static_cast<DWORD>(data.size()), reinterpret_cast<DWORD_PTR>(this));
|
||||
}
|
||||
}
|
||||
|
@@ -416,7 +416,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;
|
||||
|
@@ -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
|
||||
|
@@ -657,7 +657,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);
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "scope.h"
|
||||
#include "debug_settings.h"
|
||||
#include "newgrf_engine.h"
|
||||
#include <bit>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -212,7 +213,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<uint32_t>((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<uint32_t>((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.
|
||||
|
@@ -588,7 +588,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;
|
||||
}
|
||||
|
||||
|
@@ -617,7 +617,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);
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include "../fileio_type.h"
|
||||
#include "../fios.h"
|
||||
#include "../strings_type.h"
|
||||
#include "../core/span_type.hpp"
|
||||
#include "../core/ring_buffer.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@@ -83,10 +82,10 @@ struct ChunkHandler {
|
||||
using ChunkHandlerRef = std::reference_wrapper<const ChunkHandler>;
|
||||
|
||||
/** A table of ChunkHandler entries. */
|
||||
using ChunkHandlerTable = span<const ChunkHandlerRef>;
|
||||
using ChunkHandlerTable = std::span<const ChunkHandlerRef>;
|
||||
|
||||
/** A table of SaveLoadCompat entries. */
|
||||
using SaveLoadCompatTable = span<const struct SaveLoadCompat>;
|
||||
using SaveLoadCompatTable = std::span<const struct SaveLoadCompat>;
|
||||
|
||||
/** Handler for saving/loading an object to/from disk. */
|
||||
class SaveLoadHandler {
|
||||
|
@@ -143,7 +143,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) {
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "saveload_internal.h"
|
||||
#include "oldloader.h"
|
||||
|
||||
#include <bit>
|
||||
#include <exception>
|
||||
|
||||
#include "../safeguards.h"
|
||||
@@ -214,7 +215,7 @@ static bool VerifyOldNameChecksum(char *title, uint len)
|
||||
uint16_t sum = 0;
|
||||
for (uint i = 0; i < len - 2; i++) {
|
||||
sum += title[i];
|
||||
sum = ROL(sum, 1);
|
||||
sum = std::rotl(sum, 1);
|
||||
}
|
||||
|
||||
sum ^= 0xAAAA; // computed checksum
|
||||
|
@@ -230,7 +230,7 @@ struct NullStruct {
|
||||
};
|
||||
|
||||
/** A table of ChunkHandler entries. */
|
||||
using ChunkHandlerTable = span<const ChunkHandler>;
|
||||
using ChunkHandlerTable = std::span<const ChunkHandler>;
|
||||
|
||||
/** Type of reference (#SLE_REF, #SLE_CONDREF). */
|
||||
enum SLRefType {
|
||||
@@ -943,7 +943,7 @@ size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt);
|
||||
* @return Span of the saved data, in the autolength temp buffer
|
||||
*/
|
||||
template <typename F>
|
||||
span<byte> SlSaveToTempBuffer(F proc)
|
||||
std::span<byte> SlSaveToTempBuffer(F proc)
|
||||
{
|
||||
extern uint8_t SlSaveToTempBufferSetup();
|
||||
extern std::pair<byte *, size_t> SlSaveToTempBufferRestore(uint8_t state);
|
||||
@@ -951,7 +951,7 @@ span<byte> SlSaveToTempBuffer(F proc)
|
||||
uint8_t state = SlSaveToTempBufferSetup();
|
||||
proc();
|
||||
auto result = SlSaveToTempBufferRestore(state);
|
||||
return span<byte>(result.first, result.second);
|
||||
return std::span<byte>(result.first, result.second);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -963,7 +963,7 @@ span<byte> SlSaveToTempBuffer(F proc)
|
||||
template <typename F>
|
||||
std::vector<uint8_t> SlSaveToVector(F proc)
|
||||
{
|
||||
span<byte> result = SlSaveToTempBuffer(proc);
|
||||
std::span<byte> result = SlSaveToTempBuffer(proc);
|
||||
return std::vector<uint8_t>(result.begin(), result.end());
|
||||
}
|
||||
|
||||
|
@@ -11,18 +11,17 @@
|
||||
#define SL_SAVELOAD_COMMON_H
|
||||
|
||||
#include "../strings_type.h"
|
||||
#include "../core/span_type.hpp"
|
||||
|
||||
struct SaveLoad;
|
||||
|
||||
/** A table of SaveLoad entries. */
|
||||
using SaveLoadTable = span<const SaveLoad>;
|
||||
using SaveLoadTable = std::span<const SaveLoad>;
|
||||
|
||||
namespace upstream_sl {
|
||||
struct SaveLoad;
|
||||
|
||||
/** A table of SaveLoad entries. */
|
||||
using SaveLoadTable = span<const SaveLoad>;
|
||||
using SaveLoadTable = std::span<const SaveLoad>;
|
||||
}
|
||||
|
||||
/** SaveLoad versions
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include "bitmap_type.h"
|
||||
#include "core/alloc_type.hpp"
|
||||
#include "core/endian_type.hpp"
|
||||
#include "core/span_type.hpp"
|
||||
#include "strings_type.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -506,9 +505,9 @@ public:
|
||||
|
||||
void SortStorage();
|
||||
|
||||
span<const FlowStat> IterateUnordered() const
|
||||
std::span<const FlowStat> IterateUnordered() const
|
||||
{
|
||||
return span<const FlowStat>(this->flows_storage.data(), this->flows_storage.size());
|
||||
return std::span<const FlowStat>(this->flows_storage.data(), this->flows_storage.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -56,6 +56,7 @@
|
||||
#include <climits>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "strgen.h"
|
||||
|
||||
#include <bit>
|
||||
|
||||
#include "../table/strgen_tables.h"
|
||||
|
||||
@@ -109,7 +110,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;
|
||||
|
@@ -210,7 +210,7 @@ const char *str_fix_scc_encoded(char *str, const char *last)
|
||||
* @param data Array to format
|
||||
* @return Converted string.
|
||||
*/
|
||||
std::string FormatArrayAsHex(span<const byte> data)
|
||||
std::string FormatArrayAsHex(std::span<const byte> data)
|
||||
{
|
||||
std::string hex_output;
|
||||
hex_output.resize(data.size() * 2);
|
||||
@@ -431,19 +431,6 @@ const char *StrLastPathSegment(const char *path)
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -456,19 +443,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<char> {
|
||||
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include <iterator>
|
||||
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/span_type.hpp"
|
||||
#include "string_type.h"
|
||||
|
||||
char *strecat(char *dst, const char *src, const char *last) NOACCESS(3);
|
||||
@@ -42,7 +41,7 @@ int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
|
||||
std::string CDECL stdstr_fmt(const char *str, ...) WARN_FORMAT(1, 2);
|
||||
std::string stdstr_vfmt(const char *str, va_list va) WARN_FORMAT(1, 0);
|
||||
|
||||
std::string FormatArrayAsHex(span<const byte> data);
|
||||
std::string FormatArrayAsHex(std::span<const byte> data);
|
||||
|
||||
char *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);
|
||||
@@ -73,9 +72,7 @@ inline const char *StrLastPathSegment(const std::string &path)
|
||||
return StrLastPathSegment(path.c_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);
|
||||
|
@@ -132,7 +132,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<const StringParameterBackup> backup, uint offset)
|
||||
void CopyInDParam(const std::span<const StringParameterBackup> backup, uint offset)
|
||||
{
|
||||
for (size_t i = 0; i < backup.size(); i++) {
|
||||
auto &value = backup[i];
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#include "string_type.h"
|
||||
#include "gfx_type.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
#include "core/span_type.hpp"
|
||||
#include "vehicle_type.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
@@ -103,7 +102,7 @@ void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL);
|
||||
void SetDParamStr(size_t n, const char *str);
|
||||
void SetDParamStr(size_t n, std::string str);
|
||||
|
||||
void CopyInDParam(const span<const StringParameterBackup> backup, uint offset = 0);
|
||||
void CopyInDParam(const std::span<const StringParameterBackup> backup, uint offset = 0);
|
||||
void CopyOutDParam(std::vector<StringParameterBackup> &backup, size_t num);
|
||||
bool HaveDParamChanged(const std::vector<StringParameterBackup> &backup);
|
||||
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#define STRINGS_INTERNAL_H
|
||||
|
||||
#include "string_func.h"
|
||||
#include "core/span_type.hpp"
|
||||
#include "core/strong_typedef_type.hpp"
|
||||
|
||||
#include <array>
|
||||
@@ -27,12 +26,12 @@ struct StringParameter {
|
||||
class StringParameters {
|
||||
protected:
|
||||
StringParameters *parent = nullptr; ///< If not nullptr, this instance references data from this parent instance.
|
||||
span<StringParameter> parameters = {}; ///< Array with the actual parameters.
|
||||
std::span<StringParameter> 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<StringParameter> parameters = {}) :
|
||||
StringParameters(std::span<StringParameter> 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;
|
||||
}
|
||||
|
||||
|
@@ -225,9 +225,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<const uint32_t>(extra_cfg->param.data(), extra_cfg->num_params);
|
||||
survey["graphics_set_parameters"] = std::span<const uint32_t>(extra_cfg->param.data(), extra_cfg->num_params);
|
||||
} else {
|
||||
survey["graphics_set_parameters"] = span<const uint32_t>();
|
||||
survey["graphics_set_parameters"] = std::span<const uint32_t>();
|
||||
}
|
||||
}
|
||||
if (BaseMusic::GetUsedSet() != nullptr) {
|
||||
@@ -318,7 +318,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<const uint32_t>(c->param.data(), c->num_params);
|
||||
grf["parameters"] = std::span<const uint32_t>(c->param.data(), c->num_params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -164,97 +164,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. */
|
||||
@@ -342,97 +251,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. */
|
||||
|
@@ -179,14 +179,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;
|
||||
}
|
||||
|
||||
@@ -430,7 +430,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;
|
||||
@@ -790,12 +790,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 (std::string_view(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 (std::string_view(textfile).ends_with(".xz")) Xunzip((byte**)&buf, &filesize);
|
||||
#endif
|
||||
|
||||
if (buf == nullptr) return;
|
||||
@@ -803,7 +803,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;
|
||||
|
@@ -48,7 +48,6 @@
|
||||
#include "zoom_func.h"
|
||||
#include "group_gui_list.h"
|
||||
#include "newgrf_debug.h"
|
||||
#include "core/span_type.hpp"
|
||||
#include "3rdparty/cpp-btree/btree_map.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
@@ -549,9 +548,9 @@ struct TraceRestrictDropDownListItem {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the appropriate type dropdown TraceRestrictDropDownListItem span for the given item type @p type
|
||||
* Return the appropriate type dropdown TraceRestrictDropDownListItem std::span for the given item type @p type
|
||||
*/
|
||||
static span<const TraceRestrictDropDownListItem> GetTypeDropDownListItems(TraceRestrictGuiItemType type)
|
||||
static std::span<const TraceRestrictDropDownListItem> GetTypeDropDownListItems(TraceRestrictGuiItemType type)
|
||||
{
|
||||
static const TraceRestrictDropDownListItem actions[] = {
|
||||
{ TRIT_PF_DENY, STR_TRACE_RESTRICT_PF_DENY, TRDDLIF_NONE },
|
||||
@@ -602,9 +601,9 @@ static span<const TraceRestrictDropDownListItem> GetTypeDropDownListItems(TraceR
|
||||
};
|
||||
|
||||
if (IsTraceRestrictTypeConditional(ItemTypeFromGuiType(type))) {
|
||||
return span<const TraceRestrictDropDownListItem>(conditions);
|
||||
return std::span<const TraceRestrictDropDownListItem>(conditions);
|
||||
} else {
|
||||
return span<const TraceRestrictDropDownListItem>(actions);
|
||||
return std::span<const TraceRestrictDropDownListItem>(actions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -119,6 +119,7 @@
|
||||
#include "core/backup_type.hpp"
|
||||
#include "3rdparty/robin_hood/robin_hood.h"
|
||||
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
@@ -6670,7 +6671,7 @@ static LineSnapPoint LineSnapPointAtRailTrackEndpoint(TileIndex tile, DiagDirect
|
||||
SetBit(ret.dirs, DiagDirToDir(exit_dir));
|
||||
SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45LEFT));
|
||||
SetBit(ret.dirs, ChangeDir(DiagDirToDir(exit_dir), DIRDIFF_45RIGHT));
|
||||
if (bidirectional) ret.dirs |= ROR<uint8_t>(ret.dirs, DIRDIFF_REVERSE);
|
||||
if (bidirectional) ret.dirs |= std::rotr<uint8_t>(ret.dirs, DIRDIFF_REVERSE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -6785,7 +6786,7 @@ static void SetRailSnapTile(TileIndex tile)
|
||||
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
|
||||
_tile_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(tile, dir, false));
|
||||
LineSnapPoint &point = _tile_snap_points.back();
|
||||
point.dirs = ROR<uint8_t>(point.dirs, DIRDIFF_REVERSE);
|
||||
point.dirs = std::rotr<uint8_t>(point.dirs, DIRDIFF_REVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user