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
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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!(
19 changes: 19 additions & 0 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
@@ -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!(
@@ -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]
@@ -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" {
8 changes: 8 additions & 0 deletions src/cxx.cc
Original file line number Diff line number Diff line change
@@ -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>>(); \
53 changes: 53 additions & 0 deletions src/cxx_vector.rs
Original file line number Diff line number Diff line change
@@ -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].
@@ -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.
@@ -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.
@@ -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" {
7 changes: 6 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
@@ -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(),
@@ -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()
@@ -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 });