blob: 6a855376d84dfa3c211433adaf4be7a3abb054d6 [file]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
use std::ops::{Deref, DerefMut};
use std::ops::{Index, IndexMut};
/// A mutable, contiguous, dynamically-sized container of elements of type `T`,
/// ABI-compatible with `std::vector` from C++.
/// This layout was found empirically on Linux with modern g++ and libc++. If
/// for some version of libc++ it is different, we will need to update it with
/// conditional compilation.
pub struct Vector<T> {
// TODO(b/356221873): Ensure Vector<T> is covariant.
begin: *mut T,
end: *mut T,
capacity_end: *mut T,
}
// TODO(b/356221873): Add a test that checks that the layout of this struct is
// consistent with the layout of `std::vector` from C++.
// TODO(b/356221873): Implement Send and Sync.
// TODO(b/356221873): Implement conversion to and from std::Vec
// TODO(b/356221873): Implement FromIterator, FromIteratorMut.
// TODO(b/356221873): Implement function for resizing (resize, shrink_to_fit,
// reserve etc).
// TODO(b/356221873): Implement clear().
// TODO(b/356221873): implement insertion, removal of elements.
// TODO(b/356221873): implement append, extend.
impl<T> Vector<T> {
pub fn new() -> Vector<T> {
Vector {
begin: core::ptr::null_mut(),
end: core::ptr::null_mut(),
capacity_end: core::ptr::null_mut(),
}
}
pub fn len(&self) -> usize {
// TODO(b/356221873): delete the `if` once a stable Rust release allows
// offset_from for "the same address"
if self.begin.is_null() {
0
} else {
unsafe { self.end.offset_from(self.begin).try_into().unwrap() }
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
// TODO(b/356221873): delete the `if` once a stable Rust release allows
// offset_from for "the same address"
if self.begin.is_null() {
0
} else {
unsafe { self.capacity_end.offset_from(self.begin).try_into().unwrap() }
}
}
}
impl<T: Unpin> Vector<T> {
/// Mutates `self` as if it were a `Vec<T>`.
fn mutate_self_as_vec<F, R>(&mut self, mutate_self: F) -> R
where
F: FnOnce(&mut Vec<T>) -> R,
{
unsafe {
let mut v = if self.begin.is_null() {
Vec::new()
} else {
Vec::from_raw_parts(self.begin, self.len(), self.capacity())
};
let result = mutate_self(&mut v);
let len = v.len();
let capacity = v.capacity();
self.begin = v.as_mut_ptr();
self.end = self.begin.add(len);
self.capacity_end = self.begin.add(capacity);
core::mem::forget(v);
result
}
}
pub fn push(&mut self, value: T) {
self.mutate_self_as_vec(|v| v.push(value));
}
}
impl<T> Default for Vector<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for Vector<T> {
fn drop(&mut self) {
unsafe {
_ = Vec::from_raw_parts(self.begin, self.len(), self.capacity());
}
}
}
impl<T> Index<usize> for Vector<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).unwrap()
}
}
impl<T: Unpin> IndexMut<usize> for Vector<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}
impl<T> Deref for Vector<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
if self.is_empty() {
&[]
} else {
unsafe { std::slice::from_raw_parts(self.begin, self.len()) }
}
}
}
impl<T: Unpin> DerefMut for Vector<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
if self.is_empty() {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut(self.begin, self.len()) }
}
}
}