Skip to content
Open
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
2 changes: 1 addition & 1 deletion std.zc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import "./std/time.zc"
import "./std/result.zc"
import "./std/option.zc"
import "./std/map.zc"
import "./std/json.zc"
//import "./std/json.zc"
import "./std/path.zc"
import "./std/mem.zc"
import "./std/stack.zc"
Expand Down
117 changes: 117 additions & 0 deletions std/debug.zc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import "mem.zc"
import "vec.zc"

// Pretty rough implementation.
// Should be improved with a Map<usize, usize> when available.
struct DebugAllocator {
addrs: Vec<usize>,
sizes: Vec<usize>
}

impl DebugAllocator {

fn new() -> Self {

// Yep, both vectors will be stored on the general allocator, and that should be fine.
return Self {
addrs: Vec<usize>::new(),
sizes: Vec<usize>::new()
}
}

fn validate(self) -> bool {
if (self.addrs.length() == 0) {
println "No memory leaked.";
return true;
}

var total_size: usize = 0;

for i in 0..self.sizes.length() {
total_size += self.sizes.get(i);
}

println "{self.addrs.length()} allocations remaining, with a total size of {total_size} bytes.";
return false;
}


// --- Internal functions

fn add_addr(self, addr: usize, size: usize) {
self.addrs.push(addr);
self.sizes.push(size);
}

fn remove_addr(self, addr: usize) {
var index: isize = -1

for i in 0..self.addrs.length() {
if (self.addrs.get(i) == addr) {
index = i;
break;
}
}

if (index == -1) {
!"Panic: attempt to free an unallocated value.";
exit(1);
}

self.addrs.remove(index);
self.sizes.remove(index);
}
}

impl Allocator for DebugAllocator {

fn allocate(self, size: usize) -> u8* {
var addr: usize;

raw {
addr = (size_t) malloc(size);
}

self.add_addr(addr, size);

return (u8*) addr;
}

fn zeroed(self, size: usize) -> u8* {
var addr: usize;

raw {
addr = (size_t) calloc(1, size);
}

self.add_addr(addr, size);

return (u8*) addr;
}

fn reallocate(self, ptr: u8*, new_size: usize) -> u8* {
var addr: usize;

raw {
addr = (size_t) realloc(ptr, new_size);
}

if (addr != 0) {
if ((usize) ptr != 0) { // realloc allows ptr to be 0, it behaves like malloc.
self.remove_addr((usize) ptr);
}

self.add_addr(addr, new_size);
}

return (u8*) addr;
}

fn free(self, ptr: u8*) {
self.remove_addr((usize) ptr);

raw {
free(ptr);
}
}
}
5 changes: 3 additions & 2 deletions std/json.zc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct JsonValue {
alias JsonValuePtr = JsonValue*;

raw {
Vec_JsonValuePtr Vec_JsonValuePtr__new();
Vec_JsonValuePtr Vec_JsonValuePtr__new(Allocator allocator);
void Vec_JsonValuePtr__push(Vec_JsonValuePtr* self, JsonValue* item);
Map_JsonValuePtr Map_JsonValuePtr__new();
void Map_JsonValuePtr__put(Map_JsonValuePtr* self, char* key, JsonValue* val);
Expand Down Expand Up @@ -71,7 +71,8 @@ raw {
arr->kind = JsonType_JSON_ARRAY();
arr->string_val = 0; arr->number_val = 0; arr->bool_val = 0; arr->object_val = 0;
arr->array_val = malloc(sizeof(Vec_JsonValuePtr));
*(arr->array_val) = Vec_JsonValuePtr__new();
*(arr->array_val) = Vec_JsonValuePtr__new((Allocator){
.self = (&GLOBAL_ALLOCATOR), .vtable = (&GeneralAllocator_Allocator_VTable)});

_json_skip_ws(p);
if (**p == ']') { (*p)++; return arr; }
Expand Down
99 changes: 98 additions & 1 deletion std/mem.zc
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
trait Allocator {
fn allocate(self, size: usize) -> u8*;
fn zeroed(self, size: usize) -> u8*; // Change to allocate_zeroed when it's possible use underscores
fn reallocate(self, ptr: u8*, new_size: usize) -> u8*;
fn free(self, ptr: u8*);
}

struct GeneralAllocator {}

impl Allocator for GeneralAllocator {
fn allocate(self, size: usize) -> u8* {
raw {
return (uint8_t*) malloc(size);
}
}

fn zeroed(self, size: usize) -> u8* {
raw {
return (uint8_t*) calloc(1, size);
}
}

fn reallocate(self, ptr: u8*, new_size: usize) -> u8* {
raw {
return (uint8_t*) realloc(ptr, new_size);
}
}

fn free(self, ptr: u8*) {
raw {
return free(ptr);
}
}
}

var GLOBAL_ALLOCATOR: GeneralAllocator;

@deprecated("Replaced with `Allocator::alloc`")
fn alloc<T>() -> T* {
return (T*)malloc(sizeof(T));
}

@deprecated("Replaced with `Allocator`")
fn zalloc<T>() -> T* {
return (T*)calloc(1, sizeof(T));
}

@deprecated("Replaced with `Allocator`")
fn alloc_n<T>(n: usize) -> T* {
return (T*)malloc(sizeof(T) * n);
}
Expand Down Expand Up @@ -34,9 +73,17 @@ impl Box<T> {
return Self { ptr: p };
}

fn get(self) -> T* {
fn get_ptr(self) -> T* {
return self.ptr;
}

fn set(self, val: T) {
*self.ptr = val;
}

fn get(self) -> T {
return *self.ptr;
}

fn is_null(self) -> bool {
return self.ptr == NULL;
Expand All @@ -45,6 +92,56 @@ impl Box<T> {
fn free(self) {
if self.ptr != NULL {
free(self.ptr);
self.ptr = NULL;
}
}
}

impl Drop for Box<T> {
fn drop(self) {
self.free();
}
}


struct RcInner<T> {
value: T;
ref_count: usize;
}

struct Rc<T> {
inner: RcInner<T>*;
}

impl Rc<T> {
fn new(value: T) -> Self {
var inner: RcInner<T>* = GLOBAL_ALLOCATOR.allocate(sizeof(RcInner<T>));

inner.value = value;
inner.ref_count = 1;

return Self {
inner: inner
};
}
}

impl Clone for Rc<T> {
fn clone(self) -> Self {
self.inner.ref_count++;

return Self {
inner: self.inner
};
}
}

impl Drop for Rc<T> {
fn drop(self) {
self.inner.ref_count--;

if (self.inner.ref_count == 0) {
GLOBAL_ALLOCATOR.free(self.inner);
}
}
}
Expand Down
Loading