Codechange: Reduce size of class WaterRegion

The tile patch array is 256 bytes and is not needed for the majority
of water regions, change it to be optional via std::unique_ptr
This commit is contained in:
Jonathan G Rennison 2024-03-11 23:11:19 +00:00 committed by rubidium42
parent e42aec5a89
commit 2189607c34
1 changed files with 24 additions and 7 deletions

View File

@ -38,6 +38,8 @@ static inline int GetWaterRegionMapSizeY() { return Map::SizeY() / WATER_REGION_
static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; } static inline TWaterRegionIndex GetWaterRegionIndex(int region_x, int region_y) { return GetWaterRegionMapSizeX() * region_y + region_x; }
static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); } static inline TWaterRegionIndex GetWaterRegionIndex(TileIndex tile) { return GetWaterRegionIndex(GetWaterRegionX(tile), GetWaterRegionY(tile)); }
using TWaterRegionPatchLabelArray = std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES>;
/** /**
* Represents a square section of the map of a fixed size. Within this square individual unconnected patches of water are * Represents a square section of the map of a fixed size. Within this square individual unconnected patches of water are
* identified using a Connected Component Labeling (CCL) algorithm. Note that all information stored in this class applies * identified using a Connected Component Labeling (CCL) algorithm. Note that all information stored in this class applies
@ -49,10 +51,10 @@ class WaterRegion
private: private:
std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{}; std::array<TWaterRegionTraversabilityBits, DIAGDIR_END> edge_traversability_bits{};
bool has_cross_region_aqueducts = false; bool has_cross_region_aqueducts = false;
bool initialized = false;
TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc... TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc...
const OrthogonalTileArea tile_area; const OrthogonalTileArea tile_area;
std::array<TWaterRegionPatchLabel, WATER_REGION_NUMBER_OF_TILES> tile_patch_labels{}; std::unique_ptr<TWaterRegionPatchLabelArray> tile_patch_labels; ///< Tile patch labels, this may be nullptr in the following trivial cases: region is invalid, region is only land (0 patches), region is only water (1 patch)
bool initialized = false;
/** /**
* Returns the local index of the tile within the region. The N corner represents 0, * Returns the local index of the tile within the region. The N corner represents 0,
@ -110,7 +112,10 @@ public:
TWaterRegionPatchLabel GetLabel(TileIndex tile) const TWaterRegionPatchLabel GetLabel(TileIndex tile) const
{ {
assert(this->tile_area.Contains(tile)); assert(this->tile_area.Contains(tile));
return this->tile_patch_labels[GetLocalIndex(tile)]; if (this->tile_patch_labels == nullptr) {
return this->NumberOfPatches() == 0 ? INVALID_WATER_REGION_PATCH : 1;
}
return (*this->tile_patch_labels)[GetLocalIndex(tile)];
} }
/** /**
@ -122,7 +127,12 @@ public:
Debug(map, 3, "Updating water region ({},{})", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile)); Debug(map, 3, "Updating water region ({},{})", GetWaterRegionX(this->tile_area.tile), GetWaterRegionY(this->tile_area.tile));
this->has_cross_region_aqueducts = false; this->has_cross_region_aqueducts = false;
this->tile_patch_labels.fill(INVALID_WATER_REGION_PATCH); /* Acquire a tile patch label array if this region does not already have one */
if (this->tile_patch_labels == nullptr) {
this->tile_patch_labels = std::make_unique<TWaterRegionPatchLabelArray>();
}
this->tile_patch_labels->fill(INVALID_WATER_REGION_PATCH);
this->edge_traversability_bits.fill(0); this->edge_traversability_bits.fill(0);
TWaterRegionPatchLabel current_label = 1; TWaterRegionPatchLabel current_label = 1;
@ -143,9 +153,10 @@ public:
const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile)); const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile));
if (valid_dirs == TRACKDIR_BIT_NONE) continue; if (valid_dirs == TRACKDIR_BIT_NONE) continue;
if (this->tile_patch_labels[GetLocalIndex(tile)] != INVALID_WATER_REGION_PATCH) continue; TWaterRegionPatchLabel &tile_patch = (*this->tile_patch_labels)[GetLocalIndex(tile)];
if (tile_patch != INVALID_WATER_REGION_PATCH) continue;
this->tile_patch_labels[GetLocalIndex(tile)] = current_label; tile_patch = current_label;
highest_assigned_label = current_label; highest_assigned_label = current_label;
increase_label = true; increase_label = true;
@ -172,6 +183,12 @@ public:
this->number_of_patches = highest_assigned_label; this->number_of_patches = highest_assigned_label;
this->initialized = true; this->initialized = true;
if (this->number_of_patches == 0 || (this->number_of_patches == 1 &&
std::all_of(this->tile_patch_labels->begin(), this->tile_patch_labels->end(), [](TWaterRegionPatchLabel label) { return label == 1; }))) {
/* No need for patch storage: trivial cases */
this->tile_patch_labels.reset();
}
} }
/** /**
@ -196,7 +213,7 @@ public:
for (int y = 0; y < WATER_REGION_EDGE_LENGTH; ++y) { for (int y = 0; y < WATER_REGION_EDGE_LENGTH; ++y) {
std::string line{}; std::string line{};
for (int x = 0; x < WATER_REGION_EDGE_LENGTH; ++x) { for (int x = 0; x < WATER_REGION_EDGE_LENGTH; ++x) {
const auto label = this->tile_patch_labels[x + y * WATER_REGION_EDGE_LENGTH]; const auto label = this->GetLabel(TileAddXY(tile_area.tile, x, y));
const std::string label_str = label == INVALID_WATER_REGION_PATCH ? "." : std::to_string(label); const std::string label_str = label == INVALID_WATER_REGION_PATCH ? "." : std::to_string(label);
line = fmt::format("{:{}}", label_str, max_element_width) + " " + line; line = fmt::format("{:{}}", label_str, max_element_width) + " " + line;
} }