mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Merge remote-tracking branch 'origin/trunk' into list-str-capacity
This commit is contained in:
commit
07063a8e18
458 changed files with 20371 additions and 8316 deletions
|
@ -26,21 +26,19 @@ pub const RocDec = extern struct {
|
|||
return .{ .num = num * one_point_zero_i128 };
|
||||
}
|
||||
|
||||
// TODO: There's got to be a better way to do this other than converting to Str
|
||||
pub fn fromF64(num: f64) ?RocDec {
|
||||
var digit_bytes: [19]u8 = undefined; // 19 = max f64 digits + '.' + '-'
|
||||
var result: f64 = num * comptime @intToFloat(f64, one_point_zero_i128);
|
||||
|
||||
var fbs = std.io.fixedBufferStream(digit_bytes[0..]);
|
||||
std.fmt.formatFloatDecimal(num, .{}, fbs.writer()) catch
|
||||
return null;
|
||||
|
||||
var dec = RocDec.fromStr(RocStr.init(&digit_bytes, fbs.pos));
|
||||
|
||||
if (dec) |d| {
|
||||
return d;
|
||||
} else {
|
||||
if (result > comptime @intToFloat(f64, math.maxInt(i128))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (result < comptime @intToFloat(f64, math.minInt(i128))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret: RocDec = .{ .num = @floatToInt(i128, result) };
|
||||
return ret;
|
||||
}
|
||||
|
||||
pub fn fromStr(roc_str: RocStr) ?RocDec {
|
||||
|
@ -729,6 +727,11 @@ test "fromF64" {
|
|||
try expectEqual(RocDec{ .num = 25500000000000000000 }, dec.?);
|
||||
}
|
||||
|
||||
test "fromF64 overflow" {
|
||||
var dec = RocDec.fromF64(1e308);
|
||||
try expectEqual(dec, null);
|
||||
}
|
||||
|
||||
test "fromStr: empty" {
|
||||
var roc_str = RocStr.init("", 0);
|
||||
var dec = RocDec.fromStr(roc_str);
|
||||
|
|
|
@ -1259,95 +1259,56 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
|||
return output;
|
||||
}
|
||||
|
||||
pub fn listSetInPlace(
|
||||
bytes: ?[*]u8,
|
||||
pub fn listReplaceInPlace(
|
||||
list: RocList,
|
||||
index: usize,
|
||||
element: Opaque,
|
||||
element_width: usize,
|
||||
dec: Dec,
|
||||
) callconv(.C) ?[*]u8 {
|
||||
out_element: ?[*]u8,
|
||||
) callconv(.C) RocList {
|
||||
// INVARIANT: bounds checking happens on the roc side
|
||||
//
|
||||
// at the time of writing, the function is implemented roughly as
|
||||
// `if inBounds then LowLevelListGet input index item else input`
|
||||
// `if inBounds then LowLevelListReplace input index item else input`
|
||||
// so we don't do a bounds check here. Hence, the list is also non-empty,
|
||||
// because inserting into an empty list is always out of bounds
|
||||
|
||||
return listSetInPlaceHelp(bytes, index, element, element_width, dec);
|
||||
return listReplaceInPlaceHelp(list, index, element, element_width, out_element);
|
||||
}
|
||||
|
||||
pub fn listSet(
|
||||
bytes: ?[*]u8,
|
||||
length: usize,
|
||||
pub fn listReplace(
|
||||
list: RocList,
|
||||
alignment: u32,
|
||||
index: usize,
|
||||
element: Opaque,
|
||||
element_width: usize,
|
||||
dec: Dec,
|
||||
) callconv(.C) ?[*]u8 {
|
||||
out_element: ?[*]u8,
|
||||
) callconv(.C) RocList {
|
||||
// INVARIANT: bounds checking happens on the roc side
|
||||
//
|
||||
// at the time of writing, the function is implemented roughly as
|
||||
// `if inBounds then LowLevelListGet input index item else input`
|
||||
// `if inBounds then LowLevelListReplace input index item else input`
|
||||
// so we don't do a bounds check here. Hence, the list is also non-empty,
|
||||
// because inserting into an empty list is always out of bounds
|
||||
const ptr: [*]usize = @ptrCast([*]usize, @alignCast(@alignOf(usize), bytes));
|
||||
|
||||
if ((ptr - 1)[0] == utils.REFCOUNT_ONE) {
|
||||
return listSetInPlaceHelp(bytes, index, element, element_width, dec);
|
||||
} else {
|
||||
return listSetImmutable(bytes, length, alignment, index, element, element_width, dec);
|
||||
}
|
||||
return listReplaceInPlaceHelp(list.makeUnique(alignment, element_width), index, element, element_width, out_element);
|
||||
}
|
||||
|
||||
inline fn listSetInPlaceHelp(
|
||||
bytes: ?[*]u8,
|
||||
inline fn listReplaceInPlaceHelp(
|
||||
list: RocList,
|
||||
index: usize,
|
||||
element: Opaque,
|
||||
element_width: usize,
|
||||
dec: Dec,
|
||||
) ?[*]u8 {
|
||||
out_element: ?[*]u8,
|
||||
) RocList {
|
||||
// the element we will replace
|
||||
var element_at_index = (bytes orelse undefined) + (index * element_width);
|
||||
var element_at_index = (list.bytes orelse undefined) + (index * element_width);
|
||||
|
||||
// decrement its refcount
|
||||
dec(element_at_index);
|
||||
// copy out the old element
|
||||
@memcpy(out_element orelse undefined, element_at_index, element_width);
|
||||
|
||||
// copy in the new element
|
||||
@memcpy(element_at_index, element orelse undefined, element_width);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
inline fn listSetImmutable(
|
||||
old_bytes: ?[*]u8,
|
||||
length: usize,
|
||||
alignment: u32,
|
||||
index: usize,
|
||||
element: Opaque,
|
||||
element_width: usize,
|
||||
dec: Dec,
|
||||
) ?[*]u8 {
|
||||
const data_bytes = length * element_width;
|
||||
|
||||
var new_bytes = utils.allocateWithRefcount(data_bytes, alignment);
|
||||
|
||||
@memcpy(new_bytes, old_bytes orelse undefined, data_bytes);
|
||||
|
||||
// the element we will replace
|
||||
var element_at_index = new_bytes + (index * element_width);
|
||||
|
||||
// decrement its refcount
|
||||
dec(element_at_index);
|
||||
|
||||
// copy in the new element
|
||||
@memcpy(element_at_index, element orelse undefined, element_width);
|
||||
|
||||
// consume RC token of original
|
||||
utils.decref(old_bytes, data_bytes, alignment);
|
||||
|
||||
//return list;
|
||||
return new_bytes;
|
||||
return list;
|
||||
}
|
||||
|
||||
pub fn listFindUnsafe(
|
||||
|
|
|
@ -49,8 +49,8 @@ comptime {
|
|||
exportListFn(list.listConcat, "concat");
|
||||
exportListFn(list.listSublist, "sublist");
|
||||
exportListFn(list.listDropAt, "drop_at");
|
||||
exportListFn(list.listSet, "set");
|
||||
exportListFn(list.listSetInPlace, "set_in_place");
|
||||
exportListFn(list.listReplace, "replace");
|
||||
exportListFn(list.listReplaceInPlace, "replace_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
exportListFn(list.listAny, "any");
|
||||
exportListFn(list.listAll, "all");
|
||||
|
@ -98,6 +98,14 @@ comptime {
|
|||
num.exportDivCeil(T, ROC_BUILTINS ++ "." ++ NUM ++ ".div_ceil.");
|
||||
}
|
||||
|
||||
inline for (INTEGERS) |FROM| {
|
||||
inline for (INTEGERS) |TO| {
|
||||
// We're exporting more than we need here, but that's okay.
|
||||
num.exportToIntCheckingMax(FROM, TO, ROC_BUILTINS ++ "." ++ NUM ++ ".int_to_" ++ @typeName(TO) ++ "_checking_max.");
|
||||
num.exportToIntCheckingMaxAndMin(FROM, TO, ROC_BUILTINS ++ "." ++ NUM ++ ".int_to_" ++ @typeName(TO) ++ "_checking_max_and_min.");
|
||||
}
|
||||
}
|
||||
|
||||
inline for (FLOATS) |T| {
|
||||
num.exportAsin(T, ROC_BUILTINS ++ "." ++ NUM ++ ".asin.");
|
||||
num.exportAcos(T, ROC_BUILTINS ++ "." ++ NUM ++ ".acos.");
|
||||
|
|
|
@ -108,6 +108,39 @@ pub fn exportDivCeil(comptime T: type, comptime name: []const u8) void {
|
|||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn ToIntCheckedResult(comptime T: type) type {
|
||||
// On the Roc side we sort by alignment; putting the errorcode last
|
||||
// always works out (no number with smaller alignment than 1).
|
||||
return extern struct {
|
||||
value: T,
|
||||
out_of_bounds: bool,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn exportToIntCheckingMax(comptime From: type, comptime To: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: From) callconv(.C) ToIntCheckedResult(To) {
|
||||
if (input > std.math.maxInt(To)) {
|
||||
return .{ .out_of_bounds = true, .value = 0 };
|
||||
}
|
||||
return .{ .out_of_bounds = false, .value = @intCast(To, input) };
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(From), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn exportToIntCheckingMaxAndMin(comptime From: type, comptime To: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(input: From) callconv(.C) ToIntCheckedResult(To) {
|
||||
if (input > std.math.maxInt(To) or input < std.math.minInt(To)) {
|
||||
return .{ .out_of_bounds = true, .value = 0 };
|
||||
}
|
||||
return .{ .out_of_bounds = false, .value = @intCast(To, input) };
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(From), .linkage = .Strong });
|
||||
}
|
||||
|
||||
pub fn bytesToU16C(arg: RocList, position: usize) callconv(.C) u16 {
|
||||
return @call(.{ .modifier = always_inline }, bytesToU16, .{ arg, position });
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue