Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 68 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Current implementation supports:
* Annotations are used to specify which fields to index. Currently `hashed_unique`, `hashed_non_unique`, `ordered_unique`, and `ordered_non_unique` are supported.
* The types of all indexed fields must implement `Clone`.
* Optionally, `multi_index_derive` can be used to derive traits on the generated MultiIndexMap, eg. `#[multi_index_derive(Clone, Debug)]`
* Keyed accessors accept `&Q` where the indexed field type implements `Borrow<Q>`, so for example `String` indexes can be queried with either `&String` or `&str`, and `Vec<T>` indexes with either `&Vec<T>` or `&[T]`.
See `examples/main.rs` for more details.

## Example
Expand Down Expand Up @@ -84,7 +85,7 @@ fn main() {
map.try_insert(order1).unwrap();
map.insert(order2);

let orders = map.get_by_trader_name(&"JohnDoe".to_string());
let orders = map.get_by_trader_name("JohnDoe");
assert_eq!(orders.len(), 2);
println!("Found 2 orders for JohnDoe: [{orders:?}]");

Expand All @@ -111,11 +112,11 @@ fn main() {
assert_eq!(order2_ref.filled, true);
assert_eq!(order2_ref.volume, 0);

let orders = map.get_by_trader_name(&"JohnDoe".to_string());
let orders = map.get_by_trader_name("JohnDoe");
assert_eq!(orders.len(), 2);
println!("Found 2 orders for JohnDoe: [{orders:?}]");

let orders = map.remove_by_trader_name(&"JohnDoe".to_string());
let orders = map.remove_by_trader_name("JohnDoe");
for (_idx, order) in map.iter() {
assert_eq!(order.trader_name, "JohnDoe");
}
Expand All @@ -132,6 +133,8 @@ fn main() {
The above example will generate the following MultiIndexMap and associated Iterators.
The `Order`s are stored in a `Slab`, in contiguous memory, which allows for fast lookup and quick iteration.
A lookup table is created for each indexed field, which maps the index key to a index in the `Slab`.
These lookup tables store the owned field type as their key, such as `String` for `trader_name`.
The keyed accessors accept `&Q` where the indexed field type implements `Borrow<Q>`, so a `String` index can be queried with either `&String` or `&str`, and a `Vec<T>` index can be queried with either `&Vec<T>` or `&[T]`.
The exact type used for these depends on the annotations.
For `hashed_unique` and `hashed_non_unique` a `HashMap` is used, for `ordered_unique` and `ordered_non_unique` a `BTreeMap` is used.
* When inserting an element, we add it to the backing store, then add elements to each lookup table pointing to the index in the backing store.
Expand Down Expand Up @@ -178,25 +181,70 @@ impl MultiIndexOrderMap {
fn is_empty(&self) -> bool;
fn clear(&mut self);

fn get_by_order_id(&self, key: &u32) -> Option<&Order>;
fn get_by_timestamp(&self, key: &u64) -> Option<&Order>;
fn get_by_trader_name(&self, key: &String) -> Vec<&Order>;

fn get_mut_by_order_id(&mut self, key: &u32) -> Option<(&mut bool, &mut u64)>;
fn get_mut_by_timestamp(&mut self, key: &u64) -> Option<(&mut bool, &mut u64)>;
fn get_mut_by_trader_name(&mut self, key: &String) -> Vec<(&mut bool, &mut u64)>;

fn update_by_order_id(&mut self, key: &u32, f: impl FnOnce(&mut bool, &mut u64)) -> Option<&Order>;
fn update_by_timestamp(&mut self, key: &u64, f: impl FnOnce(&mut bool, &mut u64)) -> Option<&Order>;
fn update_by_trader_name(&mut self, key: &String, f: impl FnMut(&mut bool, &mut u64)) -> Vec<&Order>;
fn get_by_order_id<Q>(&self, key: &Q) -> Option<&Order>
where
u32: Borrow<Q>,
Q: Hash + Eq + ?Sized;
fn get_by_timestamp<Q>(&self, key: &Q) -> Option<&Order>
where
u64: Borrow<Q>,
Q: Ord + ?Sized;
fn get_by_trader_name<Q>(&self, key: &Q) -> Vec<&Order>
where
String: Borrow<Q>,
Q: Hash + Eq + ?Sized;

fn get_mut_by_order_id<Q>(&mut self, key: &Q) -> Option<(&mut bool, &mut u64)>
where
u32: Borrow<Q>,
Q: Hash + Eq + ?Sized;
fn get_mut_by_timestamp<Q>(&mut self, key: &Q) -> Option<(&mut bool, &mut u64)>
where
u64: Borrow<Q>,
Q: Ord + ?Sized;
fn get_mut_by_trader_name<Q>(&mut self, key: &Q) -> Vec<(&mut bool, &mut u64)>
where
String: Borrow<Q>,
Q: Hash + Eq + ?Sized;

fn update_by_order_id<Q>(&mut self, key: &Q, f: impl FnOnce(&mut bool, &mut u64)) -> Option<&Order>
where
u32: Borrow<Q>,
Q: Hash + Eq + ?Sized;
fn update_by_timestamp<Q>(&mut self, key: &Q, f: impl FnOnce(&mut bool, &mut u64)) -> Option<&Order>
where
u64: Borrow<Q>,
Q: Ord + ?Sized;
fn update_by_trader_name<Q>(&mut self, key: &Q, f: impl FnMut(&mut bool, &mut u64)) -> Vec<&Order>
where
String: Borrow<Q>,
Q: Hash + Eq + ?Sized;

fn modify_by_order_id(&mut self, key: &u32, f: impl FnOnce(&mut Order)) -> Option<&Order>;
fn modify_by_timestamp(&mut self, key: &u64, f: impl FnOnce(&mut Order)) -> Option<&Order>;
fn modify_by_trader_name(&mut self, key: &String, f: impl FnMut(&mut Order)) -> Vec<&Order>;
fn modify_by_order_id<Q>(&mut self, key: &Q, f: impl FnOnce(&mut Order)) -> Option<&Order>
where
u32: Borrow<Q>,
Q: Hash + Eq + ?Sized;
fn modify_by_timestamp<Q>(&mut self, key: &Q, f: impl FnOnce(&mut Order)) -> Option<&Order>
where
u64: Borrow<Q>,
Q: Ord + ?Sized;
fn modify_by_trader_name<Q>(&mut self, key: &Q, f: impl FnMut(&mut Order)) -> Vec<&Order>
where
String: Borrow<Q>,
Q: Hash + Eq + ?Sized;

fn remove_by_order_id(&mut self, key: &u32) -> Option<Order>;
fn remove_by_timestamp(&mut self, key: &u64) -> Option<Order>;
fn remove_by_trader_name(&mut self, key: &String) -> Vec<Order>;
fn remove_by_order_id<Q>(&mut self, key: &Q) -> Option<Order>
where
u32: Borrow<Q>,
Q: Hash + Eq + ?Sized;
fn remove_by_timestamp<Q>(&mut self, key: &Q) -> Option<Order>
where
u64: Borrow<Q>,
Q: Ord + ?Sized;
fn remove_by_trader_name<Q>(&mut self, key: &Q) -> Vec<Order>
where
String: Borrow<Q>,
Q: Hash + Eq + ?Sized;

fn iter(&self) -> slab::Iter<Order>;
fn iter_mut(&mut self) -> OrderMutIter;
Expand All @@ -222,4 +270,3 @@ See [Cargo.toml](Cargo.toml) for information on each dependency.
* Potentially a vector-map style lookup table would be very quick for small tables with integer indexes.
* Allow overwriting behaviour upon inserting a duplicate unique index, returning a Vec of the overwritten elements.
* Implement [clever tricks](https://www.boost.org/doc/libs/1_36_0/libs/multi_index/doc/performance.html) used in boost::multi_index_containers to improve performance.

2 changes: 1 addition & 1 deletion multi_index_map/examples/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn main() {
7, o1_note_ref,
);

let toms_orders = map.remove_by_trader_name(&"Tom".to_string());
let toms_orders = map.remove_by_trader_name("Tom");
assert_eq!(toms_orders.len(), 2);
println!("Removed Tom's order by name: {toms_orders:?}");

Expand Down
88 changes: 0 additions & 88 deletions multi_index_map/tests/hashed_non_unique_with_string.rs

This file was deleted.

Loading
Loading