Merge branch 'master' into jgrpp

# Conflicts:
#	CMakeLists.txt
#	src/3rdparty/md5/md5.h
#	src/3rdparty/squirrel/squirrel/squtils.h
#	src/animated_tile.cpp
#	src/console_func.h
#	src/core/CMakeLists.txt
#	src/core/container_func.hpp
#	src/core/smallstack_type.hpp
#	src/crashlog.cpp
#	src/crashlog.h
#	src/debug.h
#	src/economy.cpp
#	src/gamelog.cpp
#	src/industry_gui.cpp
#	src/lang/catalan.txt
#	src/misc_gui.cpp
#	src/network/network_content.h
#	src/newgrf.cpp
#	src/newgrf.h
#	src/newgrf_config.cpp
#	src/newgrf_config.h
#	src/newgrf_gui.cpp
#	src/os/unix/font_unix.cpp
#	src/os/windows/crashlog_win.cpp
#	src/rail_cmd.cpp
#	src/saveload/animated_tile_sl.cpp
#	src/script/api/script_tilelist.cpp
#	src/settings.cpp
#	src/settingsgen/settingsgen.cpp
#	src/sl/oldloader_sl.cpp
#	src/station.cpp
#	src/station_cmd.cpp
#	src/stdafx.h
#	src/strgen/strgen.cpp
#	src/strgen/strgen_base.cpp
#	src/table/settings/gui_settings.ini
#	src/train_gui.cpp
#	src/vehicle.cpp
#	src/vehicle_base.h
#	src/vehicle_cmd.cpp
#	src/vehicle_gui_base.h
#	src/viewport_sprite_sorter.h
pull/564/head
Jonathan G Rennison 10 months ago
commit ead18b2af2

@ -147,15 +147,15 @@ cpp_wrap_preserve_blocks = never
#cpp_keep_blank_lines_in_code
# No override for "Number of blank lines around class/struct/enum definition" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_class_definition
# No override for "Number of blank lines around function declarations" (Unspecified; Not consistent across source code)
# No override for "Number of blank lines around function declarations" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_function_declaration
# No override for "Number of blank lines around function definitions" (Unspecified; Not consistent across source code)
# No override for "Number of blank lines around function definitions" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_function_definition
# No override for "Number of blank lines around single line function definitions" (Unspecified; Not consistent across source code)
# No override for "Number of blank lines around single line function definitions" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_single_line_function_definition
# No override for "Number of blank lines around namespaces" (Unspecified; Not consistent across source code)
# No override for "Number of blank lines around namespaces" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_namespace
# No override for "Number of blank lines around other definitions and declarations" (Unspecified; Not consistent across source code)
# No override for "Number of blank lines around other definitions and declarations" (Unspecified; Not consistent across source code)
#cpp_blank_lines_around_other_declaration
# Braces Layout #
@ -201,69 +201,69 @@ cpp_alignment_tab_fill_style = use_spaces
cpp_allow_far_alignment = true
# Indentation and Alignment #
# No override for "Continuous line indent" (Varies throughout source code)
# No override for "Continuous line indent" (Varies throughout source code)
#cpp_continuous_line_indent
# Do not use continuous line indent in function declaration and invocation parentheses
# Do not use continuous line indent in function declaration and invocation parentheses
cpp_use_continuous_line_indent_in_method_pars = false
# Do not use continuous line indent in initializer lists
# Do not use continuous line indent in initializer lists
cpp_use_continuous_line_indent_in_expression_braces = false
# Indent namespace members (including nested ones)
# Indent namespace members (including nested ones)
cpp_namespace_indentation = all
# No override for "Indent linkage specification block members" (Unspecified)
#cpp_linkage_specification_indentation
# Do not indent access specifier from class
# Do not indent access specifier from class
cpp_indent_access_specifiers_from_class = false
# Indent class member from access specifier
cpp_indent_class_members_from_access_specifiers = true
# Do not indent if a function definition or declaration is wrapped after the type
cpp_indent_wrapped_function_names = false
# Indent 'case' labels from 'switch'
# Indent 'case' labels from 'switch'
cpp_indent_switch_labels = true
# No override for "Indent function declarations' parentheses" (Varies throughout source code)
# No override for "Indent function declarations' parentheses" (Varies throughout source code)
#cpp_indent_method_decl_pars
# No override for "Indent method calls' parentheses" (Varies throughout source code)
#cpp_indent_invocation_pars
# No override for "Indent statement (if, while, for, etc) parentheses" (Varies throughout source code)
#cpp_indent_statement_pars
# Do not change preprocessor directives indenting
# Do not change preprocessor directives indenting
cpp_indent_preprocessor_directives = do_not_change
# No override for "Indent C++/CLI generic constraints" (C++/CLI is not used)
# No override for "Indent C++/CLI generic constraints" (C++/CLI is not used)
#cpp_indent_type_constraints
# Align/indent comments started at the first column
# Align/indent comments started at the first column
cpp_indent_comment = true
# Comments that comment out code will use the indentation level of the commented code.
cpp_place_comments_at_first_column = false
# Align multiline declarators in declaration
# Align multiline declarators in declaration
cpp_align_multiple_declaration = true
# Align multiline function parameters
# Align multiline function parameters
cpp_align_multiline_parameter = true
# Align multiline call arguments
# Align multiline call arguments
cpp_align_multiline_argument = true
# Do not align first of multiline call arguments with the opening parentheses
cpp_align_first_arg_by_paren = false
# Align multiline initializer list arguments
cpp_align_multiline_expression_brace = true
# No override for "Align multiline template parameters in template declaration" (Unspecified)
# No override for "Align multiline template parameters in template declaration" (Unspecified)
#cpp_align_multiline_type_parameter
# No override for "Align multiline template arguments" (Unspecified)
#cpp_align_multiline_type_argument
# Align multiline base classes in class base clause
cpp_align_multiline_extends_list = true
# Align multiline member initializers in member initializer lists
# Align multiline member initializers in member initializer lists
cpp_align_multiline_ctor_init = true
# Outdent commas placed on new line
# Outdent commas placed on new line
cpp_outdent_commas = true
# Do not align multiline ?: operator with first line (since alignment is incorrect)
cpp_align_ternary = none
# Do not indent aligned ?: operator (since indentation varies)
# Do not indent aligned ?: operator (since indentation varies)
cpp_indent_aligned_ternary = false
# No override for "Align multiline chained method calls" (Unspecified)
#cpp_align_multiline_calls_chain
# No override for "Outdent '.' and '->' in chained method calls on new lines" (Unspecified)
# No override for "Outdent '.' and '->' in chained method calls on new lines" (Unspecified)
#cpp_outdent_dots
# Do not align multiline chained binary expressions
cpp_align_multiline_binary_expressions_chain = false
# Fix column alignment in adjacent lines
# Fix column alignment in adjacent lines
cpp_int_align_fix_in_adjacent = true
# Align assignments with adjacent assignments
cpp_int_align_eq = true
@ -277,121 +277,121 @@ cpp_int_align_comments = true
cpp_space_before_comma = false
# Put space after ALL commas
cpp_space_after_comma = true
# Put space before ptr in declaration of variable
# Put space before ptr in declaration of variable
cpp_space_before_ptr_in_data_member = true
# Do not put space after ptr in declaration of variable
# Do not put space after ptr in declaration of variable
cpp_space_after_ptr_in_data_member = false
# Put space before ptr in declaration of multiple variables
# Put space before ptr in declaration of multiple variables
cpp_space_before_ptr_in_data_members = true
# Do not put space after ptr in declaration of multiple variables
# Do not put space after ptr in declaration of multiple variables
cpp_space_after_ptr_in_data_members = false
# Put space before ptr in return type of function
# Put space before ptr in return type of function
cpp_space_before_ptr_in_method = true
# Do not put space after ptr in return type of function
# Do not put space after ptr in return type of function
cpp_space_after_ptr_in_method = false
# Do not put space before ptr in abstract declaration
# Do not put space before ptr in abstract declaration
cpp_space_before_ptr_in_abstract_decl = false
# Put space before ref in declaration of variable
# Put space before ref in declaration of variable
cpp_space_before_ref_in_data_member = true
# Do not put space after ref in declaration of variable
# Do not put space after ref in declaration of variable
cpp_space_after_ref_in_data_member = false
# Put space before ref in declaration of multiple variables
# Put space before ref in declaration of multiple variables
cpp_space_before_ref_in_data_members = true
# Do not put space after ref in declaration of multiple variables
# Do not put space after ref in declaration of multiple variables
cpp_space_after_ref_in_data_members = false
# Do not put space before ref in return type of function
# Do not put space before ref in return type of function
cpp_space_before_ref_in_method = false
# Put space after ref in return type of function
# Put space after ref in return type of function
cpp_space_after_ref_in_method = true
# Do not put space before ref in abstract declaration
# Do not put space before ref in abstract declaration
cpp_space_before_ref_in_abstract_decl = false
# Do not put space before parentheses in function parameters
# Do not put space before parentheses in function parameters
cpp_space_between_method_declaration_name_and_open_parenthesis = false
# Do not put space before parentheses in lambda parameters
# Do not put space before parentheses in lambda parameters
cpp_space_before_lambda_parentheses = false
# Do not put space within parentheses in function parameters
# Do not put space within parentheses in function parameters
cpp_space_between_method_declaration_parameter_list_parentheses = false
# Do not put space within empty parentheses in function parameters
# Do not put space within empty parentheses in function parameters
cpp_space_between_method_declaration_empty_parameter_list_parentheses = false
# Do not put space before angle brackets in template parameters
# Do not put space before angle brackets in template parameters
cpp_space_before_template_params = false
# Do not put space within angle brackets in template parameters
# Do not put space within angle brackets in template parameters
cpp_space_within_template_params = false
# Do not put space within empty angle brackets in template parameters
# Do not put space within empty angle brackets in template parameters
cpp_space_within_empty_template_params = false
# Do not put space before angle brackets in template arguments
# Do not put space before angle brackets in template arguments
cpp_space_before_template_args = false
# Do not put space within angle brackets in template arguments
# Do not put space within angle brackets in template arguments
cpp_space_within_template_args = false
# Do not put space between closing angle brackets in template arguments
# Do not put space between closing angle brackets in template arguments
cpp_space_between_closing_angle_brackets_in_template_args = false
# Put space around '=' in alias declaration and namespace alias
# Put space around '=' in alias declaration and namespace alias
cpp_space_around_alias_eq = true
# Do not put space around '->' in trailing return types
# Do not put space around '->' in trailing return types
cpp_space_around_deref_in_trailing_return_type = false
# Put space before base types list colon
# Put space before base types list colon
cpp_space_before_colon_in_inheritance_clause = true
# Put space after base types list colon
# Put space after base types list colon
cpp_space_after_colon_in_inheritance_clause = true
# No override for "Before C++/CLI generic constraint colon" (Unspecified)
# No override for "Before C++/CLI generic constraint colon" (Unspecified)
#cpp_space_before_type_parameter_constraint_colon
# No override for "After C++/CLI generic constraint colon" (Unspecified)
# No override for "After C++/CLI generic constraint colon" (Unspecified)
#cpp_space_after_type_parameter_constraint_colon
# Put space before parentheses of control statements
# Put space before parentheses of control statements
cpp_space_after_keywords_in_control_flow_statements = true
# Do not put space within parentheses of control statements
# Do not put space within parentheses of control statements
cpp_space_between_parentheses_of_control_flow_statements = false
# Do not put space before semicolon in 'for' statements
# Do not put space before semicolon in 'for' statements
cpp_space_before_semicolon_in_for_statement = false
# Put space after semicolon in 'for' statements
# Put space after semicolon in 'for' statements
cpp_space_after_semicolon_in_for_statement = true
# Put space before ':' in range-based for loop
# Put space before ':' in range-based for loop
cpp_space_before_for_colon = true
# Put space after ':' in range-based for loop
# Put space after ':' in range-based for loop
cpp_space_after_for_colon = true
# Do not put space before colon in switch case or label statement
# Do not put space before colon in switch case or label statement
cpp_space_before_colon_in_case = false
# Put space after colon in switch case or label statement
# Put space after colon in switch case or label statement
cpp_space_after_colon_in_case = true
# Put space around binary operator
# Put space around binary operator
cpp_space_around_binary_operator = true
# Put space around assignment operator
# Put space around assignment operator
cpp_space_around_assignment_operator = true
# Do not put space around dot, '->', '.*' and '->.'
# Do not put space around dot, '->', '.*' and '->.'
cpp_space_around_member_access_operator = false
# Do not put space within any parentheses
# Do not put space within any parentheses
cpp_space_within_parentheses = false
# Do not put space before array subscript brackets
# Do not put space before array subscript brackets
cpp_space_before_open_square_brackets = false
# Do not put space within array subscript brackets
# Do not put space within array subscript brackets
cpp_space_between_square_brackets = false
# Do not put space before empty parentheses in function call and initialization
# Do not put space before empty parentheses in function call and initialization
cpp_space_between_method_call_name_and_opening_parenthesis = false
# Do not put space within parentheses in cast expressions
# Do not put space within parentheses in cast expressions
cpp_space_between_typecast_parentheses = false
# Do not put space after parentheses in cast expressions
# Do not put space after parentheses in cast expressions
cpp_space_after_cast = false
# Do not put space within parentheses in function call and initialization
# Do not put space within parentheses in function call and initialization
cpp_space_between_method_call_parameter_list_parentheses = false
# Do not put space within empty parentheses in function call and initialization
# Do not put space within empty parentheses in function call and initialization
cpp_space_between_method_call_empty_parameter_list_parentheses = false
# Put space in ternary operator '? :' before '?' 
# Put space in ternary operator '? :' before '?'
cpp_space_before_ternary_quest = true
# Put space in ternary operator '? :' after '?'
# Put space in ternary operator '? :' after '?'
cpp_space_after_ternary_quest = true
# Put space in ternary operator '? :' before ':' 
# Put space in ternary operator '? :' before ':'
cpp_space_before_ternary_colon = true
# Put space in ternary operator '? :' after ':'
# Put space in ternary operator '? :' after ':'
cpp_space_after_ternary_colon = true
# Do not put space before uniform initialization braces
# Do not put space before uniform initialization braces
cpp_space_before_initializer_braces = false
# Do not put space within uniform initialization braces
# Do not put space within uniform initialization braces
cpp_space_within_initializer_braces = false
# Do not put space within empty uniform initialization braces
# Do not put space within empty uniform initialization braces
cpp_space_within_empty_initializer_braces = false
# Put space before end of line comment
# Put space before end of line comment
cpp_space_before_trailing_comment = true
# Preserve spaces before end of line comment
# Preserve spaces before end of line comment
cpp_disable_space_changes_before_trailing_comment = true
# Line breaks and Wrapping #
@ -403,75 +403,75 @@ cpp_disable_space_changes_before_trailing_comment = true
cpp_new_line_before_while = false
# Redundant override (Already overriden earlier in Visual Studio section)
#cpp_new_line_before_catch
# Do not change the line breaks of single embedded statements
# Do not change the line breaks of single embedded statements
cpp_simple_embedded_statement_style = do_not_change
# Do not change the line breaks of simple 'case' statement
# Do not change the line breaks of simple 'case' statement
cpp_simple_case_statement_style = do_not_change
# Put member function definition return type on same line
# Put member function definition return type on same line
cpp_function_definition_return_type_style = on_single_line
# Put top-level function definition return type on same line
# Put top-level function definition return type on same line
cpp_toplevel_function_definition_return_type_style = on_single_line
# Put member function declaration return type on same line
# Put member function declaration return type on same line
cpp_function_declaration_return_type_style = on_single_line
# Put top-level function declaration return type on same line
cpp_toplevel_function_declaration_return_type_style = on_single_line
# Force template<...> of a template declaration on new line
# Force template<...> of a template declaration on new line
cpp_break_template_declaration = line_break
# No override for "Break line before the requires-clause" (requires-clause is a C++20 feature)
# No override for "Break line before the requires-clause" (requires-clause is a C++20 feature)
#cpp_line_break_before_requires_clause
# Do not change the line break before the colon in member initializer lists
# Do not change the line break before the colon in member initializer lists
cpp_member_initializer_list_style = do_not_change
# Do not change the line break after the colon in member initializer lists
# Do not change the line break after the colon in member initializer lists
cpp_line_break_after_colon_in_member_initializer_lists = do_not_change
# No override for "Break line before comma in member initializer lists" (Varies throughout source code)
# No override for "Break line before comma in member initializer lists" (Varies throughout source code)
#cpp_line_break_before_comma_in_member_initializer_lists
# No override for "Break line after comma in member initializer lists" (Varies throughout source code)
# No override for "Break line after comma in member initializer lists" (Varies throughout source code)
#cpp_line_break_after_comma_in_member_initializer_lists
# No override for "Allow C++/CLI generic constraints on the same line" (C++/CLI is not used)
# No override for "Allow C++/CLI generic constraints on the same line" (C++/CLI is not used)
#cpp_place_type_constraints_on_same_line
# No override for "Keep existing line breaks" (Varies throughout source code; depends on developer preference)
# No override for "Keep existing line breaks" (Varies throughout source code; depends on developer preference)
#cpp_keep_user_linebreaks
# No override for "Hard wrap at _ characters" (Unspecified)
#cpp_max_line_length
# Do not prefer wrap before ','
# Do not prefer wrap before ','
cpp_wrap_before_comma = false
# Do not prefer wrap before ',' in base clause
# Do not prefer wrap before ',' in base clause
cpp_wrap_before_comma_in_base_clause = false
# No override for "Wrap ternary expression" (Varies throughout source code)
# No override for "Wrap ternary expression" (Varies throughout source code)
#cpp_wrap_ternary_expr_style
# No override for "Prefer wrap before '?' and ':' in ternary expressions" (Varies throughout source code)
# No override for "Prefer wrap before '?' and ':' in ternary expressions" (Varies throughout source code)
#cpp_wrap_before_ternary_opsigns
# No override for "Prefer wrap before ':'" (Varies throughout source code)
# No override for "Prefer wrap before ':'" (Varies throughout source code)
#cpp_wrap_before_colon
# No override for "Prefer wrap before first C++/CLI generic constraint" (C++/CLI is not used)
# No override for "Prefer wrap before first C++/CLI generic constraint" (C++/CLI is not used)
#cpp_wrap_before_first_type_parameter_constraint
# No override for "Wrap multiple C++/CLI generic constraints" (C++/CLI is not used)
# No override for "Wrap multiple C++/CLI generic constraints" (C++/CLI is not used)
#cpp_wrap_multiple_type_parameter_constraints_style
# No override for "Wrap enum definition" (Varies throughout source code)
# No override for "Wrap enum definition" (Varies throughout source code)
#cpp_wrap_enumeration_style
# No override for "Wrap braced initializer list" (Varies throughout source code)
# No override for "Wrap braced initializer list" (Varies throughout source code)
#cpp_wrap_braced_init_list_style
# No override for "Wrap base classes list" (Varies throughout source code)
# No override for "Wrap base classes list" (Varies throughout source code)
#cpp_wrap_base_clause_style
# No override for "Wrap constructor initializer" (Varies throughout source code)
# No override for "Wrap constructor initializer" (Varies throughout source code)
#cpp_wrap_ctor_initializer_style
# No override for "Wrap formal parameters" (Varies throughout source code)
# No override for "Wrap formal parameters" (Varies throughout source code)
#cpp_wrap_parameters_style
# Do not prefer wrap before '(' in declaration
# Do not prefer wrap before '(' in declaration
cpp_wrap_before_declaration_lpar = false
# Prefer wrap after '(' in declaration
# Prefer wrap after '(' in declaration
cpp_wrap_after_declaration_lpar = true
# Do not prefer wrap before ')' in declaration
# Do not prefer wrap before ')' in declaration
cpp_wrap_before_declaration_rpar = false
# No override for "Wrap invocation arguments" (Varies throughout source code)
# No override for "Wrap invocation arguments" (Varies throughout source code)
#cpp_wrap_arguments_style
# Do not prefer wrap before '(' in invocation
# Do not prefer wrap before '(' in invocation
cpp_wrap_before_invocation_lpar = false
# Prefer wrap after '(' in invocation
# Prefer wrap after '(' in invocation
cpp_wrap_after_invocation_lpar = true
# Do not prefer wrap before ')' in invocation
# Do not prefer wrap before ')' in invocation
cpp_wrap_before_invocation_rpar = false
# Prefer wrap after '{' in initializer lists
# Prefer wrap after '{' in initializer lists
cpp_wrap_after_expression_lbrace = true
# Do not prefer wrap before '}' in initializer lists
# Do not prefer wrap before '}' in initializer lists
cpp_wrap_before_expression_rbrace = false

