Skip to content

Commit b43fa13

Browse files
authored
Merge pull request #57 from bluss/sort-in-place
Implement sorting in place for OrderMap, OrderSet
2 parents 26e0d7c + 7048e17 commit b43fa13

File tree

5 files changed

+198
-6
lines changed

5 files changed

+198
-6
lines changed

benches/bench.rs

+80
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ extern crate fnv;
55
#[macro_use]
66
extern crate lazy_static;
77

8+
use std::hash::Hash;
89
use fnv::FnvHasher;
910
use std::hash::BuildHasherDefault;
1011
type FnvBuilder = BuildHasherDefault<FnvHasher>;
@@ -361,13 +362,16 @@ fn lookup_orderedmap_10_000_noexist(b: &mut Bencher) {
361362
// number of items to look up
362363
const LOOKUP_MAP_SIZE: u32 = 100_000_u32;
363364
const LOOKUP_SAMPLE_SIZE: u32 = 5000;
365+
const SORT_MAP_SIZE: usize = 10_000;
364366

365367

368+
// use lazy_static so that comparison benchmarks use the exact same inputs
366369
lazy_static! {
367370
static ref KEYS: Vec<u32> = {
368371
shuffled_keys(0..LOOKUP_MAP_SIZE)
369372
};
370373
}
374+
371375
lazy_static! {
372376
static ref HMAP_100K: HashMap<u32, u32> = {
373377
let c = LOOKUP_MAP_SIZE;
@@ -392,6 +396,25 @@ lazy_static! {
392396
};
393397
}
394398

399+
lazy_static! {
400+
static ref OMAP_SORT_U32: OrderMap<u32, u32> = {
401+
let mut map = OrderMap::with_capacity(SORT_MAP_SIZE);
402+
for &key in &KEYS[..SORT_MAP_SIZE] {
403+
map.insert(key, key);
404+
}
405+
map
406+
};
407+
}
408+
lazy_static! {
409+
static ref OMAP_SORT_S: OrderMap<String, String> = {
410+
let mut map = OrderMap::with_capacity(SORT_MAP_SIZE);
411+
for &key in &KEYS[..SORT_MAP_SIZE] {
412+
map.insert(format!("{:^16x}", &key), String::new());
413+
}
414+
map
415+
};
416+
}
417+
395418
#[bench]
396419
fn lookup_hashmap_100_000_multi(b: &mut Bencher) {
397420
let map = &*HMAP_100K;
@@ -643,3 +666,60 @@ fn many_retain_hashmap_100_000(b: &mut Bencher) {
643666
map
644667
});
645668
}
669+
670+
671+
// simple sort impl for comparison
672+
pub fn simple_sort<K: Ord + Hash, V>(m: &mut OrderMap<K, V>) {
673+
let mut ordered: Vec<_> = m.drain(..).collect();
674+
ordered.sort_by(|left, right| left.0.cmp(&right.0));
675+
m.extend(ordered);
676+
}
677+
678+
679+
#[bench]
680+
fn ordermap_sort_s(b: &mut Bencher) {
681+
let map = OMAP_SORT_S.clone();
682+
683+
// there's a map clone there, but it's still useful to profile this
684+
b.iter(|| {
685+
let mut map = map.clone();
686+
map.sort_keys();
687+
map
688+
});
689+
}
690+
691+
#[bench]
692+
fn ordermap_simple_sort_s(b: &mut Bencher) {
693+
let map = OMAP_SORT_S.clone();
694+
695+
// there's a map clone there, but it's still useful to profile this
696+
b.iter(|| {
697+
let mut map = map.clone();
698+
simple_sort(&mut map);
699+
map
700+
});
701+
}
702+
703+
#[bench]
704+
fn ordermap_sort_u32(b: &mut Bencher) {
705+
let map = OMAP_SORT_U32.clone();
706+
707+
// there's a map clone there, but it's still useful to profile this
708+
b.iter(|| {
709+
let mut map = map.clone();
710+
map.sort_keys();
711+
map
712+
});
713+
}
714+
715+
#[bench]
716+
fn ordermap_simple_sort_u32(b: &mut Bencher) {
717+
let map = OMAP_SORT_U32.clone();
718+
719+
// there's a map clone there, but it's still useful to profile this
720+
b.iter(|| {
721+
let mut map = map.clone();
722+
simple_sort(&mut map);
723+
map
724+
});
725+
}

benches/faststring.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
#![feature(test)]
22
extern crate test;
33
extern crate rand;
4-
extern crate fnv;
54
extern crate lazy_static;
65

7-
use fnv::FnvHasher;
8-
use std::hash::BuildHasherDefault;
9-
type FnvBuilder = BuildHasherDefault<FnvHasher>;
10-
116
use test::Bencher;
127

13-
#[macro_use] extern crate ordermap;
8+
extern crate ordermap;
149

1510
use ordermap::OrderMap;
1611

src/lib.rs

+56
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ fn hash_elem_using<B: BuildHasher, K: ?Sized + Hash>(build: &B, k: &K) -> HashVa
4545
#[derive(Copy, Debug)]
4646
struct HashValue(usize);
4747

48+
impl HashValue {
49+
#[inline(always)]
50+
fn get(self) -> usize { self.0 }
51+
}
52+
4853
impl Clone for HashValue {
4954
#[inline]
5055
fn clone(&self) -> Self { *self }
@@ -1044,6 +1049,57 @@ impl<K, V, S> OrderMap<K, V, S>
10441049
}
10451050
}
10461051

