From fca3103d8c824330b2a78f15729e406e2cdae436 Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 22 Apr 2025 13:58:21 +0200 Subject: [PATCH] Codechange: Add iterator for vehicles on a tile. --- src/vehicle.cpp | 29 ++++++++++++++++++++++++++ src/vehicle_func.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/vehicle.cpp b/src/vehicle.cpp index b9b8a1821f..5ad7891098 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -471,6 +471,35 @@ bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) return VehicleFromPosXY(x, y, data, proc, true) != nullptr; } +/** + * Iterator constructor. + * Find first vehicle on tile. + */ +VehiclesOnTile::Iterator::Iterator(TileIndex tile) : tile(tile) +{ + int x = GB(TileX(tile), HASH_RES, HASH_BITS); + int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS; + this->current = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; + this->SkipFalseMatches(); +} + +/** + * Advance the internal state to the next potential vehicle. + * The vehicle may not be on the correct tile though. + */ +void VehiclesOnTile::Iterator::Increment() +{ + this->current = this->current->hash_tile_next; +} + +/** + * Advance the internal state until it reaches a vehicle on the correct tile or the end. + */ +void VehiclesOnTile::Iterator::SkipFalseMatches() +{ + while (this->current != nullptr && this->current->tile != this->tile) this->Increment(); +} + /** * Helper function for FindVehicleOnPos/HasVehicleOnPos. * @note Do not call this function directly! diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 25f68679b5..7f3feb436a 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -46,6 +46,58 @@ static const Money VEHICLE_PROFIT_THRESHOLD = 10000; ///< Threshold for a template bool IsValidImageIndex(uint8_t image_index); +/** + * Iterate over all vehicles on a tile. + * @warning The order is non-deterministic. You have to make sure, that your processing is not order dependant. + */ +class VehiclesOnTile { +public: + /** + * Forward iterator + */ + class Iterator { + public: + using value_type = Vehicle *; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + using pointer = void; + using reference = void; + + explicit Iterator(TileIndex tile); + + bool operator==(const Iterator &rhs) const { return this->current == rhs.current; } + bool operator==(const std::default_sentinel_t &) const { return this->current == nullptr; } + + Vehicle *operator*() const { return this->current; } + + Iterator &operator++() + { + this->Increment(); + this->SkipFalseMatches(); + return *this; + } + + Iterator operator++(int) + { + Iterator result = *this; + ++*this; + return result; + } + private: + TileIndex tile; + Vehicle *current; + + void Increment(); + void SkipFalseMatches(); + }; + + explicit VehiclesOnTile(TileIndex tile) : start(tile) {} + Iterator begin() const { return this->start; } + std::default_sentinel_t end() const { return std::default_sentinel_t(); } +private: + Iterator start; +}; + typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data); void VehicleServiceInDepot(Vehicle *v);