120 void reserve(std::size_t region_count, std::size_t portal_count) {
121 region_refs_.reserve(region_count);
122 region_areas_.reserve(region_count);
123 areas_.reserve(region_count);
124 connections_.reserve(portal_count);
127 void clear()
noexcept {
128 region_refs_.clear();
129 region_areas_.clear();
131 connections_.clear();
132 graph_identity_ =
nullptr;
136 [[nodiscard]]
auto areas()
const noexcept -> std::span<const AreaSummary> {
140 [[nodiscard]]
auto connections()
const noexcept
141 -> std::span<const AreaConnection> {
145 [[nodiscard]]
auto area_of(
RegionRef region)
const noexcept ->
AreaId {
147 std::lower_bound(region_refs_.begin(), region_refs_.end(), region,
149 return lhs.chunk.value < rhs.chunk.value ||
150 (lhs.chunk.value == rhs.chunk.value &&
151 lhs.region.value < rhs.region.value);
153 if (it == region_refs_.end() || *it != region) {
154 return invalid_area_id;
156 return region_areas_[
static_cast<std::size_t
>(it - region_refs_.begin())];
159 template <
typename Shape,
typename Res
idency>
162 if (!is_valid(graph)) {
163 return invalid_area_id;
165 return area_of(graph.template region_of<Shape>(coord));
168 template <
typename Res
idency>
169 [[nodiscard]]
auto is_valid(
174 return graph_identity_ ==
static_cast<const void*
>(&graph) &&
175 graph_revision_ == graph.
revision();
179 template <
typename Res
idency,
typename Grouper>
184 std::vector<RegionRef> region_refs_;
185 std::vector<AreaId> region_areas_;
186 std::vector<AreaSummary> areas_;
187 std::vector<AreaConnection> connections_;
188 const void* graph_identity_ =
nullptr;
189 std::uint64_t graph_revision_ = 0;
198 const auto region_count =
static_cast<std::size_t
>(graph.region_count());
200 scratch.region_keys_.assign(region_count, 0);
201 scratch.unique_keys_.clear();
202 index.region_refs_.resize(region_count);
203 index.region_areas_.assign(region_count, invalid_area_id);
205 for (
const auto& topology : graph.local_topologies()) {
206 for (
const auto& region : topology.regions()) {
207 const auto ref =
RegionRef{topology.chunk(), region.id};
208 const auto offset = graph.region_index(ref);
209 if (offset == invalid_region_index) {
213 static_cast<std::uint64_t
>(std::invoke(grouper, ref, region));
214 index.region_refs_[offset] = ref;
215 scratch.region_keys_[offset] = key;
217 scratch.unique_keys_.push_back(key);
222 std::sort(scratch.unique_keys_.begin(), scratch.unique_keys_.end());
223 scratch.unique_keys_.erase(
224 std::unique(scratch.unique_keys_.begin(), scratch.unique_keys_.end()),
225 scratch.unique_keys_.end());
226 if (scratch.unique_keys_.size() >= invalid_region_index) {
227 return {AreaBuildStatus::TooManyAreas, 0, 0};
229 index.areas_.resize(scratch.unique_keys_.size());
230 for (std::size_t i = 0; i < scratch.unique_keys_.size(); ++i) {
231 index.areas_[i].id =
AreaId{
static_cast<std::uint32_t
>(i + 1)};
232 index.areas_[i].key = scratch.unique_keys_[i];
235 for (
const auto& topology : graph.local_topologies()) {
236 for (
const auto& region : topology.regions()) {
237 const auto ref =
RegionRef{topology.chunk(), region.id};
238 const auto offset = graph.region_index(ref);
242 if (offset == invalid_region_index) {
245 const auto key = scratch.region_keys_[offset];
249 const auto key_it = std::lower_bound(scratch.unique_keys_.begin(),
250 scratch.unique_keys_.end(), key);
251 const auto area_offset =
252 static_cast<std::size_t
>(key_it - scratch.unique_keys_.begin());
253 const auto id =
AreaId{
static_cast<std::uint32_t
>(area_offset + 1)};
254 index.region_areas_[offset] = id;
255 auto& area = index.areas_[area_offset];
256 detail::extend_area_bounds(area.bounds, region.bounds,
257 area.region_count == 0);
259 area.tile_count += region.tile_count;
263 scratch.edge_keys_.clear();
264 for (
const auto& portal : graph.portals()) {
265 const auto from_index = graph.region_index(portal.from);
266 const auto to_index = graph.region_index(portal.to);
269 if (from_index == invalid_region_index ||
270 to_index == invalid_region_index) {
273 const auto from = index.region_areas_[from_index];
274 const auto to = index.region_areas_[to_index];
275 if (from == invalid_area_id || to == invalid_area_id || from == to) {
278 const auto first = std::min(from.value, to.value);
279 const auto second = std::max(from.value, to.value);
280 scratch.edge_keys_.push_back((
static_cast<std::uint64_t
>(first) << 32U) |
283 std::sort(scratch.edge_keys_.begin(), scratch.edge_keys_.end());
284 for (std::size_t begin = 0; begin < scratch.edge_keys_.size();) {
285 auto end = begin + 1;
286 while (end < scratch.edge_keys_.size() &&
287 scratch.edge_keys_[end] == scratch.edge_keys_[begin]) {
290 const auto edge = scratch.edge_keys_[begin];
291 index.connections_.push_back(
293 AreaId{
static_cast<std::uint32_t
>(edge)}, end - begin});
297 index.graph_identity_ =
static_cast<const void*
>(&graph);
298 index.graph_revision_ = graph.revision();
299 return {AreaBuildStatus::Built, index.areas_.size(),
300 index.connections_.size()};