Closed Marwes closed 6 years ago
Sorry about the accidental rustfmting. I can revert it but just wanted to post this as-is for now.
Before and after for the non-mutating methods
$ cargo benchcmp old new
name old ns/iter new ns/iter diff ns/iter diff % speedup
vector_drop_last 108,379,948 108,880,821 500,873 0.46% x 1.00
vector_get 1,097,490 1,129,746 32,256 2.94% x 0.97
vector_iterate 832,342 864,973 32,631 3.92% x 0.96
vector_push_back 112,191,792 130,402,698 18,210,906 16.23% x 0.86
Merging #9 into master will increase coverage by
0.2%
. The diff coverage is100%
.
@@ Coverage Diff @@
## master #9 +/- ##
=========================================
+ Coverage 95.24% 95.45% +0.2%
=========================================
Files 12 12
Lines 2084 2090 +6
=========================================
+ Hits 1985 1995 +10
+ Misses 99 95 -4
Impacted Files | Coverage Δ | |
---|---|---|
src/sequence/vector/mod.rs | 97.77% <100%> (+1.16%) |
:arrow_up: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update f125604...b9d2234. Read the comment docs.
Yeah, the speedup can be quite drastic if you have no structural sharing (or not a lot of it). However I would like to keep the API nice and clean.
My idea is to have a VectorMut
with the mutable methods and Vector
would just be a small wrapper around it, where all its methods would be immutable except for a pub fn mutable(&mut self) -> &mut VectorMut<T>
. This way you can choose to:
Vector<T>
and have a nice functional way of using the data structure. Performance will not be as good.VectorMut<T>
for the best performance. Cloning is cheap if you need to keep previous versions of the data structure.Vector<T>
but when you don't need to keep previous versions you can call vector.mutable().push_back()
to get the best performance.Is it really worth it to create a separate type just to keep the interface of the "immutable only" types small? The "immutable only" type has nothing preventing them from supporting the methods and there is not that many methods that needs a mutable variant either. For instance, Vectorneeds
push_back,
set, ``drop_last
which is only 2 methods more than adding a mutable
method.
Anyway, I made this mostly out of curiosity of how low the overhead would be with this strategy :) I can clean this Vector
implementation up and finish the other methods if you want it but otherwise feel free to close or pick apart whatever parts are useful.
Is it really worth it to create a separate type just to keep the interface of the "immutable only" types small?
It is more about having the interface consistent, but I haven't made my mind yet. For now I'm happy with merging this after a cleanup.
Implemented drop_last_mut
as well as a few assorted that fell out of mutability (or I just noticed them as I went along).
The changes made by rustfmt are still present, but it gave me the oportunity to rustfmt the code in master (I just landed that). So, before you rebase create a .rustfmt.toml
in the project root with
write_mode = "Diff"
comment_width = 100
struct_field_align_threshold = 4
use_field_init_shorthand = true
use_try_shorthand = true
match_arm_blocks = false
then do
cargo +nightly fmt -- --write-mode=overwrite
After this commit the changes and you should be able to rebase from master cleanly.
A bit late but I finally remembered to do the rebase.
Looks good! I have only a few minor changes, but since I will splitting this in Vector
/VectorMut
(see https://github.com/orium/rpds/tree/mutable) those changes will get ironed out then.
For now I'm happy to land this after a new rebase on master and getting those commits squashed into a single one.
Done
Awesome! Thanks!
POC of using
Arc::make_mut
to avoid allocating newArc
s unnecesarily. Can speedup mutating operations quite significantly on certain workloads.The same approach could be used on most or all of the other datastructures as well though the difficulty of rewriting may vary.
Before
After