Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions compiler/pipec-arena-structures/src/adynlist.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use pipec_arena::{ASpan, Arena};

#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone, Copy, Default, Hash)]
pub enum ListNode<T> {
#[default]
Empty,
Node(T, ASpan<Self>),
}

#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub struct ADynList<T> {
first: ASpan<ListNode<T>>,
mutate: ASpan<ListNode<T>>,
Expand All @@ -24,10 +24,10 @@ where
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self.arena.take(self.current.clone()) {
match self.arena.take(self.current) {
ListNode::Empty => None,
ListNode::Node(current, next) => {
self.current = next.clone();
self.current = *next;
Some(current.clone())
}
}
Expand All @@ -36,24 +36,24 @@ where

impl<T> ADynList<T> {
pub fn push(&mut self, input: T, arena: &mut Arena) {
let handle = arena.take(self.mutate.clone());
let handle = arena.take(self.mutate);
let empty = arena.alloc(ListNode::Empty);
*handle = ListNode::Node(input, empty.clone());
*handle = ListNode::Node(input, empty);
self.mutate = empty
}
pub fn new(arena: &mut Arena) -> Self {
let out = arena.alloc(ListNode::Empty);
ADynList {
first: out.clone(),
first: out,
mutate: out,
}
}
pub fn first(&self, arena: &mut Arena) -> &mut ListNode<T> {
arena.take(self.first.clone())
arena.take(self.first)
}
pub fn iter<'a>(&'a self, arena: &'a Arena) -> ADynListIter<'a, T> {
ADynListIter {
current: self.first.clone(),
current: self.first,
arena,
}
}
Expand Down
98 changes: 35 additions & 63 deletions compiler/pipec-arena-structures/src/astring.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,47 @@
use core::cmp::PartialEq;
use core::ops::Deref;
use std::fmt::Display;
use std::mem::MaybeUninit;
use pipec_arena::{ABytes, ASlice, Arena};

#[derive(Debug, Clone)]
pub struct AString<const SIZE: usize> {
buf: [u8; SIZE],
pub struct AString {
buf: ASlice<ABytes>,
index: usize,
pub capacity: usize,
}

impl<const SIZE: usize> AString<SIZE> {
impl AString {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
#[allow(clippy::uninit_assumed_init)]
pub fn with_capacity(capacity: usize, arena: &mut Arena) -> Self {
let buf = unsafe { arena.alloc_empty(capacity) };
Self {
buf: unsafe { MaybeUninit::uninit().assume_init() },
buf,
index: 0,
capacity,
}
}

pub fn push(&mut self, input: char) -> Result<(), AStringError> {
pub fn push(&mut self, input: char, arena: &mut Arena) -> Result<(), AStringError> {
let mut buf = [0u8; 4];
let char_len = input.encode_utf8(&mut buf).len();
if self.index + char_len > SIZE {
if self.index + char_len > self.capacity {
return Err(AStringError::BufFilled);
}
self.buf[self.index..self.index + char_len].copy_from_slice(&buf[..char_len]);
let abuf = arena.take_slice(self.buf);
abuf[self.index..self.index + char_len].copy_from_slice(&buf[..char_len]);
self.index += char_len;
Ok(())
}

pub fn push_str(&mut self, input: &str) -> Result<(), AStringError> {
pub fn push_str(&mut self, input: &str, arena: &mut Arena) -> Result<(), AStringError> {
let len = input.len();
if self.index + input.len() > SIZE {
if self.index + input.len() > self.capacity {
return Err(AStringError::BufFilled);
}
self.buf[self.index..self.index + len].copy_from_slice(input.as_bytes());
arena.take_slice(self.buf)[self.index..self.index + len].copy_from_slice(input.as_bytes());
self.index += len;
Ok(())
}

pub fn as_str(&self) -> &str {
self
}
}

impl<const SIZE: usize> Display for AString<SIZE> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.deref())
}
}

impl<const SIZE: usize> PartialEq for AString<SIZE> {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}

impl<const SIZE: usize> PartialEq<AString<SIZE>> for str {
fn eq(&self, other: &AString<SIZE>) -> bool {
other.deref() == self
}
}

impl<const SIZE: usize> PartialEq<str> for AString<SIZE> {
fn eq(&self, other: &str) -> bool {
self.deref() == other
}
}

impl<const SIZE: usize> Deref for AString<SIZE> {
type Target = str;
fn deref(&self) -> &Self::Target {
unsafe { str::from_utf8_unchecked(&self.buf[..self.index]) }
pub fn as_str(&self, arena: &mut Arena) -> &str {
unsafe { str::from_utf8_unchecked(&arena.take_slice(self.buf)[..self.index]) }
}
}

Expand All @@ -84,26 +53,29 @@ pub enum AStringError {
#[cfg(test)]
mod tests {
use super::*;
use pipec_arena::Size;
#[test]
fn test_str() -> Result<(), AStringError> {
let mut string = AString::<100>::new();
string.push('h')?;
string.push('e')?;
string.push('l')?;
string.push('l')?;
string.push('o')?;
string.push_str(" world!")?;
println!("{}", &string);
assert_eq!("hello world!", &string);
let mut arena = Arena::new(Size::Megs(2));
let mut string = AString::with_capacity(100, &mut arena);
string.push('h', &mut arena)?;
string.push('e', &mut arena)?;
string.push('l', &mut arena)?;
string.push('l', &mut arena)?;
string.push('o', &mut arena)?;
string.push_str(" world!", &mut arena)?;
let as_str = string.as_str(&mut arena);
assert_eq!("hello world!", as_str);
Ok(())
}
#[test]
fn different_size_same_contents() -> Result<(), AStringError> {
let mut s1 = AString::<100>::new();
let mut s2 = AString::<50>::new();
s1.push_str("hello world!")?;
s2.push_str("hello world!")?;
assert_eq!(s1.as_str(), s2.as_str());
let mut arena = Arena::new(Size::Megs(2));
let mut s1 = AString::with_capacity(100, &mut arena);
let mut s2 = AString::with_capacity(50, &mut arena);
s1.push_str("hello world!", &mut arena)?;
s2.push_str("hello world!", &mut arena)?;
assert_eq!(s1.as_str(&mut arena), s2.as_str(&mut arena));
Ok(())
}
}
45 changes: 38 additions & 7 deletions compiler/pipec-arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub struct ASlice<T> {
pub(crate) end: usize,
}

/// Compiler can't "know" the size of ASlice<[u8]>, so this is for api convenience.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ABytes;
/// Compiler can't "know" the size of ASlice<str>, so this is for api convenience.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AStr;

impl<T> Clone for ASlice<T> {
fn clone(&self) -> Self {
*self
Expand Down Expand Up @@ -66,21 +73,34 @@ impl<T> ASlice<T> {

/// An "owned pointer" the arena returns after you do an allocation with it.
/// Lifetimes are a mess to deal with so returning a struct like this instead of say &'a mut T is easier
#[derive(Debug, Copy)]
#[derive(Debug)]
pub struct ASpan<T> {
_marker: PhantomData<T>,
pub(crate) val: usize,
}

impl<T> std::hash::Hash for ASpan<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_usize(self.val);
}
}

impl<T> PartialEq for ASpan<T> {
fn eq(&self, other: &Self) -> bool {
self.val == other.val
}
}

impl<T> Eq for ASpan<T> {}

impl<T> Clone for ASpan<T> {
fn clone(&self) -> Self {
Self {
_marker: PhantomData,
val: self.val,
}
*self
}
}

impl<T> Copy for ASpan<T> {}

impl<T> ASpan<T> {
pub(crate) fn new(input: usize) -> Self {
Self {
Expand Down Expand Up @@ -130,6 +150,17 @@ impl Arena {
}
}

/// Allocates an empty memory region given a size.
/// # Safety
/// The returned data will be empty. Yeah
pub unsafe fn alloc_empty(&mut self, size: usize) -> ASlice<ABytes> {
unsafe {
let bump = self.bump;
self.bump += size;
ASlice::from_raw_parts(bump, self.bump)
}
}

/// Takes an ASpan<T> and turns it into a &mut T.
pub fn take<'b, T>(&self, input: ASpan<T>) -> &'b mut T {
unsafe {
Expand All @@ -139,7 +170,7 @@ impl Arena {
}

/// Takes an ASlice<&[u8]> and turns it into a &mut [u8].
pub fn take_slice<'b>(&self, input: ASlice<&[u8]>) -> &'b mut [u8] {
pub fn take_slice<'b>(&self, input: ASlice<ABytes>) -> &'b mut [u8] {
unsafe {
let ptr = self.data.as_ptr().add(input.start) as *mut u8;

Expand All @@ -149,7 +180,7 @@ impl Arena {
}

/// Takes an ASlice<String> and turns it into a &mut str.
pub fn take_str_slice<'b>(&self, input: ASlice<String>) -> &'b str {
pub fn take_str_slice<'b>(&self, input: ASlice<AStr>) -> &'b str {
unsafe {
let ptr = self.data.as_ptr().add(input.start) as *mut u8;

Expand Down
6 changes: 3 additions & 3 deletions compiler/pipec-ast/src/ast/asttree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ impl ASTTree {
}
}
pub fn current_node(&mut self, arena: &mut Arena) -> Option<&ASTNode> {
let handle = arena.take(self.stream.clone());
let handle = arena.take(self.stream);
handle.get(self.pos)
}
pub fn next_node(&mut self, arena: &mut Arena) -> Option<ASTNode> {
let handle = arena.take(self.stream.clone());
let handle = arena.take(self.stream);
self.pos += 1;
handle.get(self.pos - 1).cloned()
}
pub fn peek(&mut self, arena: &mut Arena) -> Option<&ASTNode> {
let handle = arena.take(self.stream.clone());
let handle = arena.take(self.stream);
handle.get(self.pos)
}
// pub fn from_vec(vec: Vec<ASTNode>) -> Self {
Expand Down
Loading