Merge pull request #2393 from mthom/unsafe_improvements

Improve use of unsafe Rust in arena.rs (#2391)
This commit is contained in:
Mark Thom
2024-04-29 16:17:14 -06:00
committed by GitHub
7 changed files with 134 additions and 232 deletions

View File

@@ -47,7 +47,6 @@ jobs:
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack # FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features' } - { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features' }
# rust versions # rust versions
- { os: ubuntu-22.04, rust-version: "1.70", target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu'}
defaults: defaults:

View File

@@ -10,7 +10,7 @@ license = "BSD-3-Clause"
keywords = ["prolog", "prolog-interpreter", "prolog-system"] keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"] categories = ["command-line-utilities"]
build = "build/main.rs" build = "build/main.rs"
rust-version = "1.70" rust-version = "1.77"
[lib] [lib]
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]

View File

@@ -11,7 +11,6 @@ use crate::read::*;
use crate::parser::dashu::{Integer, Rational}; use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use std::alloc;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@@ -25,10 +24,7 @@ use std::sync::RwLock;
macro_rules! arena_alloc { macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
#[allow(unused_unsafe)]
unsafe {
ArenaAllocated::alloc($arena, result) ArenaAllocated::alloc($arena, result)
}
}}; }};
} }
@@ -36,13 +32,33 @@ macro_rules! arena_alloc {
macro_rules! float_alloc { macro_rules! float_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
#[allow(unused_unsafe)] unsafe { $arena.f64_tbl.build_with(result).as_ptr() }
unsafe {
$arena.f64_tbl.build_with(result).as_ptr()
}
}}; }};
} }
pub fn header_offset_from_payload<Payload: Sized>() -> usize {
let payload_offset = mem::offset_of!(TypedAllocSlab<Payload>, payload);
let slab_offset = mem::offset_of!(TypedAllocSlab<Payload>, slab);
let header_offset = slab_offset + mem::offset_of!(AllocSlab, header);
debug_assert!(payload_offset > header_offset);
payload_offset - header_offset
}
pub fn ptr_to_allocated<Payload: ArenaAllocated>(slab: &mut AllocSlab) -> TypedArenaPtr<Payload> {
let typed_slab: &mut TypedAllocSlab<Payload> = unsafe { mem::transmute(slab) };
typed_slab.to_typed_arena_ptr()
}
#[macro_export]
macro_rules! gen_ptr_to_allocated {
($payload: ty) => {
fn ptr_to_allocated(slab: &mut AllocSlab) -> TypedArenaPtr<$payload> {
ptr_to_allocated::<$payload>(slab)
}
};
}
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::Weak; use std::sync::Weak;
@@ -196,6 +212,7 @@ pub enum ArenaHeaderTag {
#[bitfield] #[bitfield]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct ArenaHeader { pub struct ArenaHeader {
#[allow(dead_code)]
size: B56, size: B56,
m: bool, m: bool,
tag: ArenaHeaderTag, tag: ArenaHeaderTag,
@@ -291,16 +308,12 @@ impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
#[inline] #[inline]
pub fn header_ptr(&self) -> *const ArenaHeader { pub fn header_ptr(&self) -> *const ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *const _ }
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *const ArenaHeader
} }
#[inline] #[inline]
fn header_ptr_mut(&mut self) -> *mut ArenaHeader { fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *mut _ }
ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *mut ArenaHeader
} }
#[inline] #[inline]
@@ -339,35 +352,31 @@ pub trait ArenaAllocated: Sized {
type PtrToAllocated; type PtrToAllocated;
fn tag() -> ArenaHeaderTag; fn tag() -> ArenaHeaderTag;
fn size(&self) -> usize; fn ptr_to_allocated(slab: &mut AllocSlab) -> Self::PtrToAllocated;
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated;
fn header_offset_from_payload() -> usize { fn header_offset_from_payload() -> usize {
mem::size_of::<ArenaHeader>() header_offset_from_payload::<Self>()
} }
#[allow(clippy::missing_safety_doc)] #[allow(clippy::missing_safety_doc)]
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated { fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>(); let size = mem::size_of::<TypedAllocSlab<Self>>();
let slab = Box::new(TypedAllocSlab {
slab: AllocSlab {
next: arena.base.take(),
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
let align = mem::align_of::<AllocSlab>() * 2; _padding: 0,
header: ArenaHeader::build_with(size as u64, Self::tag()),
},
payload: value,
});
#[cfg(target_pointer_width = "64")] let mut untyped_slab = unsafe { Box::from_raw(Box::into_raw(slab) as *mut AllocSlab) };
let align = mem::align_of::<AllocSlab>(); let allocated_ptr = Self::ptr_to_allocated(untyped_slab.as_mut());
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab; arena.base = Some(untyped_slab);
(*slab).next = arena.base; allocated_ptr
(*slab).header = ArenaHeader::build_with(value.size() as u64, Self::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset);
arena.base = slab;
result
} }
} }
@@ -505,141 +514,69 @@ impl fmt::Display for F64Offset {
impl ArenaAllocated for Integer { impl ArenaAllocated for Integer {
type PtrToAllocated = TypedArenaPtr<Integer>; type PtrToAllocated = TypedArenaPtr<Integer>;
gen_ptr_to_allocated!(Integer);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Integer ArenaHeaderTag::Integer
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
impl ArenaAllocated for Rational { impl ArenaAllocated for Rational {
type PtrToAllocated = TypedArenaPtr<Rational>; type PtrToAllocated = TypedArenaPtr<Rational>;
gen_ptr_to_allocated!(Rational);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::Rational ArenaHeaderTag::Rational
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
impl ArenaAllocated for LiveLoadState { impl ArenaAllocated for LiveLoadState {
type PtrToAllocated = TypedArenaPtr<LiveLoadState>; type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
gen_ptr_to_allocated!(LiveLoadState);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::LiveLoadState ArenaHeaderTag::LiveLoadState
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
impl ArenaAllocated for TcpListener { impl ArenaAllocated for TcpListener {
type PtrToAllocated = TypedArenaPtr<TcpListener>; type PtrToAllocated = TypedArenaPtr<TcpListener>;
gen_ptr_to_allocated!(TcpListener);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::TcpListener ArenaHeaderTag::TcpListener
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
#[cfg(feature = "http")] #[cfg(feature = "http")]
impl ArenaAllocated for HttpListener { impl ArenaAllocated for HttpListener {
type PtrToAllocated = TypedArenaPtr<HttpListener>; type PtrToAllocated = TypedArenaPtr<HttpListener>;
gen_ptr_to_allocated!(HttpListener);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpListener ArenaHeaderTag::HttpListener
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
#[cfg(feature = "http")] #[cfg(feature = "http")]
impl ArenaAllocated for HttpResponse { impl ArenaAllocated for HttpResponse {
type PtrToAllocated = TypedArenaPtr<HttpResponse>; type PtrToAllocated = TypedArenaPtr<HttpResponse>;
gen_ptr_to_allocated!(HttpResponse);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpResponse ArenaHeaderTag::HttpResponse
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
}
} }
impl ArenaAllocated for IndexPtr { impl ArenaAllocated for IndexPtr {
@@ -651,17 +588,8 @@ impl ArenaAllocated for IndexPtr {
} }
#[inline] #[inline]
fn size(&self) -> usize { fn ptr_to_allocated(slab: &mut AllocSlab) -> Self::PtrToAllocated {
mem::size_of::<Self>() TypedArenaPtr::new(ptr::addr_of_mut!(slab.header) as *mut _)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst)
}
} }
#[inline] #[inline]
@@ -669,38 +597,48 @@ impl ArenaAllocated for IndexPtr {
0 0
} }
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated { #[inline]
let size = mem::size_of::<AllocSlab>(); fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let mut slab = Box::new(AllocSlab {
next: arena.base.take(),
#[cfg(target_pointer_width = "32")]
_padding: 0,
header: unsafe { mem::transmute(value) },
});
let align = mem::align_of::<AllocSlab>(); let allocated_ptr =
let layout = alloc::Layout::from_size_align_unchecked(size, align); TypedArenaPtr::new(unsafe { mem::transmute(ptr::addr_of_mut!(slab.header)) });
arena.base = Some(slab);
let slab = alloc::alloc(layout) as *mut AllocSlab; allocated_ptr
(*slab).next = arena.base;
let result = value.copy_to_arena(
&(*slab).header as *const crate::arena::ArenaHeader
as *mut crate::machine::machine_indices::IndexPtr,
);
arena.base = slab;
result
} }
} }
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Debug)]
struct AllocSlab { pub struct AllocSlab {
next: *mut AllocSlab, next: Option<Box<AllocSlab>>,
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
_padding: u32, _padding: u32,
header: ArenaHeader, header: ArenaHeader,
} }
#[repr(C)]
#[derive(Clone, Debug)]
pub struct TypedAllocSlab<Payload> {
slab: AllocSlab,
payload: Payload,
}
impl<Payload: ArenaAllocated> TypedAllocSlab<Payload> {
#[inline]
pub fn to_typed_arena_ptr(&mut self) -> TypedArenaPtr<Payload> {
TypedArenaPtr::new(&mut self.payload as *mut _)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Arena { pub struct Arena {
base: *mut AllocSlab, base: Option<Box<AllocSlab>>,
pub f64_tbl: Arc<F64Table>, pub f64_tbl: Arc<F64Table>,
} }
@@ -712,72 +650,77 @@ impl Arena {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
Arena { Arena {
base: ptr::null_mut(), base: None,
f64_tbl: F64Table::new(), f64_tbl: F64Table::new(),
} }
} }
} }
unsafe fn drop_slab_in_place(value: &mut AllocSlab) { unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
use crate::parser::char_reader::CharReader; macro_rules! drop_typed_slab_in_place {
($payload: ty, $value: expr) => {
let slab: &mut TypedAllocSlab<$payload> = mem::transmute($value);
ptr::drop_in_place(&mut slab.payload);
};
}
match value.header.tag() { match value.header.tag() {
ArenaHeaderTag::Integer => { ArenaHeaderTag::Integer => {
ptr::drop_in_place(value.payload_offset::<Integer>()); drop_typed_slab_in_place!(Integer, value);
} }
ArenaHeaderTag::Rational => { ArenaHeaderTag::Rational => {
ptr::drop_in_place(value.payload_offset::<Rational>()); drop_typed_slab_in_place!(Rational, value);
} }
ArenaHeaderTag::InputFileStream => { ArenaHeaderTag::InputFileStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<InputFileStream>>>()); drop_typed_slab_in_place!(InputFileStream, value);
} }
ArenaHeaderTag::OutputFileStream => { ArenaHeaderTag::OutputFileStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<OutputFileStream>>()); drop_typed_slab_in_place!(OutputFileStream, value);
} }
ArenaHeaderTag::NamedTcpStream => { ArenaHeaderTag::NamedTcpStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTcpStream>>>()); drop_typed_slab_in_place!(NamedTcpStream, value);
} }
ArenaHeaderTag::NamedTlsStream => { ArenaHeaderTag::NamedTlsStream => {
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>()); drop_typed_slab_in_place!(NamedTlsStream, value);
} }
ArenaHeaderTag::HttpReadStream => { ArenaHeaderTag::HttpReadStream => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>()); drop_typed_slab_in_place!(HttpReadStream, value);
} }
ArenaHeaderTag::HttpWriteStream => { ArenaHeaderTag::HttpWriteStream => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>()); drop_typed_slab_in_place!(HttpWriteStream, value);
} }
ArenaHeaderTag::ReadlineStream => { ArenaHeaderTag::ReadlineStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>()); drop_typed_slab_in_place!(ReadlineStream, value);
} }
ArenaHeaderTag::StaticStringStream => { ArenaHeaderTag::StaticStringStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StaticStringStream>>()); drop_typed_slab_in_place!(StaticStringStream, value);
} }
ArenaHeaderTag::ByteStream => { ArenaHeaderTag::ByteStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>()); drop_typed_slab_in_place!(ByteStream, value);
} }
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => { ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
ptr::drop_in_place(value.payload_offset::<LiveLoadState>()); drop_typed_slab_in_place!(LiveLoadState, value);
} }
ArenaHeaderTag::Dropped => {} ArenaHeaderTag::Dropped => {}
ArenaHeaderTag::TcpListener => { ArenaHeaderTag::TcpListener => {
ptr::drop_in_place(value.payload_offset::<TcpListener>()); drop_typed_slab_in_place!(TcpListener, value);
} }
ArenaHeaderTag::HttpListener => { ArenaHeaderTag::HttpListener => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<HttpListener>()); drop_typed_slab_in_place!(HttpListener, value);
} }
ArenaHeaderTag::HttpResponse => { ArenaHeaderTag::HttpResponse => {
#[cfg(feature = "http")] #[cfg(feature = "http")]
ptr::drop_in_place(value.payload_offset::<HttpResponse>()); drop_typed_slab_in_place!(HttpResponse, value);
} }
ArenaHeaderTag::StandardOutputStream => { ArenaHeaderTag::StandardOutputStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>()); drop_typed_slab_in_place!(StandardOutputStream, value);
} }
ArenaHeaderTag::StandardErrorStream => { ArenaHeaderTag::StandardErrorStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>()); drop_typed_slab_in_place!(StandardErrorStream, value);
} }
ArenaHeaderTag::NullStream ArenaHeaderTag::NullStream
| ArenaHeaderTag::IndexPtrUndefined | ArenaHeaderTag::IndexPtrUndefined
@@ -789,44 +732,18 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
impl Drop for Arena { impl Drop for Arena {
fn drop(&mut self) { fn drop(&mut self) {
let mut ptr = self.base; let mut ptr = self.base.take();
while !ptr.is_null() { while let Some(mut slab) = ptr {
unsafe { unsafe {
let ptr_r = &*ptr; drop_slab_in_place(&mut slab);
ptr = slab.next;
let layout = alloc::Layout::from_size_align_unchecked(
ptr_r.slab_size(),
mem::align_of::<AllocSlab>(),
);
drop_slab_in_place(&mut *ptr);
let next_ptr = ptr_r.next;
alloc::dealloc(ptr as *mut u8, layout);
ptr = next_ptr;
} }
} }
self.base = ptr::null_mut();
} }
} }
const_assert!(mem::size_of::<AllocSlab>() == 16); const_assert!(mem::size_of::<AllocSlab>() == 16);
impl AllocSlab {
#[inline]
fn slab_size(&self) -> usize {
self.header.size() as usize + mem::size_of::<AllocSlab>()
}
fn payload_offset<T>(&self) -> *mut T {
// This looks really scary, should this method be marked as unsafe?
// Also, this seems to cause UB.
unsafe { (self as *const AllocSlab).add(1) as *mut T }
}
}
const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8); const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
#[cfg(test)] #[cfg(test)]