@ -1,5 +1,9 @@
add_files(
chrono.h
core.h
format.h
format-inl.h
ostream.h
ranges.h
std.h
)

@ -1,4 +1,4 @@
Copyright (c) 2012 - present, Victor Zverovich
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,209 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <fstream> // std::filebuf
#if defined(_WIN32) && defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
# include <__std_stream>
#endif
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace detail {
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct file_access_tag {};
} // namespace
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
#if FMT_MSC_VERSION
template class file_access<file_access_tag, std::filebuf,
&std::filebuf::_Myfile>;
auto get_file(std::filebuf&) -> FILE*;
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
template class file_access<file_access_tag, std::__stdoutbuf<char>,
&std::__stdoutbuf<char>::__file_>;
auto get_file(std::__stdoutbuf<char>&) -> FILE*;
#endif
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
#if FMT_MSC_VERSION
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#elif defined(_WIN32) && defined(__GLIBCXX__)
auto* rdbuf = os.rdbuf();
FILE* c_file;
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
c_file = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
else
return false;
if (c_file) return write_console(c_file, data);
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#else
ignore_unused(os, data);
#endif
return false;
}
inline bool write_ostream_unicode(std::wostream&,
fmt::basic_string_view<wchar_t>) {
return false;
}
// Write the content of buf to os.
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
do {
unsigned_streamsize n = size <= max_size ? size : max_size;
os.write(buf_data, static_cast<std::streamsize>(n));
buf_data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
locale_ref loc = locale_ref()) {
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
auto&& output = std::basic_ostream<Char>(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
if (loc) output.imbue(loc.get<std::locale>());
#endif
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
}
template <typename T> struct streamed_view { const T& value; };
} // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename Char>
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
void set_debug_format() = delete;
template <typename T, typename OutputIt>
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
-> OutputIt {
auto buffer = basic_memory_buffer<Char>();
detail::format_value(buffer, value, ctx.locale());
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
};
using ostream_formatter = basic_ostream_formatter<char>;
template <typename T, typename Char>
struct formatter<detail::streamed_view<T>, Char>
: basic_ostream_formatter<Char> {
template <typename OutputIt>
auto format(detail::streamed_view<T> view,
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
return basic_ostream_formatter<Char>::format(view.value, ctx);
}
};
/**
\rst
Returns a view that formats `value` via an ostream ``operator<<``.
**Example**::
fmt::print("Current thread id: {}\n",
fmt::streamed(std::this_thread::get_id()));
\endrst
*/
template <typename T>
auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
namespace detail {
inline void vprint_directly(std::ostream& os, string_view format_str,
format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
} // namespace detail
FMT_MODULE_EXPORT template <typename Char>
void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto buffer = basic_memory_buffer<Char>();
detail::vformat_to(buffer, format_str, args);
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
detail::write_buffer(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_MODULE_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
const auto& vargs = fmt::make_format_args(args...);
if (detail::is_utf8())
vprint(os, fmt, vargs);
else
detail::vprint_directly(os, fmt, vargs);
}
FMT_MODULE_EXPORT
template <typename... Args>
void print(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
}
FMT_MODULE_EXPORT template <typename... T>
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
FMT_MODULE_EXPORT
template <typename... Args>
void println(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

@ -0,0 +1,732 @@
// Formatting library for C++ - experimental range support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include <initializer_list>
#include <tuple>
#include <type_traits>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Range, typename OutputIt>
auto copy(const Range& range, OutputIt out) -> OutputIt {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
return out;
}
template <typename OutputIt>
auto copy(const char* str, OutputIt out) -> OutputIt {
while (*str) *out++ = *str++;
return out;
}
template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
*out++ = ch;
return out;
}
// Returns true if T has a std::string-like interface, like std::string_view.
template <typename T> class is_std_string_like {
template <typename U>
static auto check(U* p)
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
template <typename> static void check(...);
public:
static constexpr const bool value =
is_string<T>::value ||
std::is_convertible<T, std_string_view<char>>::value ||
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Char>
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
template <typename T> class is_map {
template <typename U> static auto check(U*) -> typename U::mapped_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
#endif
};
template <typename T> class is_set {
template <typename U> static auto check(U*) -> typename U::key_type;
template <typename> static void check(...);
public:
#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
static constexpr const bool value = false;
#else
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
#endif
};
template <typename... Ts> struct conditional_helper {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
# define FMT_DECLTYPE_RETURN(val) \
->decltype(val) { return val; } \
static_assert( \
true, "") // This makes it so that a semicolon is required after the
// macro, which helps clang-format handle the formatting.
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
return arr;
}
template <typename T, std::size_t N>
auto range_end(const T (&arr)[N]) -> const T* {
return arr + N;
}
template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};
template <typename T>
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
// Member function overload
template <typename T>
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
template <typename T>
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
// ADL overload. Only participates in overload resolution if member functions
// are not found.
template <typename T>
auto range_begin(T&& rng)
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(begin(static_cast<T&&>(rng)))> {
return begin(static_cast<T&&>(rng));
}
template <typename T>
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(end(static_cast<T&&>(rng)))> {
return end(static_cast<T&&>(rng));
}
template <typename T, typename Enable = void>
struct has_const_begin_end : std::false_type {};
template <typename T, typename Enable = void>
struct has_mutable_begin_end : std::false_type {};
template <typename T>
struct has_const_begin_end<
T,
void_t<
decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};
template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_end(std::declval<T>())),
// the extra int here is because older versions of MSVC don't
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
# undef FMT_DECLTYPE_RETURN
#endif
// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <size_t... N> using index_sequence = std::index_sequence<N...>;
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
};
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
template <typename T, size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif
template <typename T>
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
template <typename T, typename C, bool = is_tuple_like_<T>::value>
class is_tuple_formattable_ {
public:
static constexpr const bool value = false;
};
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
template <std::size_t... Is>
static std::true_type check2(index_sequence<Is...>,
integer_sequence<bool, (Is == Is)...>);
static std::false_type check2(...);
template <std::size_t... Is>
static decltype(check2(
index_sequence<Is...>{},
integer_sequence<
bool, (is_formattable<typename std::tuple_element<Is, T>::type,
C>::value)...>{})) check(index_sequence<Is...>);
public:
static constexpr const bool value =
decltype(check(tuple_index_sequence<T>{}))::value;
};
template <typename Tuple, typename F, size_t... Is>
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
using std::get;
// Using a free function get<Is>(Tuple) now.
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
ignore_unused(unused);
}
template <typename Tuple, typename F>
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
std::forward<Tuple>(t), std::forward<F>(f));
}
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
using std::get;
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
ignore_unused(unused);
}
template <typename Tuple1, typename Tuple2, typename F>
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
std::forward<F>(f));
}
namespace tuple {
// Workaround a bug in MSVC 2019 (v140).
template <typename Char, typename... T>
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
using std::get;
template <typename Tuple, typename Char, std::size_t... Is>
auto get_formatters(index_sequence<Is...>)
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
} // namespace tuple
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
// Older MSVC doesn't get the reference type correctly for arrays.
template <typename R> struct range_reference_type_impl {
using type = decltype(*detail::range_begin(std::declval<R&>()));
};
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
using type = T&;
};
template <typename T>
using range_reference_type = typename range_reference_type_impl<T>::type;
#else
template <typename Range>
using range_reference_type =
decltype(*detail::range_begin(std::declval<Range&>()));
#endif
// We don't use the Range's value_type for anything, but we do need the Range's
// reference type, with cv-ref stripped.
template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Formatter>
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
-> decltype(f.set_debug_format(set)) {
f.set_debug_format(set);
}
template <typename Formatter>
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
// These are not generic lambdas for compatibility with C++11.
template <typename ParseContext> struct parse_empty_specs {
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
f.parse(ctx);
detail::maybe_set_debug_format(f, true);
}
ParseContext& ctx;
};
template <typename FormatContext> struct format_tuple_element {
using char_type = typename FormatContext::char_type;
template <typename T>
void operator()(const formatter<T, char_type>& f, const T& v) {
if (i > 0)
ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
ctx.advance_to(f.format(v, ctx));
++i;
}
int i;
FormatContext& ctx;
basic_string_view<char_type> separator;
};
} // namespace detail
template <typename T> struct is_tuple_like {
static constexpr const bool value =
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename T, typename C> struct is_tuple_formattable {
static constexpr const bool value =
detail::is_tuple_formattable_<T, C>::value;
};
template <typename Tuple, typename Char>
struct formatter<Tuple, Char,
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
fmt::is_tuple_formattable<Tuple, Char>::value>> {
private:
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '('>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ')'>{};
public:
FMT_CONSTEXPR formatter() {}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
if (it != ctx.end() && *it != '}')
FMT_THROW(format_error("invalid format specifier"));
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
return it;
}
template <typename FormatContext>
auto format(const Tuple& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
detail::for_each2(
formatters_, value,
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
return detail::copy_str<Char>(closing_bracket_, ctx.out());
}
};
template <typename T, typename Char> struct is_range {
static constexpr const bool value =
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_convertible<T, detail::std_string_view<Char>>::value;
};
namespace detail {
template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>;
template <typename T,
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value) -> T&& {
return static_cast<T&&>(value);
}
template <typename T,
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value)
-> decltype(mapper().map(static_cast<T&&>(value))) {
return mapper().map(static_cast<T&&>(value));
}
};
template <typename Char, typename Element>
using range_formatter_type =
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
std::declval<Element>()))>,
Char>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
template <typename R, typename Char>
struct is_formattable_delayed
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
#endif
} // namespace detail
template <typename T, typename Char, typename Enable = void>
struct range_formatter;
template <typename T, typename Char>
struct range_formatter<
T, Char,
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
is_formattable<T, Char>>::value>> {
private:
detail::range_formatter_type<Char, T> underlying_;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
public:
FMT_CONSTEXPR range_formatter() {}
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
return underlying_;
}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it != end && *it == 'n') {
set_brackets({}, {});
++it;
}
if (it != end && *it != '}') {
if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
++it;
} else {
detail::maybe_set_debug_format(underlying_, true);
}
ctx.advance_to(it);
return underlying_.parse(ctx);
}
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
out = detail::copy_str<Char>(opening_bracket_, out);
int i = 0;
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
for (; it != end; ++it) {
if (i > 0) out = detail::copy_str<Char>(separator_, out);
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
++i;
}
out = detail::copy_str<Char>(closing_bracket_, out);
return out;
}
};
enum class range_format { disabled, map, set, sequence, string, debug_string };
namespace detail {
template <typename T>
struct range_format_kind_
: std::integral_constant<range_format,
std::is_same<uncvref_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence> {};
template <range_format K, typename R, typename Char, typename Enable = void>
struct range_default_formatter;
template <range_format K>
using range_format_constant = std::integral_constant<range_format, K>;
template <range_format K, typename R, typename Char>
struct range_default_formatter<
K, R, Char,
enable_if_t<(K == range_format::sequence || K == range_format::map ||
K == range_format::set)>> {
using range_type = detail::maybe_const_range<R>;
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
}
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
underlying_.underlying().set_brackets({}, {});
underlying_.underlying().set_separator(
detail::string_literal<Char, ':', ' '>{});
}
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
return underlying_.format(range, ctx);
}
};
} // namespace detail
template <typename T, typename Char, typename Enable = void>
struct range_format_kind
: conditional_t<
is_range<T, Char>::value, detail::range_format_kind_<T>,
std::integral_constant<range_format, range_format::disabled>> {};
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
range_format::disabled>
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
,
detail::is_formattable_delayed<R, Char>
#endif
>::value>>
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
Char> {
};
template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
// support in tuple_join. It is disabled by default because of issues with
// the dynamic width and precision.
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
# define FMT_TUPLE_JOIN_SPECIFIERS 0
#endif
template <typename Char, typename... T>
struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
}
template <typename FormatContext>
auto format(const tuple_join_view<Char, T...>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
return do_format(value, ctx,
std::integral_constant<size_t, sizeof...(T)>());
}
private:
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
template <typename ParseContext>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, 0>)
-> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename ParseContext, size_t N>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
std::integral_constant<size_t, N>)
-> decltype(ctx.begin()) {
auto end = ctx.begin();
#if FMT_TUPLE_JOIN_SPECIFIERS
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
if (N > 1) {
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
if (end != end1)
FMT_THROW(format_error("incompatible format specs for tuple elements"));
}
#endif
return end;
}
template <typename FormatContext>
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
auto out = std::get<sizeof...(T) - N>(formatters_)
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
if (N > 1) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
}
return out;
}
};
namespace detail {
// Check if T has an interface like a container adaptor (e.g. std::stack,
// std::queue, std::priority_queue).
template <typename T> class is_container_adaptor_like {
template <typename U> static auto check(U* p) -> typename U::container_type;
template <typename> static void check(...);
public:
static constexpr const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Container> struct all {
const Container& c;
auto begin() const -> typename Container::const_iterator { return c.begin(); }
auto end() const -> typename Container::const_iterator { return c.end(); }
};
} // namespace detail
template <typename T, typename Char>
struct formatter<T, Char,
enable_if_t<detail::is_container_adaptor_like<T>::value>>
: formatter<detail::all<typename T::container_type>, Char> {
using all = detail::all<typename T::container_type>;
template <typename FormatContext>
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
struct getter : T {
static auto get(const T& t) -> all {
return {t.*(&getter::c)}; // Access c through the derived class.
}
};
return formatter<all>::format(getter::get(t), ctx);
}
};
FMT_BEGIN_EXPORT
/**
\rst
Returns an object that formats `tuple` with elements separated by `sep`.
**Example**::
std::tuple<int, char> t = {1, 'a'};
fmt::print("{}", fmt::join(t, ", "));
// Output: "1, a"
\endrst
*/
template <typename... T>
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
-> tuple_join_view<char, T...> {
return {tuple, sep};
}
template <typename... T>
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, T...> {
return {tuple, sep};
}
/**
\rst
Returns an object that formats `initializer_list` with elements separated by
`sep`.
**Example**::
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
// Output: "1, 2, 3"
\endrst
*/
template <typename T>
auto join(std::initializer_list<T> list, string_view sep)
-> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
FMT_END_EXPORT
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

