Elle
Elle

Reputation: 334

iterate over bundled properties in boost graph in a direct way

I'm using the Boost graph library exploiting the following definitions

template <typename Vertex>
using graph = boost::adjacency_list<boost::listS,
                                    boost::vecS,
                                    boost::bidirectionalS,
                                    Vertex>

template <typename Vertex>
using vertex = typename graph<Vertex>::vertex_descriptor;

where the template parameter Vertex is employed to use the BGL with bundled properties.

I'm not that confident with boost at the moment and I'd like to understand if is there a way to get the begin() and end() iterators of the "bundled property list". In other words, let's assume I have this struct

struct City
{
  string name;
  int population;
  vector<int> zipcodes;
};

and I want to use it as template parameter for my graph. I know I can iterate over vertexes like this (assuming g is my adjacency list)

for(auto vd : boost::make_iterator_range(vertices(g))
{
      auto v = g[*vd];
      // do something with v
}

yet I'd like to do this

for(auto & v : some_iterator)
   // v is a city ...

is there any way to do this ?

Upvotes: 1

Views: 278

Answers (1)

sehe
sehe

Reputation: 392863

I've adapted my code from your now-deleted question to the more specific example. By now you already realize you are NOT in fact iterating vertices, but their bundles.

I suggest you use a transforming/indirected iterator adaptor. The easiest way I can think of is to use Boost Range Adaptors, specifically using transformed:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptors.hpp>
using boost::adaptors::transformed;

template <typename Vertex> struct Wrapper {
    using graph = boost::adjacency_list<boost::listS, boost::vecS,
                                        boost::bidirectionalS, Vertex>;

    using vertex = typename graph::vertex_descriptor;

    auto bundles() {
        auto accessor = [map = get(boost::vertex_bundle, _g)](vertex v) -> auto& {
            return map[v];
        };
        return vertices(_g) | transformed(accessor);
    }

    auto bundles() const {
        auto accessor = [map = get(boost::vertex_bundle, _g)](vertex v) -> auto& {
            return map[v];
        };
        return vertices(_g) | transformed(accessor);
    }

  private:
    graph _g {5};
};

struct City {
    std::string      name;
    int              population;
    std::vector<int> zipcodes;
};

static int id_gen = 0;
struct Sample2 { int id = ++id_gen; };

#include <iostream>
#include <iomanip>

int main() {
    Wrapper<City> demo;

    for (City& c : demo.bundles()) {
        c.name       = "name " + std::to_string(rand() % 100);
        c.population = rand() % 128 * 190'000;
        c.zipcodes   = {1234, 2345};
    }

    auto const& const_ref = demo;
    for (City const& c : const_ref.bundles()) {
        std::cout << std::quoted(c.name) << ", population " << c.population << "\n";
    }
}

Prints

"name 83", population 13300000
"name 77", population 21850000
"name 93", population 24130000
"name 86", population 20520000
"name 49", population 14630000

Upvotes: 1

Related Questions