1
1
//! This module has a map which can be iterated in a deterministic order. See the [`IndexedMap`].
2
2
3
3
use crate :: prelude:: { HashMap , hash_map} ;
4
- use alloc:: collections:: { BTreeSet , btree_set} ;
4
+ use alloc:: vec:: Vec ;
5
+ use alloc:: slice:: Iter ;
5
6
use core:: hash:: Hash ;
6
7
use core:: cmp:: Ord ;
7
- use core:: ops:: RangeBounds ;
8
+ use core:: ops:: { Bound , RangeBounds } ;
8
9
9
10
/// A map which can be iterated in a deterministic order.
10
11
///
@@ -21,19 +22,18 @@ use core::ops::RangeBounds;
21
22
/// keys in the order defined by [`Ord`].
22
23
///
23
24
/// [`BTreeMap`]: alloc::collections::BTreeMap
24
- #[ derive( Clone , Debug , PartialEq , Eq ) ]
25
+ #[ derive( Clone , Debug , Eq ) ]
25
26
pub struct IndexedMap < K : Hash + Ord , V > {
26
27
map : HashMap < K , V > ,
27
- // TODO: Explore swapping this for a sorted vec (that is only sorted on first range() call)
28
- keys : BTreeSet < K > ,
28
+ keys : Vec < K > ,
29
29
}
30
30
31
31
impl < K : Clone + Hash + Ord , V > IndexedMap < K , V > {
32
32
/// Constructs a new, empty map
33
33
pub fn new ( ) -> Self {
34
34
Self {
35
35
map : HashMap :: new ( ) ,
36
- keys : BTreeSet :: new ( ) ,
36
+ keys : Vec :: new ( ) ,
37
37
}
38
38
}
39
39
@@ -58,7 +58,8 @@ impl<K: Clone + Hash + Ord, V> IndexedMap<K, V> {
58
58
pub fn remove ( & mut self , key : & K ) -> Option < V > {
59
59
let ret = self . map . remove ( key) ;
60
60
if let Some ( _) = ret {
61
- assert ! ( self . keys. remove( key) , "map and keys must be consistent" ) ;
61
+ let idx = self . keys . iter ( ) . position ( |k| k == key) . expect ( "map and keys must be consistent" ) ;
62
+ self . keys . remove ( idx) ;
62
63
}
63
64
ret
64
65
}
@@ -68,7 +69,7 @@ impl<K: Clone + Hash + Ord, V> IndexedMap<K, V> {
68
69
pub fn insert ( & mut self , key : K , value : V ) -> Option < V > {
69
70
let ret = self . map . insert ( key. clone ( ) , value) ;
70
71
if ret. is_none ( ) {
71
- assert ! ( self . keys. insert ( key) , "map and keys must be consistent" ) ;
72
+ self . keys . push ( key) ;
72
73
}
73
74
ret
74
75
}
@@ -109,9 +110,21 @@ impl<K: Clone + Hash + Ord, V> IndexedMap<K, V> {
109
110
}
110
111
111
112
/// Returns an iterator which iterates over the `key`/`value` pairs in a given range.
112
- pub fn range < R : RangeBounds < K > > ( & self , range : R ) -> Range < K , V > {
113
+ pub fn range < R : RangeBounds < K > > ( & mut self , range : R ) -> Range < K , V > {
114
+ self . keys . sort_unstable ( ) ;
115
+ let start = match range. start_bound ( ) {
116
+ Bound :: Unbounded => 0 ,
117
+ Bound :: Included ( key) => self . keys . binary_search ( key) . unwrap_or_else ( |index| index) ,
118
+ Bound :: Excluded ( key) => self . keys . binary_search ( key) . and_then ( |index| Ok ( index + 1 ) ) . unwrap_or_else ( |index| index) ,
119
+ } ;
120
+ let end = match range. end_bound ( ) {
121
+ Bound :: Unbounded => self . keys . len ( ) ,
122
+ Bound :: Included ( key) => self . keys . binary_search ( key) . and_then ( |index| Ok ( index + 1 ) ) . unwrap_or_else ( |index| index) ,
123
+ Bound :: Excluded ( key) => self . keys . binary_search ( key) . unwrap_or_else ( |index| index) ,
124
+ } ;
125
+
113
126
Range {
114
- inner_range : self . keys . range ( range ) ,
127
+ inner_range : self . keys [ start..end ] . iter ( ) ,
115
128
map : & self . map ,
116
129
}
117
130
}
@@ -127,9 +140,15 @@ impl<K: Clone + Hash + Ord, V> IndexedMap<K, V> {
127
140
}
128
141
}
129
142
143
+ impl < K : Hash + Ord + PartialEq , V : PartialEq > PartialEq for IndexedMap < K , V > {
144
+ fn eq ( & self , other : & Self ) -> bool {
145
+ self . map == other. map
146
+ }
147
+ }
148
+
130
149
/// An iterator over a range of values in an [`IndexedMap`]
131
150
pub struct Range < ' a , K : Hash + Ord , V > {
132
- inner_range : btree_set :: Range < ' a , K > ,
151
+ inner_range : Iter < ' a , K > ,
133
152
map : & ' a HashMap < K , V > ,
134
153
}
135
154
impl < ' a , K : Hash + Ord , V : ' a > Iterator for Range < ' a , K , V > {
@@ -148,7 +167,7 @@ pub struct VacantEntry<'a, K: Hash + Ord, V> {
148
167
#[ cfg( not( feature = "hashbrown" ) ) ]
149
168
underlying_entry : hash_map:: VacantEntry < ' a , K , V > ,
150
169
key : K ,
151
- keys : & ' a mut BTreeSet < K > ,
170
+ keys : & ' a mut Vec < K > ,
152
171
}
153
172
154
173
/// An [`Entry`] for an existing key-value pair
@@ -157,7 +176,7 @@ pub struct OccupiedEntry<'a, K: Hash + Ord, V> {
157
176
underlying_entry : hash_map:: OccupiedEntry < ' a , K , V , hash_map:: DefaultHashBuilder > ,
158
177
#[ cfg( not( feature = "hashbrown" ) ) ]
159
178
underlying_entry : hash_map:: OccupiedEntry < ' a , K , V > ,
160
- keys : & ' a mut BTreeSet < K > ,
179
+ keys : & ' a mut Vec < K > ,
161
180
}
162
181
163
182
/// A mutable reference to a position in the map. This can be used to reference, add, or update the
@@ -172,7 +191,7 @@ pub enum Entry<'a, K: Hash + Ord, V> {
172
191
impl < ' a , K : Hash + Ord , V > VacantEntry < ' a , K , V > {
173
192
/// Insert a value into the position described by this entry.
174
193
pub fn insert ( self , value : V ) -> & ' a mut V {
175
- assert ! ( self . keys. insert ( self . key) , "map and keys must be consistent" ) ;
194
+ self . keys . push ( self . key ) ;
176
195
self . underlying_entry . insert ( value)
177
196
}
178
197
}
@@ -181,7 +200,8 @@ impl<'a, K: Hash + Ord, V> OccupiedEntry<'a, K, V> {
181
200
/// Remove the value at the position described by this entry.
182
201
pub fn remove_entry ( self ) -> ( K , V ) {
183
202
let res = self . underlying_entry . remove_entry ( ) ;
184
- assert ! ( self . keys. remove( & res. 0 ) , "map and keys must be consistent" ) ;
203
+ let idx = self . keys . iter ( ) . position ( |k| k == & res. 0 ) . expect ( "map and keys must be consistent" ) ;
204
+ self . keys . remove ( idx) ;
185
205
res
186
206
}
187
207
0 commit comments