intmap-2.0.0/.cargo_vcs_info.json0000644000000001360000000000100123230ustar { "git": { "sha1": "2d8d17d75eeb2812af0e95350de75f7e5b9f3265" }, "path_in_vcs": "" }intmap-2.0.0/.github/workflows/pr.yml000064400000000000000000000023311046102023000156530ustar 00000000000000name: Check and Test on: [pull_request] jobs: build: runs-on: ubuntu-latest strategy: matrix: rust: [ 1.58.1, 1.61.0 ] steps: - uses: actions/checkout@v2 - name: Cache Cargo uses: actions/cache@v2 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ matrix.build }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ matrix.build }}-cargo- - name: Install Rust run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable -y source $HOME/.cargo/env rustup update ${{ matrix.rust }} --no-self-update rustup default ${{ matrix.rust }} rustup component add rustfmt - name: Check Format run: $HOME/.cargo/bin/cargo fmt --all -- --check - name: Test run: $HOME/.cargo/bin/cargo test env: RUST_BACKTRACE: 1 - name: Integration test env: RUST_BACKTRACE: 1 run: | for p in integration_tests/*; do pushd $p $HOME/.cargo/bin/cargo test popd done intmap-2.0.0/.gitignore000064400000000000000000000000361046102023000131020ustar 00000000000000target Cargo.lock *.sublime-* intmap-2.0.0/CHANGELOG.md000064400000000000000000000017161046102023000127310ustar 00000000000000# Changelog ## [2.0.0] 2022-07-17 ### Added Breaking! - `insert` now matches behavior of built-in `insert` - Old `insert` has been renamed to `insert_checked` ## [1.1.0] 2022-06-11 ### Added - Implement Default for IntMap [@roman-kashitsyn](https://github.com/roman-kashitsyn) - Added `set_load_factor` ### Fixed - PartialEq implementation checked inclusion, not equality [@roman-kashitsyn](https://github.com/roman-kashitsyn) ### Changed - Change default load factor to 90.9 ## [1.0.0] 2022-06-10 - Bump to 1.0 as we are feature complete! ### Added - Added Entry api [@jakoschiko](https://github.com/jakoschiko) ## [0.8.0] 2022-06-09 ### Added - Added changelog! - Add support for Serde behind "serde" feature flag, disabled by default [@roman-kashitsyn](https://github.com/roman-kashitsyn) ### Changed - Improve documentation of `insert` [@jakoschiko](https://github.com/jakoschiko) - Various code modernizations [@chinoto](https://github.com/chinoto) intmap-2.0.0/Cargo.toml0000644000000017500000000000100103240ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "intmap" version = "2.0.0" authors = ["Jesper Axelsson "] description = "Specialized HashMap for u64 keys" readme = "README.md" keywords = [ "hashmap", "u64", "intmap", ] license = "MIT" repository = "https://github.com/JesperAxelsson/rust-intmap" [package.metadata.docs.rs] features = ["serde"] [dependencies.serde] version = "1.0" optional = true default-features = false [dev-dependencies.indexmap] version = "1.8.2" [dev-dependencies.rand] version = "0.8.5" intmap-2.0.0/Cargo.toml.orig000064400000000000000000000007521046102023000140060ustar 00000000000000[package] name = "intmap" version = "2.0.0" edition = "2018" description = "Specialized HashMap for u64 keys" authors = ["Jesper Axelsson "] readme = "README.md" license = "MIT" repository = "https://github.com/JesperAxelsson/rust-intmap" keywords = ["hashmap", "u64", "intmap"] [dependencies] serde = { version = "1.0", optional = true, default-features = false } [dev-dependencies] rand = "0.8.5" indexmap = "1.8.2" [package.metadata.docs.rs] features = ["serde"] intmap-2.0.0/LICENSE-MIT000064400000000000000000000020421046102023000125450ustar 00000000000000Copyright (c) 2016 Jesper Axelsson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.intmap-2.0.0/README.md000064400000000000000000000025471046102023000124020ustar 00000000000000[![crates.io](https://img.shields.io/crates/v/intmap.svg)](https://crates.io/crates/intmap) # rust-intmap Specialized hashmap for u64 keys Might be missing some functionality but you can remove, add, get and clear for now. Be aware that no effort is made against DoS attacks. Performace compared to the standard hashmap: ```` test tests::u64_get_built_in ... bench: 22,320 ns/iter (+/- 446) test tests::u64_get_intmap ... bench: 2,959 ns/iter (+/- 148) test tests::u64_insert_built_in ... bench: 27,666 ns/iter (+/- 1,230) test tests::u64_insert_intmap ... bench: 14,047 ns/iter (+/- 1,461) ```` # Breaking Changes 2.0.0 - Changed behavior of `insert` to match std::HashMap. The old behavior is renamed to `insert_checked`. # How to use Simple example. ````rust extern crate intmap; use intmap::IntMap; let mut map = IntMap::new(); for i in 0..20_000 { map.insert(i, format!("item: {:?}", i)); } ```` # How can it be so much faster? I use a specialized hash function for u64 it multiplies the key with the largest prime for u64. By keeping the internal cache a power 2 you can avoid the expensive modulus operator as per http://stackoverflow.com/questions/6670715/mod-of-power-2-on-bitwise-operators. ```` #[inline] fn hash_u64(seed: u64) -> u64 { let a = 11400714819323198549u64; let val = a.wrapping_mul(seed); val } ```` intmap-2.0.0/benches/basic_bench.rs000064400000000000000000000113611046102023000153120ustar 00000000000000#![feature(test)] extern crate intmap; extern crate rand; extern crate test; extern crate indexmap; use indexmap::IndexMap; use intmap::IntMap; use std::collections::HashMap; #[cfg(test)] mod tests { use super::*; use intmap::Entry; use test::Bencher; const VEC_COUNT: usize = 10_000; // ********** Built in ********** #[bench] fn u64_insert_built_in(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = HashMap::with_capacity(data.len()); b.iter(|| { map.clear(); for s in data.iter() { test::black_box(map.insert(s, s)); } }); } #[bench] fn u64_insert_built_in_without_capacity(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); b.iter(|| { let mut map = HashMap::new(); for s in data.iter() { test::black_box(map.insert(s, s)); } test::black_box(&map); }); } #[bench] fn u64_get_built_in(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map: HashMap<&u64, &u64> = HashMap::with_capacity(data.len()); for s in data.iter() { test::black_box(map.insert(s, s)); } b.iter(|| { for s in data.iter() { test::black_box({ map.contains_key(s); }); } }); } // ********** IndexMap ********** #[bench] fn u64_insert_indexmap(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = IndexMap::with_capacity(data.len()); b.iter(|| { map.clear(); for s in data.iter() { test::black_box(map.insert(s, s)); } }); } #[bench] fn u64_get_indexmap(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map: IndexMap<&u64, &u64> = IndexMap::with_capacity(data.len()); for s in data.iter() { test::black_box(map.insert(s, s)); } b.iter(|| { for s in data.iter() { test::black_box({ map.contains_key(s); }); } }); } // ********** Intmap ********** #[bench] fn u64_insert_intmap(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = IntMap::with_capacity(data.len()); b.iter(|| { map.clear(); for s in data.iter() { test::black_box(map.insert(*s, s)); } }); } #[bench] fn u64_insert_intmap_checked(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = IntMap::with_capacity(data.len()); b.iter(|| { map.clear(); for s in data.iter() { test::black_box(map.insert_checked(*s, s)); } }); } #[bench] fn u64_insert_intmap_entry(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = IntMap::with_capacity(data.len()); b.iter(|| { map.clear(); for s in data.iter() { test::black_box(match map.entry(*s) { Entry::Occupied(_) => panic!("unexpected while insert, i = {}", s), Entry::Vacant(entry) => entry.insert(s), }); } }); } #[bench] fn u64_insert_intmap_without_capacity(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); b.iter(|| { let mut map = IntMap::new(); for s in data.iter() { test::black_box(map.insert(*s, s)); } test::black_box(&map); }); } #[bench] fn u64_resize_intmap(b: &mut Bencher) { b.iter(|| { let mut map: IntMap = IntMap::new(); map.reserve(VEC_COUNT); test::black_box(&map); }); } #[bench] fn u64_get_intmap(b: &mut Bencher) { let data = get_random_range(VEC_COUNT); let mut map = IntMap::with_capacity(data.len()); for s in data.iter() { map.insert(*s, s); } b.iter(|| { for s in data.iter() { test::black_box(map.contains_key(*s)); } }); } // ********** Misc ********** fn get_random_range(count: usize) -> Vec { use rand::prelude::StdRng; use rand::{Rng, SeedableRng}; let mut vec = Vec::new(); let mut rng = StdRng::seed_from_u64(4242); for _ in 0..count { vec.push(rng.gen::()); } vec.sort(); vec.dedup(); vec } } intmap-2.0.0/src/entry.rs000064400000000000000000000063131046102023000134140ustar 00000000000000// ***************** Entry ********************* use crate::IntMap; /// A view into a single entry in a [`IntMap`], which may either be vacant or occupied. /// /// The entry can be constructed by calling [`IntMap::entry`] with a key. It allows inspection /// and in-place manipulation of its value without repeated lookups. pub enum Entry<'a, V: 'a> { /// The entry is occupied. Occupied(OccupiedEntry<'a, V>), /// The entry is vacant. Vacant(VacantEntry<'a, V>), } impl<'a, V> Entry<'a, V> { #[inline] pub(crate) fn new(key: u64, int_map: &'a mut IntMap) -> Self { let (cache_ix, val_ix) = Self::indices(key, int_map); match val_ix { Some(vals_ix) => Entry::Occupied(OccupiedEntry { vals_ix, vals: &mut int_map.cache[cache_ix], count: &mut int_map.count, }), None => Entry::Vacant(VacantEntry { key, int_map }), } } fn indices(key: u64, int_map: &IntMap) -> (usize, Option) { let cache_ix = int_map.calc_index(key); let vals = &int_map.cache[cache_ix]; let vals_ix = { vals.iter() } .enumerate() .find_map(|(vals_ix, &(k, _))| (k == key).then(|| vals_ix)); (cache_ix, vals_ix) } } /// A view into an occupied entry in a [`IntMap`]. It is part of the [`Entry`] enum. pub struct OccupiedEntry<'a, V: 'a> { // Index to vals, guaranteed to be valid vals_ix: usize, // Element of IntMap::cache, guaranteed to be non-empty vals: &'a mut Vec<(u64, V)>, // IntMap::count, guaranteed to be non-zero count: &'a mut usize, } impl<'a, V> OccupiedEntry<'a, V> { /// Gets a reference to the value in the entry. pub fn get(&self) -> &V { // Safety: We didn't modify the cache since we calculated the index &self.vals.get(self.vals_ix).unwrap().1 } /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut V { // Safety: We didn't modify the cache since we calculated the index &mut self.vals.get_mut(self.vals_ix).unwrap().1 } /// Converts the entry into a mutable reference to the value in the entry with a /// lifetime bound to the [`IntMap`] itself. pub fn into_mut(self) -> &'a mut V { // Safety: We didn't modify the cache since we calculated the index &mut self.vals.get_mut(self.vals_ix).unwrap().1 } /// Sets the value of the entry and returns the old value. pub fn insert(&mut self, value: V) -> V { std::mem::replace(&mut self.vals[self.vals_ix].1, value) } /// Removes the value out of the entry and returns it. pub fn remove(self) -> V { // Warning: We modify the cache here, so the index is now invalid *self.count -= 1; let kv = self.vals.swap_remove(self.vals_ix); kv.1 } } /// A view into a vacant entry in a [`IntMap`]. It is part of the [`Entry`] enum. pub struct VacantEntry<'a, V: 'a> { key: u64, int_map: &'a mut IntMap, } impl<'a, V: 'a> VacantEntry<'a, V> { pub fn insert(self, value: V) -> &'a mut V { self.int_map.insert(self.key, value); return self.int_map.get_mut(self.key).unwrap(); } } intmap-2.0.0/src/iter.rs000064400000000000000000000111701046102023000132130ustar 00000000000000use std::iter::FlatMap as IterFlatMap; use std::iter::Flatten as IterFlatten; use std::slice::Iter as SliceIter; use std::slice::IterMut as SliceIterMut; use std::vec::Drain as VecDrain; use std::vec::IntoIter as VecIntoIter; use crate::IntMap; // ***************** Iter ********************* pub struct Iter<'a, K: 'a, V: 'a> { inner: IterFlatten>>, } impl<'a, K, V> Iter<'a, K, V> { pub(crate) fn new(vec: &'a [Vec<(K, V)>]) -> Self { Iter { inner: vec.iter().flatten(), } } } impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next().map(|r| (&r.0, &r.1)) } } // ***************** Iter Mut ********************* pub struct IterMut<'a, K: 'a, V: 'a> { inner: IterFlatten>>, } impl<'a, K, V> IterMut<'a, K, V> { pub(crate) fn new(vec: &'a mut [Vec<(K, V)>]) -> IterMut<'a, K, V> { IterMut { inner: vec.iter_mut().flatten(), } } } impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next().map(|r| (&r.0, &mut r.1)) } } // ***************** Keys Iter ********************* pub struct Keys<'a, K: 'a, V: 'a> { pub(crate) inner: Iter<'a, K, V>, } impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; #[inline] fn next(&mut self) -> Option<&'a K> { self.inner.next().map(|kv| kv.0) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ***************** Values Iter ********************* pub struct Values<'a, K: 'a, V: 'a> { pub(crate) inner: Iter<'a, K, V>, } impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; #[inline] fn next(&mut self) -> Option<&'a V> { self.inner.next().map(|kv| kv.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ***************** Values Mut ********************* pub struct ValuesMut<'a, K: 'a, V: 'a> { pub(crate) inner: IterMut<'a, K, V>, } impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; #[inline] fn next(&mut self) -> Option<&'a mut V> { self.inner.next().map(|kv| kv.1) } #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ***************** Into Iter ********************* impl IntoIterator for IntMap { type Item = (u64, V); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter::new(self.cache) } } pub struct IntoIter { inner: IterFlatten>>, } impl IntoIter { pub(crate) fn new(vec: Vec>) -> Self { IntoIter { inner: vec.into_iter().flatten(), } } } impl Iterator for IntoIter { type Item = (K, V); #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } } // ***************** Drain Iter ********************* #[allow(clippy::type_complexity)] pub struct Drain<'a, K: 'a, V: 'a> { count: &'a mut usize, inner: IterFlatMap< SliceIterMut<'a, Vec<(K, V)>>, VecDrain<'a, (K, V)>, fn(&mut Vec<(K, V)>) -> VecDrain<(K, V)>, >, } impl<'a, K, V> Drain<'a, K, V> { pub(crate) fn new(vec: &'a mut [Vec<(K, V)>], count: &'a mut usize) -> Drain<'a, K, V> { Drain { count, inner: vec.iter_mut().flat_map(|v| v.drain(..)), } } } impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V); #[inline] fn next(&mut self) -> Option<(K, V)> { let next = self.inner.next(); if next.is_some() { *self.count -= 1; } next } } // ***************** Extend ********************* impl Extend<(u64, V)> for IntMap { #[inline] fn extend>(&mut self, iter: T) { for elem in iter { self.insert(elem.0, elem.1); } } } // ***************** FromIterator ********************* impl std::iter::FromIterator<(u64, V)> for IntMap { #[inline] fn from_iter>(iter: T) -> Self { let iterator = iter.into_iter(); let (lower_bound, _) = iterator.size_hint(); let mut map = IntMap::with_capacity(lower_bound); for elem in iterator { map.insert(elem.0, elem.1); } map } } intmap-2.0.0/src/lib.rs000064400000000000000000000307151046102023000130240ustar 00000000000000#[cfg(feature = "serde")] mod serde; mod entry; mod iter; use core::iter::{IntoIterator, Iterator}; use iter::*; pub use entry::*; #[derive(Clone)] pub struct IntMap { cache: Vec>, size: u32, mod_mask: u64, count: usize, load_factor: usize, } impl IntMap { /// Creates a new IntMap. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// assert_eq!(map, IntMap::default()); /// ``` pub fn new() -> Self { IntMap::with_capacity(4) } /// Creates a new IntMap with at least the given capacity, rounded /// to the next power of two. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::with_capacity(20); /// ``` pub fn with_capacity(capacity: usize) -> Self { let mut map = IntMap { cache: Vec::new(), size: 0, count: 0, mod_mask: 0, load_factor: 909, // 90.9% }; map.increase_cache(); while map.lim() < capacity { map.increase_cache(); } map } /// Sets load rate of IntMap rounded to the first decimal point. /// /// Values above 1.0 is allowed. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::with_capacity(20); /// map.set_load_factor(0.909); // Sets load factor to 90.9% /// ``` pub fn set_load_factor(&mut self, load_factor: f32) { self.load_factor = (load_factor * 1000.) as usize; self.ensure_load_rate(); } /// Returns current load_factor pub fn get_load_factor(&self) -> f32 { self.load_factor as f32 / 1000. } /// Ensures that the IntMap has space for at least `additional` more elements pub fn reserve(&mut self, additional: usize) { let capacity = (self.count + additional).next_power_of_two(); while self.lim() < capacity { self.increase_cache(); } } /// Insert key/value into the IntMap. /// /// This function returns the previous value if any otherwise `None`. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map = IntMap::new(); /// assert_eq!(map.insert(21, "Eat my shorts"), None); /// assert_eq!(map.insert(21, "Ay, caramba"), Some("Eat my shorts")); /// assert_eq!(map.get(21), Some(&"Ay, caramba")); /// ``` pub fn insert(&mut self, key: u64, value: V) -> Option { let ix = self.calc_index(key); let vals = &mut self.cache[ix]; let pos = vals.iter().position(|kv| kv.0 == key); let old = if let Some(pos) = pos { Some(vals.swap_remove(pos).1) } else { // Only increase count if we actually add a new entry self.count += 1; None }; vals.push((key, value)); if (self.count & 4) == 4 { self.ensure_load_rate(); } old } /// Insert key/value into the IntMap if the key is not yet inserted. /// /// This function returns true if key/value were inserted and false otherwise. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map = IntMap::new(); /// assert!(map.insert_checked(21, "Eat my shorts")); /// assert!(!map.insert_checked(21, "Ay, caramba")); /// assert_eq!(map.get(21), Some(&"Eat my shorts")); /// ``` pub fn insert_checked(&mut self, key: u64, value: V) -> bool { let ix = self.calc_index(key); let vals = &mut self.cache[ix]; if vals.iter().any(|kv| kv.0 == key) { return false; } self.count += 1; vals.push((key, value)); if (self.count & 4) == 4 { self.ensure_load_rate(); } true } /// Get value from the IntMap. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// let val = map.get(21); /// assert!(val.is_some()); /// assert_eq!(*val.unwrap(), 42); /// assert!(map.contains_key(21)); /// ``` pub fn get(&self, key: u64) -> Option<&V> { let ix = self.calc_index(key); let vals = &self.cache[ix]; vals.iter().find_map(|kv| (kv.0 == key).then(|| &kv.1)) } /// Get mutable value from the IntMap. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// /// assert_eq!(*map.get(21).unwrap(), 42); /// assert!(map.contains_key(21)); /// /// { /// let mut val = map.get_mut(21).unwrap(); /// *val+=1; /// } /// assert_eq!(*map.get(21).unwrap(), 43); /// ``` pub fn get_mut(&mut self, key: u64) -> Option<&mut V> { let ix = self.calc_index(key); let vals = &mut self.cache[ix]; return vals .iter_mut() .find_map(|kv| (kv.0 == key).then(move || &mut kv.1)); } /// Remove value from the IntMap. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// let val = map.remove(21); /// assert!(val.is_some()); /// assert_eq!(val.unwrap(), 42); /// assert!(!map.contains_key(21)); /// ``` pub fn remove(&mut self, key: u64) -> Option { let ix = self.calc_index(key); let vals = &mut self.cache[ix]; for i in 0..vals.len() { let peek = vals[i].0; if peek == key { self.count -= 1; let kv = vals.swap_remove(i); return Some(kv.1); } } None } /// Returns true if key is in map. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// assert!(map.contains_key(21)); /// ``` pub fn contains_key(&self, key: u64) -> bool { self.get(key).is_some() } /// Removes all elements from map. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// map.clear(); /// assert_eq!(map.len(), 0); /// ``` pub fn clear(&mut self) { for vals in &mut self.cache { vals.clear(); } self.count = 0; } /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements such that `f(key, &value)` returns false. /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(1, 11); /// map.insert(2, 12); /// map.insert(4, 13); /// /// // retain only the odd values /// map.retain(|k, v| *v % 2 == 1); /// /// assert_eq!(map.len(), 2); /// assert!(map.contains_key(1)); /// assert!(map.contains_key(4)); /// ``` pub fn retain(&mut self, mut f: F) where F: FnMut(u64, &V) -> bool, { let mut removed = 0; for vals in &mut self.cache { vals.retain(|(k, v)| { let keep = (f)(*k, v); if !keep { removed += 1; } keep }); } self.count -= removed; } /// Returns true if map is empty /// /// # Examples /// /// ``` /// use intmap::IntMap; /// /// let mut map: IntMap = IntMap::new(); /// map.insert(21, 42); /// assert!(!map.is_empty()); /// map.remove(21); /// assert!(map.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.count == 0 } //**** Iterators ***** pub fn iter(&self) -> Iter { Iter::new(&self.cache) } pub fn iter_mut(&mut self) -> IterMut { IterMut::new(&mut self.cache) } pub fn keys(&self) -> Keys { Keys { inner: self.iter() } } pub fn values(&self) -> Values { Values { inner: self.iter() } } pub fn values_mut(&mut self) -> ValuesMut { ValuesMut { inner: self.iter_mut(), } } pub fn drain(&mut self) -> Drain { Drain::new(&mut self.cache, &mut self.count) } //**** Internal hash stuff ***** #[inline(always)] fn hash_u64(seed: u64) -> u64 { let a = 11400714819323198549u64; a.wrapping_mul(seed) } #[inline(always)] pub(crate) fn calc_index(&self, key: u64) -> usize { let hash = Self::hash_u64(key); // Faster modulus (hash & self.mod_mask) as usize } #[inline(always)] fn lim(&self) -> usize { 2u64.pow(self.size) as usize } fn increase_cache(&mut self) { self.size += 1; let new_lim = self.lim(); self.mod_mask = (new_lim as u64) - 1; let mut vec: Vec> = (0..new_lim).map(|_| Vec::new()).collect(); std::mem::swap(&mut self.cache, &mut vec); for k in vec.into_iter().flatten() { let ix = self.calc_index(k.0); let vals = &mut self.cache[ix]; vals.push(k); } debug_assert!( self.cache.len() == self.lim(), "cache vector the wrong length, lim: {:?} cache: {:?}", self.lim(), self.cache.len() ); } #[inline] fn ensure_load_rate(&mut self) { // Tried using floats here but insert performance tanked. while ((self.count * 1000) / self.cache.len()) > self.load_factor { self.increase_cache(); } } /// Number of elements in map. /// pub fn len(&self) -> usize { self.count as usize } /// Force count number of slots filled. /// pub fn load(&self) -> u64 { self.cache.iter().filter(|vals| !vals.is_empty()).count() as u64 } pub fn load_rate(&self) -> f64 { (self.count as f64) / (self.cache.len() as f64) * 100f64 } /// Total number of slots available. /// pub fn capacity(&self) -> usize { self.cache.len() } pub fn assert_count(&self) -> bool { let count = self.cache.iter().flatten().count(); self.count == count } pub fn collisions(&self) -> IntMap { let mut map = IntMap::new(); for s in self.cache.iter() { let key = s.len() as u64; if key > 1 { if !map.contains_key(key) { map.insert(key, 1); } else { let counter = map.get_mut(key).unwrap(); *counter += 1; } } } // map.sort(); map } /// Gets the [`Entry`] that corresponds to the given key. /// /// # Examples /// /// ``` /// use intmap::{IntMap, Entry}; /// /// let mut counters = IntMap::new(); /// /// for number in [10, 30, 10, 40, 50, 50, 60, 50] { /// let counter = match counters.entry(number) { /// Entry::Occupied(entry) => entry.into_mut(), /// Entry::Vacant(entry) => entry.insert(0), /// }; /// *counter += 1; /// } /// /// assert_eq!(counters.get(10), Some(&2)); /// assert_eq!(counters.get(20), None); /// assert_eq!(counters.get(30), Some(&1)); /// assert_eq!(counters.get(40), Some(&1)); /// assert_eq!(counters.get(50), Some(&3)); /// assert_eq!(counters.get(60), Some(&1)); /// ``` pub fn entry(&mut self, key: u64) -> Entry { Entry::new(key, self) } } impl Default for IntMap { fn default() -> Self { Self::new() } } // ***************** Equality ********************* impl PartialEq for IntMap where V: PartialEq, { fn eq(&self, other: &IntMap) -> bool { self.iter().all(|(k, a)| other.get(*k) == Some(a)) && other.iter().all(|(k, a)| self.get(*k) == Some(a)) } } impl Eq for IntMap where V: Eq {} // ***************** Debug ********************* impl std::fmt::Debug for IntMap where V: std::fmt::Debug, { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { fmt.debug_map().entries(self.iter()).finish() } } intmap-2.0.0/src/serde.rs000064400000000000000000000027701046102023000133600ustar 00000000000000use crate::IntMap; use serde::{ de::{Deserializer, MapAccess, Visitor}, ser::SerializeMap, Deserialize, Serialize, Serializer, }; impl Serialize for IntMap { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut map = serializer.serialize_map(Some(self.len()))?; for (k, v) in self.iter() { map.serialize_entry(k, v)?; } map.end() } } impl<'de, T: Deserialize<'de>> Deserialize<'de> for IntMap { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_map(IntMapVisitor::new()) } } struct IntMapVisitor { marker: std::marker::PhantomData IntMap>, } impl IntMapVisitor { fn new() -> Self { IntMapVisitor { marker: std::marker::PhantomData, } } } impl<'de, V> Visitor<'de> for IntMapVisitor where V: Deserialize<'de>, { type Value = IntMap; fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "IntMap<{}>", std::any::type_name::()) } fn visit_map(self, mut access: M) -> Result where M: MapAccess<'de>, { let mut map = IntMap::with_capacity(access.size_hint().unwrap_or(0)); while let Some((key, value)) = access.next_entry()? { map.insert(key, value); } Ok(map) } } intmap-2.0.0/tests/basic_test.rs000064400000000000000000000256311046102023000147520ustar 00000000000000extern crate rand; extern crate intmap; use intmap::{Entry, IntMap}; #[cfg(test)] mod tests { use super::*; fn get_random_range(count: usize) -> Vec { use rand::prelude::StdRng; use rand::{Rng, SeedableRng}; let mut vec = Vec::new(); let mut rng = StdRng::seed_from_u64(4242); for _ in 0..count { vec.push(rng.gen::()); } vec.sort(); vec.dedup(); vec } #[test] fn intmap_get_insert_impl() { let count = 20_000; let data = get_random_range(count as usize); let mut map: IntMap = IntMap::new(); println!(); println!("Starting test"); for s in data.iter() { assert!( map.insert_checked(*s, *s), "intmap insert failed! ix: {:?}", s ); } assert_eq!(map.len(), count); assert!(map.assert_count()); for s in data.iter() { assert_eq!(*map.get(*s).unwrap(), *s, "intmap get failed! key: {:?}", s); } assert_eq!(map.len(), count); for s in data.iter() { assert!( map.contains_key(*s), "intmap contains_key failed! key: {:?}", s ); } assert_eq!(map.len(), count); for s in data.iter() { let val = map.remove(*s).unwrap(); assert_eq!(val, *s, "intmap remove failed! key: {:?}", s); } assert_eq!(map.len(), 0); assert!(map.assert_count()); } #[test] fn reserve() { let mut map: IntMap = IntMap::new(); map.reserve(9001); } #[test] fn add_duplicate() { let mut map = IntMap::new(); for i in 0..20_000 { assert_eq!(map.insert(i, format!("item: {:?}", i)), None); assert_eq!( map.insert(i, format!("item: {:?}", i)), Some(format!("item: {:?}", i)) ); } } #[test] fn add_duplicate_replace() { let mut map = IntMap::new(); for i in 0..20_000 { assert_eq!(map.insert_checked(i, format!("item: {:?}", i)), true); assert_eq!(map.insert_checked(i, format!("item: {:?}", i)), false); } } #[test] fn get_value_map() { let mut map = IntMap::new(); for i in 0..20_000 { assert_eq!(map.insert_checked(i, i + 1), true); } for i in 0..20_000 { assert_eq!(map.contains_key(i), true); assert_eq!(*map.get(i).unwrap(), i + 1); assert_eq!(*map.get_mut(i).unwrap(), i + 1); assert_eq!(map.remove(i).unwrap(), i + 1); } for i in 0..20_000 { assert_eq!(map.contains_key(i), false); assert_eq!(map.remove(i), None); } assert!(map.is_empty()); } #[test] fn get_value_not_in_map() { let mut map = IntMap::new(); for i in 0..20_000 { assert_eq!(map.insert_checked(i, format!("item: {:?}", i)), true); } for i in 20_000..40_000 { assert_eq!(map.get(i), None); assert_eq!(map.get_mut(i), None); } } #[test] fn add_string() { let mut map = IntMap::new(); for i in 0..20_000 { map.insert(i, format!("item: {:?}", i)); } } #[test] fn retain() { let mut map = IntMap::new(); for i in 0..20_000 { map.insert(i, format!("item: {:?}", i)); } map.retain(|k, _v| k > 10_000); for i in 10_001..20_000 { assert_eq!(map.contains_key(i), true); } } #[test] fn single_add_get() { let mut map: IntMap = IntMap::new(); map.insert(21, 42); let val = map.get(21); assert!(val.is_some()); assert_eq!(*val.unwrap(), 42); } #[test] fn map_iter() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for (k, v) in map.iter() { assert_eq!(*k, *v); } } #[test] fn map_iter_keys() { let count = 20_000; let data: Vec<_> = (0..count).collect(); let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for k in map.keys() { assert_eq!(*k, data[*k as usize]); } } #[test] fn map_iter_values() { let count = 20_000; let data: Vec<_> = (0..count).collect(); let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for v in map.values() { assert_eq!(*v, data[*v as usize]); } } #[test] fn map_iter_values_mut() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for value in map.values_mut() { *value += 1; } for n in 0..count { assert_eq!(n + 1, *map.get(n).expect("Failed to get number!")); } } #[test] fn map_mut_iter() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for kv in map.iter_mut() { *kv.1 += 1; } for n in 0..count { assert_eq!(n + 1, *map.get(n).expect("Failed to get number!")); } } #[test] fn map_iter_empty() { let mut map: IntMap = IntMap::new(); map.clear(); for kv in map.iter() { panic!("Not printing: {:?}", kv); } } #[test] fn map_mut_iter_empty() { let mut map: IntMap = IntMap::new(); map.clear(); for _ in map.iter_mut() { panic!(); } } #[test] fn map_into_iter() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for (k, v) in map.into_iter() { assert_eq!(k, v); } } #[test] fn map_drain() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } for (k, v) in map.drain() { assert_eq!(k, v); } assert_eq!(map.len(), 0); } #[test] fn map_into_iter_empty() { let mut map: IntMap = IntMap::new(); map.clear(); for kv in map.into_iter() { panic!("Not printing: {:?}", kv); } } #[test] fn extend_two_maps() { let count = 20_000; let mut map_1: IntMap = IntMap::new(); let mut map_2: IntMap = IntMap::new(); for i in 0..count { map_1.insert(i, i); } for i in count..(count * 2) { map_2.insert(i, i); } map_1.extend(map_2.into_iter()); assert_eq!(map_1.len(), (count * 2) as usize); for (k, v) in map_1.iter() { assert_eq!(k, v); } } #[test] fn from_iter_collect() { let count = 20_000; let map = (0..count).map(|i| (i, i * i)).collect::>(); for k in 0..count { assert!(map.contains_key(k)); } for (&k, &v) in map.iter() { assert_eq!(k * k, v); } } #[test] fn map_equality() { let count = 5_000; let map_1 = (0..count).map(|i| (i, i * i)).collect::>(); let map_2 = (0..count).rev().map(|i| (i, i * i)).collect::>(); assert_eq!(map_1, map_2); } #[test] fn map_inequality() { let map_1 = (0..10).map(|i| (i, i * i)).collect::>(); let map_2 = (0..5).rev().map(|i| (i, i * i)).collect::>(); assert_ne!(map_1, map_2); assert_ne!(map_2, map_1); } #[test] fn entry_api() { let count = 20_000; let data: Vec = (0..count).collect(); let mut map: IntMap = IntMap::new(); // Insert values 0..19999 for i in 0..count { match map.entry(i) { Entry::Occupied(_) => panic!("unexpected while insert, i = {}", i), Entry::Vacant(entry) => entry.insert(i), }; } assert_eq!(map.len(), count as usize); for (k, v) in map.iter() { assert_eq!(*v, data[*k as usize]); } // Replace values 0..19999 with 20000..39999 for i in 0..count { match map.entry(i) { Entry::Occupied(mut entry) => { assert_eq!(*entry.get(), i); assert_eq!(*entry.get_mut(), i); assert_eq!(entry.insert(count + i), i); assert_eq!(*entry.into_mut(), count + i); } Entry::Vacant(_) => panic!("unexpected while replace, i = {}", i), }; } assert_eq!(map.len(), count as usize); for (k, v) in map.iter() { assert_eq!(*v, count + data[*k as usize]); } // Remove values 20000..39999 for i in 0..count { match map.entry(i) { Entry::Occupied(entry) => { assert_eq!(entry.remove(), count + i); } Entry::Vacant(_) => panic!("unexpected while remove, i = {}", i), }; } assert_eq!(map.len(), 0); } #[test] fn test_debug_features() { let count = 20_000; let mut map: IntMap = IntMap::new(); for i in 0..count { map.insert(i, i); } assert_eq!(map.load(), 20_000); assert_eq!(map.capacity(), 32_768); assert!(map.load_rate() > 0.70); assert!(map.collisions().is_empty()); let mut map: IntMap = IntMap::new(); for i in 0..3 { map.insert(i, i + 1); } assert_eq!(format!("{:?}", map), "{0: 1, 1: 2, 2: 3}"); } #[test] fn load_factor() { let mut map: IntMap = IntMap::new(); map.set_load_factor(0.1); assert_eq!(map.get_load_factor(), 0.1); for i in 0..12 { map.insert(i, i); } assert_eq!(map.capacity(), 128); assert!(map.load_rate() <= 10.); assert!(map.collisions().is_empty()); let mut map: IntMap = IntMap::new(); map.set_load_factor(2.); assert_eq!(map.get_load_factor(), 2.); for i in 0..16 { map.insert(i, i); } println!("Load {}", map.load_rate()); println!("factor {:?}", map.collisions()); assert_eq!(map.capacity(), 8); assert!(map.load_rate() <= 200.); assert_eq!(format!("{:?}", map.collisions()), "{2: 8}"); } }