Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CxxVector: implement reserve() and capacity() #1300

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,15 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
writeln!(out, " return s.size();");
writeln!(out, "}}");

begin_function_definition(out);
writeln!(
out,
"::std::size_t cxxbridge1$std$vector${}$capacity(::std::vector<{}> const &s) noexcept {{",
instance, inner,
);
writeln!(out, " return s.capacity();");
writeln!(out, "}}");

begin_function_definition(out);
writeln!(
out,
Expand All @@ -1931,6 +1940,15 @@ fn write_cxx_vector(out: &mut OutFile, key: NamedImplKey) {
writeln!(out, " return &(*s)[pos];");
writeln!(out, "}}");

begin_function_definition(out);
writeln!(
out,
"void cxxbridge1$std$vector${}$reserve(::std::vector<{}> *s, ::std::size_t new_cap) {{",
instance, inner,
);
writeln!(out, " s->reserve(new_cap);");
writeln!(out, "}}");

if out.types.is_maybe_trivial(element) {
begin_function_definition(out);
writeln!(
Expand Down
19 changes: 19 additions & 0 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1678,7 +1678,9 @@ fn expand_cxx_vector(
let prefix = format!("cxxbridge1$std$vector${}$", resolve.name.to_symbol());
let link_new = format!("{}new", prefix);
let link_size = format!("{}size", prefix);
let link_capacity = format!("{}capacity", prefix);
let link_get_unchecked = format!("{}get_unchecked", prefix);
let link_reserve = format!("{}reserve", prefix);
let link_push_back = format!("{}push_back", prefix);
let link_pop_back = format!("{}pop_back", prefix);
let unique_ptr_prefix = format!(
Expand Down Expand Up @@ -1760,6 +1762,13 @@ fn expand_cxx_vector(
}
unsafe { __vector_size(v) }
}
fn __vector_capacity(v: &::cxx::CxxVector<Self>) -> usize {
extern "C" {
#[link_name = #link_capacity]
fn __vector_capacity #impl_generics(_: &::cxx::CxxVector<#elem #ty_generics>) -> usize;
}
unsafe { __vector_capacity(v) }
}
unsafe fn __get_unchecked(v: *mut ::cxx::CxxVector<Self>, pos: usize) -> *mut Self {
extern "C" {
#[link_name = #link_get_unchecked]
Expand All @@ -1770,6 +1779,16 @@ fn expand_cxx_vector(
}
unsafe { __get_unchecked(v, pos) as *mut Self }
}
unsafe fn __reserve(v: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<Self>>, new_cap: usize) {
extern "C" {
#[link_name = #link_reserve]
fn __reserve #impl_generics(
v: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
new_cap: usize,
);
}
unsafe { __reserve(v, new_cap) }
}
#by_value_methods
fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
extern "C" {
Expand Down
8 changes: 8 additions & 0 deletions src/cxx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -600,10 +600,18 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
const std::vector<CXX_TYPE> &s) noexcept { \
return s.size(); \
} \
std::size_t cxxbridge1$std$vector$##RUST_TYPE##$capacity( \
const std::vector<CXX_TYPE> &s) noexcept { \
return s.capacity(); \
} \
CXX_TYPE *cxxbridge1$std$vector$##RUST_TYPE##$get_unchecked( \
std::vector<CXX_TYPE> *s, std::size_t pos) noexcept { \
return &(*s)[pos]; \
} \
void cxxbridge1$std$vector$##RUST_TYPE##$reserve( \
std::vector<CXX_TYPE> *s, std::size_t new_cap) noexcept { \
s->reserve(new_cap); \
} \
void cxxbridge1$unique_ptr$std$vector$##RUST_TYPE##$null( \
std::unique_ptr<std::vector<CXX_TYPE>> *ptr) noexcept { \
new (ptr) std::unique_ptr<std::vector<CXX_TYPE>>(); \
Expand Down
53 changes: 53 additions & 0 deletions src/cxx_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ where
T::__vector_size(self)
}

/// Returns the capacity of the vector
///
/// Matches the behavior of C++ [std::vector\<T\>::capacity][capacity].
///
/// [capacity]: https://en.cppreference.com/w/cpp/container/vector/capacity
pub fn capacity(&self) -> usize {
T::__vector_capacity(self)
}

/// Returns true if the vector contains no elements.
///
/// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
Expand Down Expand Up @@ -196,6 +205,32 @@ where
})
}
}