View File

@@ -298,9 +298,11 @@ impl IndexStore {
_ => self _ => self
.get_meta_predicate_spec(key.0, key.1, &compilation_target) .get_meta_predicate_spec(key.0, key.1, &compilation_target)
.map(|meta_specs| { .map(|meta_specs| {
meta_specs.iter().find(|meta_spec| match meta_spec { meta_specs.iter().find(|meta_spec| {
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true, matches!(
_ => false, meta_spec,
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
)
}) })
}) })
.map(|meta_spec_opt| meta_spec_opt.is_some()) .map(|meta_spec_opt| meta_spec_opt.is_some())

View File

@@ -455,25 +455,12 @@ macro_rules! arena_allocated_impl_for_stream {
impl ArenaAllocated for StreamLayout<$stream_type> { impl ArenaAllocated for StreamLayout<$stream_type> {
type PtrToAllocated = TypedArenaPtr<StreamLayout<$stream_type>>; type PtrToAllocated = TypedArenaPtr<StreamLayout<$stream_type>>;
gen_ptr_to_allocated!(StreamLayout<$stream_type>);
#[inline] #[inline]
fn tag() -> ArenaHeaderTag { fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::$stream_tag ArenaHeaderTag::$stream_tag
} }
#[inline]
fn size(&self) -> usize {
mem::size_of::<StreamLayout<$stream_type>>()
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
// Miri seems to hit this a lot
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
} }
}; };
} }

