|
1 | 1 | #include <iostream> |
2 | | -#include <queue> |
3 | 2 | #include <vector> |
4 | 3 | #include <cassert> |
5 | 4 | #include <thread> |
6 | 5 | #include <chrono> |
7 | 6 | #include <string> |
| 7 | +#include <cstdint> |
| 8 | +#include <algorithm> |
8 | 9 |
|
9 | | -struct Order { |
| 10 | +// Phase 4: Cache Line Optimization |
| 11 | +// 64-byte alignment and tightly packed variables. |
| 12 | +// Fits perfectly into L1 cache lines. |
| 13 | +struct alignas(64) Order { |
10 | 14 | double price; |
11 | | - int quantity; |
| 15 | + uint32_t quantity; |
12 | 16 | bool is_buy; |
13 | 17 | }; |
14 | 18 |
|
15 | | -struct CompareBuy { |
16 | | - bool operator()(const Order& a, const Order& b) { return a.price < b.price; } |
| 19 | +// Phase 4 & Phase 2: Align arrays to cache lines |
| 20 | +struct alignas(64) LevelData { |
| 21 | + uint32_t buy_quantity = 0; |
| 22 | + uint32_t sell_quantity = 0; |
17 | 23 | }; |
18 | 24 |
|
19 | | -struct CompareSell { |
20 | | - bool operator()(const Order& a, const Order& b) { return a.price > b.price; } |
21 | | -}; |
| 25 | +// Phase 2 & 3: O(1) Array with Pre-allocated Memory |
| 26 | +constexpr size_t MAX_PRICE_LEVELS = 1000000; |
22 | 27 |
|
23 | 28 | class OrderBook { |
24 | | - std::priority_queue<Order, std::vector<Order>, CompareBuy> buys; |
25 | | - std::priority_queue<Order, std::vector<Order>, CompareSell> sells; |
26 | | - int trades_executed = 0; |
| 29 | + // Phase 2: Reserving this once keeps dynamic allocations OUT of the trading path |
| 30 | + std::vector<LevelData> book; |
| 31 | + uint32_t trades_executed = 0; |
| 32 | + |
| 33 | + int max_buy_price = 0; |
| 34 | + int min_sell_price = static_cast<int>(MAX_PRICE_LEVELS); |
27 | 35 |
|
28 | 36 | public: |
| 37 | + OrderBook() { |
| 38 | + book.resize(MAX_PRICE_LEVELS); |
| 39 | + } |
| 40 | + |
29 | 41 | void addOrder(const Order& order) { |
30 | | - if (order.is_buy) buys.push(order); |
31 | | - else sells.push(order); |
| 42 | + // Phase 3: Array Index represents price level (O(1) access) |
| 43 | + int price_index = static_cast<int>(order.price * 100); |
| 44 | + |
| 45 | + if (order.is_buy) { |
| 46 | + book[price_index].buy_quantity += order.quantity; |
| 47 | + if (price_index > max_buy_price) max_buy_price = price_index; |
| 48 | + } else { |
| 49 | + book[price_index].sell_quantity += order.quantity; |
| 50 | + if (price_index < min_sell_price) min_sell_price = price_index; |
| 51 | + } |
32 | 52 | match(); |
33 | 53 | } |
34 | 54 |
|
35 | 55 | void match() { |
36 | | - while (!buys.empty() && !sells.empty() && buys.top().price >= sells.top().price) { |
37 | | - Order b = buys.top(); buys.pop(); |
38 | | - Order s = sells.top(); sells.pop(); |
39 | | - int traded = std::min(b.quantity, s.quantity); |
| 56 | + while (max_buy_price >= min_sell_price) { |
| 57 | + while (max_buy_price >= 0 && book[max_buy_price].buy_quantity == 0) { |
| 58 | + max_buy_price--; |
| 59 | + } |
| 60 | + while (min_sell_price < static_cast<int>(MAX_PRICE_LEVELS) && book[min_sell_price].sell_quantity == 0) { |
| 61 | + min_sell_price++; |
| 62 | + } |
| 63 | + |
| 64 | + if (max_buy_price < min_sell_price || max_buy_price < 0 || min_sell_price >= static_cast<int>(MAX_PRICE_LEVELS)) { |
| 65 | + break; |
| 66 | + } |
40 | 67 |
|
41 | | - b.quantity -= traded; |
42 | | - s.quantity -= traded; |
| 68 | + uint32_t traded = std::min(book[max_buy_price].buy_quantity, book[min_sell_price].sell_quantity); |
| 69 | + book[max_buy_price].buy_quantity -= traded; |
| 70 | + book[min_sell_price].sell_quantity -= traded; |
43 | 71 | trades_executed++; |
44 | | - |
45 | | - if (b.quantity > 0) buys.push(b); |
46 | | - if (s.quantity > 0) sells.push(s); |
47 | 72 | } |
48 | 73 | } |
49 | 74 |
|
|
0 commit comments