Skip to content

Commit afb81c9

Browse files
authored
Merge pull request #56 from orxfun/reserve-initialized-maximum-capacity
reserve initialized maximum capacity
2 parents 963f38b + 0728260 commit afb81c9

File tree

5 files changed

+134
-21
lines changed

5 files changed

+134
-21
lines changed

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "orx-split-vec"
3-
version = "3.6.0"
3+
version = "3.7.0"
44
edition = "2021"
55
authors = ["orxfun <[email protected]>"]
66
description = "An efficient constant access time vector with dynamic capacity and pinned elements."
@@ -11,7 +11,7 @@ categories = ["data-structures", "rust-patterns"]
1111

1212
[dependencies]
1313
orx-pseudo-default = "1.4"
14-
orx-pinned-vec = "3.6"
14+
orx-pinned-vec = "3.7"
1515

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

src/algorithms/in_place_sort.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub fn in_place_sort_by<T, F>(fragments: &mut [Fragment<T>], mut compare: F)
55
where
66
F: FnMut(&T, &T) -> Ordering,
77
{
8-
if fragments.len() == 0 {
8+
if fragments.is_empty() {
99
return;
1010
}
1111

@@ -60,9 +60,9 @@ where
6060
true => None,
6161
false => {
6262
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);
63+
for (q, fragment) in fragments.iter().enumerate().skip(r_best + 1) {
64+
if let Less = compare(&fragment[0], best) {
65+
(best, r_best) = (&fragment[0], q);
6666
}
6767
}
6868

src/concurrent_pinned_vec.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ struct FragmentData {
2020
pub struct ConcurrentSplitVec<T, G: GrowthWithConstantTimeAccess = Doubling> {
2121
growth: G,
2222
data: Vec<UnsafeCell<*mut T>>,
23-
num_fragments: AtomicUsize,
2423
capacity: AtomicUsize,
2524
maximum_capacity: usize,
2625
max_num_fragments: usize,
@@ -30,7 +29,7 @@ pub struct ConcurrentSplitVec<T, G: GrowthWithConstantTimeAccess = Doubling> {
3029
impl<T, G: GrowthWithConstantTimeAccess> Drop for ConcurrentSplitVec<T, G> {
3130
fn drop(&mut self) {
3231
let mut take_fragment = |_fragment: Fragment<T>| {};
33-
unsafe { self.into_fragments(self.pinned_vec_len, &mut take_fragment) };
32+
unsafe { self.process_into_fragments(self.pinned_vec_len, &mut take_fragment) };
3433
self.zero();
3534
}
3635
}
@@ -51,15 +50,15 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentSplitVec<T, G> {
5150
}
5251

5352
fn layout(len: usize) -> std::alloc::Layout {
54-
std::alloc::Layout::array::<T>(len).unwrap()
53+
std::alloc::Layout::array::<T>(len).expect("len must not overflow")
5554
}
5655

5756
unsafe fn to_fragment(&self, data: FragmentData) -> Fragment<T> {
5857
let ptr = *self.data[data.f].get();
5958
fragment_from_raw(ptr, data.len, data.capacity)
6059
}
6160

62-
unsafe fn into_fragments<F>(&mut self, len: usize, take_fragment: &mut F)
61+
unsafe fn process_into_fragments<F>(&mut self, len: usize, take_fragment: &mut F)
6362
where
6463
F: FnMut(Fragment<T>),
6564
{
@@ -116,12 +115,23 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentSplitVec<T, G> {
116115
}
117116

118117
fn zero(&mut self) {
119-
self.num_fragments = 0.into();
120118
self.capacity = 0.into();
121119
self.maximum_capacity = 0;
122120
self.max_num_fragments = 0;
123121
self.pinned_vec_len = 0;
124122
}
123+
124+
fn num_fragments_for_capacity(&self, capacity: usize) -> usize {
125+
match capacity {
126+
0 => 0,
127+
_ => {
128+
self.growth
129+
.get_fragment_and_inner_indices_unchecked(capacity - 1)
130+
.0
131+
+ 1
132+
}
133+
}
134+
}
125135
}
126136

127137
impl<T, G: GrowthWithConstantTimeAccess> From<SplitVec<T, G>> for ConcurrentSplitVec<T, G> {
@@ -144,7 +154,7 @@ impl<T, G: GrowthWithConstantTimeAccess> From<SplitVec<T, G>> for ConcurrentSpli
144154
total_len += len;
145155
maximum_capacity += cap;
146156

147-
data.push(UnsafeCell::new(p as *mut T));
157+
data.push(UnsafeCell::new(p));
148158
}
149159
assert_eq!(total_len, pinned_vec_len);
150160
let capacity = maximum_capacity;
@@ -159,7 +169,6 @@ impl<T, G: GrowthWithConstantTimeAccess> From<SplitVec<T, G>> for ConcurrentSpli
159169
Self {
160170
growth,
161171
data,
162-
num_fragments: num_fragments.into(),
163172
capacity: capacity.into(),
164173
maximum_capacity,
165174
max_num_fragments,
@@ -174,7 +183,7 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
174183
unsafe fn into_inner(mut self, len: usize) -> Self::P {
175184
let mut fragments = Vec::with_capacity(self.max_num_fragments);
176185
let mut take_fragment = |fragment| fragments.push(fragment);
177-
self.into_fragments(len, &mut take_fragment);
186+
self.process_into_fragments(len, &mut take_fragment);
178187

179188
self.zero();
180189
SplitVec::from_raw_parts(len, fragments, self.growth.clone())
@@ -355,8 +364,7 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
355364
match new_capacity <= capacity {
356365
true => Ok(capacity),
357366
false => {
358-
let mut f = self.num_fragments.load(Ordering::Relaxed);
359-
367+
let mut f = self.num_fragments_for_capacity(capacity);
360368
let mut current_capacity = capacity;
361369

362370
while new_capacity > current_capacity {
@@ -369,7 +377,6 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
369377
current_capacity += new_fragment_capacity;
370378
}
371379

372-
self.num_fragments.store(f, Ordering::SeqCst);
373380
self.capacity.store(current_capacity, Ordering::Release);
374381

375382
Ok(current_capacity)
@@ -389,7 +396,7 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
389396
match new_capacity <= capacity {
390397
true => Ok(capacity),
391398
false => {
392-
let mut f = self.num_fragments.load(Ordering::Relaxed);
399+
let mut f = self.num_fragments_for_capacity(capacity);
393400

394401
let mut current_capacity = capacity;
395402

@@ -408,7 +415,6 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
408415
current_capacity += new_fragment_capacity;
409416
}
410417

411-
self.num_fragments.store(f, Ordering::SeqCst);
412418
self.capacity.store(current_capacity, Ordering::Release);
413419

414420
Ok(current_capacity)
@@ -468,13 +474,25 @@ impl<T, G: GrowthWithConstantTimeAccess> ConcurrentPinnedVec<T> for ConcurrentSp
468474
self.maximum_capacity
469475
}
470476

477+
unsafe fn reserve_maximum_concurrent_capacity_fill_with<F>(
478+
&mut self,
479+
current_len: usize,
480+
new_maximum_capacity: usize,
481+
_fill_with: F,
482+
) -> usize
483+
where
484+
F: Fn() -> T,
485+
{
486+
self.reserve_maximum_concurrent_capacity(current_len, new_maximum_capacity)
487+
}
488+
471489
unsafe fn set_pinned_vec_len(&mut self, len: usize) {
472490
self.pinned_vec_len = len;
473491
}
474492

475493
unsafe fn clear(&mut self, len: usize) {
476494
let mut take_fragment = |_fragment: Fragment<T>| {};
477-
unsafe { self.into_fragments(len, &mut take_fragment) };
495+
unsafe { self.process_into_fragments(len, &mut take_fragment) };
478496
self.zero();
479497

480498
let max_num_fragments = self.data.len();

src/fragment/fragment_struct.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#[derive(Default)]
2-
#[allow(clippy::include)]
32
/// A contagious fragment of the split vector.
43
///
54
/// Suppose a split vector contains 10 integers from 0 to 9.

tests/con_pinned_vec_grow.rs

+96
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,99 @@ fn con_pin_vec_grow_filled() {
102102
test(SplitVec::with_doubling_growth_and_fragments_capacity(32));
103103
test(SplitVec::with_linear_growth_and_fragments_capacity(10, 32));
104104
}
105+
106+
#[test]
107+
fn reserve() {
108+
fn test<G: GrowthWithConstantTimeAccess>(vec: SplitVec<String, G>) {
109+
let initial_capacity = vec.capacity();
110+
111+
let mut con_vec = vec.into_concurrent();
112+
let max_cap = con_vec.max_capacity();
113+
114+
unsafe { con_vec.get_ptr_mut(0).write("first".to_string()) };
115+
116+
assert_eq!(con_vec.capacity(), initial_capacity);
117+
118+
unsafe { con_vec.reserve_maximum_concurrent_capacity(0, max_cap + 1) };
119+
let new_capacity = con_vec.capacity();
120+
assert_eq!(new_capacity, initial_capacity);
121+
assert!(con_vec.max_capacity() >= max_cap + 1);
122+
123+
let vec = unsafe { con_vec.into_inner(1) };
124+
125+
assert_eq!(vec.len(), 1);
126+
assert_eq!(vec.capacity(), initial_capacity);
127+
assert_eq!(&vec[0], &"first".to_string());
128+
}
129+
130+
test(SplitVec::with_doubling_growth_and_fragments_capacity(16));
131+
test(SplitVec::with_linear_growth_and_fragments_capacity(10, 32));
132+
}
133+
134+
#[test]
135+
fn into_concurrent_fill_with() {
136+
fn test<G: GrowthWithConstantTimeAccess>(vec: SplitVec<String, G>) {
137+
let initial_capacity = vec.capacity();
138+
let vec2 = vec.clone();
139+
140+
let con_vec = vec.into_concurrent_filled_with(|| "x".to_string());
141+
let vec = unsafe { con_vec.into_inner(initial_capacity) };
142+
assert_eq!(
143+
vec,
144+
(0..initial_capacity)
145+
.map(|_| "x".to_string())
146+
.collect::<Vec<_>>()
147+
);
148+
149+
let mut vec = vec2;
150+
vec.push("y".to_string());
151+
let con_vec = vec.into_concurrent_filled_with(|| "x".to_string());
152+
let vec = unsafe { con_vec.into_inner(initial_capacity) };
153+
assert_eq!(&vec[0], &"y".to_string());
154+
assert_eq!(
155+
vec.iter().skip(1).cloned().collect::<Vec<_>>(),
156+
(1..initial_capacity)
157+
.map(|_| "x".to_string())
158+
.collect::<Vec<_>>()
159+
);
160+
}
161+
test(SplitVec::with_doubling_growth_and_fragments_capacity(32));
162+
test(SplitVec::with_linear_growth_and_fragments_capacity(10, 32));
163+
}
164+
165+
#[test]
166+
fn reserve_fill_with() {
167+
fn test<G: GrowthWithConstantTimeAccess>(vec: SplitVec<String, G>) {
168+
let initial_capacity = vec.capacity();
169+
170+
let mut con_vec = vec.into_concurrent_filled_with(|| "x".to_string());
171+
let max_cap = con_vec.max_capacity();
172+
173+
assert_eq!(con_vec.capacity(), initial_capacity);
174+
175+
unsafe {
176+
con_vec.reserve_maximum_concurrent_capacity_fill_with(
177+
initial_capacity,
178+
max_cap + 1,
179+
|| "y".to_string(),
180+
)
181+
};
182+
let new_capacity = con_vec.capacity();
183+
assert_eq!(new_capacity, initial_capacity);
184+
assert!(con_vec.max_capacity() >= max_cap + 1);
185+
186+
let vec = unsafe { con_vec.into_inner(initial_capacity) };
187+
188+
assert_eq!(vec.len(), initial_capacity);
189+
assert_eq!(vec.capacity(), initial_capacity);
190+
assert_eq!(
191+
vec,
192+
(0..initial_capacity)
193+
.map(|_| "x".to_string())
194+
.collect::<Vec<_>>()
195+
);
196+
}
197+
198+
test(SplitVec::with_doubling_growth_and_fragments_capacity(16));
199+
test(SplitVec::with_linear_growth_and_fragments_capacity(10, 32));
200+
}

0 commit comments

Comments
 (0)