block: RawBlock<F64Table>,
}
-impl Drop for F64Table {
- fn drop(&mut self) {
- self.block.deallocate();
- }
-}
-
#[cfg(test)]
fn set_f64_tbl_buf_base(ptr: *const u8) {
F64_TABLE_BUF_BASE.with(|f64_table_buf_base| {
use std::mem;
use std::ops::Deref;
use std::ptr;
+use std::ptr::NonNull;
use std::slice;
use std::str;
use std::sync::Arc;
+use std::sync::Mutex;
use std::sync::Weak;
use indexmap::IndexSet;
use modular_bitfield::prelude::*;
-use tokio::runtime::Handle;
-use tokio::sync::OwnedRwLockReadGuard;
use tokio::sync::RwLock;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
}
}
-impl indexmap::Equivalent<Atom> for LookupKey<'_, '_> {
+impl indexmap::Equivalent<Atom> for str {
fn equivalent(&self, key: &Atom) -> bool {
- &*key.as_str_with_table(self.0) == self.1
+ &*key.as_str() == self
}
}
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
const ATOM_TABLE_ALIGN: usize = 8;
-fn global_atom_table() -> &'static RwLock<Weak<RwLock<AtomTable>>> {
+#[inline(always)]
+fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {
#[cfg(feature = "rust_beta_channel")]
{
// const Weak::new will be stabilized in 1.73 which is currently in beta,
// till then we need a OnceLock for initialization
- static GLOBAL_ATOM_TABLE: RwLock<Weak<RwLock<AtomTable>>> = RwLock::const_new(Weak::new());
+ static GLOBAL_ATOM_TABLE: RwLock<Weak<AtomTable>> = RwLock::const_new(Weak::new());
&GLOBAL_ATOM_TABLE
}
#[cfg(not(feature = "rust_beta_channel"))]
{
use std::sync::OnceLock;
- static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<RwLock<AtomTable>>>> = OnceLock::new();
+ static GLOBAL_ATOM_TABLE: OnceLock<RwLock<Weak<AtomTable>>> = OnceLock::new();
GLOBAL_ATOM_TABLE.get_or_init(|| RwLock::new(Weak::new()))
}
}
-fn owned_atom_table_read_guard() -> Option<OwnedRwLockReadGuard<AtomTable>> {
- let atom_table = global_atom_table().blocking_read().upgrade()?;
-
- let guard = {
- // some test don't start a Runtime
- if let Ok(handle) = Handle::try_current() {
- handle.block_on(atom_table.read_owned())
- } else {
- tokio::runtime::Runtime::new()
- .unwrap()
- .block_on(atom_table.read_owned())
- }
- };
- Some(guard)
+#[inline(always)]
+fn arc_atom_table() -> Option<Arc<AtomTable>> {
+ global_atom_table().blocking_read().upgrade()
}
impl RawBlockTraits for AtomTable {
pub enum AtomString<'a> {
Static(&'a str),
- Dynamic(OwnedRwLockReadGuard<AtomTable, str>),
+ Dynamic(AtomTableRef<str>),
}
impl AtomString<'_> {
{
match self {
Self::Static(reference) => Self::Static(f(reference)),
- Self::Dynamic(guard) => Self::Dynamic(OwnedRwLockReadGuard::map(guard, f)),
+ Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
}
}
}
}
impl Atom {
- #[inline]
- pub fn buf(self) -> Option<OwnedRwLockReadGuard<AtomTable, u8>> {
- if let Some(guard) = self.as_ptr() {
- Some(OwnedRwLockReadGuard::map(guard, |ptr| unsafe {
- (ptr as *const u8)
- .offset(mem::size_of::<AtomHeader>() as isize)
- .as_ref()
- .unwrap()
- }))
- } else {
- None
- }
- }
-
#[inline(always)]
pub fn is_static(self) -> bool {
(self.index as usize) < STRINGS.len() << 3
}
#[inline(always)]
- pub fn as_ptr_with_table<'at>(&self, atom_table: &'at AtomTable) -> Option<&'at u8> {
+ pub fn as_ptr(self) -> Option<AtomTableRef<u8>> {
if self.is_static() {
None
} else {
+ let atom_table =
+ arc_atom_table().expect("We should only have an Atom while there is an AtomTable");
unsafe {
- atom_table
- .buf()
- .offset(((self.index as usize) - (STRINGS.len() << 3)) as isize)
- .as_ref()
+ AtomTableRef::try_map(atom_table.buf(), |buf| {
+ (buf as *const u8)
+ .offset(((self.index as usize) - (STRINGS.len() << 3)) as isize)
+ .as_ref()
+ })
}
}
}
- #[inline(always)]
- pub fn as_ptr(self) -> Option<OwnedRwLockReadGuard<AtomTable, u8>> {
- if self.is_static() {
- None
- } else {
- let guard = owned_atom_table_read_guard()
- .expect("We should only have an Atom while there is an AtomTable");
- OwnedRwLockReadGuard::try_map(guard, |atom_table| self.as_ptr_with_table(atom_table))
- .ok()
- }
- }
-
#[inline(always)]
pub fn from(index: u64) -> Self {
Self { index }
}
}
- #[inline(always)]
- pub fn as_str_with_table<'at>(&self, atom_table: &'at AtomTable) -> &'at str {
- if let Some(ptr) = self.as_ptr_with_table(atom_table) {
- let header = unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
- let len = header.len() as usize;
- let buf = (unsafe { (ptr as *const u8).offset(mem::size_of::<AtomHeader>() as isize) })
- as *mut u8;
-
- unsafe { str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) }
- } else {
- &STRINGS[(self.index >> 3) as usize]
- }
- }
-
- #[track_caller]
#[inline]
pub fn as_str(&self) -> AtomString<'static> {
if self.is_static() {
AtomString::Static(STRINGS[(self.index >> 3) as usize])
} else {
- let guard = owned_atom_table_read_guard()
- .expect("We should only have an Atom while there is an AtomTable");
- AtomString::Dynamic(OwnedRwLockReadGuard::map(guard, |atom_table| {
- self.as_str_with_table(atom_table)
- }))
+ if let Some(ptr) = self.as_ptr() {
+ AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| {
+ let header =
+ unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
+ let len = header.len() as usize;
+ let buf = (unsafe {
+ (ptr as *const u8).offset(mem::size_of::<AtomHeader>() as isize)
+ }) as *mut u8;
+
+ unsafe { str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) }
+ }))
+ } else {
+ AtomString::Static(&STRINGS[(self.index >> 3) as usize])
+ }
}
}
- pub fn defrock_brackets(&self, atom_tbl: &Arc<RwLock<AtomTable>>) -> Self {
+ pub fn defrock_brackets(&self, atom_tbl: &AtomTable) -> Self {
let s = self.as_str();
let sub_str = if s.starts_with('(') && s.ends_with(')') {
return *self;
};
- let val = sub_str.to_string();
- drop(s); // wee need to drop s as it holds a read lock on the AtomTable and build_with may need to acquire a write lock
- AtomTable::build_with(&atom_tbl, &val)
+ AtomTable::build_with(&atom_tbl, &sub_str)
}
}
}
}
+pub struct AtomTableRef<M>
+where
+ M: ?Sized,
+{
+ arc: Arc<InnerAtomTable>,
+ data: NonNull<M>,
+}
+
+impl<M> Clone for AtomTableRef<M> {
+ fn clone(&self) -> Self {
+ Self {
+ arc: Arc::clone(&self.arc),
+ data: self.data,
+ }
+ }
+}
+
+impl<M: ?Sized> AtomTableRef<M> {
+ pub fn map<N: ?Sized, F: for<'a> FnOnce(&'a M) -> &'a N>(
+ referece: Self,
+ f: F,
+ ) -> AtomTableRef<N> {
+ AtomTableRef {
+ arc: referece.arc,
+ data: f(unsafe { referece.data.as_ref() }).into(),
+ }
+ }
+
+ pub fn try_map<N, F: for<'a> FnOnce(&'a M) -> Option<&'a N>>(
+ referece: Self,
+ f: F,
+ ) -> Option<AtomTableRef<N>> {
+ let val = f(unsafe { referece.data.as_ref() })?;
+ Some(AtomTableRef {
+ arc: Arc::clone(&referece.arc),
+ data: val.into(),
+ })
+ }
+}
+
+impl<M: ?Sized> Deref for AtomTableRef<M> {
+ type Target = M;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { self.data.as_ref() }
+ }
+}
+
#[derive(Debug)]
-pub struct AtomTable {
+pub struct InnerAtomTable {
block: RawBlock<AtomTable>,
pub table: RwLock<IndexSet<Atom>>,
}
-impl Drop for AtomTable {
- fn drop(&mut self) {
- self.block.deallocate();
- }
+#[derive(Debug)]
+pub struct AtomTable {
+ inner: RwLock<Arc<InnerAtomTable>>,
+ // this lock is taking during resizing
+ update: Mutex<()>,
}
-struct LookupKey<'table, 'key>(&'table AtomTable, &'key str);
-
-impl Hash for LookupKey<'_, '_> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.1.hash(state);
+impl InnerAtomTable {
+ #[inline(always)]
+ fn lookup_str(self: &InnerAtomTable, string: &str) -> Option<Atom> {
+ STATIC_ATOMS_MAP
+ .get(string)
+ .cloned()
+ .or_else(|| self.table.blocking_read().get(string).cloned())
}
}
impl AtomTable {
#[inline]
- pub fn new() -> Arc<RwLock<Self>> {
+ pub fn new() -> Arc<Self> {
let upgraded = global_atom_table().blocking_read().upgrade();
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
if let Some(atom_table) = upgraded {
if let Some(atom_table) = guard.upgrade() {
atom_table
} else {
- let atom_table = Arc::new(RwLock::new(Self {
- block: RawBlock::new(),
- table: RwLock::new(IndexSet::new()),
- }));
+ let atom_table = Arc::new(Self {
+ inner: RwLock::new(Arc::new(InnerAtomTable {
+ block: RawBlock::new(),
+ table: RwLock::new(IndexSet::new()),
+ })),
+ update: Mutex::new(()),
+ });
*guard = Arc::downgrade(&atom_table);
atom_table
}
}
}
- #[inline]
- pub fn buf(&self) -> *const u8 {
- self.block.base as *const u8
+ pub fn active_epoch(&self) -> AtomTableRef<InnerAtomTable> {
+ let arc = Arc::clone(&self.inner.blocking_read());
+ AtomTableRef {
+ data: arc.deref().into(),
+ arc,
+ }
}
#[inline]
- pub fn top(&self) -> *const u8 {
- self.block.top
- }
-
- #[inline(always)]
- fn lookup_str(self: &AtomTable, string: &str) -> Option<Atom> {
- STATIC_ATOMS_MAP.get(string).cloned().or_else(|| {
- self.table
- .blocking_read()
- .get(&LookupKey(self, string))
- .cloned()
+ pub fn buf(&self) -> AtomTableRef<u8> {
+ AtomTableRef::<InnerAtomTable>::map(self.active_epoch(), |inner| {
+ unsafe { inner.block.base.as_ref() }.unwrap()
})
}
- pub fn build_with(atom_table: &RwLock<AtomTable>, string: &str) -> Atom {
- let mut atom_table = loop {
- // we can't just use blocking_write as tokio's RwLock is fair
- // and we can't block readers here as otherwise we will deadlock, see the guard downgrade below
- if let Ok(guard) = atom_table.try_write() {
- break guard;
+ pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
+ loop {
+ let mut epoch = atom_table.active_epoch();
+ let count = epoch.table.blocking_read().len();
+
+ if let Some(atom) = epoch.lookup_str(string) {
+ return atom;
}
- };
- if let Some(atom) = atom_table.lookup_str(string) {
- return atom;
- }
+ let update_guard = atom_table.update.lock().unwrap();
+
+ let is_same_allocation = Arc::ptr_eq(&epoch.arc, &atom_table.active_epoch().arc);
+ let is_same_atom_count = count == epoch.table.blocking_read().len();
+
+ if !(is_same_allocation && is_same_atom_count) {
+ // some other thread raced us between our lookup and us aquring the update lock, try again
+ continue;
+ }
- unsafe {
let size = mem::size_of::<AtomHeader>() + string.len();
let align_offset = 8 * mem::align_of::<AtomHeader>();
let size = (size & !(align_offset - 1)) + align_offset;
- let len_ptr = loop {
- let ptr = atom_table.block.alloc(size);
-
- if ptr.is_null() {
- atom_table.block.grow();
- } else {
- break ptr;
- }
- };
+ unsafe {
+ let len_ptr = loop {
+ let ptr = epoch.block.alloc(size);
- let ptr_base = atom_table.block.base as usize;
+ if ptr.is_null() {
+ let new_block = epoch.block.grow_new().unwrap();
+ let new_table = RwLock::new(epoch.table.blocking_read().clone());
+ let new_alloc = Arc::new(InnerAtomTable {
+ block: new_block,
+ table: new_table,
+ });
+ *atom_table.inner.blocking_write() = new_alloc;
+ epoch = atom_table.active_epoch();
+ } else {
+ break ptr;
+ }
+ };
- write_to_ptr(string, len_ptr);
+ let ptr_base = epoch.block.base as usize;
- let atom = Atom {
- index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
- };
+ write_to_ptr(string, len_ptr);
- // we need to downgrade to a read so that Atom::hash can read from the AtomTable,
- // so that it can calculate the hash for inserting the atom
- // we can't just drop the guard as otherwise another thread could race us with another atom insertion
- let atom_table = atom_table.downgrade();
+ let atom = Atom {
+ index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
+ };
- // NOTE: there is no race between downgrade and blocking write as table is only accessed writable in this function
- // and only after the write lock is acquired as we have the guard and just convert it from a write to a read guard no writer can race us
- atom_table.table.blocking_write().insert(atom);
+ epoch.table.blocking_write().insert(atom);
- drop(atom_table); // we need to keep the guard around till after the insert
+ drop(update_guard);
- atom
+ return atom;
+ }
}
}
}
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
-use tokio::sync::RwLock;
-
use std::cell::Cell;
use std::collections::VecDeque;
#[derive(Debug)]
pub(crate) struct CodeGenerator<'a> {
- pub(crate) atom_tbl: &'a RwLock<AtomTable>,
+ pub(crate) atom_tbl: &'a AtomTable,
marker: DebrayAllocator,
settings: CodeGenSettings,
pub(crate) skeleton: PredicateSkeleton,
}
impl<'b> CodeGenerator<'b> {
- pub(crate) fn new(atom_tbl: &'b RwLock<AtomTable>, settings: CodeGenSettings) -> Self {
+ pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
CodeGenerator {
atom_tbl,
marker: DebrayAllocator::new(),
use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
-use tokio::sync::RwLock;
-
use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
impl AtomOrString {
#[inline]
- pub fn as_atom(&self, atom_tbl: &RwLock<AtomTable>) -> Atom {
+ pub fn as_atom(&self, atom_tbl: &AtomTable) -> Atom {
match self {
&AtomOrString::Atom(atom) => atom,
AtomOrString::String(string) => AtomTable::build_with(atom_tbl, &string),
use indexmap::IndexMap;
-use tokio::sync::RwLock;
-
use std::cell::Cell;
use std::convert::TryFrom;
use std::iter::once;
pub struct HCPrinter<'a, Outputter> {
outputter: Outputter,
iter: StackfulPreOrderHeapIter<'a>,
- atom_tbl: Arc<RwLock<AtomTable>>,
+ atom_tbl: Arc<AtomTable>,
op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>,
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new(
heap: &'a mut Heap,
- atom_tbl: Arc<RwLock<AtomTable>>,
+ atom_tbl: Arc<AtomTable>,
stack: &'a mut Stack,
op_dir: &'a OpDir,
output: Outputter,
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
-use tokio::sync::RwLock;
use std::collections::VecDeque;
use std::hash::Hash;
pub(crate) fn constant_key_alternatives(
constant: Literal,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
// arena: &mut Arena,
) -> Vec<Literal> {
let mut constants = vec![];
fn index_constant(
&mut self,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
constant: Literal,
index: usize,
) -> Vec<Literal> {
optimal_arg: &Term,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) {
match optimal_arg {
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
HeapCellValueTag::StackVar |
HeapCellValueTag::Var) => {
let target_cell = self.machine_st.push_str_to_heap(
- string.as_str(),
+ &string.as_str(),
has_tail,
);
-use tokio::sync::RwLock;
-
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
}
#[inline]
-pub(crate) fn put_complete_string(
- heap: &mut Heap,
- s: &str,
- atom_tbl: &RwLock<AtomTable>,
-) -> HeapCellValue {
+pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
}
#[inline]
-pub(crate) fn put_partial_string(
- heap: &mut Heap,
- s: &str,
- atom_tbl: &RwLock<AtomTable>,
-) -> HeapCellValue {
+pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
match allocate_pstr(heap, s, atom_tbl) {
Some(h) => {
pstr_loc_as_cell!(h)
}
#[inline]
-pub(crate) fn allocate_pstr(
- heap: &mut Heap,
- mut src: &str,
- atom_tbl: &RwLock<AtomTable>,
-) -> Option<usize> {
+pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option<usize> {
let orig_h = heap.len();
loop {
use crate::parser::dashu::Integer;
use indexmap::IndexMap;
-use tokio::sync::RwLock;
use std::convert::TryFrom;
use std::fmt;
}
pub struct MachineState {
- pub atom_tbl: Arc<RwLock<AtomTable>>,
+ pub atom_tbl: Arc<AtomTable>,
pub arena: Arena,
pub(super) pdl: Vec<HeapCellValue>,
pub(super) s: HeapPtr,
fn push_var_eq_functors<'a>(
heap: &mut Heap,
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![];
-use tokio::sync::RwLock;
-
use crate::atom_table::*;
use crate::parser::ast::*;
impl PartialString {
#[inline]
- pub(super) fn new<'a>(src: &'a str, atom_tbl: &RwLock<AtomTable>) -> Option<(Self, &'a str)> {
+ pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> {
let terminator_idx = scan_for_terminator(src.chars());
let pstr = PartialString(AtomTable::build_with(&atom_tbl, &src[..terminator_idx]));
Some(if terminator_idx < src.as_bytes().len() {
use crate::parser::ast::*;
use indexmap::IndexSet;
-use tokio::sync::RwLock;
use std::cell::Cell;
use std::convert::TryFrom;
}
}
-fn setup_op_decl(
- mut terms: Vec<Term>,
- atom_tbl: &RwLock<AtomTable>,
-) -> Result<OpDecl, CompilationError> {
+fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
let name = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
fn setup_module_export(
mut term: Term,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
pub(super) fn setup_module_export_list(
mut export_list: Term,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
fn setup_module_decl(
mut terms: Vec<Term>,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Result<ModuleDecl, CompilationError> {
let export_list = terms.pop().unwrap();
let name = terms.pop().unwrap();
fn setup_qualified_import(
mut terms: Vec<Term>,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Result<UseModuleExport, CompilationError> {
let mut export_list = terms.pop().unwrap();
let module_src = match terms.pop().unwrap() {
_marker: PhantomData<HeapCellValue>,
}
-impl Drop for Stack {
- fn drop(&mut self) {
- self.buf.deallocate();
- }
-}
-
#[derive(Debug)]
pub(crate) struct AndFramePrelude {
pub(crate) num_cells: usize,
let frame_size = AndFrame::size_of(num_cells);
unsafe {
- let e = self.buf.ptr as usize - self.buf.base as usize;
+ let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<AndFramePrelude>();
let frame_size = OrFrame::size_of(num_cells);
unsafe {
- let b = self.buf.ptr as usize - self.buf.base as usize;
+ let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<OrFramePrelude>();
pub(crate) fn truncate(&mut self, b: usize) {
let base = self.buf.base as usize + b;
- if base < self.buf.ptr as usize {
- self.buf.ptr = base as *mut _;
+ if base < (*self.buf.ptr.get_mut()) as usize {
+ *self.buf.ptr.get_mut() = base as *mut _;
}
}
}
use indexmap::IndexMap;
use modular_bitfield::error::OutOfBounds;
use modular_bitfield::prelude::*;
-use tokio::sync::RwLock;
pub type Specifier = u32;
}
impl Literal {
- pub fn to_atom(&self, atom_tbl: &Arc<RwLock<AtomTable>>) -> Option<Atom> {
+ pub fn to_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
match self {
Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
_ => None,
use dashu::Integer;
use dashu::Rational;
-use tokio::sync::RwLock;
use crate::arena::*;
use crate::atom_table::*;
Ok(tokens)
}
-fn atomize_term(atom_tbl: &RwLock<AtomTable>, term: &Term) -> Option<Atom> {
+fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
match term {
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
_ => None,
}
}
-fn atomize_constant(atom_tbl: &RwLock<AtomTable>, c: Literal) -> Option<Atom> {
+fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
match c {
Literal::Atom(ref name) => Some(*name),
Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
use core::marker::PhantomData;
use std::alloc;
+use std::cell::UnsafeCell;
use std::ptr;
pub trait RawBlockTraits {
pub struct RawBlock<T: RawBlockTraits> {
pub base: *const u8,
pub top: *const u8,
- pub ptr: *mut u8,
+ pub ptr: UnsafeCell<*mut u8>,
_marker: PhantomData<T>,
}
RawBlock {
base: ptr::null(),
top: ptr::null(),
- ptr: ptr::null_mut(),
+ ptr: UnsafeCell::new(ptr::null_mut()),
_marker: PhantomData,
}
}
self.base = alloc::alloc(layout) as *const _;
self.top = (self.base as usize + cap) as *const _;
- self.ptr = self.base as *mut _;
+ *self.ptr.get_mut() = self.base as *mut _;
}
pub unsafe fn grow(&mut self) {
self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
self.top = (self.base as usize + size * 2) as *const _;
- self.ptr = (self.base as usize + size) as *mut _;
+ *self.ptr.get_mut() = (self.base as usize + size) as *mut _;
+ }
+ }
+
+ pub unsafe fn grow_new(&self) -> Option<Self> {
+ if self.base.is_null() {
+ Some(Self::new())
+ } else {
+ let mut new_block = Self::empty_block();
+ new_block.init_at_size(self.size() * 2);
+ if new_block.base.is_null() {
+ // allocation failed
+ None
+ } else {
+ let allocated = (*self.ptr.get()) as usize - self.base as usize;
+ self.base.copy_to(new_block.base.cast_mut(), allocated);
+ *new_block.ptr.get_mut() = new_block.base.offset(allocated as isize).cast_mut();
+ Some(new_block)
+ }
}
}
}
#[inline(always)]
- fn free_space(&self) -> usize {
+ unsafe fn free_space(&self) -> usize {
debug_assert!(
- self.ptr as *const _ >= self.base,
+ *self.ptr.get() as *const _ >= self.base,
"self.ptr = {:?} < {:?} = self.base",
- self.ptr,
+ *self.ptr.get(),
self.base
);
- self.top as usize - self.ptr as usize
+ self.top as usize - (*self.ptr.get()) as usize
}
- pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 {
+ pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
if self.free_space() >= size {
- let ptr = self.ptr;
- self.ptr = (self.ptr as usize + size) as *mut _;
+ let ptr = *self.ptr.get();
+ *self.ptr.get() = (ptr as usize + size) as *mut _;
ptr
} else {
ptr::null_mut()
}
}
+}
- pub fn deallocate(&mut self) {
- unsafe {
- let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
- alloc::dealloc(self.base as *mut _, layout);
+impl<T: RawBlockTraits> Drop for RawBlock<T> {
+ fn drop(&mut self) {
+ if !self.base.is_null() {
+ unsafe {
+ let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
+ alloc::dealloc(self.base as *mut _, layout);
+ }
self.top = ptr::null();
self.base = ptr::null();
- self.ptr = ptr::null_mut();
+ *self.ptr.get_mut() = ptr::null_mut();
}
}
}
use fxhash::FxBuildHasher;
-use tokio::sync::RwLock;
-
-use std::sync::Arc;
-
#[cfg(feature = "repl")]
use rustyline::error::ReadlineError;
#[cfg(feature = "repl")]
use std::collections::VecDeque;
use std::io::{Cursor, Error, ErrorKind, Read};
+use std::sync::Arc;
type SubtermDeque = VecDeque<(usize, usize)>;
}
}
- pub fn set_atoms_for_completion(&mut self, atoms: &Arc<RwLock<AtomTable>>) {
+ pub fn set_atoms_for_completion(&mut self, atoms: &Arc<AtomTable>) {
#[cfg(feature = "repl")]
{
let helper = self.rl.helper_mut().unwrap();
pub(crate) fn write_term_to_heap<'a, 'b>(
term: &'a Term,
heap: &'b mut Heap,
- atom_tbl: &RwLock<AtomTable>,
+ atom_tbl: &AtomTable,
) -> Result<TermWriteResult, CompilationError> {
let term_writer = TermWriter::new(heap, atom_tbl);
term_writer.write_term_to_heap(term)
#[derive(Debug)]
struct TermWriter<'a, 'b> {
heap: &'a mut Heap,
- atom_tbl: &'b RwLock<AtomTable>,
+ atom_tbl: &'b AtomTable,
queue: SubtermDeque,
var_dict: HeapVarDict,
}
impl<'a, 'b> TermWriter<'a, 'b> {
#[inline]
- fn new(heap: &'a mut Heap, atom_tbl: &'b RwLock<AtomTable>) -> Self {
+ fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
TermWriter {
heap,
atom_tbl,
use rustyline::validate::Validator;
use rustyline::{Context, Helper as RlHelper, Result};
-use tokio::sync::RwLock;
-
use std::sync::Weak;
use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP};
// TODO: Maybe add validation to the helper
pub struct Helper {
highligher: MatchingBracketHighlighter,
- pub atoms: Weak<RwLock<AtomTable>>,
+ pub atoms: Weak<AtomTable>,
}
impl Helper {
let sub_str = line.get(idx..pos).unwrap();
let atom_table = self.atoms.upgrade().unwrap();
- let guard = atom_table.blocking_read();
- let mut matching = guard
- .table
- .blocking_read()
+ let index_set = atom_table.active_epoch().table.blocking_read().clone();
+
+ let mut matching = index_set
.iter()
.chain(STATIC_ATOMS_MAP.values())
.map(|a| a.as_str())