@ -0,0 +1,349 @@
// Formatting library for C++ - formatters for standard library types
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STD_H_
#define FMT_STD_H_
#include <cstdlib>
#include <exception>
#include <memory>
#include <thread>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include "ostream.h"
#if FMT_HAS_INCLUDE(<version>)
# include <version>
#endif
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
#if FMT_CPLUSPLUS >= 201703L
# if FMT_HAS_INCLUDE(<filesystem>)
# include <filesystem>
# endif
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
# if FMT_HAS_INCLUDE(<optional>)
# include <optional>
# endif
#endif
// GCC 4 does not support FMT_HAS_INCLUDE.
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
# include <cxxabi.h>
// Android NDK with gabi++ library on some architectures does not implement
// abi::__cxa_demangle().
# ifndef __GABIXX_CXXABI_H__
# define FMT_HAS_ABI_CXA_DEMANGLE
# endif
#endif
#ifdef __cpp_lib_filesystem
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char>
void write_escaped_path(basic_memory_buffer<Char>& quoted,
const std::filesystem::path& p) {
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
}
# ifdef _WIN32
template <>
inline void write_escaped_path<char>(memory_buffer& quoted,
const std::filesystem::path& p) {
auto buf = basic_memory_buffer<wchar_t>();
write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
// Convert UTF-16 to UTF-8.
if (!unicode_to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}))
FMT_THROW(std::runtime_error("invalid utf16"));
}
# endif
template <>
inline void write_escaped_path<std::filesystem::path::value_type>(
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
const std::filesystem::path& p) {
write_escaped_string<std::filesystem::path::value_type>(
std::back_inserter(quoted), p.native());
}
} // namespace detail
FMT_MODULE_EXPORT
template <typename Char>
struct formatter<std::filesystem::path, Char>
: formatter<basic_string_view<Char>> {
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
auto out = formatter<basic_string_view<Char>>::parse(ctx);
this->set_debug_format(false);
return out;
}
template <typename FormatContext>
auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
typename FormatContext::iterator {
auto quoted = basic_memory_buffer<Char>();
detail::write_escaped_path(quoted, p);
return formatter<basic_string_view<Char>>::format(
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
}
};
FMT_END_NAMESPACE
#endif
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_optional
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename T, typename Char>
struct formatter<std::optional<T>, Char,
std::enable_if_t<is_formattable<T, Char>::value>> {
private:
formatter<T, Char> underlying_;
static constexpr basic_string_view<Char> optional =
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
'('>{};
static constexpr basic_string_view<Char> none =
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
-> decltype(u.set_debug_format(set)) {
u.set_debug_format(set);
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(std::optional<T> const& opt, FormatContext& ctx) const
-> decltype(ctx.out()) {
if (!opt) return detail::write<Char>(ctx.out(), none);
auto out = ctx.out();
out = detail::write<Char>(out, optional);
ctx.advance_to(out);
out = underlying_.format(*opt, ctx);
return detail::write(out, ')');
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_optional
#ifdef __cpp_lib_variant
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char> struct formatter<std::monostate, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const std::monostate&, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "monostate");
return out;
}
};
namespace detail {
template <typename T>
using variant_index_sequence =
std::make_index_sequence<std::variant_size<T>::value>;
template <typename> struct is_variant_like_ : std::false_type {};
template <typename... Types>
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
// formattable element check.
template <typename T, typename C> class is_variant_formattable_ {
template <std::size_t... Is>
static std::conjunction<
is_formattable<std::variant_alternative_t<Is, T>, C>...>
check(std::index_sequence<Is...>);
public:
static constexpr const bool value =
decltype(check(variant_index_sequence<T>{}))::value;
};
template <typename Char, typename OutputIt, typename T>
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
if constexpr (is_string<T>::value)
return write_escaped_string<Char>(out, detail::to_string_view(v));
else if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
else
return write<Char>(out, v);
}
} // namespace detail
template <typename T> struct is_variant_like {
static constexpr const bool value = detail::is_variant_like_<T>::value;
};
template <typename T, typename C> struct is_variant_formattable {
static constexpr const bool value =
detail::is_variant_formattable_<T, C>::value;
};
FMT_MODULE_EXPORT
template <typename Variant, typename Char>
struct formatter<
Variant, Char,
std::enable_if_t<std::conjunction_v<
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const Variant& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write<Char>(out, "variant(");
try {
std::visit(
[&](const auto& v) {
out = detail::write_variant_alternative<Char>(out, v);
},
value);
} catch (const std::bad_variant_access&) {
detail::write<Char>(out, "valueless by exception");
}
*out++ = ')';
return out;
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_variant
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
FMT_MODULE_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char,
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = true;
}
return it;
}
template <typename OutputIt>
auto format(const std::exception& ex,
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
format_specs<Char> spec;
auto out = ctx.out();
if (!with_typename_)
return detail::write_bytes(out, string_view(ex.what()), spec);
const std::type_info& ti = typeid(ex);
#ifdef FMT_HAS_ABI_CXA_DEMANGLE
int status = 0;
std::size_t size = 0;
std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
string_view demangled_name_view;
if (demangled_name_ptr) {
demangled_name_view = demangled_name_ptr.get();
// Normalization of stdlib inline namespace names.
// libc++ inline namespaces.
// std::__1::* -> std::*
// std::__1::__fs::* -> std::*
// libstdc++ inline namespaces.
// std::__cxx11::* -> std::*
// std::filesystem::__cxx11::* -> std::filesystem::*
if (demangled_name_view.starts_with("std::")) {
char* begin = demangled_name_ptr.get();
char* to = begin + 5; // std::
for (char *from = to, *end = begin + demangled_name_view.size();
from < end;) {
// This is safe, because demangled_name is NUL-terminated.
if (from[0] == '_' && from[1] == '_') {
char* next = from + 1;
while (next < end && *next != ':') next++;
if (next[0] == ':' && next[1] == ':') {
from = next + 2;
continue;
}
}
*to++ = *from++;
}
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
}
} else {
demangled_name_view = string_view(ti.name());
}
out = detail::write_bytes(out, demangled_name_view, spec);
#elif FMT_MSC_VERSION
string_view demangled_name_view(ti.name());
if (demangled_name_view.starts_with("class "))
demangled_name_view.remove_prefix(6);
else if (demangled_name_view.starts_with("struct "))
demangled_name_view.remove_prefix(7);
out = detail::write_bytes(out, demangled_name_view, spec);
#else
out = detail::write_bytes(out, string_view(ti.name()), spec);
#endif
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, Char(' '));
out = detail::write_bytes(out, string_view(ex.what()), spec);
return out;
}
};
FMT_END_NAMESPACE
#endif // FMT_STD_H_

@ -297,7 +297,7 @@ void Md5::Append(const void *data, const size_t nbytes)
if (left) memcpy(this->buf, p, left);
}
void Md5::Finish(uint8 digest[16])
void Md5::Finish(MD5Hash &digest)
{
static const uint8 pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

@ -53,6 +53,29 @@
#ifndef MD5_INCLUDED
#define MD5_INCLUDED
#include <array>
/** The number of bytes in a MD5 hash. */
static const size_t MD5_HASH_BYTES = 16;
/** Container for storing a MD5 hash/checksum/digest. */
struct MD5Hash : std::array<byte, MD5_HASH_BYTES> {
MD5Hash() : std::array<byte, MD5_HASH_BYTES>{} {}
/**
* Exclusively-or the given hash into this hash.
* @param other The other hash.
* @return Reference to this hash.
*/
MD5Hash &operator^=(const MD5Hash &other)
{
for (size_t i = 0; i < size(); i++) this->operator[](i) ^= other[i];
return *this;
}
};
char *md5sumToString(char *buf, const char *last, const MD5Hash &md5sum);
struct Md5 {
private:
uint32 count[2]; ///< message length in bits, lsw first
@ -64,7 +87,7 @@ private:
public:
Md5();
void Append(const void *data, const size_t nbytes);
void Finish(uint8 digest[16]);
void Finish(MD5Hash &digest);
};
#endif /* MD5_INCLUDED */

@ -2,6 +2,8 @@
#ifndef _SQUTILS_H_
#define _SQUTILS_H_
#include "../../fmt/format.h"
#include "../../../script/script_fatalerror.hpp"
#include <type_traits>
void *sq_vm_malloc(SQUnsignedInteger size);
@ -105,6 +107,10 @@ private:
void _realloc(SQUnsignedInteger newsize)
{
newsize = (newsize > 0)?newsize:4;
if (newsize > SIZE_MAX / sizeof(T)) {
std::string msg = fmt::format("cannot resize to {}", newsize);
throw Script_FatalError(msg);
}
_vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T));
_allocated = (size_t)newsize;
}

