mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 10:25:02 +01:00
start with gc
This commit is contained in:
parent
5e66841577
commit
e66cd52861
1 changed files with 82 additions and 0 deletions
82
src/value.rs
82
src/value.rs
|
|
@ -1,9 +1,91 @@
|
||||||
|
use std::collections::LinkedList;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
/// imagine interning or something here
|
/// imagine interning or something here
|
||||||
pub type Symbol = String;
|
pub type Symbol = String;
|
||||||
|
|
||||||
|
/// here is the actual interning or something
|
||||||
|
pub type NewSym = Gc<str>;
|
||||||
|
|
||||||
#[cfg(not(feature = "fxhash"))]
|
#[cfg(not(feature = "fxhash"))]
|
||||||
#[allow(clippy::disallowed_type)]
|
#[allow(clippy::disallowed_type)]
|
||||||
pub type HashMap<K, V> = std::collections::HashMap<K, V>;
|
pub type HashMap<K, V> = std::collections::HashMap<K, V>;
|
||||||
|
|
||||||
#[cfg(feature = "fxhash")]
|
#[cfg(feature = "fxhash")]
|
||||||
pub type HashMap<K, V> = rustc_hash::FxHashMap<K, V>;
|
pub type HashMap<K, V> = rustc_hash::FxHashMap<K, V>;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "fxhash"))]
|
||||||
|
#[allow(clippy::disallowed_type)]
|
||||||
|
pub type HashSet<T> = std::collections::HashSet<T>;
|
||||||
|
|
||||||
|
#[cfg(feature = "fxhash")]
|
||||||
|
pub type HashSet<T> = rustc_hash::FxHashSet<T>;
|
||||||
|
|
||||||
|
/// A pointer to a garbage collected value. This pointer *must* always be valid, and a value
|
||||||
|
/// is only allowed to be freed once no Gc is pointing at it anymore. This is achieved through
|
||||||
|
/// tracing through all objects from a few known roots and marking every reachable value. All other
|
||||||
|
/// values will be swept.
|
||||||
|
pub struct Gc<T: ?Sized> {
|
||||||
|
ptr: NonNull<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Deref for Gc<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
// SAFETY: Gc will always point to a valid T, since T will only be freed once all Gc are gone
|
||||||
|
// This requires tracing through *all* roots without forgetting any
|
||||||
|
// I would guess that there will be some errors with the garbage collector, but once they are
|
||||||
|
// all fixed this will be sound. But who knows.
|
||||||
|
unsafe { &*self.ptr.as_ptr() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug + ?Sized> Debug for Gc<T> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
T::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Clone for Gc<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { ..*self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Copy for Gc<T> {}
|
||||||
|
|
||||||
|
enum Object {
|
||||||
|
String(Gc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RtAlloc {
|
||||||
|
symbols: HashSet<NonNull<str>>,
|
||||||
|
objects: LinkedList<Object>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RtAlloc {
|
||||||
|
pub fn alloc_str(&mut self, str: &str) -> Gc<str> {
|
||||||
|
let ptr = Box::into_raw(str.to_owned().into_boxed_str());
|
||||||
|
// SAFETY: Box cannot be null
|
||||||
|
let new_nonnull = unsafe { NonNull::new_unchecked(ptr) };
|
||||||
|
let gc = Gc { ptr: new_nonnull };
|
||||||
|
let object = Object::String(gc.clone());
|
||||||
|
|
||||||
|
self.objects.push_back(object);
|
||||||
|
|
||||||
|
gc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intern_string(&mut self, str: &str) -> NewSym {
|
||||||
|
let original_nonnull = NonNull::from(str);
|
||||||
|
|
||||||
|
if let Some(interned) = self.symbols.get(&original_nonnull) {
|
||||||
|
return Gc { ptr: *interned };
|
||||||
|
}
|
||||||
|
|
||||||
|
self.alloc_str(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue