Skip to content

Commit 048ae69

Browse files
authored
Merge pull request #52 from orxfun/sort-methods
sort methods are implemented
2 parents be19f15 + a9065a5 commit 048ae69

File tree

5 files changed

+299
-2
lines changed

5 files changed

+299
-2
lines changed

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ keywords = ["vec", "array", "split", "fragments", "pinned"]
1010
categories = ["data-structures", "rust-patterns"]
1111

1212
[dependencies]
13-
orx-pseudo-default = "1.2"
14-
orx-pinned-vec = "3.3"
13+
orx-pseudo-default = "1.4"
14+
orx-pinned-vec = "3.4"
1515

1616
[[bench]]
1717
name = "serial_access"

src/algorithms/in_place_sort.rs

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
use crate::Fragment;
2+
use std::cmp::Ordering::{self, *};
3+
4+
pub fn in_place_sort_by<T, F>(fragments: &mut [Fragment<T>], mut compare: F)
5+
where
6+
F: FnMut(&T, &T) -> Ordering,
7+
{
8+
if fragments.len() == 0 {
9+
return;
10+
}
11+
12+
for fragment in fragments.iter_mut() {
13+
fragment.sort_by(&mut compare);
14+
}
15+
16+
let num_fragments = fragments.len();
17+
18+
let mut r = 0;
19+
let mut c = 0;
20+
21+
while r < num_fragments - 1 {
22+
let row_to_swap = get_row_to_swap(fragments, &mut compare, r, c);
23+
if let Some(target_row) = row_to_swap {
24+
let pa = std::ptr::addr_of_mut!(fragments[r][c]);
25+
let pb = std::ptr::addr_of_mut!(fragments[target_row][0]);
26+
// SAFETY: `pa` and `pb` have been created from safe mutable references and refer
27+
// to elements in the slice and therefore are guaranteed to be valid and aligned.
28+
// Note that accessing the elements behind `a` and `b` is checked and will
29+
// panic when out of bounds.
30+
unsafe { std::ptr::swap(pa, pb) };
31+
32+
let fragment_right = &fragments[target_row][1..];
33+
let value = &fragments[target_row][0];
34+
let position_to_insert = find_position_to_insert(fragment_right, &mut compare, value);
35+
if let Some(p) = position_to_insert {
36+
for i in 0..p {
37+
fragments[target_row].swap(i, i + 1);
38+
}
39+
}
40+
}
41+
42+
match c == fragments[r].len() - 1 {
43+
true => (r, c) = (r + 1, 0),
44+
false => c += 1,
45+
}
46+
}
47+
}
48+
49+
fn get_row_to_swap<T, F>(
50+
fragments: &[Fragment<T>],
51+
compare: &mut F,
52+
r: usize,
53+
c: usize,
54+
) -> Option<usize>
55+
where
56+
F: FnMut(&T, &T) -> Ordering,
57+
{
58+
let mut r_best = r + 1;
59+
match r_best == fragments.len() {
60+
true => None,
61+
false => {
62+
let mut best = &fragments[r_best][0];
63+
for q in (r_best + 1)..fragments.len() {
64+
if let Less = compare(&fragments[q][0], best) {
65+
(best, r_best) = (&fragments[q][0], q);
66+
}
67+
}
68+
69+
match compare(best, &fragments[r][c]) {
70+
Less => Some(r_best),
71+
_ => None,
72+
}
73+
}
74+
}
75+
}
76+
77+
fn find_position_to_insert<T, F>(fragment: &[T], compare: &mut F, value: &T) -> Option<usize>
78+
where
79+
F: FnMut(&T, &T) -> Ordering,
80+
{
81+
match fragment.len() {
82+
0 => None,
83+
_ => match compare(unsafe { fragment.get_unchecked(0) }, value) {
84+
Equal | Greater => None,
85+
Less => {
86+
let mut target = 0;
87+
let mut size = fragment.len();
88+
let mut left = 0;
89+
let mut right = size;
90+
while left < right {
91+
let mid = left + size / 2;
92+
93+
match compare(unsafe { fragment.get_unchecked(mid) }, value) {
94+
// Equal => return Some(mid),
95+
Greater | Equal => right = mid,
96+
Less => {
97+
target = mid + 1;
98+
left = mid;
99+
}
100+
}
101+
if size == 1 {
102+
return Some(target);
103+
}
104+
size = right - left;
105+
}
106+
107+
Some(target)
108+
}
109+
},
110+
}
111+
}
112+
113+
#[cfg(test)]
114+
mod tests {
115+
use super::*;
116+
use crate::{Doubling, Growth, Linear, Recursive};
117+
use test_case::test_case;
118+
119+
#[test]
120+
fn insertion_position() {
121+
let fragment: Fragment<u32> = vec![4, 7, 9, 13, 16, 17, 23].into();
122+
123+
let mut c = |a: &u32, b: &u32| a.cmp(b);
124+
let mut pos = |val: &u32| find_position_to_insert(&fragment, &mut c, val);
125+
126+
assert_eq!(pos(&0), None);
127+
assert_eq!(pos(&3), None);
128+
assert_eq!(pos(&4), None);
129+
130+
assert_eq!(pos(&5), Some(1));
131+
assert_eq!(pos(&6), Some(1));
132+
assert_eq!(pos(&7), Some(1));
133+
134+
assert_eq!(pos(&8), Some(2));
135+
assert_eq!(pos(&9), Some(2));
136+
137+
assert_eq!(pos(&10), Some(3));
138+
assert_eq!(pos(&11), Some(3));
139+
assert_eq!(pos(&12), Some(3));
140+
assert_eq!(pos(&13), Some(3));
141+
142+
assert_eq!(pos(&14), Some(4));
143+
assert_eq!(pos(&15), Some(4));
144+
assert_eq!(pos(&16), Some(4));
145+
146+
assert_eq!(pos(&17), Some(5));
147+
148+
assert_eq!(pos(&18), Some(6));
149+
assert_eq!(pos(&19), Some(6));
150+
assert_eq!(pos(&20), Some(6));
151+
assert_eq!(pos(&21), Some(6));
152+
assert_eq!(pos(&22), Some(6));
153+
assert_eq!(pos(&23), Some(6));
154+
155+
assert_eq!(pos(&24), Some(7));
156+
assert_eq!(pos(&25), Some(7));
157+
assert_eq!(pos(&26), Some(7));
158+
assert_eq!(pos(&100), Some(7));
159+
}
160+
161+
#[test]
162+
fn insertion_position_with_ties() {
163+
let mut c = |a: &u32, b: &u32| a.cmp(b);
164+
165+
let fragment: Fragment<u32> = vec![4, 7, 13, 13, 13, 17, 23].into();
166+
let mut pos = |val: &u32| find_position_to_insert(&fragment, &mut c, val);
167+
assert_eq!(pos(&13), Some(2));
168+
169+
let fragment: Fragment<u32> = vec![4, 7, 13, 13, 23, 23, 23].into();
170+
let mut pos = |val: &u32| find_position_to_insert(&fragment, &mut c, val);
171+
assert_eq!(pos(&23), Some(4));
172+
173+
let fragment: Fragment<u32> = vec![4, 4, 13, 13, 23, 23, 23].into();
174+
let mut pos = |val: &u32| find_position_to_insert(&fragment, &mut c, val);
175+
assert_eq!(pos(&4), None);
176+
}
177+
178+
#[test]
179+
fn sort_simple() {
180+
let mut c = |a: &u32, b: &u32| a.cmp(b);
181+
182+
let mut fragments: Vec<Fragment<u32>> =
183+
vec![vec![2, 4].into(), vec![0, 5, 6].into(), vec![1, 3].into()];
184+
185+
in_place_sort_by(&mut fragments, &mut c);
186+
187+
assert_is_sorted(fragments);
188+
}
189+
190+
#[test_case(Doubling)]
191+
#[test_case(Recursive)]
192+
#[test_case(Linear::new(10))]
193+
fn sort_growth(growth: impl Growth) {
194+
let mut c = |a: &i32, b: &i32| a.cmp(b);
195+
196+
let num_fragments = 10;
197+
let mut fragments: Vec<Fragment<_>> = vec![];
198+
199+
let mut len = 0;
200+
for _ in 0..num_fragments {
201+
let fragment_capacities: Vec<_> = fragments.iter().map(|x| x.capacity()).collect();
202+
let mut fragment =
203+
Fragment::new(growth.new_fragment_capacity_from(fragment_capacities.into_iter()));
204+
for i in 0..fragment.capacity() {
205+
let i = len + i;
206+
let value = match i % 3 {
207+
0 => i as i32,
208+
1 => 42,
209+
_ => -(i as i32),
210+
};
211+
fragment.push(value);
212+
}
213+
214+
assert_eq!(fragment.len(), fragment.capacity());
215+
len += fragment.len();
216+
fragments.push(fragment);
217+
}
218+
219+
assert_eq!(fragments.len(), num_fragments);
220+
221+
in_place_sort_by(&mut fragments, &mut c);
222+
223+
assert_is_sorted(fragments);
224+
}
225+
226+
fn assert_is_sorted<T: Ord>(fragments: Vec<Fragment<T>>) {
227+
let flattened: Vec<T> = fragments.into_iter().flat_map(|x| Vec::from(x)).collect();
228+
229+
if flattened.is_empty() {
230+
return;
231+
}
232+
233+
let mut curr = &flattened[0];
234+
for i in 1..flattened.len() {
235+
let cmp = curr.cmp(&flattened[i]);
236+
assert!(cmp != Greater);
237+
curr = &flattened[i];
238+
}
239+
}
240+
}

