Skip to content

Commit 58088dc

Browse files
committed
Add try_push_uninit and test
1 parent 0aede87 commit 58088dc

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010
# Generated by Cargo
1111
/Cargo.lock
1212
/target
13+
.idea
14+

src/arrayvec.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,22 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
206206
ArrayVecImpl::try_push(self, element)
207207
}
208208

209+
/// Push a new uninitialised value to the end of the vector and return
210+
/// a mutable reference to it.
211+
///
212+
/// This is useful if the backed value is large and won't fit on stack.
213+
///
214+
/// Capacity error carries the data - since we don't have data then we need a different error type.
215+
pub unsafe fn try_push_uninit(&mut self) -> Result<*mut T, ()> {
216+
let len = self.len();
217+
if len >= Self::CAPACITY {
218+
return Err(())
219+
}
220+
let new_ptr = self.as_mut_ptr().add(len);
221+
self.set_len(len + 1);
222+
Ok(new_ptr)
223+
}
224+
209225
/// Push `element` to the end of the vector without checking the capacity.
210226
///
211227
/// It is up to the caller to ensure the capacity of the vector is

tests/tests.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::mem;
77
use arrayvec::CapacityError;
88

99
use std::collections::HashMap;
10-
10+
use std::sync::RwLock;
1111

1212
#[test]
1313
fn test_simple() {
@@ -777,3 +777,33 @@ fn test_arraystring_zero_filled_has_some_sanity_checks() {
777777
assert_eq!(string.as_str(), "\0\0\0\0");
778778
assert_eq!(string.len(), 4);
779779
}
780+
781+
/// 3 MB struct
782+
struct ReallyBigStruct {
783+
pub(crate) field_one: [u8; 1_000_000],
784+
pub(crate) field_two: [u8; 1_000_000],
785+
pub(crate) field_three: [u8; 1_000_000],
786+
}
787+
788+
/// Const initialised struct outside of stack
789+
/// We need to initialise this outside of the stack, since otherwise there is a memory copy from
790+
/// the stack into the heap.
791+
/// With a static initialisation, we do not have a stack copy.
792+
static large_struct: RwLock<ArrayVec<ReallyBigStruct, 100>> = RwLock::new(ArrayVec::new_const());
793+
794+
#[test]
795+
fn test_push_uninit() {
796+
let mut lock = large_struct.write().unwrap();
797+
let ptr = unsafe { lock.try_push_uninit().unwrap() };
798+
let field_one = unsafe {&mut (*ptr).field_one};
799+
*field_one = [1; 1_000_000];
800+
let field_two = unsafe {&mut (*ptr).field_two};
801+
*field_two = [2; 1_000_000];
802+
let field_three = unsafe {&mut (*ptr).field_three};
803+
*field_three = [3; 1_000_000];
804+
805+
assert_eq!(lock.len(), 1);
806+
assert_eq!(lock[0].field_one[3], 1);
807+
assert_eq!(lock[0].field_two[999], 2);
808+
assert_eq!(lock[0].field_three[999_999], 3);
809+
}

0 commit comments

Comments
 (0)