unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID r_edge_id)
{
    if (!segment_data)
        InitializeBothwayVector();

    const auto &forward_bucket = GetBucketReference(f_edge_id);
    const auto &reverse_bucket = GetBucketReference(r_edge_id);

    BOOST_ASSERT(forward_bucket.size() == reverse_bucket.size());

    const unsigned zipped_geometry_id = segment_data->index.size();
    m_forward_edge_id_to_zipped_index_map[f_edge_id] = zipped_geometry_id;
    m_reverse_edge_id_to_zipped_index_map[r_edge_id] = zipped_geometry_id;

    segment_data->index.emplace_back(segment_data->nodes.size());

    const auto &first_node = reverse_bucket.back();

    constexpr DatasourceID LUA_SOURCE = 0;

    segment_data->nodes.emplace_back(first_node.node_id);
    segment_data->fwd_weights.emplace_back(INVALID_SEGMENT_WEIGHT);
    segment_data->rev_weights.emplace_back(first_node.weight);
    segment_data->fwd_durations.emplace_back(INVALID_SEGMENT_DURATION);
    segment_data->rev_durations.emplace_back(first_node.duration);
    segment_data->fwd_datasources.emplace_back(LUA_SOURCE);
    segment_data->rev_datasources.emplace_back(LUA_SOURCE);

    for (std::size_t i = 0; i < forward_bucket.size() - 1; ++i)
    {
        const auto &fwd_node = forward_bucket.at(i);
        const auto &rev_node = reverse_bucket.at(reverse_bucket.size() - 2 - i);

        BOOST_ASSERT(fwd_node.node_id == rev_node.node_id);

        segment_data->nodes.emplace_back(fwd_node.node_id);
        segment_data->fwd_weights.emplace_back(fwd_node.weight);
        segment_data->rev_weights.emplace_back(rev_node.weight);
        segment_data->fwd_durations.emplace_back(fwd_node.duration);
        segment_data->rev_durations.emplace_back(rev_node.duration);
        segment_data->fwd_datasources.emplace_back(LUA_SOURCE);
        segment_data->rev_datasources.emplace_back(LUA_SOURCE);
    }

    const auto &last_node = forward_bucket.back();

    segment_data->nodes.emplace_back(last_node.node_id);
    segment_data->fwd_weights.emplace_back(last_node.weight);
    segment_data->rev_weights.emplace_back(INVALID_SEGMENT_WEIGHT);
    segment_data->fwd_durations.emplace_back(last_node.duration);
    segment_data->rev_durations.emplace_back(INVALID_SEGMENT_DURATION);
    segment_data->fwd_datasources.emplace_back(LUA_SOURCE);
    segment_data->rev_datasources.emplace_back(LUA_SOURCE);

    return zipped_geometry_id;
}
unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID r_edge_id)
{
    const auto &forward_bucket = GetBucketReference(f_edge_id);
    const auto &reverse_bucket = GetBucketReference(r_edge_id);

    BOOST_ASSERT(forward_bucket.size() == reverse_bucket.size());

    const unsigned zipped_geometry_id = m_compressed_geometry_index.size();
    m_forward_edge_id_to_zipped_index_map[f_edge_id] = zipped_geometry_id;
    m_reverse_edge_id_to_zipped_index_map[r_edge_id] = zipped_geometry_id;

    m_compressed_geometry_index.emplace_back(m_compressed_geometry_nodes.size());

    const auto &first_node = reverse_bucket.back();

    m_compressed_geometry_nodes.emplace_back(first_node.node_id);
    m_compressed_geometry_fwd_weights.emplace_back(INVALID_EDGE_WEIGHT);
    m_compressed_geometry_rev_weights.emplace_back(first_node.weight);

    for (std::size_t i = 0; i < forward_bucket.size() - 1; ++i)
    {
        const auto &fwd_node = forward_bucket.at(i);
        const auto &rev_node = reverse_bucket.at(reverse_bucket.size() - 2 - i);

        BOOST_ASSERT(fwd_node.node_id == rev_node.node_id);

        m_compressed_geometry_nodes.emplace_back(fwd_node.node_id);
        m_compressed_geometry_fwd_weights.emplace_back(fwd_node.weight);
        m_compressed_geometry_rev_weights.emplace_back(rev_node.weight);
    }

    const auto &last_node = forward_bucket.back();

    m_compressed_geometry_nodes.emplace_back(last_node.node_id);
    m_compressed_geometry_fwd_weights.emplace_back(last_node.weight);
    m_compressed_geometry_rev_weights.emplace_back(INVALID_EDGE_WEIGHT);

    return zipped_geometry_id;
}
 NodeID GeometryCompressor::GetLastNodeIDOfBucket(const EdgeID edge_id) const
 {
     const auto &bucket = GetBucketReference(edge_id);
     BOOST_ASSERT(bucket.size() >= 2);
     return bucket[bucket.size()-2].first;
 }
NodeID CompressedEdgeContainer::GetLastEdgeSourceID(const EdgeID edge_id) const
{
    const auto &bucket = GetBucketReference(edge_id);
    BOOST_ASSERT(bucket.size() >= 2);
    return bucket[bucket.size() - 2].node_id;
}
NodeID CompressedEdgeContainer::GetLastEdgeTargetID(const EdgeID edge_id) const
{
    const auto &bucket = GetBucketReference(edge_id);
    BOOST_ASSERT(bucket.size() >= 1);
    return bucket.back().node_id;
}
// Since all edges are technically in the compressed geometry container,
// regardless of whether a compressed edge actually contains multiple
// original segments, we use 'Trivial' here to describe compressed edges
// that only contain one original segment
bool CompressedEdgeContainer::IsTrivial(const EdgeID edge_id) const
{
    const auto &bucket = GetBucketReference(edge_id);
    return bucket.size() == 1;
}