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.
This commit is contained in:
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<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 +68,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 */
@ -85,7 +84,7 @@ class Kdtree {
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; });
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);
@ -129,9 +128,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 +201,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 +221,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,7 +244,7 @@ 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]);
/* Assume this node is the best choice for now */
@ -280,9 +279,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);
@ -321,8 +320,8 @@ class Kdtree {
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);
@ -350,7 +349,7 @@ class Kdtree {
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,

View File

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

View File

@ -15,8 +15,14 @@
#include "station_base.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); }
typedef Kdtree<StationID, decltype(&Kdtree_StationXYFunc), uint16_t, int> StationKdtree;
struct Kdtree_StationXYFunc {
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;
/**

View File

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

View File

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

View File

@ -13,9 +13,14 @@
#include "core/kdtree.hpp"
#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); }
typedef Kdtree<TownID, decltype(&Kdtree_TownXYFunc), uint16_t, int> TownKdtree;
struct Kdtree_TownXYFunc {
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_local_authority_kdtree;

View File

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

View File

@ -70,12 +70,14 @@ struct ViewportSignKdtreeItem {
static ViewportSignKdtreeItem MakeSign(SignID id);
};
inline int32_t Kdtree_ViewportSignXYFunc(const ViewportSignKdtreeItem &item, int dim)
{
return (dim == 0) ? item.center : item.top;
}
struct Kdtree_ViewportSignXYFunc {
inline int32_t operator()(const ViewportSignKdtreeItem &item, int dim)
{
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;
void RebuildViewportKdtree();