Firstly, sorry about the poor formatting, I am new and know I did not make it pretty.
I am implementing a system to keep track of orders which I am storing as blocks, and I haven't gained the experience with templates to fully understand the reference docs. (Which I've read through as best I can, and gained a lot of respect for Joaquin. There just doesn't seem to be examples with ranked, composite keys)
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;
I need help making sure my multi_index is correctly formatted.
P.S. - Any help on being able to quickly pull the quantity sums of buys or sells from a given product/price would be appreciated.
Your post does not provide an MCVE and the code in it does have a number of errors that prevent it from compiling even after adding the extra code (headers and stuff) needed.
So, I rewrote the thing fixing the errors I found along the way, you can find the result below. Regarding your primary question, you don't need ranked indices for this, ordered indices do suffice. What you want is the sum of orderQuantity
s of blocks with the same productID
, desiredPrice
and buy/sell mark and a lower priorityAtPrice
than a given block: you need then an index that groups blocks by (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>
>
>
and a function that retrieves the appropriate range and does the sum of quantities:
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 example follows.
#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";
}
Output
17