@ -441,6 +441,7 @@ add_files(
strgen/strgen.h
string.cpp
string_base.h
string_extra.cpp
string_func.h
string_func_extra.h
string_type.h

@ -10,7 +10,7 @@
#include "stdafx.h"
#include "animated_tile.h"
#include "core/alloc_func.hpp"
#include "core/smallvec_type.hpp"
#include "core/container_func.hpp"
#include "tile_cmd.h"
#include "viewport_func.h"
#include "framerate_type.h"

@ -178,7 +178,7 @@ static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool inc
*/
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
{
CargoArray capacity;
CargoArray capacity{};
const Engine *e = Engine::Get(engine);
CargoID cargo_type;
@ -336,7 +336,7 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
CargoTypes real_refit_union = 0;
CargoTypes real_refit_intersection = ALL_CARGOTYPES;
CargoArray real_default_capacity;
CargoArray real_default_capacity{};
do {
CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);

@ -14,6 +14,7 @@
#include "gfx_type.h"
#include "textfile_type.h"
#include "textfile_gui.h"
#include "3rdparty/md5/md5.h"
#include <unordered_map>
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
@ -31,7 +32,7 @@ struct MD5File {
};
std::string filename; ///< filename
uint8 hash[16]; ///< md5 sum of the file
MD5Hash hash; ///< md5 sum of the file
std::string missing_warning; ///< warning when this file is missing
ChecksumResult check_result; ///< cached result of md5 check

@ -98,7 +98,7 @@ bool BaseSet<T, Tnum_files, Tsearch_in_tars>::FillSetDetails(IniFile *ini, const
return false;
}
const char *c = item->value->c_str();
for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) {
for (size_t i = 0; i < file->hash.size() * 2; i++, c++) {
uint j;
if ('0' <= *c && *c <= '9') {
j = *c - '0';
@ -284,14 +284,11 @@ template <class Tbase_set> const char *TryGetBaseSetFile(const ContentInfo *ci,
if (s->shortname != ci->unique_id) continue;
if (!md5sum) return s->files[0].filename.c_str();
byte md5[16];
memset(md5, 0, sizeof(md5));
MD5Hash md5;
for (uint i = 0; i < Tbase_set::NUM_FILES; i++) {
for (uint j = 0; j < sizeof(md5); j++) {
md5[j] ^= s->files[i].hash[j];
}
md5 ^= s->files[i].hash;
}
if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename.c_str();
if (md5 == ci->md5sum) return s->files[0].filename.c_str();
}
return nullptr;
}

@ -70,48 +70,22 @@ enum CargoType {
};
/** Test whether cargo type is not CT_INVALID */
inline bool IsCargoTypeValid(CargoType t) { return t != CT_INVALID; }
inline bool IsValidCargoType(CargoType t) { return t != CT_INVALID; }
/** Test whether cargo type is not CT_INVALID */
inline bool IsCargoIDValid(CargoID t) { return t != CT_INVALID; }
inline bool IsValidCargoID(CargoID t) { return t != CT_INVALID; }
typedef uint64 CargoTypes;
static const CargoTypes ALL_CARGOTYPES = (CargoTypes)UINT64_MAX;
/** Class for storing amounts of cargo */
struct CargoArray {
private:
uint amount[NUM_CARGO]; ///< Amount of each type of cargo.
public:
/** Default constructor. */
inline CargoArray()
{
this->Clear();
}
struct CargoArray : std::array<uint, NUM_CARGO> {
/** Reset all entries. */
inline void Clear()
{
memset(this->amount, 0, sizeof(this->amount));
}
/**
* Read/write access to an amount of a specific cargo type.
* @param cargo Cargo type to access.
*/
inline uint &operator[](CargoID cargo)
{
return this->amount[cargo];
}
/**
* Read-only access to an amount of a specific cargo type.
* @param cargo Cargo type to access.
*/
inline const uint &operator[](CargoID cargo) const
{
return this->amount[cargo];
for (uint &it : *this) {
it = 0;
}
}
/**
@ -121,24 +95,20 @@ public:
template <typename T>
inline const T GetSum() const
{
T ret = 0;
for (size_t i = 0; i < lengthof(this->amount); i++) {
ret += this->amount[i];
T result = 0;
for (const uint &it : *this) {
result += it;
}
return ret;
return result;
}
/**
* Get the amount of cargos that have an amount.
* @return The amount.
*/
inline byte GetCount() const
inline uint GetCount() const
{
byte count = 0;
for (size_t i = 0; i < lengthof(this->amount); i++) {
if (this->amount[i] != 0) count++;
}
return count;
return std::count_if(this->begin(), this->end(), [](uint amount) { return amount != 0; });
}
};

@ -23,7 +23,7 @@
struct CompanyEconomyEntry {
Money income; ///< The amount of income.
Money expenses; ///< The amount of expenses.
CargoArray delivered_cargo; ///< The amount of delivered cargo.
CargoArray delivered_cargo{}; ///< The amount of delivered cargo.
int32 performance_history; ///< Company score (scale 0-1000)
Money company_value; ///< The value of the company.
};

@ -12,6 +12,7 @@ add_files(
endian_type.hpp
enum_type.hpp
hash_func.hpp
format.hpp
geometry_func.cpp
geometry_func.hpp
geometry_type.hpp
@ -30,7 +31,6 @@ add_files(
serialisation.cpp
serialisation.hpp
smallstack_type.hpp
smallvec_type.hpp
tinystring_type.hpp
y_combinator.hpp
)

@ -5,7 +5,7 @@
* 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 container_func.hpp Functions related to use of containers. */
/** @file container_func.hpp Some simple functions to help with accessing containers. */
#ifndef CONTAINER_FUNC_HPP
#define CONTAINER_FUNC_HPP
@ -13,6 +13,42 @@
#include <iterator>
#include <algorithm>
/**
* Helper function to append an item to a container if it is not already contained.
* The container must have a \c emplace_back function.
* Consider using std::set, std::unordered_set or std::flat_set in new code.
*
* @param container A reference to the container to be extended
* @param item Reference to the item to be copy-constructed if not found
*
* @return Whether the item was already present
*/
template <typename Container>
inline bool include(Container &container, typename Container::const_reference &item)
{
const bool is_member = std::find(container.begin(), container.end(), item) != container.end();
if (!is_member) container.emplace_back(item);
return is_member;
}
/**
* Helper function to get the index of an item
* Consider using std::set, std::unordered_set or std::flat_set in new code.
*
* @param container A reference to the container to be searched.
* @param item Reference to the item to be search for
*
* @return Index of element if found, otherwise -1
*/
template <typename Container>
int find_index(Container const &container, typename Container::const_reference item)
{
auto const it = std::find(container.begin(), container.end(), item);
if (it != container.end()) return std::distance(container.begin(), it);
return -1;
}
template <typename C, typename UP> unsigned int container_unordered_remove_if (C &container, UP predicate) {
unsigned int removecount = 0;
for (auto it = container.begin(); it != container.end();) {

@ -0,0 +1,44 @@
/*
* 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 format.hpp String formatting functions and helpers. */
#ifndef FORMAT_HPP
#define FORMAT_HPP
#include "../3rdparty/fmt/format.h"
//#include "strong_typedef_type.hpp"
template <typename E, typename Char>
struct fmt::formatter<E, Char, std::enable_if_t<std::is_enum<E>::value>> : fmt::formatter<typename std::underlying_type<E>::type> {
using underlying_type = typename std::underlying_type<E>::type;
using parent = typename fmt::formatter<underlying_type>;
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx) {
return parent::parse(ctx);
}
fmt::format_context::iterator format(const E &e, format_context &ctx) const {
return parent::format(underlying_type(e), ctx);
}
};
//template <typename T, typename Char>
//struct fmt::formatter<T, Char, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value>> : fmt::formatter<typename T::Type> {
// using underlying_type = typename T::Type;
// using parent = typename fmt::formatter<underlying_type>;
//
// constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx) {
// return parent::parse(ctx);
// }
//
// fmt::format_context::iterator format(const T &t, format_context &ctx) const {
// return parent::format(underlying_type(t), ctx);
// }
//};
#endif /* FORMAT_HPP */

@ -10,7 +10,6 @@
#ifndef POOL_TYPE_HPP
#define POOL_TYPE_HPP
#include "smallvec_type.hpp"
#include "enum_type.hpp"
/** Various types of a pool. */

@ -10,8 +10,6 @@
#ifndef SMALLSTACK_TYPE_HPP
#define SMALLSTACK_TYPE_HPP
#include "smallvec_type.hpp"
/**
* A simplified pool which stores values instead of pointers and doesn't
* redefine operator new/delete. It also never zeroes memory and always reuses

@ -1,52 +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 smallvec_type.hpp Simple vector class that allows allocating an item without the need to copy this->data needlessly. */
#ifndef SMALLVEC_TYPE_HPP
#define SMALLVEC_TYPE_HPP
#include "alloc_func.hpp"
#include "mem_func.hpp"
#include <vector>
/**
* Helper function to append an item to a vector if it is not already contained
* Consider using std::set, std::unordered_set or std::flat_set in new code
*
* @param vec A reference to the vector to be extended
* @param item Reference to the item to be copy-constructed if not found
*
* @return Whether the item was already present
*/
template <typename T>
inline bool include(std::vector<T>& vec, const T &item)
{
const bool is_member = std::find(vec.begin(), vec.end(), item) != vec.end();
if (!is_member) vec.emplace_back(item);
return is_member;
}
/**
* Helper function to get the index of an item
* Consider using std::set, std::unordered_set or std::flat_set in new code
*
* @param vec A reference to the vector to be extended
* @param item Reference to the item to be search for
*
* @return Index of element if found, otherwise -1
*/
template <typename T>
int find_index(std::vector<T> const& vec, T const& item)
{
auto const it = std::find(vec.begin(), vec.end(), item);
if (it != vec.end()) return it - vec.begin();
return -1;
}
#endif /* SMALLVEC_TYPE_HPP */

@ -928,6 +928,13 @@ static bool CopyAutosave(const std::string &old_name, const std::string &new_nam
}
#endif
void CrashLog::SendSurvey() const
{
if (_game_mode == GM_NORMAL) {
_survey.Transmit(NetworkSurveyHandler::Reason::CRASH, true);
}
}
/**
* Makes the crash log, writes it to a file and then subsequently tries
* to make a crash dump and crash savegame. It uses DEBUG to write
@ -1174,9 +1181,7 @@ bool CrashLog::MakeCrashSavegameAndScreenshot() const
printf("Writing crash screenshot failed.\n\n");
}
if (_game_mode == GM_NORMAL) {
_survey.Transmit(NetworkSurveyHandler::Reason::CRASH, true);
}
this->SendSurvey();
return ret;
}

@ -194,6 +194,8 @@ public:
bool MakeVersionInfoLog() const;
bool MakeCrashSavegameAndScreenshot() const;
void SendSurvey() const;
/**
* Initialiser for crash logs; do the appropriate things so crashes are
* handled by our crash handler instead of returning straight to the OS.

@ -27,7 +27,6 @@
#include "vehicle_gui.h"
#include "order_base.h"
#include "settings_type.h"
#include "core/smallvec_type.hpp"
#include "date_type.h"
#include "company_type.h"
#include "cargo_type.h"

@ -13,7 +13,6 @@
#define DEPARTURES_FUNC_H
#include "station_base.h"
#include "core/smallvec_type.hpp"
#include "departures_type.h"
#include <vector>

@ -28,7 +28,6 @@
#include "vehicle_gui.h"
#include "order_base.h"
#include "settings_type.h"
#include "core/smallvec_type.hpp"
#include "date_type.h"
#include "company_type.h"
#include "departures_func.h"

@ -855,7 +855,7 @@ struct DepotWindow : Window {
if (v == nullptr || mode != MODE_DRAG_VEHICLE) return false;
CargoArray capacity, loaded;
CargoArray capacity{}, loaded{};
/* Display info for single (articulated) vehicle, or for whole chain starting with selected vehicle */
bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed);

@ -42,6 +42,7 @@
#include "economy_base.h"
#include "core/pool_func.hpp"
#include "core/backup_type.hpp"
#include "core/container_func.hpp"
#include "infrastructure_func.h"
#include "cargo_type.h"
#include "water.h"
@ -1113,12 +1114,9 @@ void ForAcceptingIndustries(const Station *st, CargoID cargo_type, IndustryID so
Industry *ind = i.industry;
if (ind->index == source) continue;
uint cargo_index;
for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
if (cargo_type == ind->accepts_cargo[cargo_index]) break;
}
int cargo_index = ind->GetCargoAcceptedIndex(cargo_type);
/* Check if matching cargo has been found */
if (cargo_index >= lengthof(ind->accepts_cargo)) continue;
if (cargo_index < 0) continue;
/* Check if industry temporarily refuses acceptance */
if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue;
@ -1932,7 +1930,7 @@ static void LoadUnloadVehicle(Vehicle *front)
CargoStationIDStackSet next_station = front->GetNextStoppingStation();
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT;
CargoArray consist_capleft;
CargoArray consist_capleft{};
bool should_reserve_consist = false;
bool reserve_consist_cargo_type_loading = false;
if (_settings_game.order.improved_load && use_autorefit) {

@ -8,6 +8,7 @@
/** @file error_gui.cpp GUI related to errors. */
#include "stdafx.h"
#include "core/mem_func.hpp"
#include "landscape.h"
#include "newgrf_text.h"
#include "error.h"

@ -20,6 +20,7 @@
#include "string_func_extra.h"
#include "strings_func.h"
#include "tar_type.h"
#include "core/container_func.hpp"
#include <sys/stat.h>
#include <functional>
#include <optional>
@ -631,13 +632,12 @@ const char *FiosGetScreenshotDir()
/** Basic data to distinguish a scenario. Used in the server list window */
struct ScenarioIdentifier {
uint32 scenid; ///< ID for the scenario (generated by content).
uint8 md5sum[16]; ///< MD5 checksum of file.
MD5Hash md5sum; ///< MD5 checksum of file.
std::string filename; ///< filename of the file.
bool operator == (const ScenarioIdentifier &other) const
{
return this->scenid == other.scenid &&
memcmp(this->md5sum, other.md5sum, sizeof(this->md5sum)) == 0;
return this->scenid == other.scenid && this->md5sum == other.md5sum;
}
bool operator != (const ScenarioIdentifier &other) const
@ -716,7 +716,7 @@ const char *FindScenario(const ContentInfo *ci, bool md5sum)
_scanner.Scan(false);
for (ScenarioIdentifier &id : _scanner) {
if (md5sum ? (memcmp(id.md5sum, ci->md5sum, sizeof(id.md5sum)) == 0)
if (md5sum ? (id.md5sum == ci->md5sum)
: (id.scenid == ci->unique_id)) {
return id.filename.c_str();
}

@ -289,7 +289,7 @@ private:
StringFilter string_filter; ///< Filter for available games.
QueryString filter_editbox; ///< Filter editbox;
std::vector<bool> fios_items_shown; ///< Map of the filtered out fios items
std::vector<FiosItem *> display_list; ///< Filtered display list
static void SaveGameConfirmationCallback(Window *w, bool confirmed)
{
@ -451,14 +451,8 @@ public:
Rect tr = r.Shrink(WidgetDimensions::scaled.inset).WithHeight(this->resize.step_height);
uint scroll_pos = this->vscroll->GetPosition();
for (uint row = 0; row < this->fios_items.size() && tr.top < br.bottom; row++) {
if (!this->fios_items_shown[row]) {
/* The current item is filtered out : we do not show it */
scroll_pos++;
continue;
}
if (row < scroll_pos) continue;
const FiosItem *item = &this->fios_items[row];
for (auto it = this->display_list.begin() + scroll_pos; it != this->display_list.end() && tr.top < br.bottom; ++it) {
const FiosItem *item = *it;
if (item == this->selected) {
GfxFillRect(br.left, tr.top, br.right, tr.bottom, PC_DARK_BLUE);
@ -673,16 +667,11 @@ public:
break;
case WID_SL_DRIVES_DIRECTORIES_LIST: { // Click the listbox
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
if (y == INT_MAX) return;
auto it = this->vscroll->GetScrolledItemFromWidget(this->display_list, pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
if (it == this->display_list.end()) return;
/* Get the corresponding non-filtered out item from the list */
int i = 0;
while (i <= y) {
if (!this->fios_items_shown[i]) y++;
i++;
}
const FiosItem *file = &this->fios_items[y];
const FiosItem *file = *it;
if (FiosBrowseTo(file)) {
/* Changed directory, need refresh. */
@ -750,16 +739,11 @@ public:
void OnMouseOver(Point pt, int widget) override
{
if (widget == WID_SL_DRIVES_DIRECTORIES_LIST) {
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
if (y == INT_MAX) return;
auto it = this->vscroll->GetScrolledItemFromWidget(this->display_list, pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
if (it == this->display_list.end()) return;
/* Get the corresponding non-filtered out item from the list */
int i = 0;
while (i <= y) {
if (!this->fios_items_shown[i]) y++;
i++;
}
const FiosItem *file = &this->fios_items[y];
const FiosItem *file = *it;
if (file != this->highlighted) {
this->highlighted = file;
@ -842,6 +826,35 @@ public:
this->vscroll->SetCapacityFromWidget(this, WID_SL_DRIVES_DIRECTORIES_LIST);
}
void BuildDisplayList()
{
/* Filter changes */
this->display_list.clear();
this->display_list.reserve(this->fios_items.size());
if (this->string_filter.IsEmpty()) {
/* We don't filter anything out if the filter editbox is empty */
for (auto &it : this->fios_items) {
this->display_list.push_back(&it);
}
} else {
for (auto &it : this->fios_items) {
this->string_filter.ResetState();
this->string_filter.AddLine(it.title);
/* We set the vector to show this fios element as filtered depending on the result of the filter */
if (this->string_filter.GetState()) {
this->display_list.push_back(&it);
} else if (&it == this->selected) {
/* The selected element has been filtered out */
this->selected = nullptr;
this->OnInvalidateData(SLIWD_SELECTION_CHANGES);
}
}
}
this->vscroll->SetCount(this->display_list.size());
}
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
@ -858,7 +871,6 @@ public:
_fios_path_changed = true;
this->fios_items.BuildFileList(this->abstract_filetype, this->fop);
this->vscroll->SetCount(this->fios_items.size());
this->selected = nullptr;
_load_check_data.Clear();
@ -897,30 +909,7 @@ public:
break;
case SLIWD_FILTER_CHANGES:
/* Filter changes */
this->fios_items_shown.resize(this->fios_items.size());
uint items_shown_count = 0; ///< The number of items shown in the list
/* We pass through every fios item */
for (uint i = 0; i < this->fios_items.size(); i++) {
if (this->string_filter.IsEmpty()) {
/* We don't filter anything out if the filter editbox is empty */
this->fios_items_shown[i] = true;
items_shown_count++;
} else {
this->string_filter.ResetState();
this->string_filter.AddLine(this->fios_items[i].title.c_str());
/* We set the vector to show this fios element as filtered depending on the result of the filter */
this->fios_items_shown[i] = this->string_filter.GetState();
if (this->fios_items_shown[i]) items_shown_count++;
if (&(this->fios_items[i]) == this->selected && !this->fios_items_shown[i]) {
/* The selected element has been filtered out */
this->selected = nullptr;
this->OnInvalidateData(SLIWD_SELECTION_CHANGES);
}
}
}
this->vscroll->SetCount(items_shown_count);
this->BuildDisplayList();
break;
}
}

@ -10,8 +10,6 @@
#ifndef GAME_TEXT_HPP
#define GAME_TEXT_HPP
#include "../core/smallvec_type.hpp"
struct StringParam {
enum ParamType {
RAW_STRING,

@ -109,12 +109,12 @@ void GamelogReset()
* @param gc GrfConfig, if known
* @return The buffer location.
*/
static char *PrintGrfInfo(char *buf, const char *last, uint grfid, const uint8 *md5sum, const GRFConfig *gc)
static char *PrintGrfInfo(char *buf, const char *last, uint grfid, const MD5Hash *md5sum, const GRFConfig *gc)
{
char txt[40];
if (md5sum != nullptr) {
md5sumToString(txt, lastof(txt), md5sum);
md5sumToString(txt, lastof(txt), *md5sum);
buf += seprintf(buf, last, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt);
} else {
buf += seprintf(buf, last, "GRF ID %08X", BSWAP32(grfid));
@ -247,9 +247,9 @@ void GamelogPrint(GamelogPrintProc *proc)
case GLCT_GRFADD: {
/* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, &lc->grfadd.md5sum);
buf += seprintf(buf, lastof(buffer), "Added NewGRF: ");
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfadd.grfid, lc->grfadd.md5sum, gc);
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfadd.grfid, &lc->grfadd.md5sum, gc);
auto gm = grf_names.find(lc->grfrem.grfid);
if (gm != grf_names.end() && !gm->second.was_missing) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was already added!");
grf_names[lc->grfadd.grfid] = gc;
@ -276,9 +276,9 @@ void GamelogPrint(GamelogPrintProc *proc)
case GLCT_GRFCOMPAT: {
/* Another version of the same NewGRF got loaded. */
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum);
const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, &lc->grfadd.md5sum);
buf += seprintf(buf, lastof(buffer), "Compatible NewGRF loaded: ");
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfcompat.grfid, lc->grfcompat.md5sum, gc);
buf = PrintGrfInfo(buf, lastof(buffer), lc->grfcompat.grfid, &lc->grfcompat.md5sum, gc);
if (grf_names.find(lc->grfcompat.grfid) == grf_names.end()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!");
grf_names[lc->grfcompat.grfid] = gc;
break;
@ -760,12 +760,12 @@ void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc)
GamelogGRFMove(nl->grf[n++]->ident.grfid, -(int)oi);
}
} else {
if (memcmp(og->ident.md5sum, ng->ident.md5sum, sizeof(og->ident.md5sum)) != 0) {
if (og->ident.md5sum != ng->ident.md5sum) {
/* md5sum changed, probably loading 'compatible' GRF */
GamelogGRFCompatible(&nl->grf[n]->ident);
}
if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
if (og->num_params != ng->num_params || og->param == ng->param) {
GamelogGRFParameters(ol->grf[o]->ident.grfid);
}

@ -26,6 +26,7 @@
#include "framerate_type.h"
#include "transparency.h"
#include "core/backup_type.hpp"
#include "core/container_func.hpp"
#include "viewport_func.h"
#include "table/palettes.h"

@ -8,6 +8,7 @@
/** @file gfx_layout.cpp Handling of laying out text. */
#include "stdafx.h"
#include "core/math_func.hpp"
#include "gfx_layout.h"
#include "string_func.h"
#include "debug.h"

@ -602,7 +602,7 @@ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size)
Md5 checksum;
uint8 buffer[1024];
uint8 digest[16];
MD5Hash digest;
size_t len;
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
@ -613,7 +613,7 @@ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size)
FioFCloseFile(f);
checksum.Finish(digest);
return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH;
return this->hash == digest ? CR_MATCH : CR_MISMATCH;
}
/** Names corresponding to the GraphicsFileType */

@ -22,6 +22,7 @@
#include "tilehighlight_func.h"
#include "vehicle_gui_base.h"
#include "core/geometry_func.hpp"
#include "core/container_func.hpp"
#include "company_base.h"
#include "company_gui.h"
#include "gui.h"
@ -30,7 +31,6 @@
#include "newgrf_debug.h"
#include "widgets/group_widget.h"
#include "core/smallvec_type.hpp"
#include "table/sprites.h"

@ -216,9 +216,9 @@ static std::string KeycodeToString(uint16 keycode)
std::string SaveKeycodes(const Hotkey *hotkey)
{
std::string str;
for (uint i = 0; i < hotkey->keycodes.size(); i++) {
if (i > 0) str += ",";
str += KeycodeToString(hotkey->keycodes[i]);
for (auto keycode : hotkey->keycodes) {
if (!str.empty()) str += ",";
str += KeycodeToString(keycode);
}
return str;
}
@ -260,7 +260,7 @@ Hotkey::Hotkey(const uint16 *default_keycodes, const char *name, int num) :
*/
void Hotkey::AddKeycode(uint16 keycode)
{
include(this->keycodes, keycode);
this->keycodes.insert(keycode);
}
HotkeyList::HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler) :

@ -10,10 +10,10 @@
#ifndef HOTKEYS_H
#define HOTKEYS_H
#include "core/smallvec_type.hpp"
#include "gfx_type.h"
#include "window_type.h"
#include "string_type.h"
#include "3rdparty/cpp-btree/btree_set.h"
/**
* All data for a single hotkey. The name (for saving/loading a configfile),
@ -27,7 +27,7 @@ struct Hotkey {
const char *name;
int num;
std::vector<uint16> keycodes;
btree::btree_set<uint16> keycodes;
};
#define HOTKEY_LIST_END Hotkey((uint16)0, nullptr, -1)

@ -130,6 +130,28 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
return pos - this->accepts_cargo;
}
/** Test if this industry accepts any cargo.
* @return true iff the industry accepts any cargo.
*/
bool IsCargoAccepted() const { return std::any_of(std::begin(this->accepts_cargo), std::end(this->accepts_cargo), [](const auto &cargo) { return IsValidCargoID(cargo); }); }
/** Test if this industry produces any cargo.
* @return true iff the industry produces any cargo.
*/
bool IsCargoProduced() const { return std::any_of(std::begin(this->produced_cargo), std::end(this->produced_cargo), [](const auto &cargo) { return IsValidCargoID(cargo); }); }
/** Test if this industry accepts a specific cargo.
* @param cargo Cargo type to test.
* @return true iff the industry accepts the given cargo type.
*/
bool IsCargoAccepted(CargoID cargo) const { return std::any_of(std::begin(this->accepts_cargo), std::end(this->accepts_cargo), [&cargo](const auto &cid) { return cid == cargo; }); }
/** Test if this industry produces a specific cargo.
* @param cargo Cargo type to test.
* @return true iff the industry produces the given cargo types.
*/
bool IsCargoProduced(CargoID cargo) const { return std::any_of(std::begin(this->produced_cargo), std::end(this->produced_cargo), [&cargo](const auto &cid) { return cid == cargo; }); }
/**
* Get the industry of the given tile
* @param tile the tile to get the industry from

@ -460,16 +460,8 @@ static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, Ca
/* Maybe set 'always accepted' bit (if it's not set already) */
if (HasBit(*always_accepted, a)) continue;
bool accepts = false;
for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
/* Test whether the industry itself accepts the cargo type */
if (ind->accepts_cargo[cargo_index] == a) {
accepts = true;
break;
}
}
if (accepts) continue;
/* Test whether the industry itself accepts the cargo type */
if (ind->IsCargoAccepted(a)) continue;
/* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
SetBit(*always_accepted, a);
@ -2706,20 +2698,10 @@ static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accept
if (cargo == CT_INVALID) return;
/* Check for acceptance of cargo */
for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
*c_accepts = true;
break;
}
}
if (ind->IsCargoAccepted(cargo) && !IndustryTemporarilyRefusesCargo(ind, cargo)) *c_accepts = true;
/* Check for produced cargo */
for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
if (cargo == ind->produced_cargo[j]) {
*c_produces = true;
break;
}
}
if (ind->IsCargoProduced(cargo)) *c_produces = true;
}
/**

@ -1277,14 +1277,11 @@ static bool CargoFilter(const Industry * const *industry, const std::pair<CargoI
break;
case CF_NONE:
accepted_cargo_matches = std::all_of(std::begin((*industry)->accepts_cargo), std::end((*industry)->accepts_cargo), [](CargoID cargo) {
return cargo == CT_INVALID;
});
accepted_cargo_matches = !(*industry)->IsCargoAccepted();
break;
default:
const auto &ac = (*industry)->accepts_cargo;
accepted_cargo_matches = std::find(std::begin(ac), std::end(ac), accepted_cargo) != std::end(ac);
accepted_cargo_matches = (*industry)->IsCargoAccepted(accepted_cargo);
break;
}
@ -1296,14 +1293,11 @@ static bool CargoFilter(const Industry * const *industry, const std::pair<CargoI
break;
case CF_NONE:
produced_cargo_matches = std::all_of(std::begin((*industry)->produced_cargo), std::end((*industry)->produced_cargo), [](CargoID cargo) {
return cargo == CT_INVALID;
});
produced_cargo_matches = !(*industry)->IsCargoProduced();
break;
default:
const auto &pc = (*industry)->produced_cargo;
produced_cargo_matches = std::find(std::begin(pc), std::end(pc), produced_cargo) != std::end(pc);
produced_cargo_matches = (*industry)->IsCargoProduced(produced_cargo);
break;
}
@ -2566,8 +2560,8 @@ struct IndustryCargoesWindow : public Window {
const IndustrySpec *indsp = GetIndustrySpec(it);
if (!indsp->enabled) continue;
this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(indsp->name));
CargoesField::max_cargoes = std::max<uint>(CargoesField::max_cargoes, std::count_if(indsp->accepts_cargo, endof(indsp->accepts_cargo), IsCargoIDValid));
CargoesField::max_cargoes = std::max<uint>(CargoesField::max_cargoes, std::count_if(indsp->produced_cargo, endof(indsp->produced_cargo), IsCargoIDValid));
CargoesField::max_cargoes = std::max<uint>(CargoesField::max_cargoes, std::count_if(indsp->accepts_cargo, endof(indsp->accepts_cargo), IsValidCargoID));
CargoesField::max_cargoes = std::max<uint>(CargoesField::max_cargoes, std::count_if(indsp->produced_cargo, endof(indsp->produced_cargo), IsValidCargoID));
}
d.width = std::max(d.width, this->ind_textsize.width);
d.height = this->ind_textsize.height;

@ -10,7 +10,6 @@
#ifndef LANGUAGE_H
#define LANGUAGE_H
#include "core/smallvec_type.hpp"
#ifdef WITH_ICU_I18N
#include <unicode/coll.h>
#endif /* WITH_ICU_I18N */

@ -187,7 +187,7 @@ public:
td.grf = nullptr;
CargoArray acceptance;
CargoArray acceptance{};
AddAcceptedCargo(tile, acceptance, nullptr);
GetTileDesc(tile, &td);

@ -12,6 +12,7 @@
#include "../fileio_type.h"
#include "../string_func.h"
#include "../core/endian_func.hpp"
#include "../core/mem_func.hpp"
#include "../base_media_base.h"
#include "midi.h"

@ -11,7 +11,6 @@
#define MUSIC_MIDIFILE_HPP
#include "../stdafx.h"
#include "../core/smallvec_type.hpp"
#include "midi.h"
#include <vector>
#include <string>

@ -17,6 +17,7 @@
#include "midifile.hpp"
#include "midi.h"
#include "../base_media_base.h"
#include "../core/mem_func.hpp"
#include <mutex>
#if defined(__MINGW32__)
#include "../3rdparty/mingw-std-threads/mingw.mutex.h"

@ -19,6 +19,7 @@
#include "gfx_func.h"
#include "zoom_func.h"
#include "core/random_func.hpp"
#include "core/mem_func.hpp"
#include "error.h"
#include "core/geometry_func.hpp"
#include "string_func.h"

@ -172,7 +172,7 @@ const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::string name)
{
/* Find the matching GRF file */
const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, &config->ident.md5sum);
if (f == nullptr) {
AddGRFTextToList(config->name, name.empty() ? GetString(STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN) : name);
config->status = GCS_NOT_FOUND;
@ -528,9 +528,8 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
*/
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
{
uint j;
p->Send_uint32(grf->grfid);
for (j = 0; j < sizeof(grf->md5sum); j++) {
for (size_t j = 0; j < grf->md5sum.size(); j++) {
p->Send_uint8(grf->md5sum[j]);
}
}
@ -542,9 +541,8 @@ void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
*/
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf)
{
uint j;
grf->grfid = p->Recv_uint32();
for (j = 0; j < sizeof(grf->md5sum); j++) {
for (size_t j = 0; j < grf->md5sum.size(); j++) {
grf->md5sum[j] = p->Recv_uint8();
}
}

@ -70,7 +70,7 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
tmp = Game::GetScannerLibrary()->FindMainScript(this, true);
break;
case CONTENT_TYPE_NEWGRF: {
const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum);
const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, &this->md5sum);
tmp = gc != nullptr ? gc->filename.c_str() : nullptr;
break;
}

@ -12,6 +12,8 @@
#ifndef NETWORK_CORE_TCP_CONTENT_TYPE_H
#define NETWORK_CORE_TCP_CONTENT_TYPE_H
#include "../../3rdparty/md5/md5.h"
/** The values in the enum are important; they are used as database 'keys' */
enum ContentType {
CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types
@ -67,7 +69,7 @@ struct ContentInfo {
std::string url; ///< URL related to the content
std::string description; ///< Description of the content
uint32 unique_id = 0; ///< Unique ID; either GRF ID or shortname
byte md5sum[16] = {0}; ///< The MD5 checksum
MD5Hash md5sum; ///< The MD5 checksum
std::vector<ContentID> dependencies; ///< The dependencies (unique server side ids)
StringList tags; ///< Tags associated with the content
State state = State::UNSELECTED; ///< Whether the content info is selected (for download)

@ -211,18 +211,14 @@ std::string GenerateCompanyPasswordHash(const std::string &password, const std::
}
Md5 checksum;
uint8 digest[16];
MD5Hash digest;
/* Generate the MD5 hash */
std::string salted_password_string = salted_password.str();
checksum.Append(salted_password_string.data(), salted_password_string.size());
checksum.Finish(digest);
std::ostringstream hashed_password;
hashed_password << std::hex << std::setfill('0');
for (int di = 0; di < 16; di++) hashed_password << std::setw(2) << (int)digest[di]; // Cast needed, otherwise interpreted as character to add
return hashed_password.str();
return BytesToHexString(digest.data(), digest.size());
}
/**

@ -408,7 +408,7 @@ std::string _network_server_name;
NetworkJoinInfo _network_join;
/** Make sure the server ID length is the same as a md5 hash. */
static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
static_assert(NETWORK_SERVER_ID_LENGTH == MD5_HASH_BYTES * 2 + 1);
NetworkRecvStatus ClientNetworkGameSocketHandler::SendKeyPasswordPacket(PacketType packet_type, NetworkSharedSecrets &ss, const std::string &password, const std::string *payload)
{
@ -867,7 +867,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
DeserializeGRFIdentifier(p, &c);
/* Check whether we know this GRF */
const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, &c.md5sum);
if (f == nullptr) {
/* We do not know this GRF, bail out of initialization */
char buf[sizeof(c.md5sum) * 2 + 1];

@ -37,7 +37,7 @@ ClientNetworkContentSocketHandler _network_content_client;
/** Wrapper function for the HasProc */
static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
{
return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : nullptr) != nullptr;
return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? &ci->md5sum : nullptr) != nullptr;
}
/**
@ -62,7 +62,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
ci->description = p->Recv_string(NETWORK_CONTENT_DESC_LENGTH, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
ci->unique_id = p->Recv_uint32();
for (uint j = 0; j < sizeof(ci->md5sum); j++) {
for (size_t j = 0; j < ci->md5sum.size(); j++) {
ci->md5sum[j] = p->Recv_uint8();
}
@ -144,8 +144,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
/* Do we already have a stub for this? */
for (ContentInfo *ici : this->infos) {
if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
if (ici->type == ci->type && ici->unique_id == ci->unique_id && ci->md5sum == ici->md5sum) {
/* Preserve the name if possible */
if (ci->name.empty()) ci->name = ici->name;
if (ici->IsSelected()) ci->state = ici->state;
@ -265,7 +264,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
this->Connect();
const uint max_per_packet = std::min<uint>(255, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) /
(sizeof(uint8) + sizeof(uint32) + (send_md5sum ? /*sizeof(ContentInfo::md5sum)*/16 : 0))) - 1;
(sizeof(uint8) + sizeof(uint32) + (send_md5sum ? MD5_HASH_BYTES : 0))) - 1;
uint offset = 0;
@ -280,7 +279,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
p->Send_uint32(ci->unique_id);
if (!send_md5sum) continue;
for (uint j = 0; j < sizeof(ci->md5sum); j++) {
for (uint j = 0; j < ci->md5sum.size(); j++) {
p->Send_uint8(ci->md5sum[j]);
}
}
@ -294,7 +293,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo
bool found = false;
for (ContentInfo *ci2 : this->infos) {
if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
(!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
(!send_md5sum || ci->md5sum == ci2->md5sum)) {
found = true;
break;
}

@ -12,6 +12,7 @@
#include "core/tcp_content.h"
#include "core/http.h"
#include "../core/container_func.hpp"
#include "../3rdparty/cpp-btree/btree_map.h"
/** Vector with content info */

@ -19,6 +19,7 @@
#include "../sortlist_type.h"
#include "../stringfilter_type.h"
#include "../querystring_gui.h"
#include "../core/container_func.hpp"
#include "../core/geometry_func.hpp"
#include "../textfile_gui.h"
#include "../fios.h"

@ -124,7 +124,7 @@ void NetworkAfterNewGRFScan()
for (GRFConfig *c = item->info.grfconfig; c != nullptr; c = c->next) {
assert(HasBit(c->flags, GCF_COPY));
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
if (f == nullptr) {
/* Don't know the GRF (anymore), so mark game incompatible. */
c->status = GCS_NOT_FOUND;

@ -237,7 +237,7 @@ static void SurveyGrfs(nlohmann::json &survey)
auto grfid = fmt::format("{:08x}", BSWAP32(c->ident.grfid));
auto &grf = survey[grfid];
grf["md5sum"] = BytesToHexString(c->ident.md5sum, 16);
grf["md5sum"] = BytesToHexString(c->ident.md5sum.data(), c->ident.md5sum.size());
grf["status"] = c->status;
if ((c->palette & GRFP_GRF_MASK) == GRFP_GRF_UNSET) grf["palette"] = "unset";

@ -12,6 +12,7 @@
#include <stdarg.h>
#include "newgrf_internal.h"
#include "core/container_func.hpp"
#include "debug.h"
#include "fileio_func.h"
#include "engine_func.h"
@ -8092,7 +8093,7 @@ static void GRFLoadError(ByteReader *buf)
}
/* Only two parameter numbers can be used in the string. */
for (uint i = 0; i < lengthof(error->param_value) && buf->HasData(); i++) {
for (uint i = 0; i < error->param_value.size() && buf->HasData(); i++) {
uint param_number = buf->ReadByte();
error->param_value[i] = _cur.grffile->GetParam(param_number);
}
@ -8992,7 +8993,7 @@ static bool ChangeGRFNumUsedParams(size_t len, ByteReader *buf)
grfmsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'NPAR' but got " PRINTF_SIZE ", ignoring this field", len);
buf->Skip(len);
} else {
_cur.grfconfig->num_valid_params = std::min<byte>(buf->ReadByte(), lengthof(_cur.grfconfig->param));
_cur.grfconfig->num_valid_params = std::min(buf->ReadByte(), ClampTo<uint8_t>(_cur.grfconfig->param.size()));
}
return true;
}
@ -9141,7 +9142,7 @@ static bool ChangeGRFParamMask(size_t len, ByteReader *buf)
buf->Skip(len);
} else {
byte param_nr = buf->ReadByte();
if (param_nr >= lengthof(_cur.grfconfig->param)) {
if (param_nr >= _cur.grfconfig->param.size()) {
grfmsg(2, "StaticGRFInfo: invalid parameter number in 'INFO'->'PARA'->'MASK', param %d, ignoring this field", param_nr);
buf->Skip(len - 1);
} else {
@ -9338,10 +9339,10 @@ static bool HandleParameterInfo(ByteReader *buf)
if (id >= _cur.grfconfig->param_info.size()) {
_cur.grfconfig->param_info.resize(id + 1);
}
if (_cur.grfconfig->param_info[id] == nullptr) {
_cur.grfconfig->param_info[id] = new GRFParameterInfo(id);
if (!_cur.grfconfig->param_info[id].has_value()) {
_cur.grfconfig->param_info[id] = GRFParameterInfo(id);
}
_cur_parameter = _cur.grfconfig->param_info[id];
_cur_parameter = &_cur.grfconfig->param_info[id].value();
/* Read all parameter-data and process each node. */
if (!HandleNodes(buf, _tags_parameters)) return false;
type = buf->ReadByte();
@ -10570,13 +10571,8 @@ GRFFile::GRFFile(const GRFConfig *config)
/* Copy the initial parameter list
* 'Uninitialised' parameters are zeroed as that is their default value when dynamically creating them. */
static_assert(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80);
assert(config->num_params <= lengthof(config->param));
this->param = config->param;
this->param_end = config->num_params;
if (this->param_end > 0) {
MemCpyT(this->param, config->param, this->param_end);
}
}
GRFFile::~GRFFile()

@ -17,7 +17,7 @@
#include "debug.h"
#include "core/bitmath_func.hpp"
#include "core/alloc_type.hpp"
#include "core/smallvec_type.hpp"
#include "core/mem_func.hpp"
#include "3rdparty/cpp-btree/btree_map.h"
#include <bitset>
@ -346,7 +346,7 @@ struct GRFFile : ZeroedMemoryAllocator {
std::vector<GRFVariableMapEntry> grf_variable_remaps;
std::vector<std::unique_ptr<const char, FreeDeleter>> remap_unknown_property_names;
uint32 param[0x80];
std::array<uint32_t, 0x80> param;
uint param_end; ///< one more than the highest set parameter
std::vector<GRFLabel> labels; ///< List of labels
@ -398,9 +398,9 @@ struct GRFFile : ZeroedMemoryAllocator {
/** Get GRF Parameter with range checking */
uint32 GetParam(uint number) const
{
/* Note: We implicitly test for number < lengthof(this->param) and return 0 for invalid parameters.
/* Note: We implicitly test for number < this->param.size() and return 0 for invalid parameters.
* In fact this is the more important test, as param is zeroed anyway. */
assert(this->param_end <= lengthof(this->param));
assert(this->param_end <= this->param.size());
return (number < this->param_end) ? this->param[number] : 0;
}
};

@ -15,7 +15,6 @@
#include "sprite.h"
#include "core/alloc_type.hpp"
#include "core/smallvec_type.hpp"
#include "command_type.h"
#include "direction_type.h"
#include "company_type.h"

@ -43,7 +43,7 @@
* @param filename Set the filename of this GRFConfig to filename.
*/
GRFConfig::GRFConfig(const std::string &filename) :
filename(filename), num_valid_params(lengthof(param))
filename(filename), num_valid_params(ClampTo<uint8_t>(GRFConfig::param.size()))
{
}
@ -54,6 +54,7 @@ GRFConfig::GRFConfig(const std::string &filename) :
GRFConfig::GRFConfig(const GRFConfig &config) :
ZeroedMemoryAllocator(),
ident(config.ident),
original_md5sum(config.original_md5sum),
filename(config.filename),
name(config.name),
info(config.info),
@ -63,27 +64,14 @@ GRFConfig::GRFConfig(const GRFConfig &config) :
flags(config.flags & ~(1 << GCF_COPY)),
status(config.status),
grf_bugs(config.grf_bugs),
param(config.param),
num_params(config.num_params),
num_valid_params(config.num_valid_params),
palette(config.palette),
param_info(config.param_info),
has_param_defaults(config.has_param_defaults)
{
MemCpyT<uint8>(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum));
MemCpyT<uint32>(this->param, config.param, lengthof(this->param));
if (config.error != nullptr) this->error = std::make_unique<GRFError>(*config.error);
for (uint i = 0; i < config.param_info.size(); i++) {
if (config.param_info[i] == nullptr) {
this->param_info.push_back(nullptr);
} else {
this->param_info.push_back(new GRFParameterInfo(*config.param_info[i]));
}
}
}
/** Cleanup a GRFConfig object. */
GRFConfig::~GRFConfig()
{
for (uint i = 0; i < this->param_info.size(); i++) delete this->param_info[i];
}
/**
@ -94,7 +82,7 @@ void GRFConfig::CopyParams(const GRFConfig &src)
{
this->num_params = src.num_params;
this->num_valid_params = src.num_valid_params;
MemCpyT<uint32>(this->param, src.param, lengthof(this->param));
this->param = src.param;
}
/**
@ -130,12 +118,12 @@ const char *GRFConfig::GetURL() const
void GRFConfig::SetParameterDefaults()
{
this->num_params = 0;
MemSetT<uint32>(this->param, 0, lengthof(this->param));
this->param = {};
if (!this->has_param_defaults) return;
for (uint i = 0; i < this->param_info.size(); i++) {
if (this->param_info[i] == nullptr) continue;
if (!this->param_info[i]) continue;
this->param_info[i]->SetValue(this, this->param_info[i]->def_value);
}
}
@ -161,8 +149,8 @@ void GRFConfig::SetSuitablePalette()
*/
void GRFConfig::FinalizeParameterInfo()
{
for (GRFParameterInfo *info : this->param_info) {
if (info == nullptr) continue;
for (auto &info : this->param_info) {
if (!info.has_value()) continue;
info->Finalize();
}
}
@ -180,24 +168,8 @@ bool _grf_bug_too_many_strings = false;
* @param severity The severity of this error.
* @param message The actual error-string.
*/
GRFError::GRFError(StringID severity, StringID message) :
message(message),
severity(severity),
param_value()
{
}
/**
* Create a new GRFError that is a deep copy of an existing error message.
* @param error The GRFError object to make a copy of.
*/
GRFError::GRFError(const GRFError &error) :
custom_message(error.custom_message),
data(error.data),
message(error.message),
severity(error.severity)
GRFError::GRFError(StringID severity, StringID message) : message(message), severity(severity)
{
memcpy(this->param_value, error.param_value, sizeof(this->param_value));
}
/**
@ -218,26 +190,6 @@ GRFParameterInfo::GRFParameterInfo(uint nr) :
complete_labels(false)
{}
/**
* Create a new GRFParameterInfo object that is a deep copy of an existing
* parameter info object.
* @param info The GRFParameterInfo object to make a copy of.
*/
GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) :
name(info.name),
desc(info.desc),
type(info.type),
min_value(info.min_value),
max_value(info.max_value),
def_value(info.def_value),
param_nr(info.param_nr),
first_bit(info.first_bit),
num_bit(info.num_bit),
value_names(info.value_names),
complete_labels(info.complete_labels)
{
}
/**
* Get the value of this user-changeable parameter from the given config.
* @param config The GRFConfig to get the value from.
@ -597,7 +549,7 @@ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig)
GRFListCompatibility res = GLC_ALL_GOOD;
for (GRFConfig *c = grfconfig; c != nullptr; c = c->next) {
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
if (f == nullptr || HasBit(f->flags, GCF_INVALID)) {
char buf[256];
@ -610,7 +562,7 @@ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig)
if (!HasBit(c->flags, GCF_COMPATIBLE)) {
/* Preserve original_md5sum after it has been assigned */
SetBit(c->flags, GCF_COMPATIBLE);
memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum));
c->original_md5sum = c->ident.md5sum;
}
/* Non-found has precedence over compatibility load */
@ -634,21 +586,15 @@ compatible_grf:
* already a local one, so there is no need to replace it. */
if (!HasBit(c->flags, GCF_COPY)) {
c->filename = f->filename;
memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum));
c->ident.md5sum = f->ident.md5sum;
c->name = f->name;
c->info = f->name;
c->error = nullptr;
c->version = f->version;
c->min_loadable_version = f->min_loadable_version;
c->num_valid_params = f->num_valid_params;
c->param_info = f->param_info;
c->has_param_defaults = f->has_param_defaults;
for (uint i = 0; i < f->param_info.size(); i++) {
if (f->param_info[i] == nullptr) {
c->param_info.push_back(nullptr);
} else {
c->param_info.push_back(new GRFParameterInfo(*f->param_info[i]));
}
}
}
}
}
@ -698,7 +644,7 @@ public:
GRFConfig **pd, *d;
bool stop = false;
for (pd = &_all_grfs; (d = *pd) != nullptr; pd = &d->next) {
if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false;
if (c->ident.grfid == d->ident.grfid && c->ident.md5sum == d->ident.md5sum) added = false;
/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
* before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
* just after the first with the same name. Avoids doubles in the list. */
@ -834,7 +780,7 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback)
* @param desired_version Requested version
* @return The matching grf, if it exists in #_all_grfs, else \c nullptr.
*/
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum, uint32 desired_version)
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32 desired_version)
{
assert((mode == FGCM_EXACT) != (md5sum == nullptr));
const GRFConfig *best = nullptr;
@ -873,18 +819,14 @@ GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask)
/** Build a string containing space separated parameter values, and terminate */
char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last)
std::string GRFBuildParamList(const GRFConfig *c)
{
uint i;
/* Return an empty string if there are no parameters */
if (c->num_params == 0) return strecpy(dst, "", last);
for (i = 0; i < c->num_params; i++) {
if (i > 0) dst = strecpy(dst, " ", last);
dst += seprintf(dst, last, "%d", c->param[i]);
std::string result;
for (uint i = 0; i < c->num_params; i++) {
if (!result.empty()) result += ' ';
result += std::to_string(c->param[i]);
}
return dst;
return result;
}
/**

@ -16,6 +16,7 @@
#include "fileio_type.h"
#include "textfile_type.h"
#include "newgrf_text.h"
#include "3rdparty/md5/md5.h"
#include <map>
static const uint MAX_NON_STATIC_GRF_COUNT = 256;
@ -84,15 +85,12 @@ enum GRFPalette {
/** Basic data to distinguish a GRF. Used in the server list window */
struct GRFIdentifier {
uint32 grfid; ///< GRF ID (defined by Action 0x08)
uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
MD5Hash md5sum; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
GRFIdentifier() = default;
GRFIdentifier(const GRFIdentifier &other) = default;
GRFIdentifier(GRFIdentifier &&other) = default;
GRFIdentifier(uint32 grfid, const uint8 *md5sum) : grfid(grfid)
{
MemCpyT(this->md5sum, md5sum, lengthof(this->md5sum));
}
GRFIdentifier(uint32 grfid, const MD5Hash &md5sum) : grfid(grfid), md5sum(md5sum) {}
GRFIdentifier& operator =(const GRFIdentifier &other) = default;
@ -102,27 +100,23 @@ struct GRFIdentifier {
* @param md5sum Expected md5sum, may be \c nullptr (in which case, do not check it).
* @return the object has the provided grfid and md5sum.
*/
inline bool HasGrfIdentifier(uint32 grfid, const uint8 *md5sum) const
inline bool HasGrfIdentifier(uint32 grfid, const MD5Hash *md5sum) const
{
if (this->grfid != grfid) return false;
if (md5sum == nullptr) return true;
return memcmp(md5sum, this->md5sum, sizeof(this->md5sum)) == 0;
return *md5sum == this->md5sum;
}
};
/** Information about why GRF had problems during initialisation */
struct GRFError {
GRFError(StringID severity, StringID message = 0);
GRFError(const GRFError &error);
/* Remove the copy assignment, as the default implementation will not do the right thing. */
GRFError &operator=(GRFError &rhs) = delete;
std::string custom_message; ///< Custom message (if present)
std::string data; ///< Additional data for message and custom_message
StringID message; ///< Default message
StringID severity; ///< Info / Warning / Error / Fatal
uint64 param_value[4]; ///< Values of GRF parameters to show for message and custom_message
std::array<uint32_t, 4> param_value; ///< Values of GRF parameters to show for message and custom_message
};
/** The possible types of a newgrf parameter. */
@ -135,7 +129,6 @@ enum GRFParameterType {
/** Information about one grf parameter. */
struct GRFParameterInfo {
GRFParameterInfo(uint nr);
GRFParameterInfo(GRFParameterInfo &info);
GRFTextList name; ///< The name of this parameter
GRFTextList desc; ///< The description of this parameter
GRFParameterType type; ///< The type of this parameter
@ -157,13 +150,12 @@ struct GRFParameterInfo {
struct GRFConfig : ZeroedMemoryAllocator {
GRFConfig(const std::string &filename = std::string{});
GRFConfig(const GRFConfig &config);
~GRFConfig();
/* Remove the copy assignment, as the default implementation will not do the right thing. */
GRFConfig &operator=(GRFConfig &rhs) = delete;
GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs
uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded
MD5Hash original_md5sum; ///< MD5 checksum of original file if only a 'compatible' file was loaded
std::string filename; ///< Filename - either with or without full path
std::string full_filename; ///< NOSAVE: Full filename
GRFTextWrapper name; ///< NOSAVE: GRF name (Action 0x08)
@ -176,11 +168,11 @@ struct GRFConfig : ZeroedMemoryAllocator {
uint8 flags; ///< NOSAVE: GCF_Flags, bitset
GRFStatus status; ///< NOSAVE: GRFStatus, enum
uint32 grf_bugs; ///< NOSAVE: bugs in this GRF in this run, @see enum GRFBugs
uint32 param[0x80]; ///< GRF parameters
std::array<uint32_t, 0x80> param; ///< GRF parameters
uint8 num_params; ///< Number of used parameters
uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14)
uint8 palette; ///< GRFPalette, bitset
std::vector<GRFParameterInfo *> param_info; ///< NOSAVE: extra information about the parameters
std::vector<std::optional<GRFParameterInfo>> param_info; ///< NOSAVE: extra information about the parameters
bool has_param_defaults; ///< NOSAVE: did this newgrf specify any defaults for it's parameters
struct GRFConfig *next; ///< NOSAVE: Next item in the linked list
@ -230,7 +222,7 @@ struct NewGRFScanCallback {
size_t GRFGetSizeOfDataSection(FILE *f);
void ScanNewGRFFiles(NewGRFScanCallback *callback);
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = nullptr, uint32 desired_version = 0);
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const MD5Hash *md5sum = nullptr, uint32 desired_version = 0);
GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask = 0xFFFFFFFF);
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only);
void AppendStaticGRFConfigs(GRFConfig **dst);
@ -239,7 +231,7 @@ void ClearGRFConfigList(GRFConfig **config);
void ResetGRFConfig(bool defaults);
GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig);
bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir = NEWGRF_DIR);
char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last);
std::string GRFBuildParamList(const GRFConfig *c);
/* In newgrf_gui.cpp */
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config);

@ -11,7 +11,6 @@
#define NEWGRF_DEBUG_H
#include "newgrf.h"
#include "core/smallvec_type.hpp"
#include "tile_type.h"
#include "vehicle_type.h"

@ -17,6 +17,7 @@
#include "date_func.h"
#include "vehicle_func.h"
#include "core/random_func.hpp"
#include "core/container_func.hpp"
#include "aircraft.h"
#include "station_base.h"
#include "company_base.h"

@ -23,6 +23,7 @@
#include "sortlist_type.h"
#include "stringfilter_type.h"
#include "querystring_gui.h"
#include "core/container_func.hpp"
#include "core/geometry_func.hpp"
#include "newgrf_text.h"
#include "textfile_gui.h"
@ -55,7 +56,7 @@ void ShowNewGRFError()
SetDParamStr(2, c->error->custom_message);
SetDParamStr(3, c->filename);
SetDParamStr(4, c->error->data);
for (uint i = 0; i < lengthof(c->error->param_value); i++) {
for (uint i = 0; i < c->error->param_value.size(); i++) {
SetDParam(5 + i, c->error->param_value[i]);
}
if (c->error->severity == STR_NEWGRF_ERROR_MSG_FATAL) {
@ -75,7 +76,7 @@ static void ShowNewGRFInfo(const GRFConfig *c, const Rect &r, bool show_params)
SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages
SetDParamStr(1, c->filename);
SetDParamStr(2, c->error->data);
for (uint i = 0; i < lengthof(c->error->param_value); i++) {
for (uint i = 0; i < c->error->param_value.size(); i++) {
SetDParam(3 + i, c->error->param_value[i]);
}
GetString(message, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message));
@ -113,9 +114,9 @@ static void ShowNewGRFInfo(const GRFConfig *c, const Rect &r, bool show_params)
/* Show GRF parameter list */
if (show_params) {
if (c->num_params > 0) {
GRFBuildParamList(buff, c, lastof(buff));
std::string params = GRFBuildParamList(c);
SetDParam(0, STR_JUST_RAW_STRING);
SetDParamStr(1, buff);
SetDParamStr(1, params);
} else {
SetDParam(0, STR_NEWGRF_SETTINGS_PARAMETER_NONE);
}
@ -170,7 +171,7 @@ struct NewGRFParametersWindow : public Window {
clicked_row(UINT_MAX),
editable(editable)
{
this->action14present = (c->num_valid_params != lengthof(c->param) || c->param_info.size() != 0);
this->action14present = (c->num_valid_params != c->param.size() || c->param_info.size() != 0);
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR);
@ -193,10 +194,31 @@ struct NewGRFParametersWindow : public Window {
* @param nr The param number that should be changed.
* @return GRFParameterInfo with dummy information about the given parameter.
*/
static GRFParameterInfo *GetDummyParameterInfo(uint nr)
static GRFParameterInfo &GetDummyParameterInfo(uint nr)
{
dummy_parameter_info.param_nr = nr;
return &dummy_parameter_info;
return dummy_parameter_info;
}
/**
* Test if GRF Parameter Info exists for a given parameter index.
* @param nr The param number that should be tested.
* @return True iff the parameter info exists.
*/
bool HasParameterInfo(uint nr) const
{
return nr < this->grf_config->param_info.size() && this->grf_config->param_info[nr].has_value();
}
/**
* Get GRF Parameter Info exists for a given parameter index.
* If the parameter info does not exist, a dummy parameter-info is returned instead.
* @param nr The param number that should be got.
* @return Reference to the GRFParameterInfo.
*/
GRFParameterInfo &GetParameterInfo(uint nr) const
{
return this->HasParameterInfo(nr) ? this->grf_config->param_info[nr].value() : GetDummyParameterInfo(nr);
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
@ -210,7 +232,7 @@ struct NewGRFParametersWindow : public Window {
}
case WID_NP_NUMPAR: {
SetDParamMaxValue(0, lengthof(this->grf_config->param));
SetDParamMaxValue(0, this->grf_config->param.size());
Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
d.width += padding.width;
d.height += padding.height;
@ -229,9 +251,8 @@ struct NewGRFParametersWindow : public Window {
case WID_NP_DESCRIPTION:
/* Minimum size of 4 lines. The 500 is the default size of the window. */
Dimension suggestion = {500U - WidgetDimensions::scaled.frametext.Horizontal(), (uint)FONT_HEIGHT_NORMAL * 4 + WidgetDimensions::scaled.frametext.Vertical()};
for (uint i = 0; i < this->grf_config->param_info.size(); i++) {
const GRFParameterInfo *par_info = this->grf_config->param_info[i];
if (par_info == nullptr) continue;
for (const auto &par_info : this->grf_config->param_info) {
if (!par_info.has_value()) continue;
const char *desc = GetGRFStringFromGRFText(par_info->desc);
if (desc == nullptr) continue;
Dimension d = GetStringMultiLineBoundingBox(desc, suggestion);
@ -255,9 +276,9 @@ struct NewGRFParametersWindow : public Window {
void DrawWidget(const Rect &r, int widget) const override
{
if (widget == WID_NP_DESCRIPTION) {
const GRFParameterInfo *par_info = (this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr;
if (par_info == nullptr) return;
const char *desc = GetGRFStringFromGRFText(par_info->desc);
if (!this->HasParameterInfo(this->clicked_row)) return;
const GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
const char *desc = GetGRFStringFromGRFText(par_info.desc);
if (desc == nullptr) return;
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.framerect), desc, TC_BLACK);
return;
@ -273,24 +294,23 @@ struct NewGRFParametersWindow : public Window {
int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) {
GRFParameterInfo *par_info = (i < this->grf_config->param_info.size()) ? this->grf_config->param_info[i] : nullptr;
if (par_info == nullptr) par_info = GetDummyParameterInfo(i);
uint32 current_value = par_info->GetValue(this->grf_config);
GRFParameterInfo &par_info = this->GetParameterInfo(i);
uint32 current_value = par_info.GetValue(this->grf_config);
bool selected = (i == this->clicked_row);
if (par_info->type == PTYPE_BOOL) {
if (par_info.type == PTYPE_BOOL) {
DrawBoolButton(buttons_left, ir.top + button_y_offset, current_value != 0, this->editable);
SetDParam(2, par_info->GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
} else if (par_info->type == PTYPE_UINT_ENUM) {
if (par_info->complete_labels) {
SetDParam(2, par_info.GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
} else if (par_info.type == PTYPE_UINT_ENUM) {
if (par_info.complete_labels) {
DrawDropDownButton(buttons_left, ir.top + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && this->clicked_dropdown, this->editable);
} else {
DrawArrowButtons(buttons_left, ir.top + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info->min_value, this->editable && current_value < par_info->max_value);
DrawArrowButtons(buttons_left, ir.top + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info.min_value, this->editable && current_value < par_info.max_value);
}
SetDParam(2, STR_JUST_INT);
SetDParam(3, current_value);
auto it = par_info->value_names.find(current_value);
if (it != par_info->value_names.end()) {
auto it = par_info.value_names.find(current_value);
if (it != par_info.value_names.end()) {
const char *label = GetGRFStringFromGRFText(it->second);
if (label != nullptr) {
SetDParam(2, STR_JUST_RAW_STRING);
@ -299,7 +319,7 @@ struct NewGRFParametersWindow : public Window {
}
}
const char *name = GetGRFStringFromGRFText(par_info->name);
const char *name = GetGRFStringFromGRFText(par_info.name);
if (name != nullptr) {
SetDParam(0, STR_JUST_RAW_STRING);
SetDParamStr(1, name);
@ -360,12 +380,11 @@ struct NewGRFParametersWindow : public Window {
int x = pt.x - r.left;
if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
GRFParameterInfo *par_info = *it;
if (par_info == nullptr) par_info = GetDummyParameterInfo(num);
GRFParameterInfo &par_info = it->has_value() ? it->value() : GetDummyParameterInfo(num);
/* One of the arrows is clicked */
uint32 old_val = par_info->GetValue(this->grf_config);
if (par_info->type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info->complete_labels) {
uint32 old_val = par_info.GetValue(this->grf_config);
if (par_info.type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info.complete_labels) {
if (this->clicked_dropdown) {
/* unclick the dropdown */
HideDropDownMenu(this);
@ -386,8 +405,8 @@ struct NewGRFParametersWindow : public Window {
this->closing_dropdown = false;
DropDownList list;
for (uint32 i = par_info->min_value; i <= par_info->max_value; i++) {
list.emplace_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.find(i)->second), i, false));
for (uint32 i = par_info.min_value; i <= par_info.max_value; i++) {
list.emplace_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info.value_names.find(i)->second), i, false));
}
ShowDropDownListAt(this, std::move(list), old_val, -1, wi_rect, COLOUR_ORANGE);
@ -395,26 +414,26 @@ struct NewGRFParametersWindow : public Window {
}
} else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) {
uint32 val = old_val;
if (par_info->type == PTYPE_BOOL) {
if (par_info.type == PTYPE_BOOL) {
val = !val;
} else {
if (x >= SETTING_BUTTON_WIDTH / 2) {
/* Increase button clicked */
if (val < par_info->max_value) val++;
if (val < par_info.max_value) val++;
this->clicked_increase = true;
} else {
/* Decrease button clicked */
if (val > par_info->min_value) val--;
if (val > par_info.min_value) val--;
this->clicked_increase = false;
}
}
if (val != old_val) {
par_info->SetValue(this->grf_config, val);
par_info.SetValue(this->grf_config, val);
this->clicked_button = num;
this->timeout.SetInterval(150);
}
} else if (par_info->type == PTYPE_UINT_ENUM && !par_info->complete_labels && click_count >= 2) {
} else if (par_info.type == PTYPE_UINT_ENUM && !par_info.complete_labels && click_count >= 2) {
/* Display a query box so users can enter a custom value. */
SetDParam(0, old_val);
ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE);
@ -440,19 +459,17 @@ struct NewGRFParametersWindow : public Window {
{
if (StrEmpty(str)) return;
int32 value = atoi(str);
GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr;
if (par_info == nullptr) par_info = GetDummyParameterInfo(this->clicked_row);
uint32 val = Clamp<uint32>(value, par_info->min_value, par_info->max_value);
par_info->SetValue(this->grf_config, val);
GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
uint32 val = Clamp<uint32>(value, par_info.min_value, par_info.max_value);
par_info.SetValue(this->grf_config, val);
this->SetDirty();
}
void OnDropdownSelect(int widget, int index) override
{
assert(this->clicked_dropdown);
GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr;
if (par_info == nullptr) par_info = GetDummyParameterInfo(this->clicked_row);
par_info->SetValue(this->grf_config, index);
GRFParameterInfo &par_info = this->GetParameterInfo(this->clicked_row);
par_info.SetValue(this->grf_config, index);
this->SetDirty();
}
@ -1241,7 +1258,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
if (c->status != GCS_NOT_FOUND && !compatible) continue;
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? c->original_md5sum : c->ident.md5sum);
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue;
*l = new GRFConfig(*f);
@ -1448,7 +1465,7 @@ private:
i = a->version - b->version;
if (i != 0) return i < 0;
return memcmp(a->ident.md5sum, b->ident.md5sum, lengthof(b->ident.md5sum)) < 0;
return a->ident.md5sum < b->ident.md5sum;
}
/** Filter grfs by tags/name */
@ -1469,7 +1486,7 @@ private:
for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) {
bool found = false;
for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum);
for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum);
if (found) continue;
if (_settings_client.gui.newgrf_show_old_versions) {
@ -1486,7 +1503,7 @@ private:
* If we are the best version, then we definitely want to
* show that NewGRF!.
*/
if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum)) {
if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
this->avails.push_back(c);
}
}
@ -1571,7 +1588,7 @@ void ShowMissingContentWindow(const GRFConfig *list)
ci->state = ContentInfo::DOES_NOT_EXIST;
ci->name = c->GetName();
ci->unique_id = BSWAP32(c->ident.grfid);
memcpy(ci->md5sum, HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum, sizeof(ci->md5sum));
ci->md5sum = HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum;
cv.push_back(ci);
}
ShowNetworkContentListWindow(cv.size() == 0 ? nullptr : &cv, CONTENT_TYPE_NEWGRF);

@ -709,7 +709,7 @@ void IndustryProductionCallback(Industry *ind, int reason)
*/
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type)
{
assert(std::find(ind->accepts_cargo, endof(ind->accepts_cargo), cargo_type) != endof(ind->accepts_cargo));
assert(ind->IsCargoAccepted(cargo_type));
const IndustrySpec *indspec = GetIndustrySpec(ind->type);
if (HasBit(indspec->callback_mask, CBM_IND_REFUSE_CARGO)) {

@ -8,6 +8,7 @@
/** @file newgrf_railtype.cpp NewGRF handling of rail types. */
#include "stdafx.h"
#include "core/container_func.hpp"
#include "debug.h"
#include "newgrf_railtype.h"
#include "newgrf_newsignals.h"

@ -8,6 +8,7 @@
/** @file newgrf_roadtype.cpp NewGRF handling of road types. */
#include "stdafx.h"
#include "core/container_func.hpp"
#include "debug.h"
#include "newgrf_roadtype.h"
#include "date_func.h"

@ -10,6 +10,7 @@
#ifndef NEWGRF_STORAGE_H
#define NEWGRF_STORAGE_H
#include "core/alloc_func.hpp"
#include "core/pool_type.hpp"
#include "tile_type.h"

@ -12,7 +12,6 @@
#include "string_type.h"
#include "strings_type.h"
#include "core/smallvec_type.hpp"
#include "table/control_codes.h"
#include <utility>
#include <vector>

@ -1111,37 +1111,13 @@ void ShowLastNewsMessage()
*/
static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
{
char buffer[512], buffer2[512];
StringID str;
CopyInDParam(0, ni->params, lengthof(ni->params));
str = ni->string_id;
GetString(buffer, str, lastof(buffer));
/* Copy the just gotten string to another buffer to remove any formatting
* from it such as big fonts, etc. */
const char *ptr = buffer;
char *dest = buffer2;
WChar c_last = '\0';
for (;;) {
WChar c = Utf8Consume(&ptr);
if (c == 0) break;
/* Make a space from a newline, but ignore multiple newlines */
if (c == '\n' && c_last != '\n') {
dest[0] = ' ';
dest++;
} else if (c == '\r') {
dest[0] = dest[1] = dest[2] = dest[3] = ' ';
dest += 4;
} else if (IsPrintable(c)) {
dest += Utf8Encode(dest, c);
}
c_last = c;
}
*dest = '\0';
/* Get the string, replaces newlines with spaces and remove control codes from the string. */
std::string message = StrMakeValid(GetString(ni->string_id), SVS_REPLACE_TAB_CR_NL_WITH_SPACE);
/* Truncate and show string; postfixed by '...' if necessary */
DrawString(left, right, y, buffer2, colour);
DrawString(left, right, y, message, colour);
}
struct MessageHistoryWindow : Window {

@ -509,7 +509,7 @@ public:
{
switch (GB(widget, 0, 16)) {
case WID_BO_CLASS_LIST: {
auto it = this->vscroll->GetScrolledItemFromWidget(this->object_classes, widget, this, pt.y);
auto it = this->vscroll->GetScrolledItemFromWidget(this->object_classes, pt.y, this, widget);
if (it == this->object_classes.end()) break;
this->SelectOtherClass(*it);

@ -23,6 +23,7 @@
#include "vehicle_func.h"
#include "depot_base.h"
#include "core/bitmath_func.hpp"
#include "core/container_func.hpp"
#include "core/pool_func.hpp"
#include "core/random_func.hpp"
#include "aircraft.h"

@ -449,6 +449,8 @@ public:
ret = false;
}
this->SendSurvey();
return ret;
}

@ -833,6 +833,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename));
SetScreenshotAuxiliaryText("Crash Log", log->crashlog);
log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename), log->name_buffer);
log->SendSurvey();
/* Close any possible log files */
CloseConsoleLogIfActive();

@ -11,7 +11,6 @@
#define PLANS_TYPE_H
#include "stdafx.h"
#include "core/smallvec_type.hpp"
#include "tile_type.h"
typedef uint16 PlanID;

@ -11,7 +11,7 @@
#define PROGRAMMABLE_SIGNALS_H
#include "rail_map.h"
#include "tracerestrict.h"
#include "core/smallvec_type.hpp"
#include "core/container_func.hpp"
#include <map>
/** @defgroup progsigs Programmable Pre-Signals */

@ -29,6 +29,7 @@
#include "company_base.h"
#include "core/backup_type.hpp"
#include "date_func.h"
#include "core/container_func.hpp"
#include "strings_func.h"
#include "company_gui.h"
#include "object_map.h"

@ -2429,9 +2429,9 @@ struct BuildRailWaypointWindow : PickerWindowBase {
const StationClass *waypoints;
WaypointList list;
StringFilter string_filter; ///< Filter for waypoint name
QueryString editbox; ///< Filter editbox
static QueryString editbox; ///< Filter editbox
BuildRailWaypointWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent), editbox(FILTER_LENGTH * MAX_CHAR_LENGTH, FILTER_LENGTH)
BuildRailWaypointWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent)
{
this->waypoints = StationClass::Get(STAT_CLASS_WAYP);
@ -2444,6 +2444,7 @@ struct BuildRailWaypointWindow : PickerWindowBase {
this->querystrings[WID_BRW_FILTER] = &this->editbox;
this->editbox.cancel_button = QueryString::ACTION_CLEAR;
this->string_filter.SetFilterTerm(this->editbox.text.buf);
this->list.ForceRebuild();
this->BuildPickerList();
@ -2618,6 +2619,8 @@ struct BuildRailWaypointWindow : PickerWindowBase {
}
};
/* static */ QueryString BuildRailWaypointWindow::editbox(BuildRailWaypointWindow::FILTER_LENGTH * MAX_CHAR_LENGTH, BuildRailWaypointWindow::FILTER_LENGTH);
/** Nested widget definition for the build NewGRF rail waypoint window */
static const NWidgetPart _nested_build_waypoint_widgets[] = {
NWidget(NWID_HORIZONTAL),

@ -31,6 +31,7 @@
#include "town.h"
#include "company_base.h"
#include "core/random_func.hpp"
#include "core/container_func.hpp"
#include "newgrf_debug.h"
#include "newgrf_railtype.h"
#include "newgrf_roadtype.h"

@ -39,9 +39,8 @@ void DrawRoadVehDetails(const Vehicle *v, const Rect &r)
y += FONT_HEIGHT_NORMAL;
if (v->HasArticulatedPart()) {
CargoArray max_cargo;
CargoArray max_cargo{};
StringID subtype_text[NUM_CARGO];
char capacity[512];
memset(subtype_text, 0, sizeof(subtype_text));
@ -53,23 +52,19 @@ void DrawRoadVehDetails(const Vehicle *v, const Rect &r)
}
}
GetString(capacity, STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY, lastof(capacity));
std::string capacity = GetString(STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY);
bool first = true;
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (max_cargo[i] > 0) {
char buffer[128];
if (!first) capacity += ", ";
SetDParam(0, i);
SetDParam(1, max_cargo[i]);
GetString(buffer, STR_JUST_CARGO, lastof(buffer));
if (!first) strecat(capacity, ", ", lastof(capacity));
strecat(capacity, buffer, lastof(capacity));
capacity += GetString(STR_JUST_CARGO);
if (subtype_text[i] != 0) {
GetString(buffer, subtype_text[i], lastof(buffer));
strecat(capacity, buffer, lastof(capacity));
capacity += GetString(subtype_text[i]);
}
first = false;

@ -15,7 +15,6 @@
#include "../tile_type.h"
#include "../animated_tile.h"
#include "../core/alloc_func.hpp"
#include "../core/smallvec_type.hpp"
#include "../safeguards.h"

@ -329,7 +329,7 @@ public:
la->change = ReallocT(la->change, la->changes + 1);
LoggedChange *lc = &la->change[la->changes++];
memset(lc, 0, sizeof(*lc));
*lc = LoggedChange{};
lc->ct = ct;
SlObject(lc, this->GetLoadDescription());
@ -343,7 +343,7 @@ public:
for (size_t i = 0; i < length; i++) {
LoggedChange *lc = &la->change[i];
memset(lc, 0, sizeof(*lc));
*lc = LoggedChange{};
lc->ct = (GamelogChangeType)SlReadByte();
SlObject(lc, this->GetLoadDescription());
@ -377,7 +377,7 @@ struct GLOGChunkHandler : ChunkHandler {
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
*la = LoggedAction{};
la->at = (GamelogActionType)type;
SlObject(la, slt);
@ -388,7 +388,7 @@ struct GLOGChunkHandler : ChunkHandler {
while (SlIterateArray() != -1) {
gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1);
LoggedAction *la = &gamelog_action[gamelog_actions++];
memset(la, 0, sizeof(*la));
*la = LoggedAction{};
SlObject(la, slt);
}

@ -65,14 +65,10 @@
Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (i->accepts_cargo[j] == cargo_id) {
if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED;
return CAS_ACCEPTED;
}
}
if (!i->IsCargoAccepted(cargo_id)) return CAS_NOT_ACCEPTED;
if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED;
return CAS_NOT_ACCEPTED;
return CAS_ACCEPTED;
}
/* static */ SQInteger ScriptIndustry::GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id)
@ -80,15 +76,12 @@
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID cid = ind->accepts_cargo[i];
if (cid == cargo_id) {
return ind->incoming_cargo_waiting[i];
}
}
Industry *i = ::Industry::Get(industry_id);
int j = i->GetCargoAcceptedIndex(cargo_id);
if (j < 0) return -1;
return -1;
return i->incoming_cargo_waiting[j];
}
/* static */ SQInteger ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id)
@ -98,11 +91,10 @@
const Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return i->last_month_production[j];
}
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
return -1;
return i->last_month_production[j];
}
/* static */ SQInteger ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id)
@ -112,11 +104,10 @@
const Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return i->last_month_transported[j];
}
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
return -1;
return i->last_month_transported[j];
}
/* static */ SQInteger ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id)
@ -126,11 +117,10 @@
const Industry *i = ::Industry::Get(industry_id);
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) return ::ToPercent8(i->last_month_pct_transported[j]);
}
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
return -1;
return ::ToPercent8(i->last_month_pct_transported[j]);
}
/* static */ TileIndex ScriptIndustry::GetLocation(IndustryID industry_id)

@ -23,17 +23,13 @@ ScriptIndustryList::ScriptIndustryList()
ScriptIndustryList_CargoAccepting::ScriptIndustryList_CargoAccepting(CargoID cargo_id)
{
for (const Industry *i : Industry::Iterate()) {
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (i->accepts_cargo[j] == cargo_id) this->AddItem(i->index);
}
if (i->IsCargoAccepted(cargo_id)) this->AddItem(i->index);
}
}
ScriptIndustryList_CargoProducing::ScriptIndustryList_CargoProducing(CargoID cargo_id)
{
for (const Industry *i : Industry::Iterate()) {
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == cargo_id) this->AddItem(i->index);
}
if (i->IsCargoProduced(cargo_id)) this->AddItem(i->index);
}
}

