Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

range view as data member

I'm trying out the new range-v3 library (0.5.0, clang-7.1)

I'm traversing through a graph (bfs). Each node in the graph contains some vector data (std::vector<double>). While traversing through the graph, I'm trying to create a concat_view (which is concatenation of all the vectors).

I'm trying to store this concat_view as a member variable of the graph traversal class. (default_bfs_visitor from boost graph library, to be precise). So, upfront, I will not know how many vectors I'm going to encounter. I'm doing something like this.

struct bfs_visitor 
{
private:
    ranges::v3::any_view<double> mView;
public:
    template<class Graph>
    void finish_vertex (vertex_descriptor v, const Graph& g) 
    {
        auto node = g[v];
        std::vector<double>& data = dataForNode(node);
        mView = ranges::v3::concat(mView, data);
    }
};

After I'm done visiting the graph, I process the view to extract the required information.

As the type of mView changes with each concat operation, I'm unable to explicitly specify the type of mView in the declaration.

This link says there's performance hit for any_view. Is any_view the only option?

like image 375
Surya Avatar asked Sep 15 '25 11:09

Surya


1 Answers

You nail the issue on the head:

  • the return type of ranges::v3::concat is different so you need type-erasure (any_view e.g.).
  • type erased lazy composed ranges are a bad idea performance-wise

In your situation I would not hesitate to replace view with a reified container:

Live On Coliru

struct bfs_visitor 
{
private:
    std::vector<std::reference_wrapper<double> > mView;
public:
    template<class Graph>
    void finish_vertex (vertex_descriptor v, const Graph& g) 
    {
        auto& node = g[v];
        ranges::v3::push_back(mView, dataForNode(node));
    }
};

NOTE IMPORTANT

Note that I made auto& node a reference, instead of taking a copy. Concatenating views of temporary copies is a bad idea (UB).

If you happen to know that dataForNode(node) does NOT return a reference to member data from node, then this is not a real issue and you can disregard this comment.

PHYSIC MODE ENGAGED:

If your issue was that g is Graph const& and the view is not readonly, either

  • make mView an any_view<double const>
  • store a non-const pointer to your graph in the visitor and use that instead of the g argument

In fact, if you don't need them to be references at all (this is the key property of a view):

struct bfs_visitor 
{
private:
    std::vector<double> mCollectedData;
public:
    template<class Graph>
    void finish_vertex (vertex_descriptor v, const Graph& g) {
        ranges::v3::push_back(mCollectedData, dataForNode(g[v]));
    }
};

Note Another slightly weird thing is that your visitor templates the Graph argument type, but not the vertex_descriptor. Again, it's hard to know whether it's actually wrong without seeing the rest of the code, but it's certainly a-typical.

The vertex descriptor type is characteristic of the Graph type, so consider - writing typename Graph::vertex_descriptor or typename boost::graph_traits<Graph>::vertex_descriptor - making the operator() non-template

like image 56
sehe Avatar answered Sep 17 '25 02:09

sehe