diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6344bd2ea8..b063cbba76 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -4,6 +4,7 @@ add_files( alloc_type.hpp backup_type.hpp bitmath_func.hpp + convertible_through_base.hpp endian_func.hpp enum_type.hpp format.hpp diff --git a/src/core/convertible_through_base.hpp b/src/core/convertible_through_base.hpp new file mode 100644 index 0000000000..0b22f35cd5 --- /dev/null +++ b/src/core/convertible_through_base.hpp @@ -0,0 +1,24 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file convertible_through_base.hpp Concept for unifying the convert through 'base()' behaviour of several 'strong' types. */ + +#ifndef CONVERTIBLE_THROUGH_BASE_HPP +#define CONVERTIBLE_THROUGH_BASE_HPP + +/** + * A type is considered 'convertible through base()' when it has a 'base()' + * function that returns something that can be converted to int64_t. + * @tparam T The type under consideration. + */ +template +concept ConvertibleThroughBase = requires(T const a) { + typename T::BaseType; + { a.base() } noexcept -> std::convertible_to; +}; + +#endif /* CONVERTIBLE_THROUGH_BASE_HPP */ diff --git a/src/core/format.hpp b/src/core/format.hpp index d0267e4394..a00dab44ea 100644 --- a/src/core/format.hpp +++ b/src/core/format.hpp @@ -11,11 +11,11 @@ #define FORMAT_HPP #include "../3rdparty/fmt/format.h" -#include "strong_typedef_type.hpp" +#include "convertible_through_base.hpp" -template -struct fmt::formatter::value>> : fmt::formatter::type> { - using underlying_type = typename std::underlying_type::type; +template requires std::is_enum_v +struct fmt::formatter : fmt::formatter> { + using underlying_type = typename std::underlying_type_t; using parent = typename fmt::formatter; constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx) @@ -23,14 +23,14 @@ struct fmt::formatter::value>> : fmt:: return parent::parse(ctx); } - fmt::format_context::iterator format(const E &e, format_context &ctx) const + fmt::format_context::iterator format(const E &e, fmt::format_context &ctx) const { return parent::format(underlying_type(e), ctx); } }; -template -struct fmt::formatter::value>> : fmt::formatter { +template +struct fmt::formatter : fmt::formatter { using underlying_type = typename T::BaseType; using parent = typename fmt::formatter; @@ -39,7 +39,7 @@ struct fmt::formatter::value, int> = 0> -constexpr To ClampTo(From value) +template +constexpr To ClampTo(ConvertibleThroughBase auto value) { return ClampTo(value.base()); } @@ -264,16 +264,13 @@ constexpr bool IsInsideBS(const T x, const size_t base, const size_t size) * @param max The maximum of the interval * @see IsInsideBS() */ -template , std::is_base_of>, int> = 0> -constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept +constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept { - if constexpr (std::is_base_of_v) { - return static_cast(x.base() - min) < (max - min); - } else { - return static_cast(x - min) < (max - min); - } + return static_cast(x - min) < (max - min); } +constexpr bool IsInsideMM(const ConvertibleThroughBase auto x, const size_t min, const size_t max) noexcept { return IsInsideMM(x.base(), min, max); } + /** * Type safe swap operation * @param a variable to swap with b diff --git a/src/core/strong_typedef_type.hpp b/src/core/strong_typedef_type.hpp index 2b929430b6..fe5eda2127 100644 --- a/src/core/strong_typedef_type.hpp +++ b/src/core/strong_typedef_type.hpp @@ -160,7 +160,7 @@ namespace StrongType { constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; } /* Only allow conversion to BaseType via method. */ - constexpr TBaseType base() const { return this->value; } + constexpr TBaseType base() const noexcept { return this->value; } /* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */ friend struct Compare; diff --git a/src/misc/endian_buffer.hpp b/src/misc/endian_buffer.hpp index ba59d4fd14..f8ee5ade64 100644 --- a/src/misc/endian_buffer.hpp +++ b/src/misc/endian_buffer.hpp @@ -15,8 +15,6 @@ #include "../core/enum_type.hpp" #include "../core/overflowsafe_type.hpp" -struct StrongTypedefBase; - /** * Endian-aware buffer adapter that always writes values in little endian order. * @note This class uses operator overloading (<<, just like streams) for writing @@ -50,13 +48,17 @@ public: return *this; } - template >, std::is_base_of>, int> = 0> + EndianBufferWriter &operator <<(const ConvertibleThroughBase auto data) + { + this->Write(data.base()); + return *this; + } + + template requires (!std::is_class_v) EndianBufferWriter &operator <<(const T data) { if constexpr (std::is_enum_v) { this->Write(to_underlying(data)); - } else if constexpr (std::is_base_of_v) { - this->Write(data.base()); } else { this->Write(data); } @@ -147,13 +149,18 @@ public: return *this; } - template >, std::is_base_of>, int> = 0> + template + EndianBufferReader &operator >>(T &data) + { + data = T{this->Read()}; + return *this; + } + + template requires (!std::is_class_v) EndianBufferReader &operator >>(T &data) { if constexpr (std::is_enum_v) { data = static_cast(this->Read>()); - } else if constexpr (std::is_base_of_v) { - data = T{this->Read()}; } else { data = this->Read(); } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 9f5befb6ea..b9996cbac4 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1949,8 +1949,7 @@ static bool OrderConditionCompare(OrderConditionComparator occ, int variable, in } } -template ::value, int> = 0> -static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value) +static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value) { return OrderConditionCompare(occ, variable.base(), value); } diff --git a/src/strings_func.h b/src/strings_func.h index 6a43472db1..23a5eb3ce8 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -14,7 +14,7 @@ #include "string_type.h" #include "gfx_type.h" #include "core/bitmath_func.hpp" -#include "core/strong_typedef_type.hpp" +#include "core/convertible_through_base.hpp" #include "vehicle_type.h" /** @@ -83,14 +83,12 @@ void SetDParam(size_t n, uint64_t v); void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count = 0, FontSize size = FS_NORMAL); void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL); -template ::value, int> = 0> -void SetDParam(size_t n, T v) +void SetDParam(size_t n, ConvertibleThroughBase auto v) { SetDParam(n, v.base()); } -template ::value, int> = 0> -void SetDParamMaxValue(size_t n, T max_value, uint min_count = 0, FontSize size = FS_NORMAL) +void SetDParamMaxValue(size_t n, ConvertibleThroughBase auto max_value, uint min_count = 0, FontSize size = FS_NORMAL) { SetDParamMaxValue(n, max_value.base(), min_count, size); } diff --git a/src/strings_internal.h b/src/strings_internal.h index b710be23e5..9462a1c984 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -167,8 +167,7 @@ public: this->parameters[n].data = v; } - template ::value, int> = 0> - void SetParam(size_t n, T v) + void SetParam(size_t n, ConvertibleThroughBase auto v) { SetParam(n, v.base()); } diff --git a/src/window_func.h b/src/window_func.h index 8dfbe69bae..2bd314db99 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -12,16 +12,15 @@ #include "window_type.h" #include "company_type.h" +#include "core/convertible_through_base.hpp" #include "core/geometry_type.hpp" -#include "core/strong_typedef_type.hpp" Window *FindWindowById(WindowClass cls, WindowNumber number); Window *FindWindowByClass(WindowClass cls); Window *GetMainWindow(); void ChangeWindowOwner(Owner old_owner, Owner new_owner); -template ::value, int> = 0> -Window *FindWindowById(WindowClass cls, T number) +Window *FindWindowById(WindowClass cls, ConvertibleThroughBase auto number) { return FindWindowById(cls, number.base()); } @@ -44,8 +43,7 @@ void InputLoop(); void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool gui_scope = false); void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false); -template ::value, int> = 0> -void InvalidateWindowData(WindowClass cls, T number, int data = 0, bool gui_scope = false) +void InvalidateWindowData(WindowClass cls, ConvertibleThroughBase auto number, int data = 0, bool gui_scope = false) { InvalidateWindowData(cls, number.base(), data, gui_scope); } @@ -67,8 +65,7 @@ void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_ void SetWindowDirty(WindowClass cls, WindowNumber number); void SetWindowClassesDirty(WindowClass cls); -template ::value, int> = 0> -void SetWindowDirty(WindowClass cls, T number) +void SetWindowDirty(WindowClass cls, ConvertibleThroughBase auto number) { SetWindowDirty(cls, number.base()); } @@ -76,8 +73,7 @@ void SetWindowDirty(WindowClass cls, T number) void CloseWindowById(WindowClass cls, WindowNumber number, bool force = true, int data = 0); void CloseWindowByClass(WindowClass cls, int data = 0); -template ::value, int> = 0> -void CloseWindowById(WindowClass cls, T number, bool force = true, int data = 0) +void CloseWindowById(WindowClass cls, ConvertibleThroughBase auto number, bool force = true, int data = 0) { CloseWindowById(cls, number.base(), force, data); } diff --git a/src/window_gui.h b/src/window_gui.h index 11722365a6..5a47a21517 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -348,8 +348,7 @@ public: void CreateNestedTree(); void FinishInitNested(WindowNumber window_number = 0); - template ::value, int> = 0> - void FinishInitNested(T number) + void FinishInitNested(ConvertibleThroughBase auto number) { this->FinishInitNested(number.base()); } @@ -996,8 +995,7 @@ public: Window *BringWindowToFrontById(WindowClass cls, WindowNumber number); Window *FindWindowFromPt(int x, int y); -template ::value, int> = 0> -Window *BringWindowToFrontById(WindowClass cls, T number) +Window *BringWindowToFrontById(WindowClass cls, ConvertibleThroughBase auto number) { return BringWindowToFrontById(cls, number.base()); }