src/algorithms/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod binary_search;
2+
pub mod in_place_sort;

src/pinned_vec.rs

+23
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,29 @@ impl<T, G: Growth> PinnedVec<T> for SplitVec<T, G> {
719719
{
720720
algorithms::binary_search::binary_search_by(&self.fragments, f)
721721
}
722+
723+
fn sort(&mut self)
724+
where
725+
T: Ord,
726+
{
727+
algorithms::in_place_sort::in_place_sort_by(&mut self.fragments, T::cmp)
728+
}
729+
730+
fn sort_by<F>(&mut self, compare: F)
731+
where
732+
F: FnMut(&T, &T) -> Ordering,
733+
{
734+
algorithms::in_place_sort::in_place_sort_by(&mut self.fragments, compare)
735+
}
736+
737+
fn sort_by_key<K, F>(&mut self, mut f: F)
738+
where
739+
F: FnMut(&T) -> K,
740+
K: Ord,
741+
{
742+
let compare = |a: &T, b: &T| f(a).cmp(&f(b));
743+
algorithms::in_place_sort::in_place_sort_by(&mut self.fragments, compare)
744+
}
722745
}
723746

724747
#[cfg(test)]

tests/sort.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use orx_split_vec::*;
2+
use std::cmp::Ordering;
3+
4+
#[test]
5+
fn sort() {
6+
let mut vec: SplitVec<_> = [3, 4, 1, 2, 3, 5, 8, 10, 9].into_iter().collect();
7+
vec.sort();
8+
assert_eq!(&vec, &[1, 2, 3, 3, 4, 5, 8, 9, 10]);
9+
}
10+
11+
#[test]
12+
fn sort_by() {
13+
let compare = |a: &i32, b: &i32| match a.cmp(b) {
14+
Ordering::Less => Ordering::Greater,
15+
Ordering::Greater => Ordering::Less,
16+
Ordering::Equal => Ordering::Equal,
17+
};
18+
let mut vec: SplitVec<_> = [3, 4, 1, 2, 3, 5, 8, 10, 9].into_iter().collect();
19+
vec.sort_by(compare);
20+
assert_eq!(&vec, &[10, 9, 8, 5, 4, 3, 3, 2, 1]);
21+
}
22+
23+
#[test]
24+
fn sort_by_key() {
25+
let key = |a: &i32| match a % 2 {
26+
0 => *a,
27+
_ => -a,
28+
};
29+
30+
let mut vec: SplitVec<_> = [3, 4, 1, 2, 3, 5, 8, 10, 9].into_iter().collect();
31+
vec.sort_by_key(key);
32+
assert_eq!(&vec, &[9, 5, 3, 3, 1, 2, 4, 8, 10]);
33+
}

0 commit comments

Comments
 (0)