MultiIndex Container equal_range ..以相反的顺序获取输出

时间:2018-01-16 05:45:42

标签: c++11 boost

我有一个boost :: multiIndex容器。 说:

typedef boost::multi_index<....
 > OrderSet;


OrderSet orderSet_;

int main()
{
    const auto it = orderSet_.get<0>().equal_range(boost::make_tuple(/* Some Values*/))
 if(it.first != it.second)
  while(it.second != it.first) { /* Somethings to do */; 
  --it.second;          
 }
}

程序因offset_ptr错误而崩溃。 对于程序it具有增加订单的价值。所以我想先获得最高价值然后如此... boost::equal_range(..., [&](const auto a, const auto b)-> decltype bool{return a > b;});是否有任何过载函数      像这样的东西。它就像reverse_iterator

equal_range()

更新:一个生产者和许多消费者访问多索引容器。当消费者发现equal_range,生成器添加或删除元素时,消费者会抛出错误......这只会在我反向迭代时发生......

2 个答案:

答案 0 :(得分:5)

您遗漏了必要部分:所选的索引类型。

不同的索引类型提供不同的接口。

然后,equal_range意味着有序或无序的地图。因为在无序地图上反转顺序是没有意义的,所以我将假设一个有序的地图。

接下来,使用make_tuple,我猜测复合键。

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>

struct X {
    int i;
    std::string name;
};

namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
        bmi::indexed_by<
            bmi::ordered_non_unique<
                bmi::tag<struct by_i>,
                bmi::composite_key<X,
                    bmi::member<X, int, &X::i>,
                    bmi::member<X, std::string, &X::name>
                >
            >
        >
 > OrderSet;

然后是原生订单:

#include <iostream>

int main()
{
    std::cout << std::unitbuf;

    OrderSet orderSet_ {
        { 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
    };

    auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));

    for (auto& el : boost::make_iterator_range(range))
        std::cout << el.i << "," << el.name << "; ";

    // ...

我使用Boost Range来获得相反的顺序:

#include <boost/range/adaptor/reversed.hpp>

   // ...

    // traverse these in reverse
    std::cout << "\nNow in reverse:\n";
    for (auto& el : range | boost::adaptors::reversed)
        std::cout << el.i << "," << el.name << "; ";
}

BONUS TAKE

当然你可以手动编写相同内容:

std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
    --it.second;

    auto& el = *it.second;
    std::cout << el.i << "," << el.name << "; ";
}

现场演示

<强> Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>

struct X {
    int i; //  = [] { static int gen = 0; return ++gen; }();
    std::string name;
};

namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
        bmi::indexed_by<
            bmi::ordered_non_unique<
                bmi::tag<struct by_i>,
                bmi::composite_key<X,
                    bmi::member<X, int, &X::i>,
                    bmi::member<X, std::string, &X::name>
                >
            >
        >
 > OrderSet;

#include <iostream>

int main()
{
    std::cout << std::unitbuf;

    OrderSet orderSet_ {
        { 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
    };

    {
        auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));

        for (auto& el : boost::make_iterator_range(range))
            std::cout << el.i << "," << el.name << "; ";

        // traverse these in reverse
        std::cout << "\nNow in reverse:\n";
        for (auto& el : range | boost::adaptors::reversed)
            std::cout << el.i << "," << el.name << "; ";
    }

    {
        std::cout << "\nAlso in reverse:\n";
        auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
        while(it.second != it.first) {
            auto& el = *(--it.second);
            std::cout << el.i << "," << el.name << "; ";
        }
    }

}

打印

2,five; 2,three; 
Now in reverse:
2,three; 2,five; 
Also in reverse:
2,three; 2,five; 

答案 1 :(得分:1)

更进一步,因为你说offset_ptr你可能正在使用Boost进程间分配器。

这是一个演示,展示了如何在内存映射/共享内存区域正确执行above

<强> Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>

namespace bmi = boost::multi_index;
namespace bip = boost::interprocess;

//namespace Shared { struct X; }
//namespace std { template<typename Alloc> struct uses_allocator<Shared::X, Alloc> : std::true_type {}; }

