-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Shared data structures and algorithms crate #19388
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
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| [package] | ||
| name = "shared-dsa" | ||
| version = "0.1.0" | ||
|
|
||
| # Workspace inherited keys | ||
| authors = { workspace = true } | ||
| edition = { workspace = true } | ||
| homepage = { workspace = true } | ||
| license = { workspace = true } | ||
| publish = { workspace = true } | ||
| repository = { workspace = true } | ||
| rust-version = { workspace = true } | ||
|
|
||
| [dependencies] | ||
| rustc-hash = { workspace = true } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // Copyright (c) Aptos Foundation | ||
| // Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE | ||
|
|
||
| //! Collection of data structures and algorithms, for shared use across | ||
| //! various crates. | ||
|
|
||
| mod unordered_map; | ||
| mod unordered_set; | ||
|
|
||
| pub use std::collections::hash_map::{Entry, OccupiedEntry, VacantEntry}; | ||
| pub use unordered_map::UnorderedMap; | ||
| pub use unordered_set::UnorderedSet; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,260 @@ | ||
| // Copyright (c) Aptos Foundation | ||
| // Licensed pursuant to the Innovation-Enabling Source Code License, available at https://github.com/aptos-labs/aptos-core/blob/main/LICENSE | ||
|
|
||
| use rustc_hash::{FxBuildHasher, FxHashMap}; | ||
| use std::{borrow::Borrow, collections::hash_map::Entry, fmt, hash::Hash, iter::FromIterator}; | ||
|
|
||
| /// A fast, non-cryptographic, non-hash-DoS-resistant hash map. | ||
| /// Iteration over keys or key-value pairs are not exposed to avoid any | ||
| /// reliance on non-deterministic ordering. | ||
| #[derive(Clone)] | ||
| pub struct UnorderedMap<K, V> { | ||
| inner: FxHashMap<K, V>, | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Methods that require no bounds on K/V | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| impl<K, V> UnorderedMap<K, V> { | ||
| #[inline] | ||
| pub fn new() -> Self { | ||
| Self { | ||
| inner: FxHashMap::default(), | ||
| } | ||
| } | ||
|
|
||
| /// Creates an empty map pre-allocated to hold at least `capacity` elements | ||
| /// without reallocation. The load factor is handled internally, so pass the | ||
| /// number of elements you expect, not an inflated value. | ||
| #[inline] | ||
| pub fn with_capacity(capacity: usize) -> Self { | ||
| Self { | ||
| inner: FxHashMap::with_capacity_and_hasher(capacity, FxBuildHasher), | ||
| } | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn len(&self) -> usize { | ||
| self.inner.len() | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn is_empty(&self) -> bool { | ||
| self.inner.is_empty() | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn clear(&mut self) { | ||
| self.inner.clear(); | ||
| } | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Methods that require K: Hash + Eq | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| impl<K: Hash + Eq, V> UnorderedMap<K, V> { | ||
| #[inline] | ||
| pub fn get<Q>(&self, k: &Q) -> Option<&V> | ||
| where | ||
| K: Borrow<Q>, | ||
| Q: Hash + Eq + ?Sized, | ||
| { | ||
| self.inner.get(k) | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V> | ||
| where | ||
| K: Borrow<Q>, | ||
| Q: Hash + Eq + ?Sized, | ||
| { | ||
| self.inner.get_mut(k) | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn contains_key<Q>(&self, k: &Q) -> bool | ||
| where | ||
| K: Borrow<Q>, | ||
| Q: Hash + Eq + ?Sized, | ||
| { | ||
| self.inner.contains_key(k) | ||
| } | ||
|
|
||
| /// Inserts a key-value pair. Returns the previous value if the key was | ||
| /// already present, or `None` if it was newly inserted. | ||
| #[inline] | ||
| pub fn insert(&mut self, k: K, v: V) -> Option<V> { | ||
| self.inner.insert(k, v) | ||
| } | ||
|
|
||
| /// Removes a key, returning its value if the key was present. | ||
| #[inline] | ||
| pub fn remove<Q>(&mut self, k: &Q) -> Option<V> | ||
| where | ||
| K: Borrow<Q>, | ||
| Q: Hash + Eq + ?Sized, | ||
| { | ||
| self.inner.remove(k) | ||
| } | ||
|
|
||
| /// Removes a key, returning the key-value pair if the key was present. | ||
| #[inline] | ||
| pub fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)> | ||
| where | ||
| K: Borrow<Q>, | ||
| Q: Hash + Eq + ?Sized, | ||
| { | ||
| self.inner.remove_entry(k) | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { | ||
|
vineethk marked this conversation as resolved.
|
||
| self.inner.entry(key) | ||
| } | ||
|
|
||
| /// Reserves space for at least `additional` more elements. Pass the number | ||
| /// of elements you expect to add, not an inflated value — the load factor | ||
| /// is handled internally. | ||
| #[inline] | ||
| pub fn reserve(&mut self, additional: usize) { | ||
| self.inner.reserve(additional); | ||
| } | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Trait implementations | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| impl<K, V> Default for UnorderedMap<K, V> { | ||
| #[inline] | ||
| fn default() -> Self { | ||
| Self::new() | ||
| } | ||
| } | ||
|
|
||
| impl<K, V> fmt::Debug for UnorderedMap<K, V> { | ||
| /// Only shows the length to avoid exposing arbitrary iteration order. | ||
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| f.debug_struct("UnorderedMap") | ||
| .field("len", &self.inner.len()) | ||
| .finish() | ||
| } | ||
| } | ||
|
|
||
| impl<K: Hash + Eq, V: PartialEq> PartialEq for UnorderedMap<K, V> { | ||
| #[inline] | ||
| fn eq(&self, other: &Self) -> bool { | ||
| self.inner == other.inner | ||
| } | ||
| } | ||
|
|
||
| impl<K: Hash + Eq, V: Eq> Eq for UnorderedMap<K, V> {} | ||
|
|
||
| impl<K: Hash + Eq, V> FromIterator<(K, V)> for UnorderedMap<K, V> { | ||
| #[inline] | ||
| fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self { | ||
| Self { | ||
| inner: iter.into_iter().collect(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl<K: Hash + Eq, V> Extend<(K, V)> for UnorderedMap<K, V> { | ||
| #[inline] | ||
| fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { | ||
| self.inner.extend(iter); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn test_insert_get_remove() { | ||
| let mut map = UnorderedMap::new(); | ||
| assert!(map.is_empty()); | ||
|
|
||
| assert_eq!(map.insert("a", 1), None); | ||
| assert_eq!(map.insert("b", 2), None); | ||
| assert_eq!(map.len(), 2); | ||
|
|
||
| assert_eq!(map.get("a"), Some(&1)); | ||
| assert_eq!(map.get("c"), None); | ||
| assert!(map.contains_key("b")); | ||
|
|
||
| assert_eq!(map.remove("a"), Some(1)); | ||
| assert_eq!(map.len(), 1); | ||
| assert!(!map.contains_key("a")); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_get_mut() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.insert("x", 10); | ||
| *map.get_mut("x").unwrap() = 20; | ||
| assert_eq!(map.get("x"), Some(&20)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_remove_entry() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.insert("k", 42); | ||
| assert_eq!(map.remove_entry("k"), Some(("k", 42))); | ||
| assert!(map.is_empty()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_entry_api() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.entry("a").or_insert(1); | ||
| map.entry("a").and_modify(|v| *v += 10); | ||
| assert_eq!(map.get("a"), Some(&11)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_clear() { | ||
| let mut map = UnorderedMap::with_capacity(16); | ||
| map.insert(1, 1); | ||
| map.clear(); | ||
| assert!(map.is_empty()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_default() { | ||
| let map: UnorderedMap<String, i32> = Default::default(); | ||
| assert!(map.is_empty()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_eq() { | ||
| let a: UnorderedMap<_, _> = [(1, 2), (3, 4)].into_iter().collect(); | ||
| let b: UnorderedMap<_, _> = [(3, 4), (1, 2)].into_iter().collect(); | ||
| assert_eq!(a, b); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_extend() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.insert(1, "a"); | ||
| map.extend([(2, "b"), (3, "c")]); | ||
| assert_eq!(map.len(), 3); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_reserve() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.insert(1, 1); | ||
| map.reserve(100); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_debug() { | ||
| let mut map = UnorderedMap::new(); | ||
| map.insert(1, 2); | ||
| let s = format!("{:?}", map); | ||
| assert!(s.contains("len: 1")); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.