Commit 2ff2a7a
authored
This implements a `FrozenMap` type as a flat sorted boxed slice of `(K, V)` tuples.
This is intended to be used with `TaskInput`s and `turbo_task::Value`s, where the data is stored immutably, and where we already try to call `shrink_to_fit`.
This map is smaller than `HashMap` or `BTreeMap`, and provides `O(log n)` lookups with excellent cache locality (so it's probably faster than `HashMap` in most cases).
Since the map is sorted, equality doesn't care about order, so this is a better implementation of `Eq` for our use-cases than what `IndexMap` provides.
It has a variety of ways it can be constructed: A `HashMap`, a `Vec<(K, V)>`, a `BTreeMap`, etc. There are pros and cons of all of these:
- `Vec<(K, V)>` is good if you don't need lookups until after freezing, and you don't expect many duplicates, since sorting at the end is cheaper than maintaining a map.
- A `BTreeMap` is good if you need a real map, because we can avoid a sort at the end.
- `HashMap`/`IndexMap` are okay if you're getting this data structure from somewhere else.
`IndexSet` is also provided as a thin wrapper around `IndexMap`.
## Remaining Issues
This can't be used with `ResolvedVc` as keys, because `ResolvedVc` does not implement `Ord`. I think it should be okay to do that because it's no worse than our current implementations of `Eq` and `Hash`, but I know this is contentious, so I'm leaving it out of this PR.
## Implementation Strategy
I used Claude Code to write most of this:
- Provided it rust's stdlib implementation of BTreeMap.
- Asked it to extract the public interface into a separate file, excluding nightly-only features.
- Asked it to remove all `&mut` methods.
- Asked it to implement `FrozenMap` with the same API.
Then I did a bunch of manual cleanup:
- Replaced a bunch of manual trait implementations with derives.
- Added bincode and serde traits.
- Added various `turbo-tasks` trait implementations.
- Added some methods/impls for getting the underlying slice.
- Optimized a bunch of the constructors.
Then I asked Claude Code to implement the Set version, and did another round of cleanup:
- Removed bunch of unsafe code where it was trying to transmute `(T, ())` to `T`. The memory layout of a tuple is technically undefined, so this wasn't safe, and the APIs it was trying to create doing this weren't really needed either.
- Replaced some of the iterator newtype wrappers with simpler type aliases. The newtype was overkill for our use-case.
1 parent ae0603c commit 2ff2a7a
File tree
10 files changed
+1510
-7
lines changed- turbopack/crates
- turbo-frozenmap
- src
- turbo-tasks
- src
- task
10 files changed
+1510
-7
lines changedSome generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
294 | 294 | | |
295 | 295 | | |
296 | 296 | | |
297 | | - | |
298 | | - | |
299 | 297 | | |
300 | 298 | | |
| 299 | + | |
301 | 300 | | |
302 | | - | |
303 | | - | |
| 301 | + | |
| 302 | + | |
304 | 303 | | |
305 | 304 | | |
306 | 305 | | |
| |||
309 | 308 | | |
310 | 309 | | |
311 | 310 | | |
| 311 | + | |
312 | 312 | | |
| 313 | + | |
313 | 314 | | |
314 | 315 | | |
315 | 316 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
0 commit comments