Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user