1#include "lob/book/price_ladder.hpp"
9 std::size_t levelCountArg,
bool descendingArg)
10 : minPrice(minPriceArg.getPrice()), tickSize(tickSizeArg.getPrice()),
11 maxPrice(0), levelCount(levelCountArg), descending(descendingArg) {
13 throw std::invalid_argument(
"PriceLadder minPrice must be nonzero");
16 throw std::invalid_argument(
"PriceLadder tickSize must be nonzero");
18 if (levelCount == 0) {
19 throw std::invalid_argument(
"PriceLadder levelCount must be nonzero");
21 const std::uint64_t span =
static_cast<std::uint64_t
>(levelCount - 1);
22 if (tickSize != 0 && span > (UINT64_MAX - minPrice) / tickSize) {
23 throw std::invalid_argument(
"PriceLadder range overflows a 64-bit price");
25 maxPrice = minPrice + span * tickSize;
30 levels.reserve(levelCount);
31 for (std::size_t index = 0; index < levelCount; ++index) {
32 const std::uint64_t raw = descending
33 ? maxPrice -
static_cast<std::uint64_t
>(index) * tickSize
34 : minPrice +
static_cast<std::uint64_t
>(index) * tickSize;
35 levels.emplace_back(
Price{raw});
37 words.assign((levelCount + 63) / 64, 0);
40std::size_t PriceLadder::indexOf(
Price price)
const {
41 const std::uint64_t raw = price.
getPrice();
42 std::uint64_t offset = 0;
44 if (raw > maxPrice || raw < minPrice) {
45 throw std::out_of_range(
"Price is outside the configured ladder range");
47 offset = maxPrice - raw;
49 if (raw < minPrice || raw > maxPrice) {
50 throw std::out_of_range(
"Price is outside the configured ladder range");
52 offset = raw - minPrice;
54 if (offset % tickSize != 0) {
55 throw std::invalid_argument(
"Price does not fall on a configured tick boundary");
57 return static_cast<std::size_t
>(offset / tickSize);
61 return levels[indexOf(price)];
69 const std::size_t index = indexOf(price);
70 words[index / 64] |= (std::uint64_t{1} << (index % 64));
71 if (occupied == 0 || index < bestIndex) {
86 const std::size_t index = indexOf(price);
87 words[index / 64] &= ~(std::uint64_t{1} << (index % 64));
89 if (index == bestIndex) {
90 bestIndex = occupied == 0 ?
npos : nextSetBit(index + 1);
94std::size_t PriceLadder::nextSetBit(std::size_t from)
const {
95 if (from >= levelCount) {
98 const std::size_t startWord = from / 64;
99 const unsigned startBit =
static_cast<unsigned>(from % 64);
101 const std::uint64_t firstWord = words[startWord] >> startBit;
102 if (firstWord != 0) {
103 return from +
static_cast<std::size_t
>(std::countr_zero(firstWord));
105 for (std::size_t word = startWord + 1; word < words.size(); ++word) {
106 if (words[word] != 0) {
107 const std::size_t index =
108 word * 64 +
static_cast<std::size_t
>(std::countr_zero(words[word]));
109 return index < levelCount ? index :
npos;
116 return bestIndex ==
npos ? nullptr : &levels[bestIndex];
120 return bestIndex ==
npos ? nullptr : &levels[bestIndex];
void markOccupied(Price price)
Marks a level occupied; call exactly once when its order count transitions from zero to nonzero.
PriceLadder(Price minPrice, Price tickSize, std::size_t levelCount, bool descending)
Pre-allocates every level the ladder will ever hold.
static constexpr std::size_t npos
Sentinel returned when no level is occupied.
PriceLevel & levelAt(Price price)
Returns the level slot for a price; the slot always exists.
void markEmpty(Price price)
Marks a level empty; call exactly once when its order count transitions from nonzero to zero.
PriceLevel * best()
Returns the best occupied level, or nullptr when the side is empty.
Maintains FIFO resting orders at one price.
Type-safe nonzero price value used for price ordering.
std::uint64_t getPrice() const
Returns the underlying numeric price.