Switch MultiValue to use VecDeque under the hood.

This commit is contained in:
Alex Orlenko
2024-03-02 17:00:23 +00:00
parent 4aa178fcc0
commit aa05eb4c81
3 changed files with 84 additions and 165 deletions
+4 -3
View File
@@ -1,5 +1,6 @@
use std::any::TypeId;
use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::VecDeque;
use std::ffi::{CStr, CString};
use std::fmt;
use std::marker::PhantomData;
@@ -105,7 +106,7 @@ pub(crate) struct ExtraData {
// Pool of `WrappedFailure` enums in the ref thread (as userdata)
wrapped_failure_pool: Vec<c_int>,
// Pool of `MultiValue` containers
multivalue_pool: Vec<Vec<Value<'static>>>,
multivalue_pool: Vec<VecDeque<Value<'static>>>,
// Pool of `Thread`s (coroutines) for async execution
#[cfg(feature = "async")]
thread_pool: Vec<c_int>,
@@ -3255,13 +3256,13 @@ impl LuaInner {
}
#[inline]
pub(crate) fn pop_multivalue_from_pool(&self) -> Option<Vec<Value>> {
pub(crate) fn pop_multivalue_from_pool(&self) -> Option<VecDeque<Value>> {
let extra = unsafe { &mut *self.extra.get() };
extra.multivalue_pool.pop()
}
#[inline]
pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: Vec<Value>) {
pub(crate) fn push_multivalue_to_pool(&self, mut multivalue: VecDeque<Value>) {
let extra = unsafe { &mut *self.extra.get() };
if extra.multivalue_pool.len() < MULTIVALUE_POOL_SIZE {
multivalue.clear();
+11 -33
View File
@@ -12,28 +12,17 @@ use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, MultiValue, Nil
impl<'lua, T: IntoLua<'lua>, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<T, E> {
#[inline]
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
let mut result = MultiValue::with_lua_and_capacity(lua, 2);
match self {
Ok(v) => result.push_front(v.into_lua(lua)?),
Err(e) => {
result.push_front(e.into_lua(lua)?);
result.push_front(Nil);
}
Ok(val) => (val,).into_lua_multi(lua),
Err(err) => (Nil, err).into_lua_multi(lua),
}
Ok(result)
}
#[inline]
unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
match self {
Ok(v) => v.push_into_stack(lua).map(|_| 1),
Err(e) => {
let state = lua.state();
check_stack(state, 3)?;
ffi::lua_pushnil(state);
e.push_into_stack(lua)?;
Ok(2)
}
Ok(val) => (val,).push_into_stack_multi(lua),
Err(err) => (Nil, err).push_into_stack_multi(lua),
}
}
}
@@ -42,13 +31,8 @@ impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> {
#[inline]
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
match self {
Ok(_) => return Ok(MultiValue::new()),
Err(e) => {
let mut result = MultiValue::with_lua_and_capacity(lua, 2);
result.push_front(e.into_lua(lua)?);
result.push_front(Nil);
Ok(result)
}
Ok(_) => Ok(MultiValue::new()),
Err(err) => (Nil, err).into_lua_multi(lua),
}
}
@@ -56,13 +40,7 @@ impl<'lua, E: IntoLua<'lua>> IntoLuaMulti<'lua> for StdResult<(), E> {
unsafe fn push_into_stack_multi(self, lua: &'lua Lua) -> Result<c_int> {
match self {
Ok(_) => Ok(0),
Err(e) => {
let state = lua.state();
check_stack(state, 3)?;
ffi::lua_pushnil(state);
e.push_into_stack(lua)?;
Ok(2)
}
Err(err) => (Nil, err).push_into_stack_multi(lua),
}
}
}
@@ -71,7 +49,7 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for T {
#[inline]
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
let mut v = MultiValue::with_lua_and_capacity(lua, 1);
v.push_front(self.into_lua(lua)?);
v.push_back(self.into_lua(lua)?);
Ok(v)
}
@@ -209,7 +187,7 @@ impl<'lua, T: IntoLua<'lua>> IntoLuaMulti<'lua> for Variadic<T> {
#[inline]
fn into_lua_multi(self, lua: &'lua Lua) -> Result<MultiValue<'lua>> {
let mut values = MultiValue::with_lua_and_capacity(lua, self.0.len());
values.refill(self.0.into_iter().map(|e| e.into_lua(lua)))?;
values.extend_from_values(self.0.into_iter().map(|val| val.into_lua(lua)))?;
Ok(values)
}
}
@@ -218,8 +196,8 @@ impl<'lua, T: FromLua<'lua>> FromLuaMulti<'lua> for Variadic<T> {
#[inline]
fn from_lua_multi(mut values: MultiValue<'lua>, lua: &'lua Lua) -> Result<Self> {
values
.drain_all()
.map(|e| T::from_lua(e, lua))
.drain(..)
.map(|val| T::from_lua(val, lua))
.collect::<Result<Vec<T>>>()
.map(Variadic)
}
+69 -129
View File
@@ -1,12 +1,11 @@
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::iter;
use std::ops::Index;
use std::collections::{vec_deque, HashSet, VecDeque};
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_int, c_void};
use std::string::String as StdString;
use std::sync::Arc;
use std::{fmt, mem, ptr, slice, str, vec};
use std::{fmt, mem, ptr, str};
use num_traits::FromPrimitive;
@@ -751,45 +750,19 @@ pub trait FromLua<'lua>: Sized {
/// Multiple Lua values used for both argument passing and also for multiple return values.
#[derive(Debug, Clone)]
pub struct MultiValue<'lua> {
vec: Vec<Value<'lua>>,
deque: VecDeque<Value<'lua>>,
lua: Option<&'lua Lua>,
}
impl Drop for MultiValue<'_> {
fn drop(&mut self) {
if let Some(lua) = self.lua {
let vec = mem::take(&mut self.vec);
let vec = mem::take(&mut self.deque);
lua.push_multivalue_to_pool(vec);
}
}
}
impl<'lua> MultiValue<'lua> {
/// Creates an empty `MultiValue` containing no values.
pub const fn new() -> MultiValue<'lua> {
MultiValue {
vec: Vec::new(),
lua: None,
}
}
/// Similar to `new` but can reuse previously used container with allocated capacity.
#[inline]
pub(crate) fn with_lua_and_capacity(lua: &'lua Lua, capacity: usize) -> MultiValue<'lua> {
let vec = lua
.pop_multivalue_from_pool()
.map(|mut vec| {
vec.reserve(capacity);
vec
})
.unwrap_or_else(|| Vec::with_capacity(capacity));
MultiValue {
vec,
lua: Some(lua),
}
}
}
impl<'lua> Default for MultiValue<'lua> {
#[inline]
fn default() -> MultiValue<'lua> {
@@ -797,121 +770,88 @@ impl<'lua> Default for MultiValue<'lua> {
}
}
impl<'lua> Deref for MultiValue<'lua> {
type Target = VecDeque<Value<'lua>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.deque
}
}
impl<'lua> DerefMut for MultiValue<'lua> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.deque
}
}
impl<'lua> MultiValue<'lua> {
/// Creates an empty `MultiValue` containing no values.
pub const fn new() -> MultiValue<'lua> {
MultiValue {
deque: VecDeque::new(),
lua: None,
}
}
/// Similar to `new` but can reuse previously used container with allocated capacity.
#[inline]
pub(crate) fn with_lua_and_capacity(lua: &'lua Lua, capacity: usize) -> MultiValue<'lua> {
let deque = lua
.pop_multivalue_from_pool()
.map(|mut deque| {
if capacity > 0 {
deque.reserve(capacity);
}
deque
})
.unwrap_or_else(|| VecDeque::with_capacity(capacity));
MultiValue {
deque,
lua: Some(lua),
}
}
#[inline]
pub(crate) fn extend_from_values(
&mut self,
iter: impl IntoIterator<Item = Result<Value<'lua>>>,
) -> Result<()> {
for value in iter {
self.push_back(value?);
}
Ok(())
}
}
impl<'lua> FromIterator<Value<'lua>> for MultiValue<'lua> {
#[inline]
fn from_iter<I: IntoIterator<Item = Value<'lua>>>(iter: I) -> Self {
MultiValue::from_vec(Vec::from_iter(iter))
let deque = VecDeque::from_iter(iter);
MultiValue { deque, lua: None }
}
}
impl<'lua> IntoIterator for MultiValue<'lua> {
type Item = Value<'lua>;
type IntoIter = iter::Rev<vec::IntoIter<Value<'lua>>>;
type IntoIter = vec_deque::IntoIter<Value<'lua>>;
#[inline]
fn into_iter(mut self) -> Self::IntoIter {
let vec = mem::take(&mut self.vec);
let deque = mem::take(&mut self.deque);
mem::forget(self);
vec.into_iter().rev()
deque.into_iter()
}
}
impl<'a, 'lua> IntoIterator for &'a MultiValue<'lua> {
type Item = &'a Value<'lua>;
type IntoIter = iter::Rev<slice::Iter<'a, Value<'lua>>>;
type IntoIter = vec_deque::Iter<'a, Value<'lua>>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.vec.iter().rev()
}
}
impl<'lua> Index<usize> for MultiValue<'lua> {
type Output = Value<'lua>;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
if let Some(result) = self.get(index) {
result
} else {
panic!(
"index out of bounds: the len is {} but the index is {}",
self.len(),
index
)
}
}
}
impl<'lua> MultiValue<'lua> {
#[inline]
pub fn from_vec(mut vec: Vec<Value<'lua>>) -> MultiValue<'lua> {
vec.reverse();
MultiValue { vec, lua: None }
}
#[inline]
pub fn into_vec(mut self) -> Vec<Value<'lua>> {
let mut vec = mem::take(&mut self.vec);
mem::forget(self);
vec.reverse();
vec
}
#[inline]
pub fn get(&self, index: usize) -> Option<&Value<'lua>> {
if index < self.vec.len() {
return self.vec.get(self.vec.len() - index - 1);
}
None
}
#[inline]
pub fn pop_front(&mut self) -> Option<Value<'lua>> {
self.vec.pop()
}
#[inline]
pub fn push_front(&mut self, value: Value<'lua>) {
self.vec.push(value);
}
#[inline]
pub fn clear(&mut self) {
self.vec.clear();
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
#[inline]
pub fn iter(&self) -> iter::Rev<slice::Iter<Value<'lua>>> {
self.vec.iter().rev()
}
#[inline]
pub(crate) fn drain_all(&mut self) -> iter::Rev<vec::Drain<Value<'lua>>> {
self.vec.drain(..).rev()
}
#[inline]
pub(crate) fn refill(
&mut self,
iter: impl IntoIterator<Item = Result<Value<'lua>>>,
) -> Result<()> {
self.vec.clear();
for value in iter {
self.vec.push(value?);
}
self.vec.reverse();
Ok(())
self.deque.iter()
}
}
@@ -975,8 +915,8 @@ pub trait FromLuaMulti<'lua>: Sized {
#[inline]
unsafe fn from_stack_multi(nvals: c_int, lua: &'lua Lua) -> Result<Self> {
let mut values = MultiValue::with_lua_and_capacity(lua, nvals as usize);
for idx in 1..=nvals {
values.push_front(lua.stack_value(-idx));
for idx in 0..nvals {
values.push_back(lua.stack_value(-nvals + idx));
}
if nvals > 0 {
// It's safe to clear the stack as all references moved to ref thread