compound eye
compound eye

Reputation: 2090

Is it possible to have index in boost::multi_index_container that only indexes some elements?

Is it possible to create an index in boost::multi_index_container that only indexes some of the elements in the container?

If you had a boost multi index container:

using Nodes = boost::multi_index_container<
    Node,
    indexed_by<
        sequenced<>,
        ordered_unique<
            tag<ordered_by_parent_id>,
            const_mem_fun<Node, boost::optional<unsigned int>, &Node::parentId>
        >
    >
>;

where the elements in the container have a method

const boost::optional<int> Node::parentId()

you might want an index on the return value of Node::parentId() but if you actually only need an index of the non-null values, it seems wasteful to create an index to all the elements in the collection.

You could just create a second std container holding pointers to the subset of nodes with valid parent ids, but is there a good way to handle this as an additional index on the multi index container?

Upvotes: 1

Views: 365

Answers (1)

sehe
sehe

Reputation: 392911

No you can't.

Of course you can have non-unique index, but that still has overhead for all parent-less entries.

What you can do, though, is put pointers in a separate "index" container. Then the onus is on you to guard the synchronization of these containers (as well as the lifetime of the pointed-to objects).

Update You can even transparently use reference wrappers:

using ParentIndex = bmi::multi_index_container<
    boost::reference_wrapper<Node const>,
    bmi::indexed_by<
        bmi::ordered_non_unique<
            bmi::tag<struct ordered_by_parent_id>,
            bmi::const_mem_fun<Node, boost::optional<unsigned int>, &Node::parentId>
        >
    >
>;

Here's a demo:

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <iostream>

namespace bmi = boost::multi_index;

struct Node {
    unsigned int Id;
    boost::optional<unsigned int> for_demo;
    boost::optional<unsigned int> parentId() const { return for_demo; };
};

static std::ostream& operator<<(std::ostream& os, Node const& n) {
    return os << "{" << n.Id << ", " << n.parentId() << "}";
}

using Nodes = bmi::multi_index_container<
    Node,
    bmi::indexed_by<
        bmi::sequenced<>
    >
>;

using ParentIndex = bmi::multi_index_container<
    boost::reference_wrapper<Node const>,
    bmi::indexed_by<
        bmi::ordered_non_unique<
            bmi::tag<struct ordered_by_parent_id>,
            bmi::const_mem_fun<Node, boost::optional<unsigned int>, &Node::parentId>
        >
    >
>;

int main() {
    Nodes table {
        {1, boost::none}, {2, 5}, {3, boost::none}, {4, 5}, {5, 5}, {6, 2}
    };

    ParentIndex extra;
    for (auto const& e : table) 
        if (e.parentId()) extra.emplace(e);

    for (auto& e : table) 
        std::cout << e.Id << " ";

    std::cout << "\nParented: ";

    for (Node const& e : extra) 
        std::cout << e << "; ";
}

Upvotes: 2

Related Questions