Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-05-14 18:41:13 +05:00
994 changed files with 38753 additions and 34512 deletions
+2 -2
View File
@@ -93,14 +93,14 @@ public:
* @param size the amount of bytes to allocate.
* @return the given amounts of bytes zeroed.
*/
inline void *operator new(size_t size) { return CallocT<byte>(size); }
inline void *operator new(size_t size) { return CallocT<uint8_t>(size); }
/**
* Memory allocator for an array of class instances.
* @param size the amount of bytes to allocate.
* @return the given amounts of bytes zeroed.
*/
inline void *operator new[](size_t size) { return CallocT<byte>(size); }
inline void *operator new[](size_t size) { return CallocT<uint8_t>(size); }
/**
* Memory release for a single class instance.
+6 -9
View File
@@ -22,20 +22,18 @@ struct Backup {
/**
* Backup variable.
* @param original Variable to backup.
* @param file Filename for debug output. Use FILE_LINE macro.
* @param line Linenumber for debug output. Use FILE_LINE macro.
* @param location Source location for debug output.
*/
Backup(T &original, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line) {}
Backup(T &original, const std::source_location location = std::source_location::current()) : original(original), valid(true), original_value(original), location(location) {}
/**
* Backup variable and switch to new value.
* @param original Variable to backup.
* @param new_value New value for variable.
* @param file Filename for debug output. Use FILE_LINE macro.
* @param line Linenumber for debug output. Use FILE_LINE macro.
* @param location Source location for debug output.
*/
template <typename U>
Backup(T &original, const U &new_value, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line)
Backup(T &original, const U &new_value, const std::source_location location = std::source_location::current()) : original(original), valid(true), original_value(original), location(location)
{
/* Note: We use a separate typename U, so type conversions are handled by assignment operator. */
original = new_value;
@@ -51,7 +49,7 @@ struct Backup {
{
/* We cannot assert here, as missing restoration is 'normal' when exceptions are thrown.
* Exceptions are especially used to abort world generation. */
Debug(misc, 0, "{}:{}: Backed-up value was not restored!", this->file, this->line);
Debug(misc, 0, "{}:{}: Backed-up value was not restored!", this->location.file_name(), this->location.line());
this->Restore();
}
}
@@ -140,8 +138,7 @@ private:
bool valid;
T original_value;
const char * const file;
const int line;
const std::source_location location;
};
/**
+19
View File
@@ -183,6 +183,25 @@ constexpr T ToggleBit(T &x, const uint8_t y)
return x = (T)(x ^ ((T)1U << y));
}
/**
* Assigns a bit in a variable.
*
* This function assigns a single bit in a variable. The variable is
* changed and the value is also returned. Parameter y defines the bit
* to assign and starts at the LSB with 0.
*
* @param x The variable to assign the bit
* @param y The bit position to assign
* @param value The new bit value
* @pre y < sizeof(T) * 8
* @return The new value of the old value with the bit assigned
*/
template <typename T>
constexpr T AssignBit(T &x, const uint8_t y, bool value)
{
return SB<T>(x, y, 1, value ? 1 : 0);
}
/**
* Search the first set bit in a value.
* When no bit is set, it returns 0.
+17 -2
View File
@@ -23,7 +23,7 @@
template <typename Container>
inline bool include(Container &container, typename Container::const_reference &item)
{
const bool is_member = std::find(container.begin(), container.end(), item) != container.end();
const bool is_member = std::ranges::find(container, item) != container.end();
if (!is_member) container.emplace_back(item);
return is_member;
}
@@ -40,10 +40,25 @@ inline bool include(Container &container, typename Container::const_reference &i
template <typename Container>
int find_index(Container const &container, typename Container::const_reference item)
{
auto const it = std::find(container.begin(), container.end(), item);
auto const it = std::ranges::find(container, item);
if (it != container.end()) return std::distance(container.begin(), it);
return -1;
}
/**
* Move elements between first and last to a new position, rotating elements in between as necessary.
* @param first Iterator to first element to move.
* @param last Iterator to (end-of) last element to move.
* @param position Iterator to where range should be moved to.
* @returns Iterators to first and last after being moved.
*/
template <typename TIter>
auto Slide(TIter first, TIter last, TIter position) -> std::pair<TIter, TIter>
{
if (last < position) return { std::rotate(first, last, position), position };
if (position < first) return { position, std::rotate(position, first, last) };
return { first, last };
}
#endif /* CONTAINER_FUNC_HPP */
+26 -10
View File
@@ -10,18 +10,22 @@
#ifndef ENUM_TYPE_HPP
#define ENUM_TYPE_HPP
/** Implementation of std::to_underlying (from C++23) */
template <typename enum_type>
constexpr std::underlying_type_t<enum_type> to_underlying(enum_type e) { return static_cast<std::underlying_type_t<enum_type>>(e); }
/** Some enums need to have allowed incrementing (i.e. StationClassID) */
#define DECLARE_POSTFIX_INCREMENT(enum_type) \
inline constexpr enum_type operator ++(enum_type& e, int) \
{ \
enum_type e_org = e; \
e = (enum_type)((std::underlying_type<enum_type>::type)e + 1); \
e = static_cast<enum_type>(to_underlying(e) + 1); \
return e_org; \
} \
inline constexpr enum_type operator --(enum_type& e, int) \
{ \
enum_type e_org = e; \
e = (enum_type)((std::underlying_type<enum_type>::type)e - 1); \
e = static_cast<enum_type>(to_underlying(e) - 1); \
return e_org; \
}
@@ -29,19 +33,31 @@
/** Operators to allow to work with enum as with type safe bit set in C++ */
#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);}
inline constexpr enum_type operator | (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) | to_underlying(m2)); } \
inline constexpr enum_type operator & (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) & to_underlying(m2)); } \
inline constexpr enum_type operator ^ (enum_type m1, enum_type m2) { return static_cast<enum_type>(to_underlying(m1) ^ to_underlying(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 static_cast<enum_type>(~to_underlying(m)); }
/** 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)); \
return static_cast<OtherEnumType>(to_underlying(m1) + to_underlying(m2)); \
}
/**
* Checks if a value in a bitset enum is set.
* @param x The value to check.
* @param y The flag to check.
* @return True iff the flag is set.
*/
template <typename T, class = typename std::enable_if_t<std::is_enum_v<T>>>
debug_inline constexpr bool HasFlag(const T x, const T y)
{
return (x & y) == y;
}
#endif /* ENUM_TYPE_HPP */
+1 -1
View File
@@ -12,7 +12,7 @@
#include "geometry_type.hpp"
Dimension maxdim(const Dimension &d1, const Dimension &d2);
[[nodiscard]] Dimension maxdim(const Dimension &d1, const Dimension &d2);
/**
* Check if a rectangle is empty.
+33 -33
View File
@@ -42,12 +42,12 @@ class Kdtree {
node(T element) : element(element), left(INVALID_NODE), right(INVALID_NODE) { }
};
static const size_t INVALID_NODE = SIZE_MAX; ///< Index value indicating no-such-node
static const size_t INVALID_NODE = SIZE_MAX; ///< Index value indicating no-such-node
static const size_t MIN_REBALANCE_THRESHOLD = 8; ///< Arbitrary value for "not worth rebalancing"
std::vector<node> nodes; ///< Pool of all nodes in the tree
std::vector<size_t> free_list; ///< List of dead indices in the nodes vector
size_t root; ///< Index of root node
TxyFunc xyfunc; ///< Functor to extract a coordinate from an element
size_t unbalanced; ///< Number approximating how unbalanced the tree might be
/** Create one new node in the tree, return its index in the pool */
@@ -69,8 +69,8 @@ class Kdtree {
CoordT SelectSplitCoord(It begin, It end, int level)
{
It mid = begin + (end - begin) / 2;
std::nth_element(begin, mid, end, [&](T a, T b) { return this->xyfunc(a, level % 2) < this->xyfunc(b, level % 2); });
return this->xyfunc(*mid, level % 2);
std::nth_element(begin, mid, end, [&](T a, T b) { return TxyFunc()(a, level % 2) < TxyFunc()(b, level % 2); });
return TxyFunc()(*mid, level % 2);
}
/** Construct a subtree from elements between begin and end iterators, return index of root */
@@ -84,8 +84,8 @@ class Kdtree {
} else if (count == 1) {
return this->AddNode(*begin);
} else if (count > 1) {
CoordT split_coord = SelectSplitCoord(begin, end, level);
It split = std::partition(begin, end, [&](T v) { return this->xyfunc(v, level % 2) < split_coord; });
CoordT split_coord = this->SelectSplitCoord(begin, end, level);
It split = std::partition(begin, end, [&](T v) { return TxyFunc()(v, level % 2) < split_coord; });
size_t newidx = this->AddNode(*split);
this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1);
this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1);
@@ -99,7 +99,7 @@ class Kdtree {
bool Rebuild(const T *include_element, const T *exclude_element)
{
size_t initial_count = this->Count();
if (initial_count < 8) return false; // arbitrary value for "not worth rebalancing"
if (initial_count < MIN_REBALANCE_THRESHOLD) return false;
T root_element = this->nodes[this->root].element;
std::vector<T> elements = this->FreeSubtree(this->root);
@@ -129,9 +129,9 @@ class Kdtree {
node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */
CoordT nc = this->xyfunc(n.element, dim);
CoordT nc = TxyFunc()(n.element, dim);
/* Coordinate of the new element */
CoordT ec = this->xyfunc(element, dim);
CoordT ec = TxyFunc()(element, dim);
/* Which side to insert on */
size_t &next = (ec < nc) ? n.left : n.right;
@@ -202,9 +202,9 @@ class Kdtree {
/* Dimension index of current level */
int dim = level % 2;
/* Coordinate of element splitting at this node */
CoordT nc = this->xyfunc(n.element, dim);
CoordT nc = TxyFunc()(n.element, dim);
/* Coordinate of the element being removed */
CoordT ec = this->xyfunc(element, dim);
CoordT ec = TxyFunc()(element, dim);
/* Which side to remove from */
size_t next = (ec < nc) ? n.left : n.right;
assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached
@@ -222,7 +222,7 @@ class Kdtree {
DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const
{
return abs((DistT)this->xyfunc(element, 0) - (DistT)x) + abs((DistT)this->xyfunc(element, 1) - (DistT)y);
return abs((DistT)TxyFunc()(element, 0) - (DistT)x) + abs((DistT)TxyFunc()(element, 1) - (DistT)y);
}
/** A data element and its distance to a searched-for point */
@@ -245,9 +245,9 @@ class Kdtree {
const node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */
CoordT c = this->xyfunc(n.element, dim);
CoordT c = TxyFunc()(n.element, dim);
/* This node's distance to target */
DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]);
DistT thisdist = this->ManhattanDistance(n.element, xy[0], xy[1]);
/* Assume this node is the best choice for now */
node_distance best = std::make_pair(n.element, thisdist);
@@ -280,9 +280,9 @@ class Kdtree {
const node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */
CoordT ec = this->xyfunc(n.element, dim);
CoordT ec = TxyFunc()(n.element, dim);
/* Opposite coordinate of element */
CoordT oc = this->xyfunc(n.element, 1 - dim);
CoordT oc = TxyFunc()(n.element, 1 - dim);
/* Test if this element is within rectangle */
if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
@@ -299,7 +299,7 @@ class Kdtree {
{
if (node_idx == INVALID_NODE) return 0;
const node &n = this->nodes[node_idx];
return CountValue(element, n.left) + CountValue(element, n.right) + ((n.element == element) ? 1 : 0);
return this->CountValue(element, n.left) + this->CountValue(element, n.right) + ((n.element == element) ? 1 : 0);
}
void IncrementUnbalanced(size_t amount = 1)
@@ -308,21 +308,21 @@ class Kdtree {
}
/** Check if the entire tree is in need of rebuilding */
bool IsUnbalanced()
bool IsUnbalanced() const
{
size_t count = this->Count();
if (count < 8) return false;
return this->unbalanced > this->Count() / 4;
if (count < MIN_REBALANCE_THRESHOLD) return false;
return this->unbalanced > count / 4;
}
/** Verify that the invariant is true for a sub-tree, assert if not */
void CheckInvariant(size_t node_idx, int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y)
void CheckInvariant(size_t node_idx, int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y) const
{
if (node_idx == INVALID_NODE) return;
const node &n = this->nodes[node_idx];
CoordT cx = this->xyfunc(n.element, 0);
CoordT cy = this->xyfunc(n.element, 1);
CoordT cx = TxyFunc()(n.element, 0);
CoordT cy = TxyFunc()(n.element, 1);
assert(cx >= min_x);
assert(cx < max_x);
@@ -331,26 +331,26 @@ class Kdtree {
if (level % 2 == 0) {
// split in dimension 0 = x
CheckInvariant(n.left, level + 1, min_x, cx, min_y, max_y);
CheckInvariant(n.right, level + 1, cx, max_x, min_y, max_y);
this->CheckInvariant(n.left, level + 1, min_x, cx, min_y, max_y);
this->CheckInvariant(n.right, level + 1, cx, max_x, min_y, max_y);
} else {
// split in dimension 1 = y
CheckInvariant(n.left, level + 1, min_x, max_x, min_y, cy);
CheckInvariant(n.right, level + 1, min_x, max_x, cy, max_y);
this->CheckInvariant(n.left, level + 1, min_x, max_x, min_y, cy);
this->CheckInvariant(n.right, level + 1, min_x, max_x, cy, max_y);
}
}
/** Verify the invariant for the entire tree, does nothing unless KDTREE_DEBUG is defined */
void CheckInvariant()
void CheckInvariant() const
{
#ifdef KDTREE_DEBUG
CheckInvariant(this->root, 0, std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max(), std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max());
this->CheckInvariant(this->root, 0, std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max(), std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max());
#endif
}
public:
/** Construct a new Kdtree with the given xyfunc */
Kdtree(TxyFunc xyfunc) : root(INVALID_NODE), xyfunc(xyfunc), unbalanced(0) { }
Kdtree() : root(INVALID_NODE), unbalanced(0) { }
/**
* Clear and rebuild the tree from a new sequence of elements,
@@ -368,7 +368,7 @@ public:
this->nodes.reserve(end - begin);
this->root = this->BuildSubtree(begin, end, 0);
CheckInvariant();
this->CheckInvariant();
}
/**
@@ -404,7 +404,7 @@ public:
this->InsertRecursive(element, this->root, 0);
this->IncrementUnbalanced();
}
CheckInvariant();
this->CheckInvariant();
}
}
@@ -423,7 +423,7 @@ public:
this->root = this->RemoveRecursive(element, this->root, 0);
this->IncrementUnbalanced();
}
CheckInvariant();
this->CheckInvariant();
}
/** Get number of elements stored in tree */
+7 -7
View File
@@ -22,7 +22,7 @@
template <typename T>
constexpr T abs(const T a)
{
return (a < (T)0) ? -a : a;
return (a < static_cast<T>(0)) ? -a : a;
}
/**
@@ -38,7 +38,7 @@ constexpr T Align(const T x, uint n)
{
assert((n & (n - 1)) == 0 && n != 0);
n--;
return (T)((x + n) & ~((T)n));
return static_cast<T>((x + n) & ~static_cast<T>(n));
}
/**
@@ -54,8 +54,8 @@ constexpr T Align(const T x, uint n)
template <typename T>
constexpr T *AlignPtr(T *x, uint n)
{
static_assert(sizeof(size_t) == sizeof(void *));
return reinterpret_cast<T *>(Align((size_t)x, n));
static_assert(sizeof(uintptr_t) == sizeof(void *));
return reinterpret_cast<T *>(Align(reinterpret_cast<uintptr_t>(x), n));
}
/**
@@ -251,7 +251,7 @@ constexpr T Delta(const T a, const T b)
template <typename T>
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
{
return (size_t)(x - base) < size;
return static_cast<size_t>(x - base) < size;
}
/**
@@ -268,9 +268,9 @@ template <typename T, std::enable_if_t<std::disjunction_v<std::is_convertible<T,
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
{
if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
return (size_t)(x.base() - min) < (max - min);
return static_cast<size_t>(x.base() - min) < (max - min);
} else {
return (size_t)(x - min) < (max - min);
return static_cast<size_t>(x - min) < (max - min);
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ 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>
inline void MemSetT(T *ptr, byte value, size_t num = 1)
inline void MemSetT(T *ptr, uint8_t value, size_t num = 1)
{
memset(ptr, value, num * sizeof(T));
}
+5 -5
View File
@@ -140,7 +140,7 @@ public:
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; }
inline constexpr OverflowSafeInt operator * (const uint8_t factor) const { OverflowSafeInt result = *this; result *= (int64_t)factor; return result; }
/* Operators for division. */
inline constexpr OverflowSafeInt& operator /= (const int64_t divisor) { this->m_value /= divisor; return *this; }
@@ -200,10 +200,10 @@ template <class T> inline constexpr OverflowSafeInt<T> operator * (const uint a
template <class T> inline constexpr OverflowSafeInt<T> operator / (const uint a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
/* Sometimes we got byte operator OverflowSafeInt instead of vice versa. Handle that properly. */
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 -b + (uint)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; }
template <class T> inline constexpr OverflowSafeInt<T> operator + (const uint8_t a, const OverflowSafeInt<T> b) { return b + (uint)a; }
template <class T> inline constexpr OverflowSafeInt<T> operator - (const uint8_t a, const OverflowSafeInt<T> b) { return -b + (uint)a; }
template <class T> inline constexpr OverflowSafeInt<T> operator * (const uint8_t a, const OverflowSafeInt<T> b) { return b * (uint)a; }
template <class T> inline constexpr OverflowSafeInt<T> operator / (const uint8_t a, const OverflowSafeInt<T> b) { return (OverflowSafeInt<T>)a / (int)b; }
typedef OverflowSafeInt<int64_t> OverflowSafeInt64;
typedef OverflowSafeInt<int32_t> OverflowSafeInt32;
+1 -1
View File
@@ -19,7 +19,7 @@
/* virtual */ PoolBase::~PoolBase()
{
PoolVector *pools = PoolBase::GetPools();
pools->erase(std::find(pools->begin(), pools->end(), this));
pools->erase(std::ranges::find(*pools, this));
if (pools->empty()) delete pools;
}
+5 -5
View File
@@ -115,17 +115,17 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
Titem *item;
if (Tcache && this->alloc_cache != nullptr) {
assert(sizeof(Titem) == size);
item = (Titem *)this->alloc_cache;
item = reinterpret_cast<Titem *>(this->alloc_cache);
this->alloc_cache = this->alloc_cache->next;
if (Tzero) {
/* Explicitly casting to (void *) prevents a clang warning -
* we are actually memsetting a (not-yet-constructed) object */
memset((void *)item, 0, sizeof(Titem));
memset(static_cast<void *>(item), 0, sizeof(Titem));
}
} else if (Tzero) {
item = (Titem *)CallocT<byte>(size);
item = reinterpret_cast<Titem *>(CallocT<uint8_t>(size));
} else {
item = (Titem *)MallocT<byte>(size);
item = reinterpret_cast<Titem *>(MallocT<uint8_t>(size));
}
this->data[index] = item;
SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
@@ -188,7 +188,7 @@ DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
assert(index < this->size);
assert(this->data[index] != nullptr);
if (Tcache) {
AllocCache *ac = (AllocCache *)this->data[index];
AllocCache *ac = reinterpret_cast<AllocCache *>(this->data[index]);
ac->next = this->alloc_cache;
this->alloc_cache = ac;
} else {
+3 -3
View File
@@ -78,8 +78,8 @@ 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_t)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
/* Ensure the highest possible index, i.e. Tmax_size -1, is within the bounds of Tindex. */
static_assert(Tmax_size - 1 <= MAX_UVALUE(Tindex));
static constexpr size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside
@@ -259,7 +259,7 @@ struct Pool : PoolBase {
inline void operator delete(void *p)
{
if (p == nullptr) return;
Titem *pn = (Titem *)p;
Titem *pn = static_cast<Titem *>(p);
assert(pn == Tpool->Get(pn->index));
Tpool->FreeItem(pn->index);
}
+2 -18
View File
@@ -49,17 +49,6 @@ uint32_t Randomizer::Next()
return this->state[1] = std::rotr(s, 3) - 1;
}
/**
* Generate the next pseudo random number scaled to \a limit, excluding \a limit
* itself.
* @param limit Limit of the range to be generated from.
* @return Random number in [0,\a limit)
*/
uint32_t Randomizer::Next(uint32_t limit)
{
return ((uint64_t)this->Next() * (uint64_t)limit) >> 32;
}
/**
* (Re)set the state of the random number generator.
* @param seed the new state
@@ -81,19 +70,14 @@ void SetRandomSeed(uint32_t seed)
}
#ifdef RANDOM_DEBUG
uint32_t DoRandom(int line, const char *file)
uint32_t Random(const std::source_location location)
{
if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, (byte)_current_company, file, line);
Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, (uint8_t)_current_company, location.file_name(), location.line());
}
return _random.Next();
}
uint32_t DoRandomRange(uint32_t limit, int line, const char *file)
{
return ((uint64_t)DoRandom(line, file) * (uint64_t)limit) >> 32;
}
#endif /* RANDOM_DEBUG */
/**
+37 -39
View File
@@ -10,10 +10,16 @@
#ifndef RANDOM_FUNC_HPP
#define RANDOM_FUNC_HPP
#if defined(__APPLE__)
/* Apple already has Random declared */
# define Random OTTD_Random
#endif /* __APPLE__ */
/**
* Scale a uint32_t number to be within the range [0,\a limit).
* @param value The value to scale.
* @param limit The limit to scale to.
* @return The scaled value.
*/
static constexpr uint32_t ScaleToLimit(uint32_t value, uint32_t limit)
{
return ((uint64_t)value * (uint64_t)limit) >> 32;
}
/**
* Structure to encapsulate the pseudo random number generators.
@@ -23,8 +29,15 @@ struct Randomizer {
uint32_t state[2];
uint32_t Next();
uint32_t Next(uint32_t limit);
void SetSeed(uint32_t seed);
/**
* Generate the next pseudo random number scaled to \a limit, excluding \a limit
* itself.
* @param limit Limit of the range to be generated from.
* @return Random number in [0,\a limit)
*/
inline uint32_t Next(uint32_t limit) { return ScaleToLimit(this->Next(), limit); }
};
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
@@ -57,33 +70,26 @@ inline void RestoreRandomSeeds(const SavedRandomSeeds &storage)
void SetRandomSeed(uint32_t seed);
#ifdef RANDOM_DEBUG
# ifdef __APPLE__
# define OTTD_Random() DoRandom(__LINE__, __FILE__)
# else
# define Random() DoRandom(__LINE__, __FILE__)
# endif
uint32_t DoRandom(int line, const char *file);
# define RandomRange(limit) DoRandomRange(limit, __LINE__, __FILE__)
uint32_t DoRandomRange(uint32_t limit, int line, const char *file);
uint32_t Random(const std::source_location location = std::source_location::current());
#else
static inline uint32_t Random()
inline uint32_t Random([[maybe_unused]] const std::source_location location = std::source_location::current())
{
return _random.Next();
}
/**
* Pick a random number between 0 and \a limit - 1, inclusive. That means 0
* can be returned and \a limit - 1 can be returned, but \a limit can not be
* returned.
* @param limit Limit for the range to be picked from.
* @return A random number in [0,\a limit).
*/
static inline uint32_t RandomRange(uint32_t limit)
{
return _random.Next(limit);
}
#endif
/**
* Pick a random number between 0 and \a limit - 1, inclusive. That means 0
* can be returned and \a limit - 1 can be returned, but \a limit can not be
* returned.
* @param limit Limit for the range to be picked from.
* @return A random number in [0,\a limit).
*/
inline uint32_t RandomRange(uint32_t limit, const std::source_location location = std::source_location::current())
{
return ScaleToLimit(Random(location), limit);
}
inline uint32_t InteractiveRandom()
{
return _interactive_random.Next();
@@ -109,7 +115,7 @@ inline uint32_t InteractiveRandomRange(uint32_t limit)
* @param r The given randomize-number
* @return True if the probability given by r is less or equal to (a/b)
*/
inline bool Chance16I(const uint a, const uint b, const uint32_t r)
inline bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
{
assert(b != 0);
return (((uint16_t)r * b + b / 2) >> 16) < a;
@@ -125,14 +131,10 @@ inline bool Chance16I(const uint a, const uint b, const uint32_t r)
* @param b The denominator of the fraction
* @return True with (a/b) probability
*/
#ifdef RANDOM_DEBUG
# define Chance16(a, b) Chance16I(a, b, DoRandom(__LINE__, __FILE__))
#else
inline bool Chance16(const uint a, const uint b)
inline bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location = std::source_location::current())
{
return Chance16I(a, b, Random());
return Chance16I(a, b, Random(location));
}
#endif /* RANDOM_DEBUG */
/**
* Flips a coin with a given probability and saves the randomize-number in a variable.
@@ -149,15 +151,11 @@ inline bool Chance16(const uint a, const uint b)
* @param r The variable to save the randomize-number from Random()
* @return True in (a/b) percent
*/
#ifdef RANDOM_DEBUG
# define Chance16R(a, b, r) (r = DoRandom(__LINE__, __FILE__), Chance16I(a, b, r))
#else
inline bool Chance16R(const uint a, const uint b, uint32_t &r)
inline bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location = std::source_location::current())
{
r = Random();
r = Random(location);
return Chance16I(a, b, r);
}
#endif /* RANDOM_DEBUG */
void RandomBytesWithFallback(std::span<uint8_t> buf);