MultiIndex containers -- offering vector and set access
Solution 1:
Random access index would match the "vector" interface.
An ordered unique index would match the "set" interface.
However, if you have a unique index, this will prevent insertion of duplicates. So, you would get:
Live On Compiler Explorer
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container< //
int,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct asVector>>,
bmi::ordered_unique<bmi::tag<struct asSet>, bmi::identity<int>>>>;
int main()
{
Table data{ 6, 6, 5, 5, 4, 4 };
fmt::print("As vec {}\nAs set {}\n", //
data.get<asVector>(), //
data.get<asSet>());
}
Printing
As vec {6, 5, 4}
As set {4, 5, 6}
Now, I think the "best" you could do with this is to make the order index non-unique (so, mimicking a std::multiset
instead of std::set
): Live On Compiler Explorer
bmi::ordered_non_unique<bmi::tag<struct asSet>, bmi::identity<int>>
Printing
As vec [6, 6, 5, 5, 4, 4]
As set {4, 4, 5, 5, 6, 6}
If you want to traverse unique elements, using a range adaptor would be minimally costly:
-
Using Boost Live
fmt::print("As vec {}\nAs set {}\n", // data.get<asVector>(), // data.get<asSet>() | boost::adaptors::uniqued);
-
Using RangeV3 Live
fmt::print("As vec {}\nAs set {}\n", // data.get<asVector>(), // data.get<asSet>() | ranges::views::unique);
-
Using Standard Ranges; I couldn't make this work but it should really be something like
std::ranges::unique(data.get<asSet>())
All printing
As vec {6, 6, 5, 5, 4, 4}
As set {4, 5, 6}
Other Ideas
If you don't require random access, then sequenced
index might be preferrable for you. And note that this interface comes with the handy unique()
and sort()
methods (just like std::list
).
UPDATE To The Comments
Here's a rolled-in-one response to the comments:
Live On Compiler Explorer
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <fmt/ranges.h>
#include <random>
namespace bmi = boost::multi_index;
template <typename T>
using ListSet = bmi::multi_index_container< //
T,
bmi::indexed_by<
bmi::sequenced<bmi::tag<struct byInsertion>>, //
bmi::ordered_unique<bmi::tag<struct Ordered>, bmi::identity<T>> //
>>;
int main()
{
ListSet<int> data;
std::mt19937 prng{99}; // "random" seed
for (std::uniform_int_distribution d(1, 10); data.size() < 5;) {
int el = d(prng);
if (auto [it, unique] = data.push_back(el); not unique) {
fmt::print("Element {} duplicates index #{}\n", el,
std::distance(begin(data), it));
}
}
fmt::print("By insertion {}\nOrdered {}\n", data, data.get<Ordered>());
}
Prints
Element 9 duplicates index #3
Element 8 duplicates index #1
By insertion [7, 8, 5, 9, 1]
Ordered {1, 5, 7, 8, 9}