View File

@@ -428,16 +428,14 @@ impl BrentAlgState {
pstr_chars = pstr.as_str_from(n).chars().count() - 1; pstr_chars = pstr.as_str_from(n).chars().count() - 1;
if heap[h].get_tag() == HeapCellValueTag::PStrOffset { if heap[h].get_tag() == HeapCellValueTag::PStrOffset && heap[h_offset].get_tag() == HeapCellValueTag::CStr {
if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
return if pstr_chars < max_steps { return if pstr_chars < max_steps {
CycleSearchResult::ProperList(pstr_chars + 1) CycleSearchResult::ProperList(pstr_chars + 1)
} else { } else {
let offset = max_steps as usize + n; let offset = max_steps + n;
CycleSearchResult::PStrLocation(max_steps, h_offset, offset) CycleSearchResult::PStrLocation(max_steps, h_offset, offset)
} }
} }
}
if pstr_chars + 1 > max_steps { if pstr_chars + 1 > max_steps {
return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps); return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps);

View File

@@ -327,12 +327,11 @@ impl<R: Read> Read for CharReader<R> {
return self.inner.read_vectored(bufs); return self.inner.read_vectored(bufs);
} }
let nread = {
self.refresh_buffer()?; self.refresh_buffer()?;
(&self.buf[self.pos..]).read_vectored(bufs)?
};
let nread = (&self.buf[self.pos..]).read_vectored(bufs)?;
self.consume(nread); self.consume(nread);
Ok(nread) Ok(nread)
} }
} }