@ -83,13 +83,7 @@ ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID in
if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) return;
/* Check if this industry accepts anything */
{
bool cargo_accepts = false;
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (i->accepts_cargo[j] != CT_INVALID) cargo_accepts = true;
}
if (!cargo_accepts) return;
}
if (!i->IsCargoAccepted()) return;
if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED + _settings_game.station.catchment_increase;
@ -123,11 +117,7 @@ ScriptTileList_IndustryProducing::ScriptTileList_IndustryProducing(IndustryID in
if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) return;
/* Check if this industry produces anything */
bool cargo_produces = false;
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] != CT_INVALID) cargo_produces = true;
}
if (!cargo_produces) return;
if (!i->IsCargoProduced()) return;
if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED + _settings_game.station.catchment_increase;

@ -155,18 +155,14 @@ std::string ScriptScanner::GetConsoleList(bool newest_only) const
/** Helper for creating a MD5sum of all files within of a script. */
struct ScriptFileChecksumCreator : FileScanner {
byte md5sum[16]; ///< The final md5sum.
MD5Hash md5sum; ///< The final md5sum.
Subdirectory dir; ///< The directory to look in.
/**
* Initialise the md5sum to be all zeroes,
* so we can easily xor the data.
*/
ScriptFileChecksumCreator(Subdirectory dir)
{
this->dir = dir;
memset(this->md5sum, 0, sizeof(this->md5sum));
}
ScriptFileChecksumCreator(Subdirectory dir) : dir(dir) {}
/* Add the file and calculate the md5 sum. */
virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
@ -174,7 +170,6 @@ struct ScriptFileChecksumCreator : FileScanner {
Md5 checksum;
uint8 buffer[1024];
size_t len, size;
byte tmp_md5sum[16];
/* Open the file ... */
FILE *f = FioFOpenFile(filename.c_str(), "rb", this->dir, &size);
@ -185,12 +180,14 @@ struct ScriptFileChecksumCreator : FileScanner {
size -= len;
checksum.Append(buffer, len);
}
MD5Hash tmp_md5sum;
checksum.Finish(tmp_md5sum);
FioFCloseFile(f);
/* ... and xor it to the overall md5sum. */
for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i];
this->md5sum ^= tmp_md5sum;
return true;
}
@ -238,7 +235,7 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S
checksum.Scan(".nut", path);
}
return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
return ci->md5sum == checksum.md5sum;
}
bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)

