equal_range в составном ключе boost::multi_index_container с оператором сравнения

Я пытаюсь запросить результаты из контейнера с несколькими индексами, где тип значения представляет собой структуру из трех элементов. Задается первое значение, но второе и третье должны быть больше или меньше параметра запроса.

После поиска я обнаружил, что необходимо реализовать собственное средство извлечения ключей, и некоторые ссылки здесь предлагают то же самое, но я не могу его реализовать:

Может ли кто-нибудь помочь мне заставить его работать?

Ниже приведена моя структура и реализация мультииндекса:

#define RANKFILTERVIEW 0

struct TPQ {
    int UID;
    int Value;
    int Rank;
    TPQ():UID(0),Value(0),Rank(0)
    { }
    TPQ(int _T, int _V, int _R):UID(_T),Value(_V),Rank(_R)
    { }
};

typedef bip::allocator<
    TPQ,bip::managed_shared_memory::segment_manager
> shared_struct_allocator;

typedef bmi::multi_index_container<
    TPQ,
    bmi::indexed_by<
        bmi::ordered_unique<bmi::tag<struct Composite>,
            bmi::composite_key<TPQ,
                bmi::member<TPQ, int,&TPQ::UID>,
                bmi::member<TPQ, int,&TPQ::Value>,
                bmi::member<TPQ, int,&TPQ::Rank>
        > >
    >,
    shared_struct_allocator
> Rank_Set;

typedef nth_index<Rank_Set, RANKFILTERVIEW>::type Rank_view;

int main()
{
    bip::managed_shared_memory segment(bip::open_only,"RANKSOTRE");

    int UID =52478;

    std::pair<Rank_Set*, std::size_t> RankOrderRecord=segment.find<Rank_Set>("RANKDATARECORD");

    /// Here I want the result as stated below.
    auto range = RankOrderRecord.first->get<Composite>().equal_range(boost::make_tuple(UID,_2>500,_3>5));

}

У меня есть набор инструкций, что сортировка или перестановка должны игнорироваться.


person Shailendra kumar    schedule 29.05.2018    source источник
comment
У меня есть набор инструкций, что сортировка или перестановка должны игнорироваться. - что ты имеешь в виду? Вы имеете в виду, что вы должны использовать индекс...?   -  person sehe    schedule 29.05.2018


Ответы (1)


Ты почти понял. Действительно, в порядковых индексах можно запрашивать по частичному ключу. Поскольку поля являются регулярными целочисленными типами, довольно легко получить хорошую нижнюю и верхнюю границу:

auto range = boost::make_iterator_range(
    view.lower_bound(boost::make_tuple(UID, 501, 6)),
    view.lower_bound(boost::make_tuple(UID+1)));

Вот полная демонстрация:

Жить на Coliru

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

#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp> // for Coliru

#include <boost/range/iterator_range.hpp>

#include <iostream>

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

struct TPQ {
    int UID   = 0;
    int Value = 0;
    int Rank  = 0;

    TPQ() = default;
    TPQ(int _T, int _V, int _R) : UID(_T), Value(_V), Rank(_R) {}
};

static inline std::ostream& operator<<(std::ostream& os, TPQ const& tpq) {
    return os << "{ UID: " << tpq.UID
              << ", Value: " << tpq.Value
              << ", Rank: " << tpq.Rank << "}";
}

using shared_struct_allocator = bip::allocator<TPQ, bip::managed_mapped_file::segment_manager>;

using Rank_Set = bmi::multi_index_container<
    TPQ,
    bmi::indexed_by<
        bmi::ordered_unique<
            bmi::tag<struct RankFilterView>,
            bmi::composite_key<TPQ,
                bmi::member<TPQ, int, &TPQ::UID>, 
                bmi::member<TPQ, int, &TPQ::Value>,
                bmi::member<TPQ, int, &TPQ::Rank>
            >
        >
    >,
    shared_struct_allocator>;

using Rank_view = bmi::index<Rank_Set, RankFilterView>::type;

int main() {
    bip::managed_mapped_file segment(bip::open_or_create, "RANKSOTRE", 10*1024);
    auto& table = *segment.find_or_construct<Rank_Set>("RANKDATARECORD")(segment.get_segment_manager());

    table.insert({
        {52478, 501, 6}, // Match!
        {52478, 500, 6}, // - Value too small
        {52479, 0,   0}, // - UID too high
        {52478, 502, 6}, // Match!
        {52478, 502, 7}, // Match!
        {52478, 501, 5}, // - Rank too small
        {52477, 502, 7}, // - UID too small
        {52478, 999, 9}, // Match!
    });

    int UID = 52478;
    Rank_view& view = table.get<RankFilterView>(); 

    auto range = boost::make_iterator_range(
        view.lower_bound(boost::make_tuple(UID, 501, 6)),
        view.upper_bound(UID));

    for (TPQ const& tpq : range) {
        std::cout << tpq << "\n";
    }

}

Который будет печатать, как и ожидалось:

{ UID: 52478, Value: 501, Rank: 6}
{ UID: 52478, Value: 502, Rank: 6}
{ UID: 52478, Value: 502, Rank: 7}
{ UID: 52478, Value: 999, Rank: 9}
person sehe    schedule 29.05.2018
comment
Вместо view.lower_bound(boost::make_tuple(UID+1)) можно использовать view.upper_bound(boost::make_tuple(UID)), что не зависит от целостности UID. - person Joaquín M López Muñoz; 29.05.2018
comment
Кроме того, вы можете обойтись без make_tuple и написать view.upper_bound(UID) напрямую. - person Joaquín M López Muñoz; 29.05.2018
comment
Я удивлен, что вам не нужно определять RankFilterView (только объявить его). У вас есть объяснение, почему это нормально? - person Caleth; 29.05.2018
comment
@JoaquínMLópezMuñoz ммм. Я ошибся с подходом upper_bound в прошлом. Я не совсем уверен, что это было с Boost MultiIndex, так что, вероятно, это одна из этих деформаций, от которой требуется время, чтобы избавиться. (Обновлен ответ после тестирования :)) - person sehe; 29.05.2018
comment
@Калет Ага. Это только предварительное объявление. Пока никакая операция не требует, чтобы тип был полным (например, sizeof(RankFilterView)), нет необходимости его определять. Это довольно распространенная идиома для типов тегов. - person sehe; 29.05.2018
comment
Спасибо @sehe за ваш ответ. Позвольте мне применить это в моем коде и вернуться к вам. Большое спасибо - person Shailendra kumar; 30.05.2018
comment
@sehe, поскольку я не получал желаемого результата, используя это решение, поэтому я немного изменил вашу ссылку на coliru и делюсь ею снова. Проблема здесь в том, что мне нужны записи с рангом больше нуля, но он выбирает записи, в которых совпадают первые два элемента. Вот ссылка - person Shailendra kumar; 31.05.2018
comment
Вам придется фильтровать вручную. Все, что вы можете ожидать от упорядоченного индекса, — это упорядоченные диапазоны. Это не база данных SQL, и база данных SQL также будет использовать несколько индексов для удовлетворения такого запроса. - person sehe; 31.05.2018