Slick OrderBook 1.1.0
High-Performance C++23 OrderBook Library
Loading...
Searching...
No Matches
orderbook_manager_impl.hpp
Go to the documentation of this file.
1// Copyright 2026 Slick Quant
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
7
8template<typename OrderBookT>
9OrderBookManager<OrderBookT>::OrderBookManager(std::size_t initial_symbol_capacity)
10 : symbol_map_() {
11 // Reserve capacity to avoid rehashing during initial symbol registration
12 // Note: reserve() is not available in std::map, only in vector-based containers
13 // This is a no-op if FlatMap is std::map, otherwise it pre-allocates
14 if constexpr (requires { symbol_map_.reserve(initial_symbol_capacity); }) {
15 symbol_map_.reserve(initial_symbol_capacity);
16 }
17}
18
19template<typename OrderBookT>
21 std::unique_lock lock(other.mutex_);
22 symbol_map_ = std::move(other.symbol_map_);
23 other.symbol_map_.clear();
24}
25
26template<typename OrderBookT>
28 if (this != &other) [[likely]] {
29 SymbolMap released; // Destroy the old orderbooks after both locks are released
30 {
31 std::scoped_lock lock(mutex_, other.mutex_);
32 released = std::exchange(symbol_map_, std::move(other.symbol_map_));
33 other.symbol_map_.clear();
34 }
35 }
36 return *this;
37}
38
39template<typename OrderBookT>
40template<typename Projection>
41auto OrderBookManager<OrderBookT>::find(SymbolId symbol, Projection&& proj) const {
42 std::shared_lock lock(mutex_);
43 auto it = symbol_map_.find(symbol);
44 return proj(it != symbol_map_.end() ? &it->second : nullptr);
45}
46
47template<typename OrderBookT>
48template<typename Projection>
49auto OrderBookManager<OrderBookT>::findOrCreate(SymbolId symbol, Projection&& proj) {
50 // First, try read-only access (shared lock) - common case
51 {
52 std::shared_lock lock(mutex_);
53 auto it = symbol_map_.find(symbol);
54 if (it != symbol_map_.end()) [[likely]] {
55 return proj(it->second);
56 }
57 }
58
59 // Symbol doesn't exist - need exclusive lock to insert
60 std::unique_lock lock(mutex_);
61
62 // Double-check pattern: another thread might have inserted while we waited
63 auto it = symbol_map_.find(symbol);
64 if (it == symbol_map_.end()) {
65 it = symbol_map_.emplace(symbol, std::make_shared<OrderBookT>(symbol)).first;
66 }
67 return proj(it->second);
68}
69
70template<typename OrderBookT>
72 return findOrCreate(symbol, [](const OrderBookPtr& book) { return book.get(); });
73}
74
75template<typename OrderBookT>
77 return findOrCreate(symbol, [](const OrderBookPtr& book) { return book; });
78}
79
80template<typename OrderBookT>
82 return find(symbol, [](const OrderBookPtr* book) -> const OrderBookT* { return book ? book->get() : nullptr; });
83}
84
85template<typename OrderBookT>
87 return find(symbol, [](const OrderBookPtr* book) -> OrderBookT* { return book ? book->get() : nullptr; });
88}
89
90template<typename OrderBookT>
91std::shared_ptr<OrderBookT> OrderBookManager<OrderBookT>::getSharedOrderBook(SymbolId symbol) const {
92 return find(symbol, [](const OrderBookPtr* book) { return book ? *book : OrderBookPtr{}; });
93}
94
95template<typename OrderBookT>
97 std::shared_lock lock(mutex_);
98 return symbol_map_.contains(symbol);
99}
100
101template<typename OrderBookT>
103 std::unique_lock lock(mutex_);
104 return symbol_map_.erase(symbol) > 0;
105}
106
107template<typename OrderBookT>
108std::vector<SymbolId> OrderBookManager<OrderBookT>::getSymbols() const {
109 std::shared_lock lock(mutex_);
110 std::vector<SymbolId> symbols;
111 symbols.reserve(symbol_map_.size());
112
113 for (const auto& [symbol_id, _] : symbol_map_) {
114 symbols.push_back(symbol_id);
115 }
116
117 return symbols;
118}
119
120template<typename OrderBookT>
122 std::shared_lock lock(mutex_);
123 return symbol_map_.size();
124}
125
126template<typename OrderBookT>
128 std::unique_lock lock(mutex_);
129 symbol_map_.clear();
130}
131
132template<typename OrderBookT>
133void OrderBookManager<OrderBookT>::reserve(std::size_t capacity) {
134 // No lock needed - should be called before concurrent access
135 if constexpr (requires { symbol_map_.reserve(capacity); }) {
136 symbol_map_.reserve(capacity);
137 }
138}
139
140
Multi-symbol OrderBook Manager.
detail::FlatMap< SymbolId, OrderBookPtr > SymbolMap
OrderBookManager & operator=(const OrderBookManager &)=delete
std::size_t symbolCount() const
Get number of active symbols Thread-safe: Uses shared lock.
bool removeOrderBook(SymbolId symbol)
Remove orderbook for a symbol Thread-safe: Uses exclusive lock.
std::vector< SymbolId > getSymbols() const
Get all active symbol IDs Thread-safe: Uses shared lock.
const OrderBookT * getOrderBook(SymbolId symbol) const
Get existing orderbook (read-only access) Thread-safe: Uses shared lock for read-only access Lifetime...
OrderBookT * getOrCreateOrderBook(SymbolId symbol)
Get existing orderbook or create new one if it doesn't exist Thread-safe: Uses shared_mutex for symbo...
std::shared_ptr< OrderBookT > getOrCreateSharedOrderBook(SymbolId symbol)
Get existing orderbook or create new one, as a retaining handle Thread-safe; the orderbook stays aliv...
void reserve(std::size_t capacity)
Reserve capacity for expected number of symbols Not thread-safe: Should be called before concurrent a...
OrderBookManager(std::size_t initial_symbol_capacity=64)
Constructor.
bool hasSymbol(SymbolId symbol) const
Check if symbol exists in manager Thread-safe: Uses shared lock.
void clear()
Clear all orderbooks Thread-safe: Uses exclusive lock.
std::shared_ptr< OrderBookT > getSharedOrderBook(SymbolId symbol) const
Get existing orderbook as a retaining handle Thread-safe; the orderbook stays alive while the handle ...
std::shared_ptr< OrderBookT > OrderBookPtr
#define SLICK_NAMESPACE_END
Definition config.hpp:127
#define SLICK_NAMESPACE_BEGIN
Definition config.hpp:126
uint16_t SymbolId
Symbol identifier - can be hash or sequential ID.
Definition types.hpp:27