/// Reserve additional space in the vector
///
/// Note that this follows Rust semantics of being *additional*
/// capacity instead of absolute capacity. Equivalent to `vec.reserve(vec.size() + additional)`
/// in C++
pub fn reserve(self: Pin<&mut Self>, additional: usize) {
unsafe {
let len = self.as_ref().len();
T::__reserve(self, len + additional);
}
}
}

impl<A> Extend<A> for Pin<&mut CxxVector<A>>
where
A: ExternType<Kind = Trivial>,
A: VectorElement,
{
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
let iter = iter.into_iter();
self.as_mut().reserve(iter.size_hint().0);
for i in iter {
self.as_mut().push(i);
}
}
}

/// Iterator over elements of a `CxxVector` by shared reference.
Expand Down Expand Up @@ -350,8 +385,12 @@ pub unsafe trait VectorElement: Sized {
#[doc(hidden)]
fn __vector_size(v: &CxxVector<Self>) -> usize;
#[doc(hidden)]
fn __vector_capacity(v: &CxxVector<Self>) -> usize;
#[doc(hidden)]
unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
#[doc(hidden)]
unsafe fn __reserve(v: Pin<&mut CxxVector<Self>>, new_capacity: usize);
#[doc(hidden)]
unsafe fn __push_back(v: Pin<&mut CxxVector<Self>>, value: &mut ManuallyDrop<Self>) {
// Opaque C type vector elements do not get this method because they can
// never exist by value on the Rust side of the bridge.
Expand Down Expand Up @@ -422,13 +461,27 @@ macro_rules! impl_vector_element {
}
unsafe { __vector_size(v) }
}
fn __vector_capacity(v: &CxxVector<$ty>) -> usize {
extern "C" {
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$capacity")]
fn __vector_capacity(_: &CxxVector<$ty>) -> usize;
}
unsafe { __vector_capacity(v) }
}
unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
extern "C" {
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
}
unsafe { __get_unchecked(v, pos) }
}
unsafe fn __reserve(v: Pin<&mut CxxVector<$ty>>, pos: usize) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$vector$", $segment, "$reserve")]
fn __reserve(_: Pin<&mut CxxVector<$ty>>, _: usize);
}
unsafe { __reserve(v, pos) }
}
vector_element_by_value_methods!($kind, $segment, $ty);
fn __unique_ptr_null() -> MaybeUninit<*mut c_void> {
extern "C" {
Expand Down
7 changes: 6 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fn test_c_return() {
assert_eq!("Hello \u{fffd}World", ffi::c_return_rust_string_lossy());
assert_eq!("2020", ffi::c_return_unique_ptr_string().to_str().unwrap());
assert_eq!(4, ffi::c_return_unique_ptr_vector_u8().len());
assert!(4 <= ffi::c_return_unique_ptr_vector_u8().capacity());
assert_eq!(
200_u8,
ffi::c_return_unique_ptr_vector_u8().into_iter().sum(),
Expand All @@ -65,6 +66,7 @@ fn test_c_return() {
ffi::c_return_unique_ptr_vector_f64().into_iter().sum(),
);
assert_eq!(2, ffi::c_return_unique_ptr_vector_shared().len());
assert!(2 <= ffi::c_return_unique_ptr_vector_shared().capacity());
assert_eq!(
2021_usize,
ffi::c_return_unique_ptr_vector_shared()
Expand Down Expand Up @@ -159,7 +161,10 @@ fn test_c_take() {
assert_eq!(vector.pin_mut().pop(), Some(9));
check!(ffi::c_take_unique_ptr_vector_u8(vector));
let mut vector = ffi::c_return_unique_ptr_vector_f64();
vector.pin_mut().push(9.0);
vector.pin_mut().extend(Some(9.0));
assert!(vector.pin_mut().capacity() >= 1);
vector.pin_mut().reserve(100);
assert!(vector.pin_mut().capacity() >= 101);
check!(ffi::c_take_unique_ptr_vector_f64(vector));
let mut vector = ffi::c_return_unique_ptr_vector_shared();
vector.pin_mut().push(ffi::Shared { z: 9 });
Expand Down