mirror of https://github.com/OpenTTD/OpenTTD
Codechange: add concept of ConvertibleThroughBase for strong types
This makes it possible to write templated alternatives for ConvertibleThroughBase which are then available for any (strong) type that implements a base() function In the end making adding new ConvertibleThroughBase types less awkward.pull/13433/head
parent
3e747397f0
commit
55588b052e
|
@ -4,6 +4,7 @@ add_files(
|
||||||
alloc_type.hpp
|
alloc_type.hpp
|
||||||
backup_type.hpp
|
backup_type.hpp
|
||||||
bitmath_func.hpp
|
bitmath_func.hpp
|
||||||
|
convertible_through_base.hpp
|
||||||
endian_func.hpp
|
endian_func.hpp
|
||||||
enum_type.hpp
|
enum_type.hpp
|
||||||
format.hpp
|
format.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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @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 <typename T>
|
||||||
|
concept ConvertibleThroughBase = requires(T const a) {
|
||||||
|
typename T::BaseType;
|
||||||
|
{ a.base() } noexcept -> std::convertible_to<int64_t>;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONVERTIBLE_THROUGH_BASE_HPP */
|
|
@ -11,11 +11,11 @@
|
||||||
#define FORMAT_HPP
|
#define FORMAT_HPP
|
||||||
|
|
||||||
#include "../3rdparty/fmt/format.h"
|
#include "../3rdparty/fmt/format.h"
|
||||||
#include "strong_typedef_type.hpp"
|
#include "convertible_through_base.hpp"
|
||||||
|
|
||||||
template <typename E, typename Char>
|
template <typename E, typename Char> requires std::is_enum_v<E>
|
||||||
struct fmt::formatter<E, Char, std::enable_if_t<std::is_enum<E>::value>> : fmt::formatter<typename std::underlying_type<E>::type> {
|
struct fmt::formatter<E, Char> : fmt::formatter<typename std::underlying_type_t<E>> {
|
||||||
using underlying_type = typename std::underlying_type<E>::type;
|
using underlying_type = typename std::underlying_type_t<E>;
|
||||||
using parent = typename fmt::formatter<underlying_type>;
|
using parent = typename fmt::formatter<underlying_type>;
|
||||||
|
|
||||||
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx)
|
constexpr fmt::format_parse_context::iterator parse(fmt::format_parse_context &ctx)
|
||||||
|
@ -23,14 +23,14 @@ struct fmt::formatter<E, Char, std::enable_if_t<std::is_enum<E>::value>> : fmt::
|
||||||
return parent::parse(ctx);
|
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);
|
return parent::format(underlying_type(e), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char>
|
template <ConvertibleThroughBase T, typename Char>
|
||||||
struct fmt::formatter<T, Char, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value>> : fmt::formatter<typename T::BaseType> {
|
struct fmt::formatter<T, Char> : fmt::formatter<typename T::BaseType> {
|
||||||
using underlying_type = typename T::BaseType;
|
using underlying_type = typename T::BaseType;
|
||||||
using parent = typename fmt::formatter<underlying_type>;
|
using parent = typename fmt::formatter<underlying_type>;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ struct fmt::formatter<T, Char, std::enable_if_t<std::is_base_of<StrongTypedefBas
|
||||||
return parent::parse(ctx);
|
return parent::parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::format_context::iterator format(const T &t, format_context &ctx) const
|
fmt::format_context::iterator format(const T &t, fmt::format_context &ctx) const
|
||||||
{
|
{
|
||||||
return parent::format(t.base(), ctx);
|
return parent::format(t.base(), ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#ifndef MATH_FUNC_HPP
|
#ifndef MATH_FUNC_HPP
|
||||||
#define MATH_FUNC_HPP
|
#define MATH_FUNC_HPP
|
||||||
|
|
||||||
#include "strong_typedef_type.hpp"
|
#include "convertible_through_base.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the absolute value of (scalar) variable.
|
* Returns the absolute value of (scalar) variable.
|
||||||
|
@ -217,8 +217,8 @@ constexpr To ClampTo(From value)
|
||||||
/**
|
/**
|
||||||
* Specialization of ClampTo for #StrongType::Typedef.
|
* Specialization of ClampTo for #StrongType::Typedef.
|
||||||
*/
|
*/
|
||||||
template <typename To, typename From, std::enable_if_t<std::is_base_of<StrongTypedefBase, From>::value, int> = 0>
|
template <typename To>
|
||||||
constexpr To ClampTo(From value)
|
constexpr To ClampTo(ConvertibleThroughBase auto value)
|
||||||
{
|
{
|
||||||
return ClampTo<To>(value.base());
|
return ClampTo<To>(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
|
* @param max The maximum of the interval
|
||||||
* @see IsInsideBS()
|
* @see IsInsideBS()
|
||||||
*/
|
*/
|
||||||
template <typename T, std::enable_if_t<std::disjunction_v<std::is_convertible<T, size_t>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
|
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
|
||||||
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
|
|
||||||
{
|
{
|
||||||
if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
|
return static_cast<size_t>(x - min) < (max - min);
|
||||||
return static_cast<size_t>(x.base() - min) < (max - min);
|
|
||||||
} else {
|
|
||||||
return static_cast<size_t>(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
|
* Type safe swap operation
|
||||||
* @param a variable to swap with b
|
* @param a variable to swap with b
|
||||||
|
|
|
@ -160,7 +160,7 @@ namespace StrongType {
|
||||||
constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
|
constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
|
||||||
|
|
||||||
/* Only allow conversion to BaseType via method. */
|
/* 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(). */
|
/* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */
|
||||||
friend struct Compare;
|
friend struct Compare;
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
#include "../core/enum_type.hpp"
|
#include "../core/enum_type.hpp"
|
||||||
#include "../core/overflowsafe_type.hpp"
|
#include "../core/overflowsafe_type.hpp"
|
||||||
|
|
||||||
struct StrongTypedefBase;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endian-aware buffer adapter that always writes values in little endian order.
|
* Endian-aware buffer adapter that always writes values in little endian order.
|
||||||
* @note This class uses operator overloading (<<, just like streams) for writing
|
* @note This class uses operator overloading (<<, just like streams) for writing
|
||||||
|
@ -50,13 +48,17 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, std::enable_if_t<std::disjunction_v<std::negation<std::is_class<T>>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
|
EndianBufferWriter &operator <<(const ConvertibleThroughBase auto data)
|
||||||
|
{
|
||||||
|
this->Write(data.base());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> requires (!std::is_class_v<T>)
|
||||||
EndianBufferWriter &operator <<(const T data)
|
EndianBufferWriter &operator <<(const T data)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_enum_v<T>) {
|
if constexpr (std::is_enum_v<T>) {
|
||||||
this->Write(to_underlying(data));
|
this->Write(to_underlying(data));
|
||||||
} else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
|
|
||||||
this->Write(data.base());
|
|
||||||
} else {
|
} else {
|
||||||
this->Write(data);
|
this->Write(data);
|
||||||
}
|
}
|
||||||
|
@ -147,13 +149,18 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, std::enable_if_t<std::disjunction_v<std::negation<std::is_class<T>>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
|
template <ConvertibleThroughBase T>
|
||||||
|
EndianBufferReader &operator >>(T &data)
|
||||||
|
{
|
||||||
|
data = T{this->Read<typename T::BaseType>()};
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> requires (!std::is_class_v<T>)
|
||||||
EndianBufferReader &operator >>(T &data)
|
EndianBufferReader &operator >>(T &data)
|
||||||
{
|
{
|
||||||
if constexpr (std::is_enum_v<T>) {
|
if constexpr (std::is_enum_v<T>) {
|
||||||
data = static_cast<T>(this->Read<std::underlying_type_t<T>>());
|
data = static_cast<T>(this->Read<std::underlying_type_t<T>>());
|
||||||
} else if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
|
|
||||||
data = T{this->Read<typename T::BaseType>()};
|
|
||||||
} else {
|
} else {
|
||||||
data = this->Read<T>();
|
data = this->Read<T>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1949,8 +1949,7 @@ static bool OrderConditionCompare(OrderConditionComparator occ, int variable, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
static bool OrderConditionCompare(OrderConditionComparator occ, ConvertibleThroughBase auto variable, int value)
|
||||||
static bool OrderConditionCompare(OrderConditionComparator occ, T variable, int value)
|
|
||||||
{
|
{
|
||||||
return OrderConditionCompare(occ, variable.base(), value);
|
return OrderConditionCompare(occ, variable.base(), value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "string_type.h"
|
#include "string_type.h"
|
||||||
#include "gfx_type.h"
|
#include "gfx_type.h"
|
||||||
#include "core/bitmath_func.hpp"
|
#include "core/bitmath_func.hpp"
|
||||||
#include "core/strong_typedef_type.hpp"
|
#include "core/convertible_through_base.hpp"
|
||||||
#include "vehicle_type.h"
|
#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 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);
|
void SetDParamMaxDigits(size_t n, uint count, FontSize size = FS_NORMAL);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void SetDParam(size_t n, ConvertibleThroughBase auto v)
|
||||||
void SetDParam(size_t n, T v)
|
|
||||||
{
|
{
|
||||||
SetDParam(n, v.base());
|
SetDParam(n, v.base());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void SetDParamMaxValue(size_t n, ConvertibleThroughBase auto max_value, uint min_count = 0, FontSize size = FS_NORMAL)
|
||||||
void SetDParamMaxValue(size_t n, T max_value, uint min_count = 0, FontSize size = FS_NORMAL)
|
|
||||||
{
|
{
|
||||||
SetDParamMaxValue(n, max_value.base(), min_count, size);
|
SetDParamMaxValue(n, max_value.base(), min_count, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,8 +167,7 @@ public:
|
||||||
this->parameters[n].data = v;
|
this->parameters[n].data = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void SetParam(size_t n, ConvertibleThroughBase auto v)
|
||||||
void SetParam(size_t n, T v)
|
|
||||||
{
|
{
|
||||||
SetParam(n, v.base());
|
SetParam(n, v.base());
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,15 @@
|
||||||
|
|
||||||
#include "window_type.h"
|
#include "window_type.h"
|
||||||
#include "company_type.h"
|
#include "company_type.h"
|
||||||
|
#include "core/convertible_through_base.hpp"
|
||||||
#include "core/geometry_type.hpp"
|
#include "core/geometry_type.hpp"
|
||||||
#include "core/strong_typedef_type.hpp"
|
|
||||||
|
|
||||||
Window *FindWindowById(WindowClass cls, WindowNumber number);
|
Window *FindWindowById(WindowClass cls, WindowNumber number);
|
||||||
Window *FindWindowByClass(WindowClass cls);
|
Window *FindWindowByClass(WindowClass cls);
|
||||||
Window *GetMainWindow();
|
Window *GetMainWindow();
|
||||||
void ChangeWindowOwner(Owner old_owner, Owner new_owner);
|
void ChangeWindowOwner(Owner old_owner, Owner new_owner);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
Window *FindWindowById(WindowClass cls, ConvertibleThroughBase auto number)
|
||||||
Window *FindWindowById(WindowClass cls, T number)
|
|
||||||
{
|
{
|
||||||
return FindWindowById(cls, number.base());
|
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 InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool gui_scope = false);
|
||||||
void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false);
|
void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void InvalidateWindowData(WindowClass cls, ConvertibleThroughBase auto number, int data = 0, bool gui_scope = false)
|
||||||
void InvalidateWindowData(WindowClass cls, T number, int data = 0, bool gui_scope = false)
|
|
||||||
{
|
{
|
||||||
InvalidateWindowData(cls, number.base(), data, gui_scope);
|
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 SetWindowDirty(WindowClass cls, WindowNumber number);
|
||||||
void SetWindowClassesDirty(WindowClass cls);
|
void SetWindowClassesDirty(WindowClass cls);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void SetWindowDirty(WindowClass cls, ConvertibleThroughBase auto number)
|
||||||
void SetWindowDirty(WindowClass cls, T number)
|
|
||||||
{
|
{
|
||||||
SetWindowDirty(cls, number.base());
|
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 CloseWindowById(WindowClass cls, WindowNumber number, bool force = true, int data = 0);
|
||||||
void CloseWindowByClass(WindowClass cls, int data = 0);
|
void CloseWindowByClass(WindowClass cls, int data = 0);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void CloseWindowById(WindowClass cls, ConvertibleThroughBase auto number, bool force = true, int data = 0)
|
||||||
void CloseWindowById(WindowClass cls, T number, bool force = true, int data = 0)
|
|
||||||
{
|
{
|
||||||
CloseWindowById(cls, number.base(), force, data);
|
CloseWindowById(cls, number.base(), force, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,8 +348,7 @@ public:
|
||||||
void CreateNestedTree();
|
void CreateNestedTree();
|
||||||
void FinishInitNested(WindowNumber window_number = 0);
|
void FinishInitNested(WindowNumber window_number = 0);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
void FinishInitNested(ConvertibleThroughBase auto number)
|
||||||
void FinishInitNested(T number)
|
|
||||||
{
|
{
|
||||||
this->FinishInitNested(number.base());
|
this->FinishInitNested(number.base());
|
||||||
}
|
}
|
||||||
|
@ -996,8 +995,7 @@ public:
|
||||||
Window *BringWindowToFrontById(WindowClass cls, WindowNumber number);
|
Window *BringWindowToFrontById(WindowClass cls, WindowNumber number);
|
||||||
Window *FindWindowFromPt(int x, int y);
|
Window *FindWindowFromPt(int x, int y);
|
||||||
|
|
||||||
template <typename T, std::enable_if_t<std::is_base_of<StrongTypedefBase, T>::value, int> = 0>
|
Window *BringWindowToFrontById(WindowClass cls, ConvertibleThroughBase auto number)
|
||||||
Window *BringWindowToFrontById(WindowClass cls, T number)
|
|
||||||
{
|
{
|
||||||
return BringWindowToFrontById(cls, number.base());
|
return BringWindowToFrontById(cls, number.base());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue