Now fix the geo_cells.bin writer to use the positional offset vectors instead of hash lookups:


Edit

        // Write entry files in parallel
        std::unordered_map<uint64_t, uint32_t> street_offsets, addr_offsets, interp_offsets;
        {
            auto f1 = std::async(std::launch::async, [&]() {
                return write_entries(output_dir + "/street_entries.bin", sorted_geo_cells, data.cell_to_ways);
            });
            if (write_addresses) {
                auto f2 = std::async(std::launch::async, [&]() {
                    return write_entries(output_dir + "/addr_entries.bin", sorted_geo_cells, data.cell_to_addrs);
                });
                auto f3 = std::async(std::launch::async, [&]() {
                    return write_entries(output_dir + "/interp_entries.bin", sorted_geo_cells, data.cell_to_interps);
                });
                addr_offsets = f2.get();
                interp_offsets = f3.get();
            }
            street_offsets = f1.get();
        }

        {
            std::ofstream f(output_dir + "/geo_cells.bin", std::ios::binary);
            for (uint64_t cell_id : sorted_geo_cells) {
                f.write(reinterpret_cast<const char*>(&cell_id), sizeof(cell_id));
                auto write_offset = [&](const std::unordered_map<uint64_t, uint32_t>& offsets) {
                    auto it = offsets.find(cell_id);
                    uint32_t offset = (it != offsets.end()) ? it->second : NO_DATA;
                    f.write(reinterpret_cast<const char*>(&offset), sizeof(offset));
                };
                write_offset(street_offsets);
                write_offset(addr_offsets);
                write_offset(interp_offsets);
            }
        }

        // Write entry files in parallel (returns positional offset vectors, not hash maps)
        std::vector<uint32_t> street_offsets, addr_offsets, interp_offsets;
        {
            auto f1 = std::async(std::launch::async, [&]() {
                return write_entries(output_dir + "/street_entries.bin", sorted_geo_cells, data.cell_to_ways);
            });
            if (write_addresses) {
                auto f2 = std::async(std::launch::async, [&]() {
                    return write_entries(output_dir + "/addr_entries.bin", sorted_geo_cells, data.cell_to_addrs);
                });
                auto f3 = std::async(std::launch::async, [&]() {
                    return write_entries(output_dir + "/interp_entries.bin", sorted_geo_cells, data.cell_to_interps);
                });
                addr_offsets = f2.get();
                interp_offsets = f3.get();
            }
            street_offsets = f1.get();
        }

        // Build geo_cells.bin in memory buffer (avoids 332M × 4 small writes + hash lookups)
        {
            size_t n = sorted_geo_cells.size();
            size_t row_size = sizeof(uint64_t) + 3 * sizeof(uint32_t); // cell_id + 3 offsets
            std::vector<char> buf(n * row_size);
            char* ptr = buf.data();

            // Fill empty offset vectors if not writing addresses
            if (addr_offsets.empty()) addr_offsets.resize(n, NO_DATA);
            if (interp_offsets.empty()) interp_offsets.resize(n, NO_DATA);

            for (size_t i = 0; i < n; i++) {
                memcpy(ptr, &sorted_geo_cells[i], sizeof(uint64_t)); ptr += sizeof(uint64_t);
                memcpy(ptr, &street_offsets[i], sizeof(uint32_t)); ptr += sizeof(uint32_t);
                memcpy(ptr, &addr_offsets[i], sizeof(uint32_t)); ptr += sizeof(uint32_t);
                memcpy(ptr, &interp_offsets[i], sizeof(uint32_t)); ptr += sizeof(uint32_t);
            }

            std::ofstream f(output_dir + "/geo_cells.bin", std::ios::binary);
            f.write(buf.data(), buf.size());
        }