1052+
/// Sort the map’s key-value pairs by the default ordering of the keys.
1053+
///
1054+
/// See `sort_by` for details.
1055+
pub fn sort_keys(&mut self)
1056+
where K: Ord,
1057+
{
1058+
self.sort_by(|k1, _, k2, _| Ord::cmp(k1, k2))
1059+
}
1060+
1061+
/// Sort the map’s key-value pairs in place using the comparison
1062+
/// function `compare`.
1063+
///
1064+
/// The comparison function receives two key and value pairs to compare (you
1065+
/// can sort by keys or values or their combination as needed).
1066+
///
1067+
/// Computes in **O(n log n)** time and **O(n)** space. The sort is stable.
1068+
pub fn sort_by<F>(&mut self, mut compare: F)
1069+
where F: FnMut(&K, &V, &K, &V) -> Ordering,
1070+
{
1071+
// here we temporarily use the hash field in a bucket to store the old
1072+
// index instead.
1073+
//
1074+
// Save the old hash values in `side_index`.
1075+
// Then we can sort `self.entries` in place.
1076+
let mut side_index = Vec::from_iter(enumerate(&mut self.entries).map(|(i, elt)| {
1077+
replace(&mut elt.hash, HashValue(i)).get()
1078+
}));
1079+
1080+
self.entries.sort_by(move |ei, ej| compare(&ei.key, &ei.value, &ej.key, &ej.value));
1081+
1082+
// Here we write back the hash values from side_index and fill
1083+
// in side_index with a mapping from the old to the new index instead.
1084+
for (i, ent) in enumerate(&mut self.entries) {
1085+
let old_index = ent.hash.get();
1086+
ent.hash = HashValue(replace(&mut side_index[old_index], i));
1087+
}
1088+
1089+
// Apply new index to self.indices
1090+
dispatch_32_vs_64!(self.apply_new_index(&side_index));
1091+
}
1092+
1093+
fn apply_new_index<Sz>(&mut self, new_index: &[usize])
1094+
where Sz: Size
1095+
{
1096+
for pos in self.indices.iter_mut() {
1097+
if let Some((i, _)) = pos.resolve::<Sz>() {
1098+
pos.set_pos::<Sz>(new_index[i]);
1099+
}
1100+
}
1101+
}
1102+
10471103
/// Sort the key-value pairs of the map and return a by value iterator of
10481104
/// the key-value pairs with the result.
10491105
///

src/set.rs

+18
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,24 @@ impl<T, S> OrderSet<T, S>
342342
self.map.retain(move |x, &mut ()| keep(x))
343343
}
344344

345+
/// Sort the set’s values by their default ordering.
346+
///
347+
/// See `sort_by` for details.
348+
pub fn sort(&mut self)
349+
where T: Ord,
350+
{
351+
self.map.sort_keys()
352+
}
353+
354+
/// Sort the set’s values in place using the comparison function `compare`.
355+
///
356+
/// Computes in **O(n log n)** time and **O(n)** space. The sort is stable.
357+
pub fn sort_by<F>(&mut self, mut compare: F)
358+
where F: FnMut(&T, &T) -> Ordering,
359+
{
360+
self.map.sort_by(move |a, _, b, _| compare(a, b));
361+
}
362+
345363
/// Sort the values of the set and return a by value iterator of
346364
/// the values with the result.
347365
///

tests/quick.rs

+43
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,49 @@ quickcheck! {
273273
// check the order
274274
itertools::assert_equal(map.keys(), initial_map.keys().filter(|&k| !remove_map.contains_key(k)));
275275
}
276+
277+
fn sort_1(keyvals: Large<Vec<(i8, i8)>>) -> () {
278+
let mut map: OrderMap<_, _> = OrderMap::from_iter(keyvals.to_vec());
279+
let mut answer = keyvals.0;
280+
answer.sort_by_key(|t| t.0);
281+
282+
// reverse dedup: Because OrderMap::from_iter keeps the last value for
283+
// identical keys
284+
answer.reverse();
285+
answer.dedup_by_key(|t| t.0);
286+
answer.reverse();
287+
288+
map.sort_by(|k1, _, k2, _| Ord::cmp(k1, k2));
289+
290+
// check it contains all the values it should
291+
for &(key, val) in &answer {
292+
assert_eq!(map[&key], val);
293+
}
294+
295+
// check the order
296+
297+
let mapv = Vec::from_iter(map);
298+
assert_eq!(answer, mapv);
299+
300+
}
301+
302+
fn sort_2(keyvals: Large<Vec<(i8, i8)>>) -> () {
303+
let mut map: OrderMap<_, _> = OrderMap::from_iter(keyvals.to_vec());
304+
map.sort_by(|_, v1, _, v2| Ord::cmp(v1, v2));
305+
assert_sorted_by_key(map, |t| t.1);
306+
}
307+
}
308+
309+
fn assert_sorted_by_key<I, Key, X>(iterable: I, key: Key)
310+
where I: IntoIterator,
311+
I::Item: Ord + Clone + Debug,
312+
Key: Fn(&I::Item) -> X,
313+
X: Ord,
314+
{
315+
let input = Vec::from_iter(iterable);
316+
let mut sorted = input.clone();
317+
sorted.sort_by_key(key);
318+
assert_eq!(input, sorted);
276319
}
277320

278321
#[derive(Clone, Debug, Hash, PartialEq, Eq)]

0 commit comments

Comments
 (0)