-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Parameterize the index type of maps and sets
The index type is a new generic parameter defaulting to `usize`: pub struct IndexSet<T, S = RandomState, Idx = usize> pub struct IndexMap<K, V, S = RandomState, Idx = usize> In `no_std` builds, `S` has no default, but still `Idx = usize`. This may be used to optimized the storage size in the raw table, for example using a `u32` index if you know that `u32::MAX` capacity is sufficient for you. It may also be useful to define a newtype index custom to a particular domain, which only needs to implement the new `Indexable` trait to be useful here.
- Loading branch information
Showing
12 changed files
with
595 additions
and
285 deletions.
There are no files selected for viewing
This file contains 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,50 @@ | ||
use fxhash::FxBuildHasher; | ||
use indexmap::{IndexMap, IndexSet, Indexable}; | ||
use std::convert::TryFrom; | ||
use std::ops::{Index, IndexMut}; | ||
|
||
fn main() { | ||
let map: FancyMap<_, _> = (-10..=10).map(|i| (i, i * i)).collect(); | ||
let set: FancySet<_> = map.values().copied().collect(); | ||
println!("map to squares: {:?}", map); | ||
println!("unique squares: {:?}", set); | ||
} | ||
|
||
/// A custom index newtype ensures it can't be confused with indexes for | ||
/// unrelated containers. This one is also smaller to reduce map memory, | ||
/// which also reduces the maximum capacity. | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
pub struct FancyIndex(u16); | ||
|
||
pub type FancyMap<K, V> = IndexMap<K, V, FxBuildHasher, FancyIndex>; | ||
pub type FancySet<T> = IndexSet<T, FxBuildHasher, FancyIndex>; | ||
|
||
impl Indexable for FancyIndex { | ||
fn try_from_usize(i: usize) -> Option<Self> { | ||
u16::try_from(i).ok().map(FancyIndex) | ||
} | ||
|
||
fn try_into_usize(self) -> Option<usize> { | ||
Some(self.0.into()) | ||
} | ||
} | ||
|
||
impl<K, V> Index<FancyIndex> for FancyMap<K, V> { | ||
type Output = V; | ||
|
||
fn index(&self, index: FancyIndex) -> &V { | ||
let (_key, value) = self | ||
.get_index(index) | ||
.expect("IndexMap: index out of bounds"); | ||
value | ||
} | ||
} | ||
|
||
impl<K, V> IndexMut<FancyIndex> for FancyMap<K, V> { | ||
fn index_mut(&mut self, index: FancyIndex) -> &mut V { | ||
let (_key, value) = self | ||
.get_index_mut(index) | ||
.expect("IndexMap: index out of bounds"); | ||
value | ||
} | ||
} |
This file contains 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,89 @@ | ||
use crate::IndexMap; | ||
use core::ops::{Index, IndexMut}; | ||
|
||
/// Indexable types can convert to and from `usize`. | ||
pub trait Indexable: Sized + Copy + Ord + Send + Sync { | ||
/// Creates an index from a `usize` or returns `None`. | ||
fn try_from_usize(i: usize) -> Option<Self>; | ||
|
||
/// Creates an index from a `usize`; panics on failure. | ||
#[inline] | ||
fn from_usize(i: usize) -> Self { | ||
Self::try_from_usize(i).expect("invalid index!") | ||
} | ||
|
||
/// Converts the index to a `usize` or returns `None`. | ||
fn try_into_usize(self) -> Option<usize>; | ||
|
||
/// Converts the index to a `usize`; panics on failure. | ||
#[inline] | ||
fn into_usize(self) -> usize { | ||
self.try_into_usize().expect("invalid index!") | ||
} | ||
} | ||
|
||
impl Indexable for usize { | ||
#[inline] | ||
fn try_from_usize(i: usize) -> Option<Self> { | ||
Some(i) | ||
} | ||
|
||
#[inline] | ||
fn from_usize(i: usize) -> Self { | ||
i | ||
} | ||
|
||
#[inline] | ||
fn try_into_usize(self) -> Option<usize> { | ||
Some(self) | ||
} | ||
|
||
#[inline] | ||
fn into_usize(self) -> usize { | ||
self | ||
} | ||
} | ||
|
||
macro_rules! impl_indexable { | ||
($($ty:ident)*) => {$( | ||
impl Indexable for $ty { | ||
#[inline] | ||
fn try_from_usize(i: usize) -> Option<Self> { | ||
if i <= core::$ty::MAX as usize { | ||
Some(i as $ty) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
#[inline] | ||
fn try_into_usize(self) -> Option<usize> { | ||
if self <= core::usize::MAX as $ty { | ||
Some(self as usize) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<K, V, S> Index<$ty> for IndexMap<K, V, S, $ty> { | ||
type Output = V; | ||
|
||
fn index(&self, index: $ty) -> &V { | ||
self.get_index(index) | ||
.expect("IndexMap: index out of bounds") | ||
.1 | ||
} | ||
} | ||
|
||
impl<K, V, S> IndexMut<$ty> for IndexMap<K, V, S, $ty> { | ||
fn index_mut(&mut self, index: $ty) -> &mut V { | ||
self.get_index_mut(index) | ||
.expect("IndexMap: index out of bounds") | ||
.1 | ||
} | ||
} | ||
)*} | ||
} | ||
|
||
impl_indexable!(u8 u16 u32 u64 u128); |
This file contains 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
Oops, something went wrong.