-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BTreeMap cursors #141
Comments
I disagree, because it allows violating invariants for a type where the For example, today if you give me a But with the addition of a safe |
Alright I've changed those functions to be |
Why only the unsafe APIs and not equivalent safe ones that do a comparison against the neighbors? |
A safe insert that inserts in the "correct" place but with improved performance when that place is close to the cursor might be nice. (Like the |
I wouldn't use them in |
The API docs say
The cursor API doesn't fall under any of those categories and I don't think "normally" provides enough wiggle room here. |
I maintain the rangemap crate, which is essentially the same as the motivating use case described above, plus automatic coalescing of adjacent ranges that map to the same value. E.g. if you insert I have longed for this API since day one. I care about performance, of course, but I care even more about how much simpler my implementation could be if I could build on top of So I guess this is just my 2c from experiencing the lack of BTreeMap cursors: they feel to me like a very natural and powerful extension. |
This looks quite complete and ready for unstable experimentation. Time to open a tracking issue and merge 105641. :) |
Implement cursors for BTreeMap See the ACP for an overview of the API: rust-lang/libs-team#141 The implementation is split into 2 commits: - The first changes the internal insertion functions to return a handle to the newly inserted element. The lifetimes involved are a bit hairy since we need a mutable handle to both the `BTreeMap` itself (which holds the root) and the nodes allocated in memory. I have tested that this passes the standard library testsuite under miri. - The second commit implements the cursor API itself. This is more straightforward to follow but still involves some unsafe code to deal with simultaneous mutable borrows of the tree root and the node that is currently being iterated.
Implement cursors for BTreeMap See the ACP for an overview of the API: rust-lang/libs-team#141 The implementation is split into 2 commits: - The first changes the internal insertion functions to return a handle to the newly inserted element. The lifetimes involved are a bit hairy since we need a mutable handle to both the `BTreeMap` itself (which holds the root) and the nodes allocated in memory. I have tested that this passes the standard library testsuite under miri. - The second commit implements the cursor API itself. This is more straightforward to follow but still involves some unsafe code to deal with simultaneous mutable borrows of the tree root and the node that is currently being iterated.
Implement cursors for BTreeMap See the ACP for an overview of the API: rust-lang/libs-team#141 The implementation is split into 2 commits: - The first changes the internal insertion functions to return a handle to the newly inserted element. The lifetimes involved are a bit hairy since we need a mutable handle to both the `BTreeMap` itself (which holds the root) and the nodes allocated in memory. I have tested that this passes the standard library testsuite under miri. - The second commit implements the cursor API itself. This is more straightforward to follow but still involves some unsafe code to deal with simultaneous mutable borrows of the tree root and the node that is currently being iterated.
Implement cursors for BTreeMap See the ACP for an overview of the API: rust-lang/libs-team#141 The implementation is split into 2 commits: - The first changes the internal insertion functions to return a handle to the newly inserted element. The lifetimes involved are a bit hairy since we need a mutable handle to both the `BTreeMap` itself (which holds the root) and the nodes allocated in memory. I have tested that this passes the standard library testsuite under miri. - The second commit implements the cursor API itself. This is more straightforward to follow but still involves some unsafe code to deal with simultaneous mutable borrows of the tree root and the node that is currently being iterated.
Proposal
Problem statement
One of the fundamental properties of
BTreeMap
is that it maintains elements in sorted order and enables efficient element lookup inO(log(N))
time. However the current API is overly fitted towards a key-value API like aHashMap
and fails to expose the ability to make queries about "nearby" keys. For example, finding the first element whose key is greater than X.There is limited support for this with the
range
API, but this is hard to use and doesn't allow mutating the tree (by inserting/deleting elements) while iterating. This is insufficient to address existing use cases.Motivation, use-cases
One specific use case where such manipulations are useful is when using a
BTreeMap
to represent a set of non-overlapping ranges with associated values. This is often used to associate metadata with ranges of memory addresses.As a proof of concept, I implemented a
RangeTree
type which conceptually holds a map ofRange<K> -> V
. It has 3 main operations:get
: returns the range containing the given key.remove
: removes any ranges that intersect the given range of keys. Partially overlapping ranges are truncated or split into 2 sub-ranges.insert
: removes any intersecting ranges (with the same behavior asremove
for partially overlapping ranges) and then inserts a new range.There are two implementations of these operations: one with just the standard library API and one with the new proposed cursor API.
Benchmark results show a 25% to 50% speedup by using cursors:
Solution sketches
This proposal adds
Cursor
andCursorMut
types toBTreeMap
based on similar types forLinkedList
.A Cursor is like an iterator, except that it can freely seek back-and-forth, and can safely mutate the tree during iteration. This is because the lifetime of its yielded references is tied to its own lifetime, instead of just the underlying tree. A cursor either points to an element in the tree, or to a "ghost" non-element that is logically located after the last element and before the first element.
This proposal adds the following APIs to
BTreeMap
:Links and related work
LinkedList
cursor RFC and tracking issue.What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.
The text was updated successfully, but these errors were encountered: