1
0
Fork 0

Codechange: Use functor for Kdtree's XYFunc. (#13074)

Kdtree uses a function pointer and incorrectly calls it a functor. The function pointer needs to be passed on instantiaton.

Instead, use an actual functor. This simplifies instantiation.
pull/13094/head
Peter Nelson 2024-11-19 20:29:56 +00:00 committed by GitHub
parent 369ea29e1e
commit fc8685d618
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 40 additions and 28 deletions

View File

@ -47,7 +47,6 @@ class Kdtree {
std::vector<node> nodes; ///< Pool of all nodes in the tree 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 std::vector<size_t> free_list; ///< List of dead indices in the nodes vector
size_t root; ///< Index of root node 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 size_t unbalanced; ///< Number approximating how unbalanced the tree might be
/** Create one new node in the tree, return its index in the pool */ /** Create one new node in the tree, return its index in the pool */
@ -69,8 +68,8 @@ class Kdtree {
CoordT SelectSplitCoord(It begin, It end, int level) CoordT SelectSplitCoord(It begin, It end, int level)
{ {
It mid = begin + (end - begin) / 2; 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); }); std::nth_element(begin, mid, end, [&](T a, T b) { return TxyFunc()(a, level % 2) < TxyFunc()(b, level % 2); });
return this->xyfunc(*mid, level % 2); return TxyFunc()(*mid, level % 2);
} }
/** Construct a subtree from elements between begin and end iterators, return index of root */ /** Construct a subtree from elements between begin and end iterators, return index of root */
@ -85,7 +84,7 @@ class Kdtree {
return this->AddNode(*begin); return this->AddNode(*begin);
} else if (count > 1) { } else if (count > 1) {
CoordT split_coord = SelectSplitCoord(begin, end, level); CoordT split_coord = SelectSplitCoord(begin, end, level);
It split = std::partition(begin, end, [&](T v) { return this->xyfunc(v, level % 2) < split_coord; }); It split = std::partition(begin, end, [&](T v) { return TxyFunc()(v, level % 2) < split_coord; });
size_t newidx = this->AddNode(*split); size_t newidx = this->AddNode(*split);
this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1); this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1);
this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1); this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1);
@ -129,9 +128,9 @@ class Kdtree {
node &n = this->nodes[node_idx]; node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */ /* 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 */ /* Coordinate of the new element */
CoordT ec = this->xyfunc(element, dim); CoordT ec = TxyFunc()(element, dim);
/* Which side to insert on */ /* Which side to insert on */
size_t &next = (ec < nc) ? n.left : n.right; size_t &next = (ec < nc) ? n.left : n.right;
@ -202,9 +201,9 @@ class Kdtree {
/* Dimension index of current level */ /* Dimension index of current level */
int dim = level % 2; int dim = level % 2;
/* Coordinate of element splitting at this node */ /* 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 */ /* Coordinate of the element being removed */
CoordT ec = this->xyfunc(element, dim); CoordT ec = TxyFunc()(element, dim);
/* Which side to remove from */ /* Which side to remove from */
size_t next = (ec < nc) ? n.left : n.right; 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 assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached
@ -222,7 +221,7 @@ class Kdtree {
DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const 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 */ /** A data element and its distance to a searched-for point */
@ -245,7 +244,7 @@ class Kdtree {
const node &n = this->nodes[node_idx]; const node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */ /* 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 */ /* This node's distance to target */
DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]); DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]);
/* Assume this node is the best choice for now */ /* Assume this node is the best choice for now */
@ -280,9 +279,9 @@ class Kdtree {
const node &n = this->nodes[node_idx]; const node &n = this->nodes[node_idx];
/* Coordinate of element splitting at this node */ /* Coordinate of element splitting at this node */
CoordT ec = this->xyfunc(n.element, dim); CoordT ec = TxyFunc()(n.element, dim);
/* Opposite coordinate of element */ /* 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 */ /* 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); if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
@ -321,8 +320,8 @@ class Kdtree {
if (node_idx == INVALID_NODE) return; if (node_idx == INVALID_NODE) return;
const node &n = this->nodes[node_idx]; const node &n = this->nodes[node_idx];
CoordT cx = this->xyfunc(n.element, 0); CoordT cx = TxyFunc()(n.element, 0);
CoordT cy = this->xyfunc(n.element, 1); CoordT cy = TxyFunc()(n.element, 1);
assert(cx >= min_x); assert(cx >= min_x);
assert(cx < max_x); assert(cx < max_x);
@ -350,7 +349,7 @@ class Kdtree {
public: public:
/** Construct a new Kdtree with the given xyfunc */ /** 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, * Clear and rebuild the tree from a new sequence of elements,

View File

@ -36,7 +36,7 @@ StationPool _station_pool("Station");
INSTANTIATE_POOL_METHODS(Station) INSTANTIATE_POOL_METHODS(Station)
StationKdtree _station_kdtree(Kdtree_StationXYFunc); StationKdtree _station_kdtree{};
void RebuildStationKdtree() void RebuildStationKdtree()
{ {

View File

@ -15,8 +15,14 @@
#include "station_base.h" #include "station_base.h"
#include "map_func.h" #include "map_func.h"
inline uint16_t Kdtree_StationXYFunc(StationID stid, int dim) { return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy); } struct Kdtree_StationXYFunc {
typedef Kdtree<StationID, decltype(&Kdtree_StationXYFunc), uint16_t, int> StationKdtree; inline uint16_t operator()(StationID stid, int dim)
{
return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy);
}
};
using StationKdtree = Kdtree<StationID, Kdtree_StationXYFunc, uint16_t, int>;
extern StationKdtree _station_kdtree; extern StationKdtree _station_kdtree;
/** /**

View File

@ -68,7 +68,7 @@ TownPool _town_pool("Town");
INSTANTIATE_POOL_METHODS(Town) INSTANTIATE_POOL_METHODS(Town)
TownKdtree _town_kdtree(&Kdtree_TownXYFunc); TownKdtree _town_kdtree{};
void RebuildTownKdtree() void RebuildTownKdtree()
{ {

View File

@ -50,7 +50,7 @@
#include "safeguards.h" #include "safeguards.h"
TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc); TownKdtree _town_local_authority_kdtree{};
typedef GUIList<const Town*, const bool &> GUITownList; typedef GUIList<const Town*, const bool &> GUITownList;

View File

@ -13,9 +13,14 @@
#include "core/kdtree.hpp" #include "core/kdtree.hpp"
#include "town.h" #include "town.h"
inline uint16_t Kdtree_TownXYFunc(TownID tid, int dim) { return (dim == 0) ? TileX(Town::Get(tid)->xy) : TileY(Town::Get(tid)->xy); } struct Kdtree_TownXYFunc {
typedef Kdtree<TownID, decltype(&Kdtree_TownXYFunc), uint16_t, int> TownKdtree; inline uint16_t operator()(TownID tid, int dim)
{
return (dim == 0) ? TileX(Town::Get(tid)->xy) : TileY(Town::Get(tid)->xy);
}
};
using TownKdtree = Kdtree<TownID, Kdtree_TownXYFunc, uint16_t, int>;
extern TownKdtree _town_kdtree; extern TownKdtree _town_kdtree;
extern TownKdtree _town_local_authority_kdtree; extern TownKdtree _town_local_authority_kdtree;

View File

@ -102,7 +102,7 @@
Point _tile_fract_coords; Point _tile_fract_coords;
ViewportSignKdtree _viewport_sign_kdtree(&Kdtree_ViewportSignXYFunc); ViewportSignKdtree _viewport_sign_kdtree{};
static int _viewport_sign_maxwidth = 0; static int _viewport_sign_maxwidth = 0;

View File

@ -70,12 +70,14 @@ struct ViewportSignKdtreeItem {
static ViewportSignKdtreeItem MakeSign(SignID id); static ViewportSignKdtreeItem MakeSign(SignID id);
}; };
inline int32_t Kdtree_ViewportSignXYFunc(const ViewportSignKdtreeItem &item, int dim) struct Kdtree_ViewportSignXYFunc {
{ inline int32_t operator()(const ViewportSignKdtreeItem &item, int dim)
return (dim == 0) ? item.center : item.top; {
} return (dim == 0) ? item.center : item.top;
}
};
typedef Kdtree<ViewportSignKdtreeItem, decltype(&Kdtree_ViewportSignXYFunc), int32_t, int32_t> ViewportSignKdtree; using ViewportSignKdtree = Kdtree<ViewportSignKdtreeItem, Kdtree_ViewportSignXYFunc, int32_t, int32_t>;
extern ViewportSignKdtree _viewport_sign_kdtree; extern ViewportSignKdtree _viewport_sign_kdtree;
void RebuildViewportKdtree(); void RebuildViewportKdtree();