Kluthen57
Kluthen57

Reputation: 59

Boost Multi Index: index based on list content

I'm new to Boost Multi Index container, and was wondering if it could solve in a more effecient way my problem, simplified thus:

struct A {
   int id;
}

struct B {
   int id;
   std::list<A> products;
}

Each A having a strictly unique ID, I want to be able with a single multi index container, be able to look for B. By B's id, and by A's Id.

At the moment i'm working with nice std::map, and map linking A ids to B ids. So to say. It works fine enough. But, I'm having other parameters for such a look up and it's getting really nasty :)

EDIT:

As per comment request I'll elaborate somewhat:

I've Satellites, which in turn have many Transponders and many Sources. I want to be able to find a Satellite for a given Transponder id or Source id( which are indeed unique )

Sadly I don't have hand on Satellite struct, means, I can't alter it.

Briefly it looks like that :

struct Satellite {
 int norad_id;
 std::list<Transponder> transponders;
 std::list<Source> sources;
 ... some more data
}

What I want to do is simply search a whatever of Satellites, and find a Satellite having a specific transponder-, or source-, or norad id.

At the moment, I'm using 3 nice maps

std::map<int /*norad*/ ,Satellite> satellites;
std::map<int /*transponder  id*/, int/* norad */> transponder_to_satellite;
std::map<int /* source_id */,  int /* norad */ > source_to_satellite;

From the example @sehe provided, I see it would be somewhat easier if I were to spawn a relationnal struct. I guess I'll give it a try ... :)

Upvotes: 1

Views: 71

Answers (1)

sehe
sehe

Reputation: 392911

In the absense of exact use cases, here' some suggestions to model the indices based on what you showed¹

struct Product {
int id;
};

struct Category {
int id;
};

struct ProductCategoryRelation {
    int productId;
    int categoryId;
};

namespace bmi = boost::multi_index;

using RelationTable = bmi::multi_index_container<
    ProductCategoryRelation,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::tag<struct by_product>,
            bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::productId>
        >,
        bmi::ordered_unique<
            bmi::tag<struct by_category>,
            bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::categoryId>
        >
    >
>;

You could also get quite smart with a composite key, which is versatile in ordered_* indexes:

using RelationTable = bmi::multi_index_container<
    ProductCategoryRelation,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::tag<struct by_product>,
            bmi::composite_key<ProductCategoryRelation,
                bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::categoryId>,
                bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::productId>
            >
        >
    >
>;

Here's a small demo:

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <list>

struct Product {
   int id;
};

struct Category {
   int id;
};

struct ProductCategoryRelation {
    int productId;
    int categoryId;
};

namespace bmi = boost::multi_index;

using RelationTable = bmi::multi_index_container<
    ProductCategoryRelation,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::tag<struct compound>,
            bmi::composite_key<ProductCategoryRelation,
                bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::categoryId>,
                bmi::member<ProductCategoryRelation, int, &ProductCategoryRelation::productId>
            >
        >
    >
>;

#include <iostream>
#include <boost/range/iterator_range.hpp>

int main() {
    RelationTable table {
        ProductCategoryRelation { 1, 7 },
        ProductCategoryRelation { 2, 7 },
        ProductCategoryRelation { 3, 7 },
        ProductCategoryRelation { 4, 6 },
        ProductCategoryRelation { 5, 6 },
        ProductCategoryRelation { 6, 6 },
        ProductCategoryRelation { 7, 5 },
        ProductCategoryRelation { 8, 5 },
        ProductCategoryRelation { 9, 5 },
    };

    // find all products in category 6:
    for (auto& rel : boost::make_iterator_range(table.get<compound>().equal_range(6)))
        std::cout << "Product " << rel.productId << " is in category " << rel.categoryId << "\n";
}

Prints:

Product 4 is in category 6
Product 5 is in category 6
Product 6 is in category 6

¹ I crystal-balled the class names into something "realistic"

Upvotes: 1

Related Questions