Reputation: 2090
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
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:
#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