namespace Shared {
    using Segment = bip::managed_mapped_file;
    template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;

    using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;

    struct X {
        using allocator_type = Alloc<char>;

        template <typename Alloc>
        X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}

        int i;
        String name;
    };

    typedef boost::multi_index_container<X,
            bmi::indexed_by<
                bmi::ordered_non_unique<
                    bmi::tag<struct by_i>,
                    bmi::composite_key<X,
                        bmi::member<X, int, &X::i>,
                        bmi::member<X, String, &X::name>
                    >
                >
            >,
            Alloc<X>
     > OrderSet;
}

#include <iostream>

int main()
{
    std::cout << std::unitbuf;

    Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);

    auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());

    if (orderSet_.empty()) {
        // can't get multi-index to use the scoped allocator "magically" :(
        orderSet_.emplace(1, "one", orderSet_.get_allocator());
        orderSet_.emplace(1, "one", orderSet_.get_allocator());
        orderSet_.emplace(1, "two", orderSet_.get_allocator());
        orderSet_.emplace(2, "three", orderSet_.get_allocator());
        orderSet_.emplace(3, "four", orderSet_.get_allocator());
        orderSet_.emplace(2, "five", orderSet_.get_allocator());
    }

    {
        auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));

        for (auto& el : boost::make_iterator_range(range))
            std::cout << el.i << "," << el.name << "; ";

        // traverse these in reverse
        std::cout << "\nNow in reverse:\n";
        for (auto& el : range | boost::adaptors::reversed)
            std::cout << el.i << "," << el.name << "; ";
    }

    {
        std::cout << "\nAlso in reverse:\n";
        auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
        while(it.second != it.first) {
            auto& el = *(--it.second);
            std::cout << el.i << "," << el.name << "; ";
        }
    }

    std::cout << "\nBye\n";
}

打印

2,five; 2,three; 
Now in reverse:
2,three; 2,five; 
Also in reverse:
2,three; 2,five; 
Bye

两次(证明所有数据在共享内存段中都是正确的)。

BONUS TAKE

显然,Boost Multi-Index并没有完全适用于范围分配器,因为它会更优雅:

<强> Live On Coliru

#include <set>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>

#include <boost/container/set.hpp>
#include <boost/container/scoped_allocator.hpp>

#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/iterator_range.hpp>
namespace bip = boost::interprocess;

namespace Shared {
    using Segment = bip::managed_mapped_file;
    template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;

    using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;

    struct X {
        using allocator_type = Alloc<char>;

        template <typename Alloc>
        X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}

        bool operator<(X const& other) const { return i < other.i; }
        bool operator<(int other) const { return i < other; }

        int i;
        String name;
    };

    template <typename T>
        using Multiset = boost::container::multiset<
            T,
            std::less<T>,
            boost::container::scoped_allocator_adaptor<Alloc<X> >
        >;

    using OrderSet = Multiset<X>;
}

#include <iostream>

int main()
{
    std::cout << std::unitbuf;

    Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);

    auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());

    if (orderSet_.empty()) {
        // scoped-allocator automatically propagates to the string
        orderSet_.emplace(1, "one");
        orderSet_.emplace(1, "one");
        orderSet_.emplace(1, "two");
        orderSet_.emplace(2, "three");
        orderSet_.emplace(3, "four");
        orderSet_.emplace(2, "five");
    }

    {
        auto const range = orderSet_.equal_range({2, "", orderSet_.get_allocator()});

        for (auto& el : boost::make_iterator_range(range))
            std::cout << el.i << "," << el.name << "; ";

        // traverse these in reverse
        std::cout << "\nNow in reverse:\n";
        for (auto& el : range | boost::adaptors::reversed)
            std::cout << el.i << "," << el.name << "; ";
    }

    {
        std::cout << "\nAlso in reverse:\n";
        auto it = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
        while(it.second != it.first) {
            auto& el = *(--it.second);
            std::cout << el.i << "," << el.name << "; ";
        }
    }

    std::cout << "\nBye\n";
}