Boost :: Multi_Index промежуточные итоги - PullRequest
0 голосов
/ 30 октября 2019

Во-первых, извините за плохое форматирование, я новичок и знаю, что не сделал это красиво.

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

struct Block{//Variable types apart from the bool are immutable, values may be modified though
/*  
This is to replace the previous lookup structure consisting of a map of buys and sells, to a map of products, to a map of prices, to a map of priorities, pointing to a struct holding the blockID and quantity

For a modify, if they are changing products or prices, it will create a new order, else they can shrink quantity desired without changing the priorityAtPrice
If they want to increase the quantity they lose their priority, but the order will keep the other values
*/
    const int32_t productID; //One of ~20 different products 
    mutable uint32_t orderQuantity;//Number of products wanted at that price
    const int64_t desiredPrice; //Prices are not unique
    mutable uint64_t priorityAtPrice;//It's a global priority, in case someone alters their order
    const uint64_t blockID;//Unique to every block
    bool buy;//Tag to note if they are a looking to sell or buy

    bool operator<(const Block& lilBlock)const{return blockID<lilBlock.blockID>}

};
struct idHash{
    uint64_t operator()(const Block& lilBlock)const{
        return lilBlock.blockID;
    }
}
struct ObtainElementByBlockID {};
struct ObtainSublistByProductAndPrice {};
struct PlaceInLine {};
struct randomAccess {};

typedef boost::multi_index_container<
Block*,//Data type being stored, in this case, it is a pointer to Block.
//I'd like to store the block objects in an array[size uint64_t] indexed by the BlockIDs, since they are unique and will be accessed often, so keeping as much in cache is desirable
boost::multi_index::indexed_by<
    boost::multi_index::hashed_unique<//Ideally should be fed an ID and retrieve the orderBlock in O(1) time
    //It is never needed to compare IDs beyond checking if that is the ID being queried for
        boost::multi_index::tag<ObtainElementByBlockID>
        ,boost::multi_index::member<Block,uint64_t, blockID>
        ,idHash
    >
    ,boost::multi_index::random_access<
        boost::multi_index::tag<randomAccess>
        ,boost::multi_index::member<Block,uint64_t,blockID>
    >   
    ,boost::multi_index::ordered_non_unique<//Should return a sublist at a product/price pair ordered by priorityAtPrice
        boost::multi_index::tag<ObtainSublistByProductAndPrice>
        ,boost::multi_index::composite_key<
            Block,
            boost::multi_index::member<Block, int32_t, &Block::productID>
            ,boost::multi_index::member<Block, int64_t, &Block::desiredPrice>
            ,boost::multi_index::member<Block, uint64_t, &Block::priorityAtPrice>
        >
        ,boost::multi_index::composite_key_compare<
            std::equal<int32_t>
            ,std::equal<uint64_t>
            ,std::less<uint64_t>
        >
    >
    /*
    I think what I want has to do with rank
    At product/price/buy, the value returned should be the sum of the quantities with a lower priority. 

    Say at   [chairs, 5$, buy=true]   there are orders(priority,quantity)
    such that {(2,5),(6,12),(896, 3)}
    with block IDs {753, 54, 712}
    Querying for the place in line of a block, given the blockID 712
    It should return 17, since there are orders ahead of block 712 with quantities 5+12=17
    (It might actually need to return 18, but that's trivial)
    */
    ,boost::multi_index::ranked_non_unique<
        boost::multi_index::tag<PlaceInLine>
        ,boost::multi_index::composite_key<
            Block,
            boost::multi_index::member<Block, int32_t, &Block::productID>
            ,boost::multi_index::member<Block, int64_t, &Block::desiredPrice>
            ,boost::multi_index::member<Block,priorityAtPrice>
        >
        ,boost::multi_index::composite_key_compare<
            std::equal<int32_t>
            ,std::equal<uint64_t>
            ,std::less<uint64_t>
        >
    >

> BlockDatabase;

Мне нужна помощь, чтобы убедиться,мой multi_index правильно отформатирован.

PS - Любая помощь в возможности быстро получить количество покупок или продаж определенного товара / цены будет принята.

1 Ответ

0 голосов
/ 03 ноября 2019

Ваше сообщение не предоставляет MCVE , и код в нем содержит ряд ошибок, которые мешают его компиляции даже после добавления необходимого дополнительного кода (заголовков и прочего).

