associative_cache/
indices.rs

1//! Various kinds of associativity and `Indices` implementations.
2
3use super::{Capacity, Indices};
4use std::collections::hash_map::DefaultHasher;
5use std::hash::{Hash, Hasher};
6use std::marker::PhantomData;
7use std::ops::Range;
8
9#[inline]
10fn hash_to_usize<H>(mut hasher: impl Hasher, h: &H) -> usize
11where
12    H: ?Sized + Hash,
13{
14    h.hash(&mut hasher);
15    hasher.finish() as usize
16}
17
18macro_rules! define_hash_n_way {
19    ( $( $( #[$attr:meta] )* $name:ident => $n:expr; )* ) => { $(
20        $( #[ $attr ] )*
21        #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
22        pub struct $name<H = DefaultHasher> {
23            _hasher: PhantomData<H>,
24        }
25
26        impl<T, C, H> Indices<T, C> for $name<H>
27        where
28            T: ?Sized + Hash,
29            C: Capacity,
30            H: Hasher + Default,
31        {
32            type Indices = Range<usize>;
33
34            #[inline]
35            fn indices(key: &T) -> Self::Indices {
36                assert!(C::CAPACITY >= $n);
37                let hasher = H::default();
38                let base = hash_to_usize(hasher, key) % (C::CAPACITY / $n) * $n;
39                base..base + $n
40            }
41        }
42    )* }
43}
44
45define_hash_n_way! {
46    /// Direct-mapped (i.e. one-way associative) caching based on the key's
47    /// `Hash` implementation.
48    ///
49    /// See the `Indices` trait's documentation for more on associativity.
50    HashDirectMapped => 1;
51    /// Two-way set associative caching based on the key's `Hash`
52    /// implementation.
53    ///
54    /// See the `Indices` trait's documentation for more on associativity.
55    HashTwoWay => 2;
56    /// Four-way set associative caching based on the key's `Hash`
57    /// implementation.
58    ///
59    /// See the `Indices` trait's documentation for more on associativity.
60    HashFourWay => 4;
61    /// Eight-way set associative caching based on the key's `Hash`
62    /// implementation.
63    ///
64    /// See the `Indices` trait's documentation for more on associativity.
65    HashEightWay => 8;
66    /// Sixteen-way set associative caching based on the key's `Hash`
67    /// implementation.
68    ///
69    /// See the `Indices` trait's documentation for more on associativity.
70    HashSixteenWay => 16;
71    /// 32-way set associative caching based on the key's `Hash` implementation.
72    ///
73    /// See the `Indices` trait's documentation for more on associativity.
74    HashThirtyTwoWay => 32;
75}
76
77macro_rules! define_pointer_n_way {
78    ( $( $( #[$attr:meta] )* $name: ident => $n:expr; )* ) => {
79        $(
80            $( #[$attr] )*
81            #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
82            pub struct $name;
83
84            impl<T, C> Indices<*mut T, C> for $name
85            where
86                C: Capacity
87            {
88                type Indices = Range<usize>;
89
90                #[inline]
91                fn indices(&ptr: &*mut T) -> Self::Indices {
92                    assert!(C::CAPACITY >= $n);
93
94                    let ptr = ptr as usize;
95
96                    // The bottom bits of the pointer are all zero because of
97                    // alignment, so get rid of them. The compiler should be
98                    // able to clean up this divide into a right shift because
99                    // of the constant, power-of-two divisor.
100                    let i = ptr / std::mem::align_of::<T>();
101
102                    let base = i % (C::CAPACITY / $n) * $n;
103                    base..(base + $n)
104                }
105            }
106
107            impl<T, C> Indices<*const T, C> for $name
108            where
109                C: Capacity
110            {
111                type Indices = <Self as Indices<*mut T, C>>::Indices;
112
113                #[inline]
114                fn indices(&ptr: &*const T) -> Self::Indices {
115                    <Self as Indices<*mut T, C>>::indices(&(ptr as *mut T))
116                }
117            }
118        )*
119    };
120}
121
122define_pointer_n_way! {
123    /// Direct-mapped (i.e. one-way associative) caching based on the key's
124    /// pointer value.
125    ///
126    /// See the `Indices` trait's documentation for more on associativity.
127    PointerDirectMapped => 1;
128    /// Two-way set associative caching based on the key's pointer value.
129    ///
130    /// See the `Indices` trait's documentation for more on associativity.
131    PointerTwoWay => 2;
132    /// Four-way set associative caching based on the key's pointer value.
133    ///
134    /// See the `Indices` trait's documentation for more on associativity.
135    PointerFourWay => 4;
136    /// Eight-way set associative caching based on the key's pointer value.
137    ///
138    /// See the `Indices` trait's documentation for more on associativity.
139    PointerEightWay => 8;
140    /// Sixteen-way set associative caching based on the key's pointer value.
141    ///
142    /// See the `Indices` trait's documentation for more on associativity.
143    PointerSixteenWay => 16;
144    /// 32-way set associative caching based on the key's pointer value.
145    ///
146    /// See the `Indices` trait's documentation for more on associativity.
147    PointerThirtyTwoWay => 32;
148}
149
150#[cfg(test)]
151mod tests {
152    use super::*;
153    use crate::Capacity4;
154
155    #[test]
156    fn pointer_direct_mapped() {
157        assert_eq!(
158            <PointerDirectMapped as Indices<*mut u64, Capacity4>>::indices(&(0 as *mut u64)),
159            0..1
160        );
161        assert_eq!(
162            <PointerDirectMapped as Indices<*mut u64, Capacity4>>::indices(&(8 as *mut u64)),
163            1..2
164        );
165        assert_eq!(
166            <PointerDirectMapped as Indices<*mut u64, Capacity4>>::indices(&(16 as *mut u64)),
167            2..3
168        );
169        assert_eq!(
170            <PointerDirectMapped as Indices<*mut u64, Capacity4>>::indices(&(24 as *mut u64)),
171            3..4
172        );
173        assert_eq!(
174            <PointerDirectMapped as Indices<*mut u64, Capacity4>>::indices(&(32 as *mut u64)),
175            0..1
176        );
177    }
178
179    #[test]
180    fn pointer_two_way() {
181        assert_eq!(
182            <PointerTwoWay as Indices<*mut u64, Capacity4>>::indices(&(0 as *mut u64)),
183            0..2
184        );
185        assert_eq!(
186            <PointerTwoWay as Indices<*mut u64, Capacity4>>::indices(&(8 as *mut u64)),
187            2..4
188        );
189        assert_eq!(
190            <PointerTwoWay as Indices<*mut u64, Capacity4>>::indices(&(16 as *mut u64)),
191            0..2
192        );
193        assert_eq!(
194            <PointerTwoWay as Indices<*mut u64, Capacity4>>::indices(&(24 as *mut u64)),
195            2..4
196        );
197        assert_eq!(
198            <PointerTwoWay as Indices<*mut u64, Capacity4>>::indices(&(32 as *mut u64)),
199            0..2
200        );
201    }
202}