Customizing Adjacency List Storage

The adjacency_list is constructed from two kinds of containers: one for the vertex set, and another for each vertex’s out-edge list. BGL provides selector classes (vecS, listS, setS, etc.) that map to STL containers. You can also use your own container types.

When customizing the VertexList, define a container generator. When customizing the OutEdgeList, define a container generator and the parallel edge traits.

Container Generator

The adjacency_list uses a traits class called container_gen to map selectors to container types. The default version and an example specialization for listS:

namespace boost {
    template <class Selector, class ValueType>
    struct container_gen {};

    template <class ValueType>
    struct container_gen<listS, ValueType> {
        typedef std::list<ValueType> type;
    };
}

To use your own container, define a selector class and specialize container_gen:

struct custom_containerS {};

namespace boost {
    template <class ValueType>
    struct container_gen<custom_containerS, ValueType> {
        typedef custom_container<ValueType> type;
    };
}

To pass additional template parameters (e.g., an allocator), add them to the selector:

template <class Allocator>
struct list_with_allocatorS {};

namespace boost {
    template <class Alloc, class ValueType>
    struct container_gen<list_with_allocatorS<Alloc>, ValueType> {
        typedef typename Alloc::template rebind<ValueType>::other Allocator;
        typedef std::list<ValueType, Allocator> type;
    };
}

using MyGraph = adjacency_list<list_with_allocatorS<std::allocator<int>>, vecS, directedS>;

Push and Erase

You must tell adjacency_list how to add and remove elements from your container by overloading push() and erase():

template <class T>
std::pair<typename custom_container<T>::iterator, bool>
push(custom_container<T>& c, const T& v) {
    c.push_back(v);
    return std::make_pair(boost::prior(c.end()), true);
}

template <class T>
void erase(custom_container<T>& c, const T& x) {
    c.erase(std::remove(c.begin(), c.end(), x), c.end());
}

Default push() and erase() implementations are provided for all STL container types.

Parallel Edge Traits

When customizing the OutEdgeList, specialize parallel_edge_traits to indicate whether the container allows parallel edges:

template <>
struct parallel_edge_traits<custom_containerS> {
    typedef allow_parallel_edge_tag type;
};

Use allow_parallel_edge_tag for Sequence containers and disallow_parallel_edge_tag for AssociativeContainers.

Ordered Out-Edge Containers

An ordered out-edge container (for example a std::multiset with a custom comparator) must sort edges by target vertex first. The comparator may then break ties with anything else, such as an edge property. This keeps all edges to the same target next to each other, which edge_range() relies on.

To find the edges from u to v, edge(), edge_range() and remove_edge() need a lookup by target alone. When the comparator is std::less (as with setS and multisetS), the container’s own find() and equal_range() do this in O(log(E/V)). Any other comparator could read data that a target alone does not have, so in that case BGL instead walks the out-edges of u one by one and checks each target, which takes O(E/V). Iterating with out_edges() is unaffected and follows the container’s order.

See example/ordered_out_edges.cpp for out-edges ordered by target and then by name.