hayami_im/
lib.rs

1/*!
2A generic symbol table implementation supporting `O(1)` `clone`, `push`, and `pop` operations which can be shared between threads.
3
4For a faster implementation which is limited to a single thread only, see the `hayami-im-rc` crate.
5*/
6#![deny(missing_docs, unsafe_code, missing_debug_implementations)]
7
8use ahash::RandomState;
9use im::HashMap;
10use std::borrow::Borrow;
11use std::fmt::{self, Debug, Formatter};
12use std::hash::Hash;
13use std::hash::{BuildHasher, Hasher};
14
15pub use symbolmap_trait::{MutSymbolMap, SymbolMap, SymbolStack};
16
17/// The `Arc` in use
18///
19/// Supports `elysees` (default) or `std`
20#[cfg(feature = "elysees")]
21#[allow(unused)]
22type Arc<T> = elysees::Arc<T>;
23#[cfg(not(feature = "elysees"))]
24#[allow(unused)]
25type Arc<T> = std::sync::Arc<T>;
26
27/**
28A symbol table implementation supporting snapshots, i.e. an `O(1)` cloning operation.
29*/
30pub struct SymbolTable<K: Hash + Eq, V, S: BuildHasher = RandomState> {
31    /// This layer of the symbol table
32    symbols: HashMap<K, V, S>,
33    /// The depth of this symbol table
34    depth: usize,
35    /// A link to the previous layer's table, forming a singly-linked list
36    prev: Option<Arc<SymbolTable<K, V, S>>>,
37}
38
39impl<K: Hash + Eq, V, S: BuildHasher + Default> Default for SymbolTable<K, V, S> {
40    #[inline]
41    fn default() -> SymbolTable<K, V, S> {
42        SymbolTable {
43            symbols: HashMap::default(),
44            depth: 0,
45            prev: None,
46        }
47    }
48}
49
50impl<K: Hash + Eq, V> SymbolTable<K, V> {
51    /// Create a new, empty symbol table
52    #[inline]
53    pub fn new() -> SymbolTable<K, V> {
54        Self::default()
55    }
56}
57
58impl<K: Hash + Eq, V, S: BuildHasher> SymbolTable<K, V, S> {
59    /// Get a reference to the table's BuildHasher
60    #[inline]
61    pub fn hasher(&self) -> &std::sync::Arc<S> {
62        self.symbols.hasher()
63    }
64    /// Construct an empty hash map using the provided hasher.
65    #[inline]
66    pub fn with_hasher<RS>(hasher: RS) -> SymbolTable<K, V, S>
67    where
68        std::sync::Arc<S>: From<RS>,
69    {
70        SymbolTable {
71            symbols: HashMap::with_hasher(hasher),
72            depth: 0,
73            prev: None,
74        }
75    }
76}
77
78impl<K: Hash + Eq, V: PartialEq, S: BuildHasher> PartialEq for SymbolTable<K, V, S> {
79    #[inline]
80    fn eq(&self, other: &Self) -> bool {
81        //TODO: think about comparing previous tables...
82        self.depth == other.depth && self.symbols == other.symbols && self.prev == other.prev
83    }
84}
85
86impl<K: Hash + Eq, V: Eq, S: BuildHasher> Eq for SymbolTable<K, V, S> {}
87
88impl<K: Hash + Eq, V: Hash, S: BuildHasher> Hash for SymbolTable<K, V, S> {
89    fn hash<H: Hasher>(&self, hasher: &mut H) {
90        //TODO: think about hashing previous tables...
91        self.symbols.hash(hasher);
92        self.depth.hash(hasher);
93        self.prev.hash(hasher);
94    }
95}
96
97impl<K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for SymbolTable<K, V, S> {
98    #[inline]
99    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
100        fmt.debug_struct("SymbolTable")
101            .field("symbols", &self.symbols)
102            .field("depth", &self.depth)
103            .field("prev", &self.prev)
104            .finish()
105    }
106}
107
108impl<K: Hash + Eq, V, S: BuildHasher> SymbolTable<K, V, S> {
109    /// Get an `Arc` to the previous layer's table, if there is any
110    #[inline]
111    pub fn get_prev(&self) -> Option<&Arc<SymbolTable<K, V, S>>> {
112        self.prev.as_ref()
113    }
114}
115
116impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher> Clone for SymbolTable<K, V, S> {
117    #[inline]
118    fn clone(&self) -> SymbolTable<K, V, S> {
119        SymbolTable {
120            symbols: self.symbols.clone(),
121            depth: self.depth,
122            prev: self.prev.clone(),
123        }
124    }
125}
126
127impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher> SymbolTable<K, V, S> {
128    /// Get a new symbol table extending this one
129    #[inline]
130    pub fn extend(self) -> SymbolTable<K, V, S> {
131        let symbols = self.symbols.clone();
132        let depth = self.depth + 1;
133        SymbolTable {
134            symbols,
135            depth,
136            prev: Some(Arc::new(self)),
137        }
138    }
139}
140
141impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher> SymbolMap<K> for SymbolTable<K, V, S> {
142    type Value = V;
143    #[inline]
144    fn insert(&mut self, key: K, value: Self::Value) {
145        self.symbols.insert(key, value);
146    }
147    #[inline]
148    fn get<Q>(&self, key: &Q) -> Option<&Self::Value>
149    where
150        Q: ?Sized + Hash + Eq,
151        K: Borrow<Q>,
152    {
153        self.symbols.get(key)
154    }
155    #[inline]
156    fn contains_key<Q>(&self, key: &Q) -> bool
157    where
158        Q: ?Sized + Hash + Eq,
159        K: Borrow<Q>,
160    {
161        self.symbols.contains_key(key)
162    }
163    #[inline]
164    fn is_empty(&self) -> bool {
165        self.symbols.is_empty()
166    }
167    #[inline]
168    fn try_get_mut<Q>(&mut self, key: &Q) -> Option<&mut Self::Value>
169    where
170        Q: ?Sized + Hash + Eq,
171        K: Borrow<Q>,
172    {
173        self.symbols.get_mut(key)
174    }
175    #[inline]
176    fn push(&mut self) {
177        self.prev = Some(Arc::new((*self).clone()));
178        self.depth += 1;
179    }
180    #[inline]
181    fn pop(&mut self) {
182        if let Some(prev) = self.prev.as_deref() {
183            *self = (*prev).clone();
184        }
185    }
186    #[inline]
187    fn depth(&self) -> usize {
188        self.depth
189    }
190}
191
192impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher> MutSymbolMap<K> for SymbolTable<K, V, S> {}
193
194impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher> SymbolStack<K> for SymbolTable<K, V, S> {
195    #[inline]
196    fn prev(&self) -> Option<&Self> {
197        self.prev.as_deref()
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use symbolmap_trait::testing;
205    #[test]
206    fn basic_symbol_table_test() {
207        testing::basic_symbol_table_test(&mut SymbolTable::new())
208    }
209}