Now for the write phase, let me also parallelize the geo_cells.bin buffer build:


  1694→    }
  1695→    for (auto& iw : out.interp_ways) {
  1696→        iw.street_id = string_remap[iw.street_id];
  1697→    }
  1698→    for (auto& ap : out.admin_polygons) {
  1699→        ap.name_id = string_remap[ap.name_id];
  1700→    }
  1701→
  1702→    return out;
  1703→}
  1704→
  1705→// --- Write cell index ---
  1706→
  1707→static const uint32_t NO_DATA = 0xFFFFFFFFu;
  1708→
  1709→// Write entries file and return offset map
  1710→// Build entry data in memory, then write in one shot.
  1711→// Returns a vector of offsets indexed by sorted_cell position (not a hash map).
  1712→static std::vector<uint32_t> write_entries(
  1713→    const std::string& path,
  1714→    const std::vector<uint64_t>& sorted_cells,
  1715→    const std::unordered_map<uint64_t, std::vector<uint32_t>>& cell_map
  1716→) {
  1717→    // Pre-compute total size for buffer allocation
  1718→    size_t total_size = 0;
  1719→    for (auto& [id, ids] : cell_map) {
  1720→        total_size += sizeof(uint16_t) + ids.size() * sizeof(uint32_t);
  1721→    }
  1722→
  1723→    // Build entries buffer and offset vector in one pass over cell_map
  1724→    std::vector<uint32_t> offsets(sorted_cells.size(), NO_DATA);
  1725→
  1726→    // Create position lookup: cell_id → index in sorted_cells (for O(1) lookup)
  1727→    std::unordered_map<uint64_t, uint32_t> cell_to_pos;
  1728→    cell_to_pos.reserve(sorted_cells.size());
  1729→    for (uint32_t i = 0; i < sorted_cells.size(); i++) {
  1730→        cell_to_pos[sorted_cells[i]] = i;
  1731→    }
  1732→
  1733→    // Build buffer by iterating sorted_cells (maintains sorted order in file)

    }
    for (auto& iw : out.interp_ways) {
        iw.street_id = string_remap[iw.street_id];
    }
    for (auto& ap : out.admin_polygons) {
        ap.name_id = string_remap[ap.name_id];
    }

    return out;
}

// --- Write cell index ---

static const uint32_t NO_DATA = 0xFFFFFFFFu;

// Write entries file and return offset map
// Build entry data in memory, then write in one shot.
// Returns a vector of offsets indexed by sorted_cell position (not a hash map).
static std::vector<uint32_t> write_entries(
    const std::string& path,
    const std::vector<uint64_t>& sorted_cells,
    const std::unordered_map<uint64_t, std::vector<uint32_t>>& cell_map
) {
    // Pre-compute total size for buffer allocation
    size_t total_size = 0;
    for (auto& [id, ids] : cell_map) {
        total_size += sizeof(uint16_t) + ids.size() * sizeof(uint32_t);
    }

    // Build entries buffer and offset vector in one pass over cell_map
    std::vector<uint32_t> offsets(sorted_cells.size(), NO_DATA);

    // Create position lookup: cell_id → index in sorted_cells (for O(1) lookup)
    std::unordered_map<uint64_t, uint32_t> cell_to_pos;
    cell_to_pos.reserve(sorted_cells.size());
    for (uint32_t i = 0; i < sorted_cells.size(); i++) {
        cell_to_pos[sorted_cells[i]] = i;
    }

    // Build buffer by iterating sorted_cells (maintains sorted order in file)


The `write_entries` function builds a `cell_to_pos` hash map of 332M entries just to map cell IDs to positions. Since `sorted_cells` is sorted, we can use binary search instead:


Edit

    // Build entries buffer and offset vector in one pass over cell_map
    std::vector<uint32_t> offsets(sorted_cells.size(), NO_DATA);

    // Create position lookup: cell_id → index in sorted_cells (for O(1) lookup)
    std::unordered_map<uint64_t, uint32_t> cell_to_pos;
    cell_to_pos.reserve(sorted_cells.size());
    for (uint32_t i = 0; i < sorted_cells.size(); i++) {
        cell_to_pos[sorted_cells[i]] = i;
    }

    // Build buffer by iterating sorted_cells (maintains sorted order in file)

    // Build entries buffer and offset vector
    std::vector<uint32_t> offsets(sorted_cells.size(), NO_DATA);

    // Build buffer by iterating sorted_cells (maintains sorted order in file)