Update to 14.0-beta1
This commit is contained in:
@@ -3,11 +3,11 @@ add_files(
|
||||
alloc_func.hpp
|
||||
alloc_type.hpp
|
||||
backup_type.hpp
|
||||
bitmath_func.cpp
|
||||
bitmath_func.hpp
|
||||
endian_func.hpp
|
||||
endian_type.hpp
|
||||
enum_type.hpp
|
||||
format.hpp
|
||||
geometry_func.cpp
|
||||
geometry_func.hpp
|
||||
geometry_type.hpp
|
||||
@@ -22,11 +22,7 @@ add_files(
|
||||
pool_type.hpp
|
||||
random_func.cpp
|
||||
random_func.hpp
|
||||
smallmap_type.hpp
|
||||
smallmatrix_type.hpp
|
||||
smallstack_type.hpp
|
||||
smallvec_type.hpp
|
||||
span_type.hpp
|
||||
string_compare_type.hpp
|
||||
container_func.hpp
|
||||
strong_typedef_type.hpp
|
||||
)
|
||||
|
||||
@@ -9,22 +9,24 @@
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
#include "../error_func.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Function to exit with an error message after malloc() or calloc() have failed
|
||||
* @param size number of bytes we tried to allocate
|
||||
*/
|
||||
void NORETURN MallocError(size_t size)
|
||||
[[noreturn]] void MallocError(size_t size)
|
||||
{
|
||||
error("Out of memory. Cannot allocate " PRINTF_SIZE " bytes", size);
|
||||
FatalError("Out of memory. Cannot allocate {} bytes", size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to exit with an error message after realloc() have failed
|
||||
* @param size number of bytes we tried to allocate
|
||||
*/
|
||||
void NORETURN ReallocError(size_t size)
|
||||
[[noreturn]] void ReallocError(size_t size)
|
||||
{
|
||||
error("Out of memory. Cannot reallocate " PRINTF_SIZE " bytes", size);
|
||||
FatalError("Out of memory. Cannot reallocate {} bytes", size);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* binary needlessly large.
|
||||
*/
|
||||
|
||||
void NORETURN MallocError(size_t size);
|
||||
void NORETURN ReallocError(size_t size);
|
||||
[[noreturn]] void MallocError(size_t size);
|
||||
[[noreturn]] void ReallocError(size_t size);
|
||||
|
||||
/**
|
||||
* Checks whether allocating memory would overflow size_t.
|
||||
@@ -26,7 +26,7 @@ void NORETURN ReallocError(size_t size);
|
||||
* @param element_size Size of the structure to allocate.
|
||||
* @param num_elements Number of elements to allocate.
|
||||
*/
|
||||
static inline void CheckAllocationConstraints(size_t element_size, size_t num_elements)
|
||||
inline void CheckAllocationConstraints(size_t element_size, size_t num_elements)
|
||||
{
|
||||
if (num_elements > SIZE_MAX / element_size) MallocError(SIZE_MAX);
|
||||
}
|
||||
@@ -38,7 +38,7 @@ static inline void CheckAllocationConstraints(size_t element_size, size_t num_el
|
||||
* @param num_elements Number of elements to allocate.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void CheckAllocationConstraints(size_t num_elements)
|
||||
inline void CheckAllocationConstraints(size_t num_elements)
|
||||
{
|
||||
CheckAllocationConstraints(sizeof(T), num_elements);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ static inline void CheckAllocationConstraints(size_t num_elements)
|
||||
* @return nullptr when num_elements == 0, non-nullptr otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *MallocT(size_t num_elements)
|
||||
inline T *MallocT(size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
@@ -82,7 +82,7 @@ static inline T *MallocT(size_t num_elements)
|
||||
* @return nullptr when num_elements == 0, non-nullptr otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *CallocT(size_t num_elements)
|
||||
inline T *CallocT(size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
@@ -108,7 +108,7 @@ static inline T *CallocT(size_t num_elements)
|
||||
* @return nullptr when num_elements == 0, non-nullptr otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *ReallocT(T *t_ptr, size_t num_elements)
|
||||
inline T *ReallocT(T *t_ptr, size_t num_elements)
|
||||
{
|
||||
/*
|
||||
* MorphOS cannot handle 0 elements allocations, or rather that always
|
||||
@@ -128,9 +128,4 @@ static inline T *ReallocT(T *t_ptr, size_t num_elements)
|
||||
return t_ptr;
|
||||
}
|
||||
|
||||
/** alloca() has to be called in the parent function, so define AllocaM() as a macro */
|
||||
#define AllocaM(T, num_elements) \
|
||||
(CheckAllocationConstraints<T>(num_elements), \
|
||||
(T*)alloca((num_elements) * sizeof(T)))
|
||||
|
||||
#endif /* ALLOC_FUNC_HPP */
|
||||
|
||||
@@ -86,7 +86,7 @@ class ZeroedMemoryAllocator
|
||||
{
|
||||
public:
|
||||
ZeroedMemoryAllocator() {}
|
||||
virtual ~ZeroedMemoryAllocator() {}
|
||||
virtual ~ZeroedMemoryAllocator() = default;
|
||||
|
||||
/**
|
||||
* Memory allocator for a single class instance.
|
||||
|
||||
@@ -144,4 +144,46 @@ private:
|
||||
const int line;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class to backup a specific variable and restore it upon destruction of this object to prevent
|
||||
* stack values going out of scope before resetting the global to its original value. Contrary to
|
||||
* #Backup this restores the variable automatically and there is no manual option to restore.
|
||||
*/
|
||||
template <typename T>
|
||||
struct AutoRestoreBackup {
|
||||
/*
|
||||
* There is explicitly no only original constructor version, as that would make it possible
|
||||
* for the new value to go out of scope before this object goes out of scope, thus defeating
|
||||
* the whole goal and reason for existing of this object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Backup variable and switch to new value.
|
||||
* @param original Variable to backup.
|
||||
* @param new_value New value for variable.
|
||||
*/
|
||||
AutoRestoreBackup(T &original, T new_value) : original(original), original_value(original)
|
||||
{
|
||||
original = new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the variable upon object destruction.
|
||||
*/
|
||||
~AutoRestoreBackup()
|
||||
{
|
||||
this->original = this->original_value;
|
||||
}
|
||||
|
||||
private:
|
||||
T &original;
|
||||
T original_value;
|
||||
|
||||
/* Prevent copy, assignment and allocation on stack. */
|
||||
AutoRestoreBackup(const AutoRestoreBackup&) = delete;
|
||||
AutoRestoreBackup& operator=(AutoRestoreBackup&) = delete;
|
||||
static void *operator new(std::size_t) = delete;
|
||||
static void *operator new[](std::size_t) = delete;
|
||||
};
|
||||
|
||||
#endif /* BACKUP_TYPE_HPP */
|
||||
|
||||
@@ -1,80 +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 bitmath_func.cpp Functions related to bit mathematics. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "bitmath_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
const uint8 _ffb_64[64] = {
|
||||
0, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
5, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the first set bit in a 64 bit variable.
|
||||
*
|
||||
* This algorithm is a static implementation of a log
|
||||
* congruence search algorithm. It checks the first half
|
||||
* if there is a bit set search there further. And this
|
||||
* way further. If no bit is set return 0.
|
||||
*
|
||||
* @param x The value to search
|
||||
* @return The position of the first bit set
|
||||
*/
|
||||
uint8 FindFirstBit(uint64 x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
/* The macro FIND_FIRST_BIT is better to use when your x is
|
||||
not more than 128. */
|
||||
|
||||
uint8 pos = 0;
|
||||
|
||||
if ((x & 0xffffffffULL) == 0) { x >>= 32; pos += 32; }
|
||||
if ((x & 0x0000ffffULL) == 0) { x >>= 16; pos += 16; }
|
||||
if ((x & 0x000000ffULL) == 0) { x >>= 8; pos += 8; }
|
||||
if ((x & 0x0000000fULL) == 0) { x >>= 4; pos += 4; }
|
||||
if ((x & 0x00000003ULL) == 0) { x >>= 2; pos += 2; }
|
||||
if ((x & 0x00000001ULL) == 0) { pos += 1; }
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the last set bit in a 64 bit variable.
|
||||
*
|
||||
* This algorithm is a static implementation of a log
|
||||
* congruence search algorithm. It checks the second half
|
||||
* if there is a bit set search there further. And this
|
||||
* way further. If no bit is set return 0.
|
||||
*
|
||||
* @param x The value to search
|
||||
* @return The position of the last bit set
|
||||
*/
|
||||
uint8 FindLastBit(uint64 x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
|
||||
uint8 pos = 0;
|
||||
|
||||
if ((x & 0xffffffff00000000ULL) != 0) { x >>= 32; pos += 32; }
|
||||
if ((x & 0x00000000ffff0000ULL) != 0) { x >>= 16; pos += 16; }
|
||||
if ((x & 0x000000000000ff00ULL) != 0) { x >>= 8; pos += 8; }
|
||||
if ((x & 0x00000000000000f0ULL) != 0) { x >>= 4; pos += 4; }
|
||||
if ((x & 0x000000000000000cULL) != 0) { x >>= 2; pos += 2; }
|
||||
if ((x & 0x0000000000000002ULL) != 0) { pos += 1; }
|
||||
|
||||
return pos;
|
||||
}
|
||||
@@ -29,7 +29,7 @@
|
||||
* @return The selected bits, aligned to a LSB.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline uint GB(const T x, const uint8 s, const uint8 n)
|
||||
debug_inline constexpr static uint GB(const T x, const uint8_t s, const uint8_t n)
|
||||
{
|
||||
return (x >> s) & (((T)1U << n) - 1);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ static inline uint GB(const T x, const uint8 s, const uint8 n)
|
||||
* @return The new value of \a x
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
static inline T SB(T &x, const uint8 s, const uint8 n, const U d)
|
||||
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
|
||||
{
|
||||
x &= (T)(~((((T)1U << n) - 1) << s));
|
||||
x |= (T)(d << s);
|
||||
@@ -80,7 +80,7 @@ static inline T SB(T &x, const uint8 s, const uint8 n, const U d)
|
||||
* @return The new value of \a x
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
static inline T AB(T &x, const uint8 s, const uint8 n, const U i)
|
||||
constexpr T AB(T &x, const uint8_t s, const uint8_t n, const U i)
|
||||
{
|
||||
const T mask = ((((T)1U << n) - 1) << s);
|
||||
x = (T)((x & ~mask) | ((x + (i << s)) & mask));
|
||||
@@ -100,7 +100,7 @@ static inline T AB(T &x, const uint8 s, const uint8 n, const U i)
|
||||
* @return True if the bit is set, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasBit(const T x, const uint8 y)
|
||||
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
|
||||
{
|
||||
return (x & ((T)1U << y)) != 0;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ static inline bool HasBit(const T x, const uint8 y)
|
||||
* @return The new value of the old value with the bit set
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T SetBit(T &x, const uint8 y)
|
||||
constexpr T SetBit(T &x, const uint8_t y)
|
||||
{
|
||||
return x = (T)(x | ((T)1U << y));
|
||||
}
|
||||
@@ -148,7 +148,7 @@ static inline T SetBit(T &x, const uint8 y)
|
||||
* @return The new value of the old value with the bit cleared
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ClrBit(T &x, const uint8 y)
|
||||
constexpr T ClrBit(T &x, const uint8_t y)
|
||||
{
|
||||
return x = (T)(x & ~((T)1U << y));
|
||||
}
|
||||
@@ -178,52 +178,44 @@ static inline T ClrBit(T &x, const uint8 y)
|
||||
* @return The new value of the old value with the bit toggled
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ToggleBit(T &x, const uint8 y)
|
||||
constexpr T ToggleBit(T &x, const uint8_t y)
|
||||
{
|
||||
return x = (T)(x ^ ((T)1U << y));
|
||||
}
|
||||
|
||||
|
||||
/** Lookup table to check which bit is set in a 6 bit variable */
|
||||
extern const uint8 _ffb_64[64];
|
||||
|
||||
/**
|
||||
* Returns the first non-zero bit in a 6-bit value (from right).
|
||||
* Search the first set bit in a value.
|
||||
* When no bit is set, it returns 0.
|
||||
*
|
||||
* Returns the position of the first bit that is not zero, counted from the
|
||||
* LSB. Ie, 110100 returns 2, 000001 returns 0, etc. When x == 0 returns
|
||||
* 0.
|
||||
*
|
||||
* @param x The 6-bit value to check the first zero-bit
|
||||
* @return The first position of a bit started from the LSB or 0 if x is 0.
|
||||
* @param x The value to search.
|
||||
* @return The position of the first bit set.
|
||||
*/
|
||||
#define FIND_FIRST_BIT(x) _ffb_64[(x)]
|
||||
|
||||
/**
|
||||
* Finds the position of the first non-zero bit in an integer.
|
||||
*
|
||||
* This function returns the position of the first bit set in the
|
||||
* integer. It does only check the bits of the bitmask
|
||||
* 0x3F3F (0011111100111111) and checks only the
|
||||
* bits of the bitmask 0x3F00 if and only if the
|
||||
* lower part 0x00FF is 0. This results the bits at 0x00C0 must
|
||||
* be also zero to check the bits at 0x3F00.
|
||||
*
|
||||
* @param value The value to check the first bits
|
||||
* @return The position of the first bit which is set
|
||||
* @see FIND_FIRST_BIT
|
||||
*/
|
||||
static inline uint8 FindFirstBit2x64(const int value)
|
||||
template <typename T>
|
||||
constexpr uint8_t FindFirstBit(T x)
|
||||
{
|
||||
if ((value & 0xFF) == 0) {
|
||||
return FIND_FIRST_BIT((value >> 8) & 0x3F) + 8;
|
||||
if (x == 0) return 0;
|
||||
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return std::countr_zero<std::underlying_type_t<T>>(x);
|
||||
} else {
|
||||
return FIND_FIRST_BIT(value & 0x3F);
|
||||
return std::countr_zero(x);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 FindFirstBit(uint64 x);
|
||||
uint8 FindLastBit(uint64 x);
|
||||
/**
|
||||
* Search the last set bit in a value.
|
||||
* When no bit is set, it returns 0.
|
||||
*
|
||||
* @param x The value to search.
|
||||
* @return The position of the last bit set.
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr uint8_t FindLastBit(T x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
|
||||
return std::numeric_limits<T>::digits - std::countl_zero(x) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the first bit in an integer.
|
||||
@@ -236,7 +228,7 @@ uint8 FindLastBit(uint64 x);
|
||||
* @return The new value with the first bit cleared
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T KillFirstBit(T value)
|
||||
constexpr T KillFirstBit(T value)
|
||||
{
|
||||
return value &= (T)(value - 1);
|
||||
}
|
||||
@@ -248,20 +240,13 @@ static inline T KillFirstBit(T value)
|
||||
* @return the number of bits.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline uint CountBits(T value)
|
||||
constexpr uint CountBits(T value)
|
||||
{
|
||||
uint num;
|
||||
|
||||
/* This loop is only called once for every bit set by clearing the lowest
|
||||
* bit in each loop. The number of bits is therefore equal to the number of
|
||||
* times the loop was called. It was found at the following website:
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html */
|
||||
|
||||
for (num = 0; value != 0; num++) {
|
||||
value &= (T)(value - 1);
|
||||
if constexpr (std::is_enum_v<T>) {
|
||||
return std::popcount<std::underlying_type_t<T>>(value);
|
||||
} else {
|
||||
return std::popcount(value);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,7 +256,7 @@ static inline uint CountBits(T value)
|
||||
* @return does \a value have exactly 1 bit set?
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasExactlyOneBit(T value)
|
||||
constexpr bool HasExactlyOneBit(T value)
|
||||
{
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
@@ -283,48 +268,16 @@ static inline bool HasExactlyOneBit(T value)
|
||||
* @return does \a value have at most 1 bit set?
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool HasAtMostOneBit(T value)
|
||||
constexpr bool HasAtMostOneBit(T value)
|
||||
{
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ROtate \a x Left by \a n
|
||||
*
|
||||
* @note Assumes a byte has 8 bits
|
||||
* @param x The value which we want to rotate
|
||||
* @param n The number how many we want to rotate
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @return A bit rotated number
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ROL(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x << n | x >> (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
/**
|
||||
* ROtate \a x Right by \a n
|
||||
*
|
||||
* @note Assumes a byte has 8 bits
|
||||
* @param x The value which we want to rotate
|
||||
* @param n The number how many we want to rotate
|
||||
* @pre n < sizeof(T) * 8
|
||||
* @return A bit rotated number
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T ROR(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x >> n | x << (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable ensemble of each set bit in a value.
|
||||
* @tparam Tbitpos Type of the position variable.
|
||||
* @tparam Tbitset Type of the bitset value.
|
||||
*/
|
||||
*/
|
||||
template <typename Tbitpos = uint, typename Tbitset = uint>
|
||||
struct SetBitIterator {
|
||||
struct Iterator {
|
||||
@@ -341,7 +294,7 @@ struct SetBitIterator {
|
||||
|
||||
bool operator==(const Iterator &other) const
|
||||
{
|
||||
return this->bitset == other.bitset && (this->bitset == 0 || this->bitpos == other.bitpos);
|
||||
return this->bitset == other.bitset;
|
||||
}
|
||||
bool operator!=(const Iterator &other) const { return !(*this == other); }
|
||||
Tbitpos operator*() const { return this->bitpos; }
|
||||
@@ -352,12 +305,14 @@ struct SetBitIterator {
|
||||
Tbitpos bitpos;
|
||||
void Validate()
|
||||
{
|
||||
while (this->bitset != 0 && (this->bitset & 1) == 0) this->Next();
|
||||
if (this->bitset != 0) {
|
||||
typename std::make_unsigned<Tbitset>::type unsigned_value = this->bitset;
|
||||
this->bitpos = static_cast<Tbitpos>(FindFirstBit(unsigned_value));
|
||||
}
|
||||
}
|
||||
void Next()
|
||||
{
|
||||
this->bitset = static_cast<Tbitset>(this->bitset >> 1);
|
||||
this->bitpos++;
|
||||
this->bitset = KillFirstBit(this->bitset);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -373,10 +328,10 @@ private:
|
||||
#if defined(__APPLE__)
|
||||
/* Make endian swapping use Apple's macros to increase speed
|
||||
* (since it will use hardware swapping if available).
|
||||
* Even though they should return uint16 and uint32, we get
|
||||
* Even though they should return uint16_t and uint32_t, we get
|
||||
* warnings if we don't cast those (why?) */
|
||||
# define BSWAP32(x) (static_cast<uint32>(CFSwapInt32(x)))
|
||||
# define BSWAP16(x) (static_cast<uint16>(CFSwapInt16(x)))
|
||||
# define BSWAP32(x) (static_cast<uint32_t>(CFSwapInt32(x)))
|
||||
# define BSWAP16(x) (static_cast<uint16_t>(CFSwapInt16(x)))
|
||||
#elif defined(_MSC_VER)
|
||||
/* MSVC has intrinsics for swapping, resulting in faster code */
|
||||
# define BSWAP32(x) (_byteswap_ulong(x))
|
||||
@@ -387,11 +342,11 @@ private:
|
||||
* @param x the variable to bitswap
|
||||
* @return the bitswapped value.
|
||||
*/
|
||||
static inline uint32 BSWAP32(uint32 x)
|
||||
static inline uint32_t BSWAP32(uint32_t x)
|
||||
{
|
||||
#if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ >= 3))
|
||||
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
||||
return static_cast<uint32>(__builtin_bswap32(static_cast<int32>(x)));
|
||||
return static_cast<uint32_t>(__builtin_bswap32(static_cast<int32_t>(x)));
|
||||
#else
|
||||
return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000);
|
||||
#endif /* defined(__GNUC__) */
|
||||
@@ -402,7 +357,7 @@ private:
|
||||
* @param x the variable to bitswap
|
||||
* @return the bitswapped value.
|
||||
*/
|
||||
static inline uint16 BSWAP16(uint16 x)
|
||||
static inline uint16_t BSWAP16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
@@ -5,48 +5,45 @@
|
||||
* 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. */
|
||||
/** @file container_func.hpp Some simple functions to help with accessing containers. */
|
||||
|
||||
#ifndef SMALLVEC_TYPE_HPP
|
||||
#define SMALLVEC_TYPE_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
#include <vector>
|
||||
#ifndef CONTAINER_FUNC_HPP
|
||||
#define CONTAINER_FUNC_HPP
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 vec A reference to the vector to be extended
|
||||
* @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 T>
|
||||
inline bool include(std::vector<T>& vec, const T &item)
|
||||
template <typename Container>
|
||||
inline bool include(Container &container, typename Container::const_reference &item)
|
||||
{
|
||||
const bool is_member = std::find(vec.begin(), vec.end(), item) != vec.end();
|
||||
if (!is_member) vec.emplace_back(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
|
||||
* 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 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 T>
|
||||
int find_index(std::vector<T> const& vec, T const& item)
|
||||
template <typename Container>
|
||||
int find_index(Container const &container, typename Container::const_reference item)
|
||||
{
|
||||
auto const it = std::find(vec.begin(), vec.end(), item);
|
||||
if (it != vec.end()) return it - vec.begin();
|
||||
auto const it = std::find(container.begin(), container.end(), item);
|
||||
if (it != container.end()) return std::distance(container.begin(), it);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* SMALLVEC_TYPE_HPP */
|
||||
#endif /* CONTAINER_FUNC_HPP */
|
||||
@@ -38,18 +38,4 @@
|
||||
# define TO_LE32X(x) (x)
|
||||
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
|
||||
|
||||
static inline uint16 ReadLE16Aligned(const void *x)
|
||||
{
|
||||
return FROM_LE16(*(const uint16*)x);
|
||||
}
|
||||
|
||||
static inline uint16 ReadLE16Unaligned(const void *x)
|
||||
{
|
||||
#if OTTD_ALIGNMENT == 1
|
||||
return ((const byte*)x)[0] | ((const byte*)x)[1] << 8;
|
||||
#else
|
||||
return FROM_LE16(*(const uint16*)x);
|
||||
#endif /* OTTD_ALIGNMENT == 1 */
|
||||
}
|
||||
|
||||
#endif /* ENDIAN_FUNC_HPP */
|
||||
|
||||
@@ -10,14 +10,6 @@
|
||||
#ifndef ENDIAN_TYPE_HPP
|
||||
#define ENDIAN_TYPE_HPP
|
||||
|
||||
#if defined(ARM) || defined(__arm__) || defined(__alpha__)
|
||||
/** The architecture requires aligned access. */
|
||||
# define OTTD_ALIGNMENT 1
|
||||
#else
|
||||
/** The architecture does not require aligned access. */
|
||||
# define OTTD_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
/** Little endian builds use this for TTD_ENDIAN. */
|
||||
#define TTD_LITTLE_ENDIAN 0
|
||||
/** Big endian builds use this for TTD_ENDIAN. */
|
||||
|
||||
@@ -28,44 +28,20 @@
|
||||
|
||||
|
||||
/** Operators to allow to work with enum as with type safe bit set in C++ */
|
||||
# define DECLARE_ENUM_AS_BIT_SET(mask_t) \
|
||||
inline constexpr mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 | (std::underlying_type<mask_t>::type)m2);} \
|
||||
inline constexpr mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 & (std::underlying_type<mask_t>::type)m2);} \
|
||||
inline constexpr mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((std::underlying_type<mask_t>::type)m1 ^ (std::underlying_type<mask_t>::type)m2);} \
|
||||
inline constexpr mask_t& operator |= (mask_t& m1, mask_t m2) {m1 = m1 | m2; return m1;} \
|
||||
inline constexpr mask_t& operator &= (mask_t& m1, mask_t m2) {m1 = m1 & m2; return m1;} \
|
||||
inline constexpr mask_t& operator ^= (mask_t& m1, mask_t m2) {m1 = m1 ^ m2; return m1;} \
|
||||
inline constexpr mask_t operator ~(mask_t m) {return (mask_t)(~(std::underlying_type<mask_t>::type)m);}
|
||||
#define DECLARE_ENUM_AS_BIT_SET(enum_type) \
|
||||
inline constexpr enum_type operator | (enum_type m1, enum_type m2) {return (enum_type)((std::underlying_type<enum_type>::type)m1 | (std::underlying_type<enum_type>::type)m2);} \
|
||||
inline constexpr enum_type operator & (enum_type m1, enum_type m2) {return (enum_type)((std::underlying_type<enum_type>::type)m1 & (std::underlying_type<enum_type>::type)m2);} \
|
||||
inline constexpr enum_type operator ^ (enum_type m1, enum_type m2) {return (enum_type)((std::underlying_type<enum_type>::type)m1 ^ (std::underlying_type<enum_type>::type)m2);} \
|
||||
inline constexpr enum_type& operator |= (enum_type& m1, enum_type m2) {m1 = m1 | m2; return m1;} \
|
||||
inline constexpr enum_type& operator &= (enum_type& m1, enum_type m2) {m1 = m1 & m2; return m1;} \
|
||||
inline constexpr enum_type& operator ^= (enum_type& m1, enum_type m2) {m1 = m1 ^ m2; return m1;} \
|
||||
inline constexpr enum_type operator ~(enum_type m) {return (enum_type)(~(std::underlying_type<enum_type>::type)m);}
|
||||
|
||||
|
||||
/**
|
||||
* Informative template class exposing basic enumeration properties used by several
|
||||
* other templates below. Here we have only forward declaration. For each enum type
|
||||
* we will create specialization derived from MakeEnumPropsT<>.
|
||||
* i.e.:
|
||||
* template <> struct EnumPropsT<Track> : MakeEnumPropsT<Track, byte, TRACK_BEGIN, TRACK_END, INVALID_TRACK> {};
|
||||
*/
|
||||
template <typename Tenum_t> struct EnumPropsT;
|
||||
|
||||
/**
|
||||
* Helper template class that makes basic properties of given enumeration type visible
|
||||
* from outsize. It is used as base class of several EnumPropsT specializations each
|
||||
* dedicated to one of commonly used enumeration types.
|
||||
* @param Tenum_t enumeration type that you want to describe
|
||||
* @param Tstorage_t what storage type would be sufficient (i.e. byte)
|
||||
* @param Tbegin first valid value from the contiguous range (i.e. TRACK_BEGIN)
|
||||
* @param Tend one past the last valid value from the contiguous range (i.e. TRACK_END)
|
||||
* @param Tinvalid value used as invalid value marker (i.e. INVALID_TRACK)
|
||||
* @param Tnum_bits Number of bits for storing the enum in command parameters
|
||||
*/
|
||||
template <typename Tenum_t, typename Tstorage_t, Tenum_t Tbegin, Tenum_t Tend, Tenum_t Tinvalid, uint Tnum_bits = 8 * sizeof(Tstorage_t)>
|
||||
struct MakeEnumPropsT {
|
||||
typedef Tenum_t type; ///< enum type (i.e. Trackdir)
|
||||
typedef Tstorage_t storage; ///< storage type (i.e. byte)
|
||||
static const Tenum_t begin = Tbegin; ///< lowest valid value (i.e. TRACKDIR_BEGIN)
|
||||
static const Tenum_t end = Tend; ///< one after the last valid value (i.e. TRACKDIR_END)
|
||||
static const Tenum_t invalid = Tinvalid; ///< what value is used as invalid value (i.e. INVALID_TRACKDIR)
|
||||
static const uint num_bits = Tnum_bits; ///< Number of bits for storing the enum in command parameters
|
||||
};
|
||||
/** Operator that allows this enumeration to be added to any other enumeration. */
|
||||
#define DECLARE_ENUM_AS_ADDABLE(EnumType) \
|
||||
template <typename OtherEnumType, typename = typename std::enable_if<std::is_enum_v<OtherEnumType>, OtherEnumType>::type> \
|
||||
constexpr OtherEnumType operator + (OtherEnumType m1, EnumType m2) { \
|
||||
return static_cast<OtherEnumType>(static_cast<typename std::underlying_type<OtherEnumType>::type>(m1) + static_cast<typename std::underlying_type<EnumType>::type>(m2)); \
|
||||
}
|
||||
|
||||
#endif /* ENUM_TYPE_HPP */
|
||||
|
||||
48
src/core/format.hpp
Normal file
48
src/core/format.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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::BaseType> {
|
||||
using underlying_type = typename T::BaseType;
|
||||
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(t.base(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FORMAT_HPP */
|
||||
@@ -48,5 +48,3 @@ Rect BoundingRect(const Rect &r1, const Rect &r2)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const RectPadding RectPadding::zero = {0, 0, 0, 0};
|
||||
|
||||
@@ -19,7 +19,7 @@ Dimension maxdim(const Dimension &d1, const Dimension &d2);
|
||||
* @param r Rectangle to check.
|
||||
* @return True if and only if the rectangle doesn't define space.
|
||||
*/
|
||||
static inline bool IsEmptyRect(const Rect &r)
|
||||
inline bool IsEmptyRect(const Rect &r)
|
||||
{
|
||||
return (r.left | r.top | r.right | r.bottom) == 0;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
constexpr Point() : x(0), y(0) {}
|
||||
constexpr Point(int x, int y) : x(x), y(y) {}
|
||||
};
|
||||
|
||||
/** Dimensions (a width and height) of a rectangle in 2D */
|
||||
@@ -28,7 +31,8 @@ struct Dimension {
|
||||
uint width;
|
||||
uint height;
|
||||
|
||||
Dimension(uint w = 0, uint h = 0) : width(w), height(h) {};
|
||||
constexpr Dimension() : width(0), height(0) {}
|
||||
constexpr Dimension(uint w, uint h) : width(w), height(h) {}
|
||||
|
||||
bool operator< (const Dimension &other) const
|
||||
{
|
||||
@@ -45,10 +49,10 @@ struct Dimension {
|
||||
|
||||
/** Padding dimensions to apply to each side of a Rect. */
|
||||
struct RectPadding {
|
||||
uint8 left;
|
||||
uint8 top;
|
||||
uint8 right;
|
||||
uint8 bottom;
|
||||
uint8_t left;
|
||||
uint8_t top;
|
||||
uint8_t right;
|
||||
uint8_t bottom;
|
||||
|
||||
static const RectPadding zero;
|
||||
|
||||
@@ -56,15 +60,17 @@ struct RectPadding {
|
||||
* Get total horizontal padding of RectPadding.
|
||||
* @return total horizontal padding.
|
||||
*/
|
||||
inline uint Horizontal() const { return this->left + this->right; }
|
||||
constexpr uint Horizontal() const { return this->left + this->right; }
|
||||
|
||||
/**
|
||||
* Get total vertical padding of RectPadding.
|
||||
* @return total vertical padding.
|
||||
*/
|
||||
inline uint Vertical() const { return this->top + this->bottom; }
|
||||
constexpr uint Vertical() const { return this->top + this->bottom; }
|
||||
};
|
||||
|
||||
inline const RectPadding RectPadding::zero{};
|
||||
|
||||
/** Specification of a rectangle with absolute coordinates of all edges */
|
||||
struct Rect {
|
||||
int left;
|
||||
@@ -212,7 +218,7 @@ struct Rect {
|
||||
/**
|
||||
* Test if a point falls inside this Rect.
|
||||
* @param pt the point to test.
|
||||
* @return true iif the point falls inside the Rect.
|
||||
* @return true iff the point falls inside the Rect.
|
||||
*/
|
||||
inline bool Contains(const Point &pt) const
|
||||
{
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#define KDTREE_HPP
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
* K-dimensional tree, specialised for 2-dimensional space.
|
||||
@@ -55,7 +53,7 @@ class Kdtree {
|
||||
/** Create one new node in the tree, return its index in the pool */
|
||||
size_t AddNode(const T &element)
|
||||
{
|
||||
if (this->free_list.size() == 0) {
|
||||
if (this->free_list.empty()) {
|
||||
this->nodes.emplace_back(element);
|
||||
return this->nodes.size() - 1;
|
||||
} else {
|
||||
@@ -449,14 +447,14 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all items contained within the given rectangle.
|
||||
* @note Start coordinates are inclusive, end coordinates are exclusive. x1<x2 && y1<y2 is a precondition.
|
||||
* @param x1 Start first coordinate, points found are greater or equals to this.
|
||||
* @param y1 Start second coordinate, points found are greater or equals to this.
|
||||
* @param x2 End first coordinate, points found are less than this.
|
||||
* @param y2 End second coordinate, points found are less than this.
|
||||
* @param outputter Callback used to return values from the search.
|
||||
*/
|
||||
* Find all items contained within the given rectangle.
|
||||
* @note Start coordinates are inclusive, end coordinates are exclusive. x1<x2 && y1<y2 is a precondition.
|
||||
* @param x1 Start first coordinate, points found are greater or equals to this.
|
||||
* @param y1 Start second coordinate, points found are greater or equals to this.
|
||||
* @param x2 End first coordinate, points found are less than this.
|
||||
* @param y2 End second coordinate, points found are less than this.
|
||||
* @param outputter Callback used to return values from the search.
|
||||
*/
|
||||
template <typename Outputter>
|
||||
void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, const Outputter &outputter) const
|
||||
{
|
||||
|
||||
@@ -12,41 +12,6 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* Compute least common multiple (lcm) of arguments \a a and \a b, the smallest
|
||||
* integer value that is a multiple of both \a a and \a b.
|
||||
* @param a First number.
|
||||
* @param b second number.
|
||||
* @return Least common multiple of values \a a and \a b.
|
||||
*
|
||||
* @note This function only works for non-negative values of \a a and \a b.
|
||||
*/
|
||||
int LeastCommonMultiple(int a, int b)
|
||||
{
|
||||
if (a == 0 || b == 0) return 0; // By definition.
|
||||
if (a == 1 || a == b) return b;
|
||||
if (b == 1) return a;
|
||||
|
||||
return a * b / GreatestCommonDivisor(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute greatest common divisor (gcd) of \a a and \a b.
|
||||
* @param a First number.
|
||||
* @param b second number.
|
||||
* @return Greatest common divisor of \a a and \a b.
|
||||
*/
|
||||
int GreatestCommonDivisor(int a, int b)
|
||||
{
|
||||
while (b != 0) {
|
||||
int t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deterministic approximate division.
|
||||
* Cancels out division errors stemming from the integer nature of the division over multiple runs.
|
||||
@@ -74,10 +39,10 @@ int DivideApprox(int a, int b)
|
||||
* @return Rounded integer square root.
|
||||
* @note Algorithm taken from http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
|
||||
*/
|
||||
uint32 IntSqrt(uint32 num)
|
||||
uint32_t IntSqrt(uint32_t num)
|
||||
{
|
||||
uint32 res = 0;
|
||||
uint32 bit = 1UL << 30; // Second to top bit number.
|
||||
uint32_t res = 0;
|
||||
uint32_t bit = 1UL << 30; // Second to top bit number.
|
||||
|
||||
/* 'bit' starts at the highest power of four <= the argument. */
|
||||
while (bit > num) bit >>= 2;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#ifndef MATH_FUNC_HPP
|
||||
#define MATH_FUNC_HPP
|
||||
|
||||
#include "strong_typedef_type.hpp"
|
||||
|
||||
/**
|
||||
* Returns the absolute value of (scalar) variable.
|
||||
*
|
||||
@@ -18,7 +20,7 @@
|
||||
* @return The unsigned value
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T abs(const T a)
|
||||
constexpr T abs(const T a)
|
||||
{
|
||||
return (a < (T)0) ? -a : a;
|
||||
}
|
||||
@@ -32,7 +34,7 @@ static inline T abs(const T a)
|
||||
* @return The smallest multiple of n equal or greater than x
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Align(const T x, uint n)
|
||||
constexpr T Align(const T x, uint n)
|
||||
{
|
||||
assert((n & (n - 1)) == 0 && n != 0);
|
||||
n--;
|
||||
@@ -50,7 +52,7 @@ static inline T Align(const T x, uint n)
|
||||
* @see Align()
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T *AlignPtr(T *x, uint n)
|
||||
constexpr T *AlignPtr(T *x, uint n)
|
||||
{
|
||||
static_assert(sizeof(size_t) == sizeof(void *));
|
||||
return reinterpret_cast<T *>(Align((size_t)x, n));
|
||||
@@ -74,7 +76,7 @@ static inline T *AlignPtr(T *x, uint n)
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Clamp(const T a, const T min, const T max)
|
||||
constexpr T Clamp(const T a, const T min, const T max)
|
||||
{
|
||||
assert(min <= max);
|
||||
if (a <= min) return min;
|
||||
@@ -97,7 +99,7 @@ static inline T Clamp(const T a, const T min, const T max)
|
||||
* @returns A value between min and max which is closest to a.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T SoftClamp(const T a, const T min, const T max)
|
||||
constexpr T SoftClamp(const T a, const T min, const T max)
|
||||
{
|
||||
if (min > max) {
|
||||
using U = std::make_unsigned_t<T>;
|
||||
@@ -124,7 +126,7 @@ static inline T SoftClamp(const T a, const T min, const T max)
|
||||
* @returns A value between min and max which is closest to a.
|
||||
* @see ClampU(uint, uint, uint)
|
||||
*/
|
||||
static inline int Clamp(const int a, const int min, const int max)
|
||||
constexpr int Clamp(const int a, const int min, const int max)
|
||||
{
|
||||
return Clamp<int>(a, min, max);
|
||||
}
|
||||
@@ -145,44 +147,80 @@ static inline int Clamp(const int a, const int min, const int max)
|
||||
* @returns A value between min and max which is closest to a.
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
static inline uint ClampU(const uint a, const uint min, const uint max)
|
||||
constexpr uint ClampU(const uint a, const uint min, const uint max)
|
||||
{
|
||||
return Clamp<uint>(a, min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a signed 64-bit int to a signed 32-bit one
|
||||
* Clamp the given value down to lie within the requested type.
|
||||
*
|
||||
* This function clamps a 64-bit integer to a 32-bit integer.
|
||||
* If the 64-bit value is smaller than the smallest 32-bit integer
|
||||
* value 0x80000000 this value is returned (the left one bit is the sign bit).
|
||||
* If the 64-bit value is greater than the greatest 32-bit integer value 0x7FFFFFFF
|
||||
* this value is returned. In all other cases the 64-bit value 'fits' in a
|
||||
* 32-bits integer field and so the value is casted to int32 and returned.
|
||||
* For example ClampTo<uint8_t> will return a value clamped to the range of 0
|
||||
* to 255. Anything smaller will become 0, anything larger will become 255.
|
||||
*
|
||||
* @param a The 64-bit value to clamps
|
||||
* @return The 64-bit value reduced to a 32-bit value
|
||||
* @param a The 64-bit value to clamp.
|
||||
* @return The 64-bit value reduced to a value within the given allowed range
|
||||
* for the return type.
|
||||
* @see Clamp(int, int, int)
|
||||
*/
|
||||
static inline int32 ClampToI32(const int64 a)
|
||||
template <typename To, typename From, std::enable_if_t<std::is_integral<From>::value, int> = 0>
|
||||
constexpr To ClampTo(From value)
|
||||
{
|
||||
return static_cast<int32>(Clamp<int64>(a, INT32_MIN, INT32_MAX));
|
||||
static_assert(std::numeric_limits<To>::is_integer, "Do not clamp from non-integer values");
|
||||
static_assert(std::numeric_limits<From>::is_integer, "Do not clamp to non-integer values");
|
||||
|
||||
if constexpr (sizeof(To) >= sizeof(From) && std::numeric_limits<To>::is_signed == std::numeric_limits<From>::is_signed) {
|
||||
/* Same signedness and To type is larger or equal than From type, no clamping is required. */
|
||||
return static_cast<To>(value);
|
||||
}
|
||||
|
||||
if constexpr (sizeof(To) > sizeof(From) && std::numeric_limits<To>::is_signed) {
|
||||
/* Signed destination and a larger To type, no clamping is required. */
|
||||
return static_cast<To>(value);
|
||||
}
|
||||
|
||||
/* Get the bigger of the two types based on essentially the number of bits. */
|
||||
using BiggerType = typename std::conditional<sizeof(From) >= sizeof(To), From, To>::type;
|
||||
|
||||
if constexpr (std::numeric_limits<To>::is_signed) {
|
||||
/* The output is a signed number. */
|
||||
if constexpr (std::numeric_limits<From>::is_signed) {
|
||||
/* Both input and output are signed. */
|
||||
return static_cast<To>(std::clamp<BiggerType>(value,
|
||||
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
|
||||
}
|
||||
|
||||
/* The input is unsigned, so skip the minimum check and use unsigned variant of the biggest type as intermediate type. */
|
||||
using BiggerUnsignedType = typename std::make_unsigned<BiggerType>::type;
|
||||
return static_cast<To>(std::min<BiggerUnsignedType>(std::numeric_limits<To>::max(), value));
|
||||
}
|
||||
|
||||
/* The output is unsigned. */
|
||||
|
||||
if constexpr (std::numeric_limits<From>::is_signed) {
|
||||
/* Input is signed; account for the negative numbers in the input. */
|
||||
if constexpr (sizeof(To) >= sizeof(From)) {
|
||||
/* If the output type is larger or equal to the input type, then only clamp the negative numbers. */
|
||||
return static_cast<To>(std::max<From>(value, 0));
|
||||
}
|
||||
|
||||
/* The output type is smaller than the input type. */
|
||||
using BiggerSignedType = typename std::make_signed<BiggerType>::type;
|
||||
return static_cast<To>(std::clamp<BiggerSignedType>(value,
|
||||
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
|
||||
}
|
||||
|
||||
/* The input and output are unsigned, just clamp at the high side. */
|
||||
return static_cast<To>(std::min<BiggerType>(value, std::numeric_limits<To>::max()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce an unsigned 64-bit int to an unsigned 16-bit one
|
||||
*
|
||||
* @param a The 64-bit value to clamp
|
||||
* @return The 64-bit value reduced to a 16-bit value
|
||||
* @see ClampU(uint, uint, uint)
|
||||
* Specialization of ClampTo for #StrongType::Typedef.
|
||||
*/
|
||||
static inline uint16 ClampToU16(const uint64 a)
|
||||
template <typename To, typename From, std::enable_if_t<std::is_base_of<StrongTypedefBase, From>::value, int> = 0>
|
||||
constexpr To ClampTo(From value)
|
||||
{
|
||||
/* MSVC thinks, in its infinite wisdom, that int min(int, int) is a better
|
||||
* match for min(uint64, uint) than uint64 min(uint64, uint64). As such we
|
||||
* need to cast the UINT16_MAX to prevent MSVC from displaying its
|
||||
* infinite loads of warnings. */
|
||||
return static_cast<uint16>(std::min(a, static_cast<uint64>(UINT16_MAX)));
|
||||
return ClampTo<To>(value.base());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +231,7 @@ static inline uint16 ClampToU16(const uint64 a)
|
||||
* @return The absolute difference between the given scalars
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T Delta(const T a, const T b)
|
||||
constexpr T Delta(const T a, const T b)
|
||||
{
|
||||
return (a < b) ? b - a : a - b;
|
||||
}
|
||||
@@ -211,7 +249,7 @@ static inline T Delta(const T a, const T b)
|
||||
* @return True if the value is in the interval, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
|
||||
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
|
||||
{
|
||||
return (size_t)(x - base) < size;
|
||||
}
|
||||
@@ -226,10 +264,14 @@ static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
|
||||
* @param max The maximum of the interval
|
||||
* @see IsInsideBS()
|
||||
*/
|
||||
template <typename T>
|
||||
static constexpr inline bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
|
||||
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 T x, const size_t min, const size_t max) noexcept
|
||||
{
|
||||
return (size_t)(x - min) < (max - min);
|
||||
if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
|
||||
return (size_t)(x.base() - min) < (max - min);
|
||||
} else {
|
||||
return (size_t)(x - min) < (max - min);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,7 +280,7 @@ static constexpr inline bool IsInsideMM(const T x, const size_t min, const size_
|
||||
* @param b variable to swap with a
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void Swap(T &a, T &b)
|
||||
constexpr void Swap(T &a, T &b)
|
||||
{
|
||||
T t = a;
|
||||
a = b;
|
||||
@@ -250,7 +292,7 @@ static inline void Swap(T &a, T &b)
|
||||
* @param i value to convert, range 0..255
|
||||
* @return value in range 0..100
|
||||
*/
|
||||
static inline uint ToPercent8(uint i)
|
||||
constexpr uint ToPercent8(uint i)
|
||||
{
|
||||
assert(i < 256);
|
||||
return i * 101 >> 8;
|
||||
@@ -261,14 +303,12 @@ static inline uint ToPercent8(uint i)
|
||||
* @param i value to convert, range 0..65535
|
||||
* @return value in range 0..100
|
||||
*/
|
||||
static inline uint ToPercent16(uint i)
|
||||
constexpr uint ToPercent16(uint i)
|
||||
{
|
||||
assert(i < 65536);
|
||||
return i * 101 >> 16;
|
||||
}
|
||||
|
||||
int LeastCommonMultiple(int a, int b);
|
||||
int GreatestCommonDivisor(int a, int b);
|
||||
int DivideApprox(int a, int b);
|
||||
|
||||
/**
|
||||
@@ -277,7 +317,7 @@ int DivideApprox(int a, int b);
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded up
|
||||
*/
|
||||
static inline uint CeilDiv(uint a, uint b)
|
||||
constexpr uint CeilDiv(uint a, uint b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
@@ -288,7 +328,7 @@ static inline uint CeilDiv(uint a, uint b)
|
||||
* @param b Denominator
|
||||
* @return a rounded up to the nearest multiple of b.
|
||||
*/
|
||||
static inline uint Ceil(uint a, uint b)
|
||||
constexpr uint Ceil(uint a, uint b)
|
||||
{
|
||||
return CeilDiv(a, b) * b;
|
||||
}
|
||||
@@ -299,7 +339,7 @@ static inline uint Ceil(uint a, uint b)
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded to nearest
|
||||
*/
|
||||
static inline int RoundDivSU(int a, uint b)
|
||||
constexpr int RoundDivSU(int a, uint b)
|
||||
{
|
||||
if (a > 0) {
|
||||
/* 0.5 is rounded to 1 */
|
||||
@@ -310,23 +350,6 @@ static inline int RoundDivSU(int a, uint b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes (a / b) rounded away from zero.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded away from zero
|
||||
*/
|
||||
static inline int DivAwayFromZero(int a, uint b)
|
||||
{
|
||||
const int _b = static_cast<int>(b);
|
||||
if (a > 0) {
|
||||
return (a + _b - 1) / _b;
|
||||
} else {
|
||||
/* Note: Behaviour of negative numerator division is truncation toward zero. */
|
||||
return (a - _b + 1) / _b;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 IntSqrt(uint32 num);
|
||||
uint32_t IntSqrt(uint32_t num);
|
||||
|
||||
#endif /* MATH_FUNC_HPP */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* @param num number of items to be copied. (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemCpyT(T *destination, const T *source, size_t num = 1)
|
||||
inline void MemCpyT(T *destination, const T *source, size_t num = 1)
|
||||
{
|
||||
memcpy(destination, source, num * sizeof(T));
|
||||
}
|
||||
@@ -33,7 +33,7 @@ static inline void MemCpyT(T *destination, const T *source, size_t num = 1)
|
||||
* @param num number of items to be copied. (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemMoveT(T *destination, const T *source, size_t num = 1)
|
||||
inline void MemMoveT(T *destination, const T *source, size_t num = 1)
|
||||
{
|
||||
memmove(destination, source, num * sizeof(T));
|
||||
}
|
||||
@@ -46,7 +46,7 @@ static inline void MemMoveT(T *destination, const T *source, size_t num = 1)
|
||||
* @param num number of items to be set (!not number of bytes!)
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemSetT(T *ptr, byte value, size_t num = 1)
|
||||
inline void MemSetT(T *ptr, byte value, size_t num = 1)
|
||||
{
|
||||
memset(ptr, value, num * sizeof(T));
|
||||
}
|
||||
@@ -60,42 +60,9 @@ static inline void MemSetT(T *ptr, byte value, size_t num = 1)
|
||||
* @return an int value indicating the relationship between the content of the two buffers
|
||||
*/
|
||||
template <typename T>
|
||||
static inline int MemCmpT(const T *ptr1, const T *ptr2, size_t num = 1)
|
||||
inline int MemCmpT(const T *ptr1, const T *ptr2, size_t num = 1)
|
||||
{
|
||||
return memcmp(ptr1, ptr2, num * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe memory reverse operation.
|
||||
* Reverse a block of memory in steps given by the
|
||||
* type of the pointers.
|
||||
*
|
||||
* @param ptr1 Start-pointer to the block of memory.
|
||||
* @param ptr2 End-pointer to the block of memory.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemReverseT(T *ptr1, T *ptr2)
|
||||
{
|
||||
assert(ptr1 != nullptr && ptr2 != nullptr);
|
||||
assert(ptr1 < ptr2);
|
||||
|
||||
do {
|
||||
Swap(*ptr1, *ptr2);
|
||||
} while (++ptr1 < --ptr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type safe memory reverse operation (overloaded)
|
||||
*
|
||||
* @param ptr Pointer to the block of memory.
|
||||
* @param num The number of items we want to reverse.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void MemReverseT(T *ptr, size_t num)
|
||||
{
|
||||
assert(ptr != nullptr);
|
||||
|
||||
MemReverseT(ptr, ptr + (num - 1));
|
||||
}
|
||||
|
||||
#endif /* MEM_FUNC_HPP */
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
#ifndef MULTIMAP_HPP
|
||||
#define MULTIMAP_HPP
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
template<typename Tkey, typename Tvalue, typename Tcompare>
|
||||
class MultiMap;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "math_func.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#ifdef __has_builtin
|
||||
# if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_sub_overflow) && __has_builtin(__builtin_mul_overflow)
|
||||
@@ -38,7 +37,7 @@ private:
|
||||
public:
|
||||
constexpr OverflowSafeInt() : m_value(0) { }
|
||||
|
||||
constexpr OverflowSafeInt(const OverflowSafeInt& other) : m_value(other.m_value) { }
|
||||
constexpr OverflowSafeInt(const OverflowSafeInt &other) : m_value(other.m_value) { }
|
||||
constexpr OverflowSafeInt(const T int_) : m_value(int_) { }
|
||||
|
||||
inline constexpr OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; }
|
||||
@@ -54,7 +53,7 @@ public:
|
||||
inline constexpr OverflowSafeInt& operator += (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (unlikely(__builtin_add_overflow(this->m_value, other.m_value, &this->m_value))) {
|
||||
if (__builtin_add_overflow(this->m_value, other.m_value, &this->m_value)) [[unlikely]] {
|
||||
this->m_value = (other.m_value < 0) ? T_MIN : T_MAX;
|
||||
}
|
||||
#else
|
||||
@@ -77,7 +76,7 @@ public:
|
||||
inline constexpr OverflowSafeInt& operator -= (const OverflowSafeInt& other)
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
if (unlikely(__builtin_sub_overflow(this->m_value, other.m_value, &this->m_value))) {
|
||||
if (__builtin_sub_overflow(this->m_value, other.m_value, &this->m_value)) [[unlikely]] {
|
||||
this->m_value = (other.m_value < 0) ? T_MAX : T_MIN;
|
||||
}
|
||||
#else
|
||||
@@ -94,11 +93,11 @@ public:
|
||||
|
||||
/* Operators for addition and subtraction. */
|
||||
inline constexpr OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
inline constexpr OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64_t)other; return result; }
|
||||
|
||||
inline constexpr OverflowSafeInt& operator ++ () { return *this += 1; }
|
||||
inline constexpr OverflowSafeInt& operator -- () { return *this += -1; }
|
||||
@@ -115,7 +114,7 @@ public:
|
||||
{
|
||||
#ifdef HAS_OVERFLOW_BUILTINS
|
||||
const bool is_result_positive = (this->m_value < 0) == (factor < 0); // -ve * -ve == +ve
|
||||
if (unlikely(__builtin_mul_overflow(this->m_value, factor, &this->m_value))) {
|
||||
if (__builtin_mul_overflow(this->m_value, factor, &this->m_value)) [[unlikely]] {
|
||||
this->m_value = is_result_positive ? T_MAX : T_MIN;
|
||||
}
|
||||
#else
|
||||
@@ -137,14 +136,14 @@ public:
|
||||
}
|
||||
|
||||
/* Operators for multiplication. */
|
||||
inline constexpr OverflowSafeInt operator * (const int64 factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint16 factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const byte factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const int64_t factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const uint16_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
inline constexpr OverflowSafeInt operator * (const byte factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
|
||||
|
||||
/* Operators for division. */
|
||||
inline constexpr OverflowSafeInt& operator /= (const int64 divisor) { this->m_value /= divisor; return *this; }
|
||||
inline constexpr OverflowSafeInt& operator /= (const int64_t divisor) { this->m_value /= divisor; return *this; }
|
||||
inline constexpr OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; }
|
||||
inline constexpr OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; }
|
||||
inline constexpr OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; }
|
||||
@@ -182,11 +181,11 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/* Sometimes we got int64 operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const int64 a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const int64 a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const int64 a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const int64 a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
/* Sometimes we got int64_t operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const int64_t a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator - (const int64_t a, const OverflowSafeInt<T> b) { return -b + a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const int64_t a, const OverflowSafeInt<T> b) { return b * a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const int64_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
/* Sometimes we got int operator OverflowSafeInt instead of vice versa. Handle that properly. */
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator + (const int a, const OverflowSafeInt<T> b) { return b + a; }
|
||||
@@ -206,8 +205,8 @@ template <class T> inline constexpr OverflowSafeInt<T> operator - (const byte a
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator * (const byte a, const OverflowSafeInt<T> b) { return b * (uint)a; }
|
||||
template <class T> inline constexpr OverflowSafeInt<T> operator / (const byte a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
|
||||
|
||||
typedef OverflowSafeInt<int64> OverflowSafeInt64;
|
||||
typedef OverflowSafeInt<int32> OverflowSafeInt32;
|
||||
typedef OverflowSafeInt<int64_t> OverflowSafeInt64;
|
||||
typedef OverflowSafeInt<int32_t> OverflowSafeInt32;
|
||||
|
||||
/* Some basic "unit tests". Also has the bonus of confirming that constexpr is working. */
|
||||
static_assert(OverflowSafeInt32(INT32_MIN) - 1 == OverflowSafeInt32(INT32_MIN));
|
||||
@@ -215,6 +214,10 @@ static_assert(OverflowSafeInt32(INT32_MAX) + 1 == OverflowSafeInt32(INT32_MAX));
|
||||
static_assert(OverflowSafeInt32(INT32_MAX) * 2 == OverflowSafeInt32(INT32_MAX));
|
||||
static_assert(OverflowSafeInt32(INT32_MIN) * 2 == OverflowSafeInt32(INT32_MIN));
|
||||
|
||||
/* Specialisation of the generic ClampTo function for overflow safe integers to normal integers. */
|
||||
template <typename To, typename From>
|
||||
constexpr To ClampTo(OverflowSafeInt<From> value) { return ClampTo<To>(From(value)); }
|
||||
|
||||
#undef HAS_OVERFLOW_BUILTINS
|
||||
|
||||
#endif /* OVERFLOWSAFE_TYPE_HPP */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{
|
||||
PoolVector *pools = PoolBase::GetPools();
|
||||
pools->erase(std::find(pools->begin(), pools->end(), this));
|
||||
if (pools->size() == 0) delete pools;
|
||||
if (pools->empty()) delete pools;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
#include "pool_type.hpp"
|
||||
#include "../error_func.h"
|
||||
|
||||
#include "../saveload/saveload_error.hpp" // SlErrorCorruptFmt
|
||||
|
||||
/**
|
||||
* Helper for defining the method's signature.
|
||||
@@ -127,7 +130,7 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||
* Allocates new item
|
||||
* @param size size of item
|
||||
* @return pointer to allocated item
|
||||
* @note error() on failure! (no free item)
|
||||
* @note FatalError() on failure! (no free item)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
{
|
||||
@@ -138,7 +141,7 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
this->checked--;
|
||||
#endif /* WITH_ASSERT */
|
||||
if (index == NO_FREE_ITEM) {
|
||||
error("%s: no more free items", this->name);
|
||||
FatalError("{}: no more free items", this->name);
|
||||
}
|
||||
|
||||
this->first_free = index + 1;
|
||||
@@ -154,16 +157,14 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
{
|
||||
extern void NORETURN SlErrorCorruptFmt(const char *format, ...);
|
||||
|
||||
if (index >= Tmax_size) {
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
|
||||
SlErrorCorruptFmt("{} index {} out of range ({})", this->name, index, Tmax_size);
|
||||
}
|
||||
|
||||
if (index >= this->size) this->ResizeFor(index);
|
||||
|
||||
if (this->data[index] != nullptr) {
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index);
|
||||
SlErrorCorruptFmt("{} index {} already in use", this->name, index);
|
||||
}
|
||||
|
||||
return this->AllocateItem(size, index);
|
||||
|
||||
@@ -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. */
|
||||
@@ -80,7 +79,7 @@ private:
|
||||
template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PT_NORMAL, bool Tcache = false, bool Tzero = true>
|
||||
struct Pool : PoolBase {
|
||||
/* Ensure Tmax_size is within the bounds of Tindex. */
|
||||
static_assert((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
|
||||
static_assert((uint64_t)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
|
||||
|
||||
static constexpr size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside
|
||||
|
||||
@@ -98,7 +97,7 @@ struct Pool : PoolBase {
|
||||
Titem **data; ///< Pointer to array of pointers to Titem
|
||||
|
||||
Pool(const char *name);
|
||||
virtual void CleanPool();
|
||||
void CleanPool() override;
|
||||
|
||||
/**
|
||||
* Returns Titem with given index
|
||||
@@ -143,8 +142,8 @@ struct Pool : PoolBase {
|
||||
template <class T>
|
||||
struct PoolIterator {
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef T *pointer;
|
||||
typedef T &reference;
|
||||
typedef size_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
@@ -187,8 +186,8 @@ struct Pool : PoolBase {
|
||||
template <class T, class F>
|
||||
struct PoolIteratorFiltered {
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef T *pointer;
|
||||
typedef T &reference;
|
||||
typedef size_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
@@ -276,13 +275,12 @@ struct Pool : PoolBase {
|
||||
|
||||
/**
|
||||
* Allocates space for new Titem at given memory address
|
||||
* @param size size of Titem
|
||||
* @param ptr where are we allocating the item?
|
||||
* @return pointer to allocated memory (== ptr)
|
||||
* @note use of this is strongly discouraged
|
||||
* @pre the memory must not be allocated in the Pool!
|
||||
*/
|
||||
inline void *operator new(size_t size, void *ptr)
|
||||
inline void *operator new(size_t, void *ptr)
|
||||
{
|
||||
for (size_t i = 0; i < Tpool->first_unused; i++) {
|
||||
/* Don't allow creating new objects over existing.
|
||||
@@ -376,7 +374,7 @@ struct Pool : PoolBase {
|
||||
* @note when this function is called, PoolItem::Get(index) == nullptr.
|
||||
* @note it's called only when !CleaningPool()
|
||||
*/
|
||||
static inline void PostDestructor(size_t index) { }
|
||||
static inline void PostDestructor([[maybe_unused]] size_t index) { }
|
||||
|
||||
/**
|
||||
* Returns an iterable ensemble of all valid Titem
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../stdafx.h"
|
||||
#include "random_func.hpp"
|
||||
#include "bitmath_func.hpp"
|
||||
#include "../debug.h"
|
||||
|
||||
#ifdef RANDOM_DEBUG
|
||||
#include "../network/network.h"
|
||||
@@ -17,9 +18,20 @@
|
||||
#include "../network/network_internal.h"
|
||||
#include "../company_func.h"
|
||||
#include "../fileio_func.h"
|
||||
#include "../date_func.h"
|
||||
#include "../timer/timer_game_calendar.h"
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# include <bcrypt.h>
|
||||
#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
// No includes required.
|
||||
#elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
|
||||
# include <sys/random.h>
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
Randomizer _random, _interactive_random;
|
||||
@@ -28,13 +40,13 @@ Randomizer _random, _interactive_random;
|
||||
* Generate the next pseudo random number
|
||||
* @return the random number
|
||||
*/
|
||||
uint32 Randomizer::Next()
|
||||
uint32_t Randomizer::Next()
|
||||
{
|
||||
const uint32 s = this->state[0];
|
||||
const uint32 t = this->state[1];
|
||||
const uint32_t s = this->state[0];
|
||||
const uint32_t t = this->state[1];
|
||||
|
||||
this->state[0] = s + ROR(t ^ 0x1234567F, 7) + 1;
|
||||
return this->state[1] = ROR(s, 3) - 1;
|
||||
this->state[0] = s + std::rotr(t ^ 0x1234567F, 7) + 1;
|
||||
return this->state[1] = std::rotr(s, 3) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,16 +55,16 @@ uint32 Randomizer::Next()
|
||||
* @param limit Limit of the range to be generated from.
|
||||
* @return Random number in [0,\a limit)
|
||||
*/
|
||||
uint32 Randomizer::Next(uint32 limit)
|
||||
uint32_t Randomizer::Next(uint32_t limit)
|
||||
{
|
||||
return ((uint64)this->Next() * (uint64)limit) >> 32;
|
||||
return ((uint64_t)this->Next() * (uint64_t)limit) >> 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)set the state of the random number generator.
|
||||
* @param seed the new state
|
||||
*/
|
||||
void Randomizer::SetSeed(uint32 seed)
|
||||
void Randomizer::SetSeed(uint32_t seed)
|
||||
{
|
||||
this->state[0] = seed;
|
||||
this->state[1] = seed;
|
||||
@@ -62,24 +74,74 @@ void Randomizer::SetSeed(uint32 seed)
|
||||
* (Re)set the state of the random number generators.
|
||||
* @param seed the new state
|
||||
*/
|
||||
void SetRandomSeed(uint32 seed)
|
||||
void SetRandomSeed(uint32_t seed)
|
||||
{
|
||||
_random.SetSeed(seed);
|
||||
_interactive_random.SetSeed(seed * 0x1234567);
|
||||
}
|
||||
|
||||
#ifdef RANDOM_DEBUG
|
||||
uint32 DoRandom(int line, const char *file)
|
||||
uint32_t DoRandom(int line, const char *file)
|
||||
{
|
||||
if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
|
||||
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", _date, _date_fract, _frame_counter, (byte)_current_company, file, line);
|
||||
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, (byte)_current_company, file, line);
|
||||
}
|
||||
|
||||
return _random.Next();
|
||||
}
|
||||
|
||||
uint32 DoRandomRange(uint32 limit, int line, const char *file)
|
||||
uint32_t DoRandomRange(uint32_t limit, int line, const char *file)
|
||||
{
|
||||
return ((uint64)DoRandom(line, file) * (uint64)limit) >> 32;
|
||||
return ((uint64_t)DoRandom(line, file) * (uint64_t)limit) >> 32;
|
||||
}
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
/**
|
||||
* Fill the given buffer with random bytes.
|
||||
*
|
||||
* This function will attempt to use a cryptographically-strong random
|
||||
* generator, but will fall back to a weaker random generator if none is
|
||||
* available.
|
||||
*
|
||||
* In the end, the buffer will always be filled with some form of random
|
||||
* bytes when this function returns.
|
||||
*
|
||||
* @param buf The buffer to fill with random bytes.
|
||||
*/
|
||||
void RandomBytesWithFallback(std::span<uint8_t> buf)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
auto res = BCryptGenRandom(nullptr, static_cast<PUCHAR>(buf.data()), static_cast<ULONG>(buf.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
if (res >= 0) return;
|
||||
#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
arc4random_buf(buf.data(), buf.size());
|
||||
return;
|
||||
#elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
|
||||
auto res = getrandom(buf.data(), buf.size(), 0);
|
||||
if (res > 0 && static_cast<size_t>(res) == buf.size()) return;
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
auto res = EM_ASM_INT({
|
||||
var buf = $0;
|
||||
var bytes = $1;
|
||||
|
||||
var crypto = window.crypto;
|
||||
if (crypto === undefined || crypto.getRandomValues === undefined) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto.getRandomValues(Module.HEAPU8.subarray(buf, buf + bytes));
|
||||
return 1;
|
||||
}, buf.data(), buf.size());
|
||||
if (res > 0) return;
|
||||
#else
|
||||
# warning "No cryptographically-strong random generator available; using a fallback instead"
|
||||
#endif
|
||||
|
||||
static bool warned_once = false;
|
||||
Debug(misc, warned_once ? 1 : 0, "Cryptographically-strong random generator unavailable; using fallback");
|
||||
warned_once = true;
|
||||
|
||||
for (uint i = 0; i < buf.size(); i++) {
|
||||
buf[i] = static_cast<uint8_t>(InteractiveRandom());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
*/
|
||||
struct Randomizer {
|
||||
/** The state of the randomizer */
|
||||
uint32 state[2];
|
||||
uint32_t state[2];
|
||||
|
||||
uint32 Next();
|
||||
uint32 Next(uint32 limit);
|
||||
void SetSeed(uint32 seed);
|
||||
uint32_t Next();
|
||||
uint32_t Next(uint32_t limit);
|
||||
void SetSeed(uint32_t seed);
|
||||
};
|
||||
extern Randomizer _random; ///< Random used in the game state calculations
|
||||
extern Randomizer _interactive_random; ///< Random used everywhere else, where it does not (directly) influence the game state
|
||||
@@ -39,7 +39,7 @@ struct SavedRandomSeeds {
|
||||
* Saves the current seeds
|
||||
* @param storage Storage for saving
|
||||
*/
|
||||
static inline void SaveRandomSeeds(SavedRandomSeeds *storage)
|
||||
inline void SaveRandomSeeds(SavedRandomSeeds *storage)
|
||||
{
|
||||
storage->random = _random;
|
||||
storage->interactive_random = _interactive_random;
|
||||
@@ -49,24 +49,24 @@ static inline void SaveRandomSeeds(SavedRandomSeeds *storage)
|
||||
* Restores previously saved seeds
|
||||
* @param storage Storage where SaveRandomSeeds() stored th seeds
|
||||
*/
|
||||
static inline void RestoreRandomSeeds(const SavedRandomSeeds &storage)
|
||||
inline void RestoreRandomSeeds(const SavedRandomSeeds &storage)
|
||||
{
|
||||
_random = storage.random;
|
||||
_interactive_random = storage.interactive_random;
|
||||
}
|
||||
|
||||
void SetRandomSeed(uint32 seed);
|
||||
void SetRandomSeed(uint32_t seed);
|
||||
#ifdef RANDOM_DEBUG
|
||||
# ifdef __APPLE__
|
||||
# define OTTD_Random() DoRandom(__LINE__, __FILE__)
|
||||
# else
|
||||
# define Random() DoRandom(__LINE__, __FILE__)
|
||||
# endif
|
||||
uint32 DoRandom(int line, const char *file);
|
||||
uint32_t DoRandom(int line, const char *file);
|
||||
# define RandomRange(limit) DoRandomRange(limit, __LINE__, __FILE__)
|
||||
uint32 DoRandomRange(uint32 limit, int line, const char *file);
|
||||
uint32_t DoRandomRange(uint32_t limit, int line, const char *file);
|
||||
#else
|
||||
static inline uint32 Random()
|
||||
static inline uint32_t Random()
|
||||
{
|
||||
return _random.Next();
|
||||
}
|
||||
@@ -78,18 +78,18 @@ void SetRandomSeed(uint32 seed);
|
||||
* @param limit Limit for the range to be picked from.
|
||||
* @return A random number in [0,\a limit).
|
||||
*/
|
||||
static inline uint32 RandomRange(uint32 limit)
|
||||
static inline uint32_t RandomRange(uint32_t limit)
|
||||
{
|
||||
return _random.Next(limit);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint32 InteractiveRandom()
|
||||
inline uint32_t InteractiveRandom()
|
||||
{
|
||||
return _interactive_random.Next();
|
||||
}
|
||||
|
||||
static inline uint32 InteractiveRandomRange(uint32 limit)
|
||||
inline uint32_t InteractiveRandomRange(uint32_t limit)
|
||||
{
|
||||
return _interactive_random.Next(limit);
|
||||
}
|
||||
@@ -109,10 +109,10 @@ static inline uint32 InteractiveRandomRange(uint32 limit)
|
||||
* @param r The given randomize-number
|
||||
* @return True if the probability given by r is less or equal to (a/b)
|
||||
*/
|
||||
static inline bool Chance16I(const uint a, const uint b, const uint32 r)
|
||||
inline bool Chance16I(const uint a, const uint b, const uint32_t r)
|
||||
{
|
||||
assert(b != 0);
|
||||
return (((uint16)r * b + b / 2) >> 16) < a;
|
||||
return (((uint16_t)r * b + b / 2) >> 16) < a;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +128,7 @@ static inline bool Chance16I(const uint a, const uint b, const uint32 r)
|
||||
#ifdef RANDOM_DEBUG
|
||||
# define Chance16(a, b) Chance16I(a, b, DoRandom(__LINE__, __FILE__))
|
||||
#else
|
||||
static inline bool Chance16(const uint a, const uint b)
|
||||
inline bool Chance16(const uint a, const uint b)
|
||||
{
|
||||
return Chance16I(a, b, Random());
|
||||
}
|
||||
@@ -152,11 +152,13 @@ static inline bool Chance16(const uint a, const uint b)
|
||||
#ifdef RANDOM_DEBUG
|
||||
# define Chance16R(a, b, r) (r = DoRandom(__LINE__, __FILE__), Chance16I(a, b, r))
|
||||
#else
|
||||
static inline bool Chance16R(const uint a, const uint b, uint32 &r)
|
||||
inline bool Chance16R(const uint a, const uint b, uint32_t &r)
|
||||
{
|
||||
r = Random();
|
||||
return Chance16I(a, b, r);
|
||||
}
|
||||
#endif /* RANDOM_DEBUG */
|
||||
|
||||
void RandomBytesWithFallback(std::span<uint8_t> buf);
|
||||
|
||||
#endif /* RANDOM_FUNC_HPP */
|
||||
|
||||
@@ -1,151 +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 smallmap_type.hpp Simple mapping class targeted for small sets of data. Stored data shall be POD ("Plain Old Data")! */
|
||||
|
||||
#ifndef SMALLMAP_TYPE_HPP
|
||||
#define SMALLMAP_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* Implementation of simple mapping class.
|
||||
* It has inherited accessors from std::vector().
|
||||
* @tparam T Key type.
|
||||
* @tparam U Value type.
|
||||
* @tparam S Unit of allocation.
|
||||
*
|
||||
* @see std::vector
|
||||
*/
|
||||
template <typename T, typename U>
|
||||
struct SmallMap : std::vector<std::pair<T, U> > {
|
||||
typedef std::pair<T, U> Pair;
|
||||
typedef Pair *iterator;
|
||||
typedef const Pair *const_iterator;
|
||||
|
||||
/** Creates new SmallMap. Data are initialized in std::vector constructor */
|
||||
inline SmallMap() { }
|
||||
/** Data are freed in std::vector destructor */
|
||||
inline ~SmallMap() { }
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline typename std::vector<Pair>::const_iterator Find(const T &key) const
|
||||
{
|
||||
typename std::vector<Pair>::const_iterator it;
|
||||
for (it = std::vector<Pair>::begin(); it != std::vector<Pair>::end(); it++) {
|
||||
if (key == it->first) return it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds given key in this map
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline Pair *Find(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return &std::vector<Pair>::operator[](i);
|
||||
}
|
||||
return this->End();
|
||||
}
|
||||
|
||||
inline const Pair *End() const
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
inline Pair *End()
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key) const
|
||||
{
|
||||
return this->Find(key) != std::vector<Pair>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key)
|
||||
{
|
||||
return this->Find(key) != this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given pair from this map
|
||||
* @param pair pair to remove
|
||||
* @note it has to be pointer to pair in this map. It is overwritten by the last item.
|
||||
*/
|
||||
inline void Erase(Pair *pair)
|
||||
{
|
||||
assert(pair >= std::vector<Pair>::data() && pair < this->End());
|
||||
auto distance = pair - std::vector<Pair>::data();
|
||||
std::vector<Pair>::erase(std::vector<Pair>::begin() + distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given key from this map
|
||||
* @param key key to remove
|
||||
* @return true iff the key was found
|
||||
* @note last item is moved to its place, so don't increase your iterator if true is returned!
|
||||
*/
|
||||
inline bool Erase(const T &key)
|
||||
{
|
||||
auto *pair = this->Find(key);
|
||||
if (pair == this->End()) return false;
|
||||
|
||||
this->Erase(pair);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new item to this map.
|
||||
* @param key key
|
||||
* @param data data
|
||||
* @return true iff the key wasn't already present
|
||||
*/
|
||||
inline bool Insert(const T &key, const U &data)
|
||||
{
|
||||
if (this->Contains(key)) return false;
|
||||
std::vector<Pair>::emplace_back(key, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data belonging to this key
|
||||
* @param key key
|
||||
* @return data belonging to this key
|
||||
* @note if this key wasn't present, new entry is created
|
||||
*/
|
||||
inline U &operator[](const T &key)
|
||||
{
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return std::vector<Pair>::operator[](i).second;
|
||||
}
|
||||
Pair &n = std::vector<Pair>::emplace_back();
|
||||
n.first = key;
|
||||
return n.second;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLMAP_TYPE_HPP */
|
||||
@@ -1,320 +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 smallmatrix_type.hpp Simple matrix class that allows allocating an item without the need to copy this->data needlessly. */
|
||||
|
||||
#ifndef SMALLMATRIX_TYPE_HPP
|
||||
#define SMALLMATRIX_TYPE_HPP
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
|
||||
/**
|
||||
* Simple matrix template class.
|
||||
*
|
||||
* Allocating a matrix in one piece reduces overhead in allocations compared
|
||||
* with allocating a vector of vectors and saves some pointer dereferencing.
|
||||
* However, you can only get rectangular matrixes like this and if you're
|
||||
* changing their height very often performance will probably be worse than
|
||||
* with a vector of vectors, due to more frequent copying of memory blocks.
|
||||
*
|
||||
* No iterators are provided as iterating the columns would require persistent
|
||||
* column objects. Those do not exist. Providing iterators with transient
|
||||
* column objects would tie each iterator to a column object, thus replacing
|
||||
* previously retrieved columns when iterating and defeating the point of
|
||||
* iteration.
|
||||
*
|
||||
* It's expected that the items don't need to be constructed or deleted by the
|
||||
* container. Only memory allocation and deallocation is performed. This is the
|
||||
* same for all openttd "SmallContainer" classes.
|
||||
*
|
||||
* @tparam T The type of the items stored
|
||||
*/
|
||||
template <typename T>
|
||||
class SmallMatrix {
|
||||
protected:
|
||||
T *data; ///< The pointer to the first item
|
||||
uint width; ///< Number of items over first axis
|
||||
uint height; ///< Number of items over second axis
|
||||
uint capacity; ///< The available space for storing items
|
||||
|
||||
public:
|
||||
|
||||
SmallMatrix() : data(nullptr), width(0), height(0), capacity(0) {}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param other The other matrix to copy.
|
||||
*/
|
||||
SmallMatrix(const SmallMatrix &other) : data(nullptr), width(0), height(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
~SmallMatrix()
|
||||
{
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment.
|
||||
* @param other The other matrix to assign.
|
||||
*/
|
||||
SmallMatrix &operator=(const SmallMatrix &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items from other vector.
|
||||
*/
|
||||
inline void Assign(const SmallMatrix &other)
|
||||
{
|
||||
if (&other == this) return;
|
||||
|
||||
this->height = other.Height();
|
||||
this->width = other.Width();
|
||||
uint num_items = this->width * this->height;
|
||||
if (num_items > this->capacity) {
|
||||
this->capacity = num_items;
|
||||
free(this->data);
|
||||
this->data = MallocT<T>(num_items);
|
||||
MemCpyT(this->data, other[0], num_items);
|
||||
} else if (num_items > 0) {
|
||||
MemCpyT(this->data, other[0], num_items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all rows from the matrix.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
/* In fact we just reset the width avoiding the need to
|
||||
* probably reallocate the same amount of memory the matrix was
|
||||
* previously using. */
|
||||
this->width = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list and free allocated memory.
|
||||
*/
|
||||
inline void Reset()
|
||||
{
|
||||
this->height = 0;
|
||||
this->width = 0;
|
||||
this->capacity = 0;
|
||||
free(this->data);
|
||||
this->data = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the matrix down to the smallest possible size.
|
||||
*/
|
||||
inline void Compact()
|
||||
{
|
||||
uint capacity = this->height * this->width;
|
||||
if (capacity >= this->capacity) return;
|
||||
this->capacity = capacity;
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a column, replacing it with the last one.
|
||||
* @param x Position of the column.
|
||||
*/
|
||||
void EraseColumn(uint x)
|
||||
{
|
||||
if (x < --this->width) {
|
||||
MemCpyT<T>(this->data + x * this->height,
|
||||
this->data + this->width * this->height,
|
||||
this->height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove columns from the matrix while preserving the order of other columns.
|
||||
* @param x First column to remove.
|
||||
* @param count Number of consecutive columns to remove.
|
||||
*/
|
||||
void EraseColumnPreservingOrder(uint x, uint count = 1)
|
||||
{
|
||||
if (count == 0) return;
|
||||
assert(x < this->width);
|
||||
assert(x + count <= this->width);
|
||||
this->width -= count;
|
||||
uint to_move = (this->width - x) * this->height;
|
||||
if (to_move > 0) {
|
||||
MemMoveT(this->data + x * this->height,
|
||||
this->data + (x + count) * this->height, to_move);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a row, replacing it with the last one.
|
||||
* @param y Position of the row.
|
||||
*/
|
||||
void EraseRow(uint y)
|
||||
{
|
||||
if (y < this->height - 1) {
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
this->data[x * this->height + y] =
|
||||
this->data[(x + 1) * this->height - 1];
|
||||
}
|
||||
}
|
||||
this->Resize(this->width, this->height - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove columns from the matrix while preserving the order of other columns.
|
||||
* @param y First column to remove.
|
||||
* @param count Number of consecutive columns to remove.
|
||||
*/
|
||||
void EraseRowPreservingOrder(uint y, uint count = 1)
|
||||
{
|
||||
if (this->height > count + y) {
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
MemMoveT(this->data + x * this->height + y,
|
||||
this->data + x * this->height + y + count,
|
||||
this->height - count - y);
|
||||
}
|
||||
}
|
||||
this->Resize(this->width, this->height - count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append rows.
|
||||
* @param to_add Number of rows to append.
|
||||
*/
|
||||
inline void AppendRow(uint to_add = 1)
|
||||
{
|
||||
this->Resize(this->width, to_add + this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append rows.
|
||||
* @param to_add Number of rows to append.
|
||||
*/
|
||||
inline void AppendColumn(uint to_add = 1)
|
||||
{
|
||||
this->Resize(to_add + this->width, this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size to a specific width and height, preserving item positions
|
||||
* as far as possible in the process.
|
||||
* @param new_width Target width.
|
||||
* @param new_height Target height.
|
||||
*/
|
||||
inline void Resize(uint new_width, uint new_height)
|
||||
{
|
||||
uint new_capacity = new_width * new_height;
|
||||
T *new_data = nullptr;
|
||||
void (*copy)(T *dest, const T *src, size_t count) = nullptr;
|
||||
if (new_capacity > this->capacity) {
|
||||
/* If the data doesn't fit into current capacity, resize and copy ... */
|
||||
new_data = MallocT<T>(new_capacity);
|
||||
copy = &MemCpyT<T>;
|
||||
} else {
|
||||
/* ... otherwise just move the columns around, if necessary. */
|
||||
new_data = this->data;
|
||||
copy = &MemMoveT<T>;
|
||||
}
|
||||
if (this->height != new_height || new_data != this->data) {
|
||||
if (this->height > 0) {
|
||||
if (new_height > this->height) {
|
||||
/* If matrix is growing, copy from the back to avoid
|
||||
* overwriting uncopied data. */
|
||||
for (uint x = this->width; x > 0; --x) {
|
||||
if (x * new_height > new_capacity) continue;
|
||||
(*copy)(new_data + (x - 1) * new_height,
|
||||
this->data + (x - 1) * this->height,
|
||||
std::min(this->height, new_height));
|
||||
}
|
||||
} else {
|
||||
/* If matrix is shrinking copy from the front. */
|
||||
for (uint x = 0; x < this->width; ++x) {
|
||||
if ((x + 1) * new_height > new_capacity) break;
|
||||
(*copy)(new_data + x * new_height,
|
||||
this->data + x * this->height,
|
||||
std::min(this->height, new_height));
|
||||
}
|
||||
}
|
||||
}
|
||||
this->height = new_height;
|
||||
if (new_data != this->data) {
|
||||
free(this->data);
|
||||
this->data = new_data;
|
||||
this->capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
this->width = new_width;
|
||||
}
|
||||
|
||||
inline uint Height() const
|
||||
{
|
||||
return this->height;
|
||||
}
|
||||
|
||||
inline uint Width() const
|
||||
{
|
||||
return this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item x/y (const).
|
||||
*
|
||||
* @param x X-position of the item.
|
||||
* @param y Y-position of the item.
|
||||
* @return Item at specified position.
|
||||
*/
|
||||
inline const T &Get(uint x, uint y) const
|
||||
{
|
||||
assert(x < this->width && y < this->height);
|
||||
return this->data[x * this->height + y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item x/y.
|
||||
*
|
||||
* @param x X-position of the item.
|
||||
* @param y Y-position of the item.
|
||||
* @return Item at specified position.
|
||||
*/
|
||||
inline T &Get(uint x, uint y)
|
||||
{
|
||||
assert(x < this->width && y < this->height);
|
||||
return this->data[x * this->height + y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline const T *operator[](uint x) const
|
||||
{
|
||||
assert(x < this->width);
|
||||
return this->data + x * this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline T *operator[](uint x)
|
||||
{
|
||||
assert(x < this->width);
|
||||
return this->data + x * this->height;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLMATRIX_TYPE_HPP */
|
||||
@@ -10,7 +10,6 @@
|
||||
#ifndef SMALLSTACK_TYPE_HPP
|
||||
#define SMALLSTACK_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file span_type.hpp Minimized implementation of C++20 std::span. */
|
||||
|
||||
#ifndef CORE_SPAN_TYPE_HPP
|
||||
#define CORE_SPAN_TYPE_HPP
|
||||
|
||||
/* This is a partial copy/paste from https://github.com/gsl-lite/gsl-lite/blob/master/include/gsl/gsl-lite.hpp */
|
||||
|
||||
/* Template to check if a template variable defines size() and data(). */
|
||||
template <class, class = void>
|
||||
struct has_size_and_data : std::false_type{};
|
||||
template <class C>
|
||||
struct has_size_and_data
|
||||
<
|
||||
C, std::void_t<
|
||||
decltype(std::size(std::declval<C>())),
|
||||
decltype(std::data(std::declval<C>()))>
|
||||
> : std::true_type{};
|
||||
|
||||
/* Template to check if two elements are compatible. */
|
||||
template <class, class, class = void>
|
||||
struct is_compatible_element : std::false_type {};
|
||||
template <class C, class E>
|
||||
struct is_compatible_element
|
||||
<
|
||||
C, E, std::void_t<
|
||||
decltype(std::data(std::declval<C>())),
|
||||
typename std::remove_pointer_t<decltype(std::data( std::declval<C&>()))>(*)[]>
|
||||
> : std::is_convertible<typename std::remove_pointer_t<decltype(std::data(std::declval<C&>()))>(*)[], E(*)[]>{};
|
||||
|
||||
/* Template to check if a container is compatible. gsl-lite also includes is_array and is_std_array, but as we don't use them, they are omitted. */
|
||||
template <class C, class E>
|
||||
struct is_compatible_container : std::bool_constant
|
||||
<
|
||||
has_size_and_data<C>::value
|
||||
&& is_compatible_element<C,E>::value
|
||||
>{};
|
||||
|
||||
/**
|
||||
* A trimmed down version of what std::span will be in C++20.
|
||||
*
|
||||
* It is fully forwards compatible, so if this codebase switches to C++20,
|
||||
* all "span" instances can be replaced by "std::span" without loss of
|
||||
* functionality.
|
||||
*
|
||||
* Currently it only supports basic functionality:
|
||||
* - size() and friends
|
||||
* - begin() and friends
|
||||
*
|
||||
* It is meant to simplify function parameters, where we only want to walk
|
||||
* a continuous list.
|
||||
*/
|
||||
template<class T>
|
||||
class span {
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef typename std::remove_cv< T >::type value_type;
|
||||
|
||||
typedef T &reference;
|
||||
typedef T *pointer;
|
||||
typedef const T &const_reference;
|
||||
typedef const T *const_pointer;
|
||||
|
||||
typedef pointer iterator;
|
||||
typedef const_pointer const_iterator;
|
||||
|
||||
typedef size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
constexpr span() noexcept : first(nullptr), last(nullptr) {}
|
||||
|
||||
constexpr span(pointer data_in, size_t size_in) : first(data_in), last(data_in + size_in) {}
|
||||
|
||||
template<class Container, typename std::enable_if<(is_compatible_container<Container, element_type>::value), int>::type = 0>
|
||||
constexpr span(Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {}
|
||||
template<class Container, typename std::enable_if<(std::is_const<element_type>::value && is_compatible_container<Container, element_type>::value), int>::type = 0>
|
||||
constexpr span(const Container &list) noexcept : first(std::data(list)), last(std::data(list) + std::size(list)) {}
|
||||
|
||||
constexpr size_t size() const noexcept { return static_cast<size_t>( last - first ); }
|
||||
constexpr std::ptrdiff_t ssize() const noexcept { return static_cast<std::ptrdiff_t>( last - first ); }
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
constexpr iterator begin() const noexcept { return iterator(first); }
|
||||
constexpr iterator end() const noexcept { return iterator(last); }
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept { return const_iterator(first); }
|
||||
constexpr const_iterator cend() const noexcept { return const_iterator(last); }
|
||||
|
||||
constexpr reference operator[](size_type idx) const { return first[idx]; }
|
||||
|
||||
private:
|
||||
pointer first;
|
||||
pointer last;
|
||||
};
|
||||
|
||||
#endif /* CORE_SPAN_TYPE_HPP */
|
||||
@@ -1,27 +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 string_compare_type.hpp Comparator class for "const char *" so it can be used as a key for std::map */
|
||||
|
||||
#ifndef STRING_COMPARE_TYPE_HPP
|
||||
#define STRING_COMPARE_TYPE_HPP
|
||||
|
||||
/** Comparator for strings. */
|
||||
struct StringCompare {
|
||||
/**
|
||||
* Compare two strings.
|
||||
* @param a The first string.
|
||||
* @param b The second string.
|
||||
* @return True is the first string is deemed "lower" than the second string.
|
||||
*/
|
||||
bool operator () (const char *a, const char *b) const
|
||||
{
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* STRING_COMPARE_TYPE_HPP */
|
||||
@@ -10,64 +10,173 @@
|
||||
#ifndef STRONG_TYPEDEF_TYPE_HPP
|
||||
#define STRONG_TYPEDEF_TYPE_HPP
|
||||
|
||||
/** Non-templated base for #StrongTypedef for use with type trait queries. */
|
||||
#include "../3rdparty/fmt/format.h"
|
||||
|
||||
/** Non-templated base for #StrongType::Typedef for use with type trait queries. */
|
||||
struct StrongTypedefBase {};
|
||||
|
||||
/**
|
||||
* Templated helper to make a type-safe 'typedef' representing a single POD value.
|
||||
* A normal 'typedef' is not distinct from its base type and will be treated as
|
||||
* identical in many contexts. This class provides a distinct type that can still
|
||||
* be assign from and compared to values of its base type.
|
||||
*
|
||||
* @note This is meant to be used as a base class, not directly.
|
||||
* @tparam T Storage type
|
||||
* @tparam Tthis Type of the derived class (i.e. the concrete usage of this class).
|
||||
*/
|
||||
template <class T, class Tthis>
|
||||
struct StrongTypedef : StrongTypedefBase {
|
||||
using Type = T;
|
||||
namespace StrongType {
|
||||
/**
|
||||
* Mix-in which makes the new Typedef comparable with itself and its base type.
|
||||
*/
|
||||
struct Compare {
|
||||
template <typename TType, typename TBaseType>
|
||||
struct mixin {
|
||||
friend constexpr bool operator ==(const TType &lhs, const TType &rhs) { return lhs.value == rhs.value; }
|
||||
friend constexpr bool operator ==(const TType &lhs, const TBaseType &rhs) { return lhs.value == rhs; }
|
||||
|
||||
T value{}; ///< Backing storage field.
|
||||
friend constexpr bool operator !=(const TType &lhs, const TType &rhs) { return lhs.value != rhs.value; }
|
||||
friend constexpr bool operator !=(const TType &lhs, const TBaseType &rhs) { return lhs.value != rhs; }
|
||||
|
||||
constexpr StrongTypedef() = default;
|
||||
constexpr StrongTypedef(const StrongTypedef &o) = default;
|
||||
constexpr StrongTypedef(StrongTypedef &&o) = default;
|
||||
friend constexpr bool operator <=(const TType &lhs, const TType &rhs) { return lhs.value <= rhs.value; }
|
||||
friend constexpr bool operator <=(const TType &lhs, const TBaseType &rhs) { return lhs.value <= rhs; }
|
||||
|
||||
constexpr StrongTypedef(const T &value) : value(value) {}
|
||||
friend constexpr bool operator <(const TType &lhs, const TType &rhs) { return lhs.value < rhs.value; }
|
||||
friend constexpr bool operator <(const TType &lhs, const TBaseType &rhs) { return lhs.value < rhs; }
|
||||
|
||||
constexpr Tthis &operator =(const StrongTypedef &rhs) { this->value = rhs.value; return static_cast<Tthis &>(*this); }
|
||||
constexpr Tthis &operator =(StrongTypedef &&rhs) { this->value = std::move(rhs.value); return static_cast<Tthis &>(*this); }
|
||||
constexpr Tthis &operator =(const T &rhs) { this->value = rhs; return static_cast<Tthis &>(*this); }
|
||||
friend constexpr bool operator >=(const TType &lhs, const TType &rhs) { return lhs.value >= rhs.value; }
|
||||
friend constexpr bool operator >=(const TType &lhs, const TBaseType &rhs) { return lhs.value >= rhs; }
|
||||
|
||||
explicit constexpr operator T() const { return this->value; }
|
||||
friend constexpr bool operator >(const TType &lhs, const TType &rhs) { return lhs.value > rhs.value; }
|
||||
friend constexpr bool operator >(const TType &lhs, const TBaseType &rhs) { return lhs.value > rhs; }
|
||||
};
|
||||
};
|
||||
|
||||
constexpr bool operator ==(const StrongTypedef &rhs) const { return this->value == rhs.value; }
|
||||
constexpr bool operator !=(const StrongTypedef &rhs) const { return this->value != rhs.value; }
|
||||
constexpr bool operator ==(const T &rhs) const { return this->value == rhs; }
|
||||
constexpr bool operator !=(const T &rhs) const { return this->value != rhs; }
|
||||
};
|
||||
/**
|
||||
* Mix-in which makes the new Typedef behave more like an integer. This means you can add and subtract from it.
|
||||
*
|
||||
* Operators like divide, multiply and module are explicitly denied, as that often makes little sense for the
|
||||
* new type. If you want to do these actions on the new Typedef, you are better off first casting it to the
|
||||
* base type.
|
||||
*/
|
||||
struct Integer {
|
||||
template <typename TType, typename TBaseType>
|
||||
struct mixin {
|
||||
friend constexpr TType &operator ++(TType &lhs) { lhs.value++; return lhs; }
|
||||
friend constexpr TType &operator --(TType &lhs) { lhs.value--; return lhs; }
|
||||
friend constexpr TType operator ++(TType &lhs, int) { TType res = lhs; lhs.value++; return res; }
|
||||
friend constexpr TType operator --(TType &lhs, int) { TType res = lhs; lhs.value--; return res; }
|
||||
|
||||
/**
|
||||
* Extension of #StrongTypedef with operators for addition and subtraction.
|
||||
* @tparam T Storage type
|
||||
* @tparam Tthis Type of the derived class (i.e. the concrete usage of this class).
|
||||
*/
|
||||
template <class T, class Tthis>
|
||||
struct StrongIntegralTypedef : StrongTypedef<T, Tthis> {
|
||||
using StrongTypedef<T, Tthis>::StrongTypedef;
|
||||
friend constexpr TType &operator +=(TType &lhs, const TType &rhs) { lhs.value += rhs.value; return lhs; }
|
||||
friend constexpr TType operator +(const TType &lhs, const TType &rhs) { return TType{ lhs.value + rhs.value }; }
|
||||
friend constexpr TType operator +(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value + rhs }; }
|
||||
|
||||
constexpr Tthis &operator ++() { this->value++; return static_cast<Tthis &>(*this); }
|
||||
constexpr Tthis &operator --() { this->value--; return static_cast<Tthis &>(*this); }
|
||||
constexpr Tthis operator ++(int) { auto res = static_cast<Tthis &>(*this); this->value++; return res; }
|
||||
constexpr Tthis operator --(int) { auto res = static_cast<Tthis &>(*this); this->value--; return res; }
|
||||
friend constexpr TType &operator -=(TType &lhs, const TType &rhs) { lhs.value -= rhs.value; return lhs; }
|
||||
friend constexpr TType operator -(const TType &lhs, const TType &rhs) { return TType{ lhs.value - rhs.value }; }
|
||||
friend constexpr TType operator -(const TType &lhs, const TBaseType &rhs) { return TType{ lhs.value - rhs }; }
|
||||
|
||||
constexpr Tthis &operator +=(const Tthis &rhs) { this->value += rhs.value; return *static_cast<Tthis *>(this); }
|
||||
constexpr Tthis &operator -=(const Tthis &rhs) { this->value -= rhs.value; return *static_cast<Tthis *>(this); }
|
||||
/* For most new types, the rest of the operators make no sense. For example,
|
||||
* what does it actually mean to multiply a Year with a value. Or to do a
|
||||
* bitwise OR on a Date. Or to divide a TileIndex by 2. Conceptually, they
|
||||
* don't really mean anything. So force the user to first cast it to the
|
||||
* base type, so the operation no longer returns the new Typedef. */
|
||||
|
||||
constexpr Tthis operator +(const Tthis &rhs) const { return Tthis{ this->value + rhs.value }; }
|
||||
constexpr Tthis operator -(const Tthis &rhs) const { return Tthis{ this->value - rhs.value }; }
|
||||
constexpr Tthis operator +(const T &rhs) const { return Tthis{ this->value + rhs }; }
|
||||
constexpr Tthis operator -(const T &rhs) const { return Tthis{ this->value - rhs }; }
|
||||
};
|
||||
constexpr TType &operator *=(const TType &rhs) = delete;
|
||||
constexpr TType operator *(const TType &rhs) = delete;
|
||||
constexpr TType operator *(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator /=(const TType &rhs) = delete;
|
||||
constexpr TType operator /(const TType &rhs) = delete;
|
||||
constexpr TType operator /(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator %=(const TType &rhs) = delete;
|
||||
constexpr TType operator %(const TType &rhs) = delete;
|
||||
constexpr TType operator %(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator &=(const TType &rhs) = delete;
|
||||
constexpr TType operator &(const TType &rhs) = delete;
|
||||
constexpr TType operator &(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator |=(const TType &rhs) = delete;
|
||||
constexpr TType operator |(const TType &rhs) = delete;
|
||||
constexpr TType operator |(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator ^=(const TType &rhs) = delete;
|
||||
constexpr TType operator ^(const TType &rhs) = delete;
|
||||
constexpr TType operator ^(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator <<=(const TType &rhs) = delete;
|
||||
constexpr TType operator <<(const TType &rhs) = delete;
|
||||
constexpr TType operator <<(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType &operator >>=(const TType &rhs) = delete;
|
||||
constexpr TType operator >>(const TType &rhs) = delete;
|
||||
constexpr TType operator >>(const TBaseType &rhs) = delete;
|
||||
|
||||
constexpr TType operator ~() = delete;
|
||||
constexpr TType operator -() = delete;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Mix-in which makes the new Typedef compatible with another type (which is not the base type).
|
||||
*
|
||||
* @note The base type of the new Typedef will be cast to the other type; so make sure they are compatible.
|
||||
*
|
||||
* @tparam TCompatibleType The other type to be compatible with.
|
||||
*/
|
||||
template <typename TCompatibleType>
|
||||
struct Compatible {
|
||||
template <typename TType, typename TBaseType>
|
||||
struct mixin {
|
||||
friend constexpr bool operator ==(const TType &lhs, TCompatibleType rhs) { return lhs.value == static_cast<TBaseType>(rhs); }
|
||||
friend constexpr bool operator !=(const TType &lhs, TCompatibleType rhs) { return lhs.value != static_cast<TBaseType>(rhs); }
|
||||
|
||||
friend constexpr bool operator <=(const TType &lhs, TCompatibleType rhs) { return lhs.value <= static_cast<TBaseType>(rhs); }
|
||||
friend constexpr bool operator <(const TType &lhs, TCompatibleType rhs) { return lhs.value < static_cast<TBaseType>(rhs); }
|
||||
friend constexpr bool operator >=(const TType &lhs, TCompatibleType rhs) { return lhs.value >= static_cast<TBaseType>(rhs); }
|
||||
friend constexpr bool operator >(const TType &lhs, TCompatibleType rhs) { return lhs.value > static_cast<TBaseType>(rhs); }
|
||||
|
||||
friend constexpr TType operator +(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value + rhs) }; }
|
||||
friend constexpr TType operator -(const TType &lhs, TCompatibleType rhs) { return { static_cast<TBaseType>(lhs.value - rhs) }; }
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Templated helper to make a type-safe 'typedef' representing a single POD value.
|
||||
* A normal 'typedef' is not distinct from its base type and will be treated as
|
||||
* identical in many contexts. This class provides a distinct type that can still
|
||||
* be assign from and compared to values of its base type.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* using MyType = StrongType::Typedef<int, struct MyTypeTag, StrongType::Explicit, StrongType::Compare, StrongType::Integer>;
|
||||
*
|
||||
* @tparam TBaseType Type of the derived class (i.e. the concrete usage of this class).
|
||||
* @tparam TTag An unique struct to keep types of the same TBaseType distinct.
|
||||
* @tparam TProperties A list of mixins to add to the class.
|
||||
*/
|
||||
template <typename TBaseType, typename TTag, typename... TProperties>
|
||||
struct EMPTY_BASES Typedef : public StrongTypedefBase, public TProperties::template mixin<Typedef<TBaseType, TTag, TProperties...>, TBaseType>... {
|
||||
using BaseType = TBaseType;
|
||||
|
||||
constexpr Typedef() = default;
|
||||
constexpr Typedef(const Typedef &) = default;
|
||||
constexpr Typedef(Typedef &&) = default;
|
||||
|
||||
constexpr Typedef(const TBaseType &value) : value(value) {}
|
||||
|
||||
constexpr Typedef &operator =(const Typedef &rhs) { this->value = rhs.value; return *this; }
|
||||
constexpr Typedef &operator =(Typedef &&rhs) { this->value = std::move(rhs.value); return *this; }
|
||||
constexpr Typedef &operator =(const TBaseType &rhs) { this->value = rhs; return *this; }
|
||||
|
||||
/* Only allow conversion to BaseType via method. */
|
||||
constexpr TBaseType base() const { return this->value; }
|
||||
|
||||
/* Only allow TProperties classes access to the internal value. Everyone else needs to call .base(). */
|
||||
friend struct Compare;
|
||||
friend struct Integer;
|
||||
template <typename TCompatibleType> friend struct Compatible;
|
||||
|
||||
/* GCC / MSVC don't pick up on the "friend struct" above, where CLang does.
|
||||
* As in our CI we compile for all three targets, it is sufficient to have one
|
||||
* that errors on this; but nobody should be using "value" directly. Instead,
|
||||
* use base() to convert to the base type. */
|
||||
#ifdef __clang__
|
||||
protected:
|
||||
#endif /* __clang__ */
|
||||
TBaseType value{};
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* STRONG_TYPEDEF_TYPE_HPP */
|
||||
|
||||
Reference in New Issue
Block a user