Итак, я переписал вещь, исправляющую ошибки, которые я нашел по пути, вы можете найти результат ниже. Что касается вашего основного вопроса, вам не нужны ранжированные индексы, для этого достаточно упорядоченных индексов. То, что вы хотите, это сумма orderQuantity s блоков с одинаковыми productID, desiredPrice и маркой покупки / продажи и меньшим значением priorityAtPrice, чем у данного блока: вам нужен индекс, который группирует блоки по (productID, desiredPrice, buy, priorityAtPrice):

boost::multi_index::ordered_non_unique<
    boost::multi_index::tag<ObtainSublistByProductPriceAndBuy>
    ,boost::multi_index::composite_key<
        Block,
        boost::multi_index::member<Block, const int32_t, &Block::productID>
        ,boost::multi_index::member<Block, const int64_t, &Block::desiredPrice>
        ,boost::multi_index::member<Block, bool, &Block::buy>
        ,boost::multi_index::member<Block, const uint64_t, &Block::priorityAtPrice>
    >
>

и функция, которая извлекает соответствующий диапазон и выполняет сумму величин:

uint32_t placeInLine(const BlockDatabase& bd, const Block& b)
{
    auto& index = bd.get<ObtainSublistByProductPriceAndBuy>();
    auto  first = index.lower_bound(
        std::make_tuple(b.productID, b.desiredPrice, b.buy));
    auto  last  = index.lower_bound(
        std::make_tuple(b.productID, b.desiredPrice, b.buy, b.priorityAtPrice));
    return std::accumulate(
      first, last, uint32_t(0),
      [](uint32_t n, const Block* pb){ return n + pb->orderQuantity; });
}

CompleteПример:

Live On Coliru

#include <array>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <numeric>

struct Block{

    const int32_t productID;
    mutable uint32_t orderQuantity;
    const int64_t desiredPrice;
    mutable uint64_t priorityAtPrice;
    const uint64_t blockID;
    bool buy;

    bool operator<(const Block& lilBlock)const{return blockID<lilBlock.blockID;}
};

struct ObtainElementByBlockID {};
struct RandomAccess {};
struct ObtainSublistByProductAndPrice {};
struct ObtainSublistByProductPriceAndBuy {};

typedef boost::multi_index_container<
Block*,
boost::multi_index::indexed_by<
    boost::multi_index::hashed_unique<
        boost::multi_index::tag<ObtainElementByBlockID>
        ,boost::multi_index::member<Block,const uint64_t,&Block::blockID>
    >
    ,boost::multi_index::random_access<
        boost::multi_index::tag<RandomAccess>
    >   
    ,boost::multi_index::ordered_non_unique<
        boost::multi_index::tag<ObtainSublistByProductAndPrice>
        ,boost::multi_index::composite_key<
            Block,
            boost::multi_index::member<Block, const int32_t, &Block::productID>
            ,boost::multi_index::member<Block, const int64_t, &Block::desiredPrice>
            ,boost::multi_index::member<Block, const uint64_t, &Block::priorityAtPrice>
        >
    >
    ,boost::multi_index::ordered_non_unique<
        boost::multi_index::tag<ObtainSublistByProductPriceAndBuy>
        ,boost::multi_index::composite_key<
            Block,
            boost::multi_index::member<Block, const int32_t, &Block::productID>
            ,boost::multi_index::member<Block, const int64_t, &Block::desiredPrice>
            ,boost::multi_index::member<Block, bool, &Block::buy>
            ,boost::multi_index::member<Block, const uint64_t, &Block::priorityAtPrice>
        >
    >
>
> BlockDatabase;

uint32_t placeInLine(const BlockDatabase& bd, const Block& b)
{
    auto& index = bd.get<ObtainSublistByProductPriceAndBuy>();
    auto  first = index.lower_bound(
        std::make_tuple(b.productID, b.desiredPrice, b.buy));
    auto  last  = index.lower_bound(
        std::make_tuple(b.productID, b.desiredPrice, b.buy, b.priorityAtPrice));
    return std::accumulate(
      first, last, uint32_t(0),
      [](uint32_t n, const Block* pb){ return n + pb->orderQuantity; });
}

int main()
{
    const int32_t chairsID = 0;

    auto blocks = std::array{
      Block{chairsID,  5, 5,   2, 753, true},
      Block{chairsID, 12, 5,   6,  54, true},
      Block{chairsID,  3, 5, 896, 712, true}
    };

    BlockDatabase bd;
    for(auto& b: blocks) bd.insert(&b);

    // retrieve block with blockID 712
    auto it = bd.find(712);

    // output sum of quantities for blocks with same productID, desiredPrice
    // and buy tag and lower priorityAtPrice
    std::cout << placeInLine(bd, **it) << "\n";
}

Выход

17
...