refcount details of builtins

This commit is contained in:
Folkert 2021-02-19 17:13:09 +01:00
parent 9e2c1b750f
commit 17fddaf0dd
7 changed files with 50 additions and 20 deletions

View file

@ -296,6 +296,10 @@ pub const RocDict = extern struct {
}
fn getKey(self: *const RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize) Opaque {
if (key_width == 0) {
return null;
}
const offset = blk: {
if (alignment.keyFirst()) {
break :blk (index * key_width);
@ -329,6 +333,10 @@ pub const RocDict = extern struct {
}
fn getValue(self: *const RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize) Opaque {
if (value_width == 0) {
return null;
}
const offset = blk: {
if (alignment.keyFirst()) {
break :blk (self.capacity() * key_width) + (index * value_width);
@ -492,6 +500,8 @@ pub fn dictRemove(input: RocDict, alignment: Alignment, key: Opaque, key_width:
if (dict.dict_entries_len == 0) {
const data_bytes = dict.capacity() * slotSize(key_width, value_width);
decref(std.heap.c_allocator, alignment, dict.dict_bytes, data_bytes);
output.* = RocDict.empty();
return;
}
output.* = dict;
@ -660,6 +670,7 @@ pub fn dictUnion(dict1: RocDict, dict2: RocDict, alignment: Alignment, key_width
// we need an extra RC token for the key
inc_key(key);
inc_value(value);
const dec_key = doNothing;
const dec_value = doNothing;
@ -702,7 +713,7 @@ pub fn dictIntersection(dict1: RocDict, dict2: RocDict, alignment: Alignment, ke
}
}
pub fn dictDifference(dict1: RocDict, dict2: RocDict, alignment: Alignment, key_width: usize, value_width: usize, hash_fn: HashFn, is_eq: EqFn, dec_key: Inc, dec_value: Inc, output: *RocDict) callconv(.C) void {
pub fn dictDifference(dict1: RocDict, dict2: RocDict, alignment: Alignment, key_width: usize, value_width: usize, hash_fn: HashFn, is_eq: EqFn, dec_key: Dec, dec_value: Dec, output: *RocDict) callconv(.C) void {
output.* = dict1.makeUnique(std.heap.c_allocator, alignment, key_width, value_width);
var i: usize = 0;
@ -748,7 +759,7 @@ pub fn setFromList(list: RocList, alignment: Alignment, key_width: usize, value_
}
const StepperCaller = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, output: Opaque) callconv(.C) void {
pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, accum: Opaque, alignment: Alignment, key_width: usize, value_width: usize, accum_width: usize, inc_key: Inc, inc_value: Inc, output: Opaque) callconv(.C) void {
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
var i: usize = 0;
@ -756,10 +767,16 @@ pub fn dictWalk(dict: RocDict, stepper: Opaque, stepper_caller: StepperCaller, a
while (i < size) : (i += 1) {
switch (dict.getSlot(i, key_width, value_width)) {
Slot.Filled => {
const key = dict.getKey(i, alignment, key_width, value_width);
const value = dict.getValue(i, alignment, key_width, value_width);
if (value_width == 0) {
const key = dict.getKey(i, alignment, key_width, value_width);
stepper_caller(stepper, key, value, output, output);
stepper_caller(stepper, key, null, output, output);
} else {
const key = dict.getKey(i, alignment, key_width, value_width);
const value = dict.getValue(i, alignment, key_width, value_width);
stepper_caller(stepper, key, value, output, output);
}
},
else => {},
}

View file

@ -192,15 +192,15 @@ pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment:
}
}
pub fn listKeepOks(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, dec_result: Dec) callconv(.C) RocList {
return listKeepResult(list, RocResult.isOk, transform, caller, alignment, before_width, result_width, after_width, dec_result);
pub fn listKeepOks(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) callconv(.C) RocList {
return listKeepResult(list, RocResult.isOk, transform, caller, alignment, before_width, result_width, after_width, inc_closure, dec_result);
}
pub fn listKeepErrs(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, dec_result: Dec) callconv(.C) RocList {
return listKeepResult(list, RocResult.isErr, transform, caller, alignment, before_width, result_width, after_width, dec_result);
pub fn listKeepErrs(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) callconv(.C) RocList {
return listKeepResult(list, RocResult.isErr, transform, caller, alignment, before_width, result_width, after_width, inc_closure, dec_result);
}
pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, dec_result: Dec) RocList {
pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) RocList {
if (list.bytes) |source_ptr| {
const size = list.len();
var i: usize = 0;
@ -212,6 +212,7 @@ pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, t
var kept: usize = 0;
while (i < size) : (i += 1) {
const before_element = source_ptr + (i * before_width);
inc_closure(transform);
caller(transform, before_element, temporary);
const result = utils.RocResult{ .bytes = temporary };

View file

@ -50,6 +50,9 @@ pub const RocStr = extern struct {
const length = @sizeOf(usize) + number_of_chars;
var new_bytes: []usize = allocator.alloc(usize, length) catch unreachable;
const stdout = std.io.getStdOut().writer();
stdout.print("Hello, {d}!\n", .{length}) catch unreachable;
if (in_place == InPlace.InPlace) {
new_bytes[0] = @intCast(usize, number_of_chars);
} else {
@ -833,8 +836,10 @@ pub fn strConcatC(result_in_place: InPlace, arg1: RocStr, arg2: RocStr) callconv
fn strConcat(allocator: *Allocator, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
if (arg1.isEmpty()) {
// the second argument is borrowed, so we must increment its refcount before returning
return RocStr.clone(allocator, result_in_place, arg2);
} else if (arg2.isEmpty()) {
// the first argument is owned, so we can return it without cloning
return RocStr.clone(allocator, result_in_place, arg1);
} else {
const combined_length = arg1.len() + arg2.len();

View file

@ -16,25 +16,25 @@ pub fn decref(
var bytes = bytes_or_null orelse return;
const usizes: [*]usize = @ptrCast([*]usize, @alignCast(8, bytes));
const isizes: [*]isize = @ptrCast([*]isize, @alignCast(8, bytes));
const refcount = (usizes - 1)[0];
const refcount = (isizes - 1)[0];
const refcount_isize = @bitCast(isize, refcount);
switch (alignment) {
16 => {
if (refcount == REFCOUNT_ONE) {
if (refcount == REFCOUNT_ONE_ISIZE) {
allocator.free((bytes - 16)[0 .. 16 + data_bytes]);
} else if (refcount_isize < 0) {
(usizes - 1)[0] = refcount + 1;
(isizes - 1)[0] = refcount - 1;
}
},
else => {
// NOTE enums can currently have an alignment of < 8
if (refcount == REFCOUNT_ONE) {
if (refcount == REFCOUNT_ONE_ISIZE) {
allocator.free((bytes - 8)[0 .. 8 + data_bytes]);
} else if (refcount_isize < 0) {
(usizes - 1)[0] = refcount + 1;
(isizes - 1)[0] = refcount - 1;
}
},
}
@ -72,11 +72,11 @@ pub fn allocateWithRefcount(
var new_bytes: []align(8) u8 = allocator.alignedAlloc(u8, 8, length) catch unreachable;
var as_usize_array = @ptrCast([*]usize, new_bytes);
var as_usize_array = @ptrCast([*]isize, new_bytes);
if (result_in_place) {
as_usize_array[0] = @intCast(usize, number_of_slots);
as_usize_array[0] = @intCast(isize, number_of_slots);
} else {
as_usize_array[0] = REFCOUNT_ONE;
as_usize_array[0] = REFCOUNT_ONE_ISIZE;
}
var as_u8_array = @ptrCast([*]u8, new_bytes);