@ -11,7 +11,6 @@
#define SQUIRREL_HELPER_HPP
#include "squirrel.hpp"
#include "../core/smallvec_type.hpp"
#include "../economy_type.h"
#include "../string_func.h"
#include "../tile_type.h"

@ -271,9 +271,9 @@ static size_t LookupManyOfMany(const std::vector<std::string> &many, const char
* @return returns the number of items found, or -1 on an error
*/
template<typename T>
static int ParseIntList(const char *p, T *items, int maxitems)
static int ParseIntList(const char *p, T *items, size_t maxitems)
{
int n = 0; // number of items read so far
size_t n = 0; // number of items read so far
bool comma = false; // do we accept comma?
while (*p != '\0') {
@ -306,7 +306,7 @@ static int ParseIntList(const char *p, T *items, int maxitems)
* We have read comma when (n != 0) and comma is not allowed */
if (n != 0 && !comma) return -1;
return n;
return ClampTo<int>(n);
}
/**
@ -2087,7 +2087,8 @@ static GRFConfig *GRFLoadConfig(IniFile &ini, const char *grpname, bool is_stati
for (item = group->item; item != nullptr; item = item->next) {
GRFConfig *c = nullptr;
uint8 grfid_buf[4], md5sum[16];
uint8 grfid_buf[4];
MD5Hash md5sum;
const char *filename = item->name.c_str();
bool has_grfid = false;
bool has_md5sum = false;
@ -2096,12 +2097,12 @@ static GRFConfig *GRFLoadConfig(IniFile &ini, const char *grpname, bool is_stati
has_grfid = DecodeHexText(filename, grfid_buf, lengthof(grfid_buf));
if (has_grfid) {
filename += 1 + 2 * lengthof(grfid_buf);
has_md5sum = DecodeHexText(filename, md5sum, lengthof(md5sum));
if (has_md5sum) filename += 1 + 2 * lengthof(md5sum);
has_md5sum = DecodeHexText(filename, md5sum.data(), md5sum.size());
if (has_md5sum) filename += 1 + 2 * md5sum.size();
uint32 grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
if (has_md5sum) {
const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, md5sum);
const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
if (s != nullptr) c = new GRFConfig(*s);
}
if (c == nullptr && !FioCheckFileExists(filename, NEWGRF_DIR)) {
@ -2113,7 +2114,7 @@ static GRFConfig *GRFLoadConfig(IniFile &ini, const char *grpname, bool is_stati
/* Parse parameters */
if (item->value.has_value() && !item->value->empty()) {
int count = ParseIntList(item->value->c_str(), c->param, lengthof(c->param));
int count = ParseIntList(item->value->c_str(), c->param.data(), c->param.size());
if (count < 0) {
SetDParamStr(0, filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
@ -2255,13 +2256,10 @@ static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfig *li
for (c = list; c != nullptr; c = c->next) {
/* Hex grfid (4 bytes in nibbles), "|", hex md5sum (16 bytes in nibbles), "|", file system path. */
char key[4 * 2 + 1 + 16 * 2 + 1 + MAX_PATH];
char params[512];
GRFBuildParamList(params, c, lastof(params));
char *pos = key + seprintf(key, lastof(key), "%08X|", BSWAP32(c->ident.grfid));
pos = md5sumToString(pos, lastof(key), c->ident.md5sum);
seprintf(pos, lastof(key), "|%s", c->filename.c_str());
group->GetItem(key, true)->SetValue(params);
group->GetItem(key, true)->SetValue(GRFBuildParamList(c));
}
}

@ -10,7 +10,6 @@
#ifndef SETTINGS_FUNC_H
#define SETTINGS_FUNC_H
#include "core/smallvec_type.hpp"
#include "company_type.h"
#include "string_type.h"

@ -12,7 +12,7 @@
#include "../strings_type.h"
#include "../misc/getoptdata.h"
#include "../ini_type.h"
#include "../core/smallvec_type.hpp"
#include "../core/mem_func.hpp"
#include <stdarg.h>
@ -406,7 +406,6 @@ static bool CompareFiles(const char *n1, const char *n2)
/** Options of settingsgen. */
static const OptionData _opts[] = {
GETOPT_NOVAL( 'v', "--version"),
GETOPT_NOVAL( 'h', "--help"),
GETOPT_GENERAL('h', '?', nullptr, ODF_NO_VALUE),
GETOPT_VALUE( 'o', "--output"),
@ -461,15 +460,10 @@ int CDECL main(int argc, char *argv[])
if (i == -1) break;
switch (i) {
case 'v':
puts("$Revision$");
return 0;
case 'h':
puts("settingsgen - $Revision$\n"
puts("settingsgen\n"
"Usage: settingsgen [options] ini-file...\n"
"with options:\n"
" -v, --version Print version information and exit\n"
" -h, -?, --help Print this help message and exit\n"
" -b FILE, --before FILE Copy FILE before all settings\n"
" -a FILE, --after FILE Copy FILE after all settings\n"

@ -72,7 +72,7 @@ void DrawShipDetails(const Vehicle *v, const Rect &r)
Money feeder_share = 0;
if (v->Next() != nullptr) {
CargoArray max_cargo;
CargoArray max_cargo{};
StringID subtype_text[NUM_CARGO];
char capacity[512];

@ -11,7 +11,6 @@
#include "../animated_tile.h"
#include "../tile_type.h"
#include "../core/alloc_func.hpp"
#include "../core/smallvec_type.hpp"
#include "saveload.h"

@ -27,7 +27,7 @@
#include "../company_base.h"
#include "../disaster_vehicle.h"
#include "../animated_tile.h"
#include "../core/smallvec_type.hpp"
#include "../core/container_func.hpp"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "saveload_internal.h"

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save