Remove examples/custom-malloc for now

This commit is contained in:
Richard Feldman 2021-07-20 07:12:25 -04:00
parent 3a575d1c9d
commit 660faa3bf1
8 changed files with 9 additions and 369 deletions

View File

@ -193,15 +193,15 @@ mod cli_run {
// use_valgrind: true,
// }
// ],
"custom-malloc" => vec![
Example {
filename: "Main.roc",
executable_filename: "custom-malloc-example",
stdin: &[],
expected_ending: "ms!\nThe list was small!\n",
use_valgrind: true,
}
],
// "custom-malloc" => vec![
// Example {
// filename: "Main.roc",
// executable_filename: "custom-malloc-example",
// stdin: &[],
// expected_ending: "ms!\nThe list was small!\n",
// use_valgrind: true,
// }
// ],
"task" => vec![
Example {
filename: "Main.roc",

View File

@ -1 +0,0 @@
custom-malloc-example

View File

@ -1,18 +0,0 @@
app "custom-malloc-example"
packages { base: "platform" }
imports [ base.Task.{ Task } ]
provides [ main ] to base
main : Task.Task {} []
main =
_ <- Task.await (Task.putLine "About to allocate a list!")
# This is the only allocation in this Roc code!
# (The strings all get stored in the application
# binary, and are never allocated on the heap.)
list = [ 1, 2, 3, 4 ]
if List.len list > 100 then
Task.putLine "The list was big!"
else
Task.putLine "The list was small!"

View File

@ -1,97 +0,0 @@
interface File
exposes [ FileReadErr, FileOpenErr, FileWriteErr, DirReadErr, readUtf8, writeUtf8 ]
imports [ Task.{ Task }, fx.Effect.{ after }, Path ]
# TODO FIXME should be able to import this as Path.{ Path }, but there's a bug.
Path : Path.Path
# These various file errors come from the POSIX errno values - see
# http://www.virtsync.com/c-error-codes-include-errno for the actual codes, and
# https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html for documentation
#
# The goal of this design is:
# * Whenever a function returns a `Task`, that task's error type represents all the errors that could happen.
# * The errors are union-friendly; if I run a task that reads, and then another that writes, I should get all the read *and* write errors.
# * To make the errors friendlier to chaining, they should always include the `Path` of the attempted operation. This way it's possible to tell which one failed after the fact.
## These errors can happen when opening a file, before attempting to read from
## it or write to it. The #FileReadErr and #FileWriteErr tag unions begin with
## these tags and then add more specific ones.
FileOpenErr a :
[
FileNotFound Path,
PermissionDenied Path,
SymLinkLoop Path,
TooManyOpenFiles Path,
IoError Path,
UnknownError I64 Path,
]a
## Errors when attempting to read a non-directory file.
FileReadErr a :
FileOpenErr
[
FileWasDir Path,
InvalidSeek Path,
IllegalByteSequence Path,
FileBusy Path,
]a
## Errors when attempting to read a directory.
DirReadErr a :
FileOpenErr
[
FileWasNotDir Path,
]a
## Errors when attempting to write a non-directory file.
FileWriteErr a :
FileOpenErr
[
FileWasDir Path,
ReadOnlyFileSystem Path,
]a
## Read a file's raw bytes
#readBytes : Path -> Task (List U8) (FileReadErr *)
#readBytes = \path ->
# Effect.readBytes (Path.toStr path)
## Read a file's bytes and interpret them as UTF-8 encoded text.
readUtf8 : Path -> Task.Task Str (FileReadErr [ BadUtf8 Str.Utf8ByteProblem Nat ]*)
readUtf8 = \path ->
Effect.map (Effect.readAllUtf8 (Path.toStr path)) \answer ->
# errno values - see
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
when answer.errno is
0 ->
when Str.fromUtf8 answer.bytes is
Ok str -> Ok str
Err (BadUtf8 problem index) -> Err (BadUtf8 problem index)
1 -> Err (PermissionDenied path)
2 -> Err (FileNotFound path)
19 -> Err (FileWasDir path)
# TODO handle other errno scenarios that could come up
_ -> Err (UnknownError answer.errno path)
writeUtf8 : Path, Str -> Task.Task {} (FileWriteErr [ BadThing ]*)
writeUtf8 = \path, data ->
path
|> Path.toStr
|> Effect.writeAllUtf8 data
|> Effect.map \res ->
when res.errno is
0 -> Ok {}
_ -> Err BadThing
## Read a file's bytes, one chunk at a time, and use it to build up a state.
##
## After each chunk is read, it gets passed to a callback which builds up a
## state - optionally while running other tasks.
#readChunks : Path, U64, state, (state, List U8 -> Task state []err) -> Task state (FileReadErr err)
## Like #readChunks except after each chunk you can either `Continue`,
## specifying how many bytes you'd like to read next, or `Stop` early.
#readChunksOrStop : Path, U64, state, (state, List U8 -> [ Continue U64 (Task state []err), Stop (Task state []err) ]) -> Task state (FileReadErr err)

View File

@ -1,16 +0,0 @@
platform folkertdev/foo
requires {}{ main : Task {} [] }
exposes []
packages {}
imports [ Task ]
provides [ mainForHost ]
effects fx.Effect
{
# TODO change errno to I32
readAllUtf8 : Str -> Effect { errno : I64, bytes : List U8 },
writeAllUtf8 : Str, Str -> Effect { errno: I64 },
putLine : Str -> Effect {}
}
mainForHost : Task.Task {} [] as Fx
mainForHost = main

View File

@ -1,16 +0,0 @@
interface Path
exposes [ Path, fromStr, toStr ]
imports []
Path : [ @Path Str ]
fromStr : Str -> Result Path [ MalformedPath ]*
fromStr = \str ->
# TODO actually validate the path - may want a Parser for this!
Ok (@Path str)
toStr : Path -> Str
toStr = \@Path str ->
str

View File

@ -1,41 +0,0 @@
interface Task
exposes [ Task, succeed, fail, await, map, putLine, attempt ]
imports [ fx.Effect ]
Task ok err : Effect.Effect (Result ok err)
succeed : val -> Task val *
succeed = \val ->
Effect.always (Ok val)
fail : err -> Task * err
fail = \val ->
Effect.always (Err val)
await : Task a err, (a -> Task b err) -> Task b err
await = \effect, transform ->
Effect.after effect \result ->
when result is
Ok a -> transform a
Err err -> Task.fail err
attempt : Task a b, (Result a b -> Task c d) -> Task c d
attempt = \effect, transform ->
Effect.after effect \result ->
when result is
Ok ok -> transform (Ok ok)
Err err -> transform (Err err)
map : Task a err, (a -> b) -> Task b err
map = \effect, transform ->
Effect.after effect \result ->
when result is
Ok a -> Task.succeed (transform a)
Err err -> Task.fail err
putLine : Str -> Task {} *
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})

View File

@ -1,171 +0,0 @@
const std = @import("std");
const str = @import("str");
const RocStr = str.RocStr;
const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;
extern fn roc__mainForHost_1_exposed([*]u8) void;
extern fn roc__mainForHost_1_size() i64;
extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
extern fn roc__mainForHost_1_Fx_size() i64;
extern fn roc__mainForHost_1_Fx_result_size() i64;
extern fn malloc(size: usize) callconv(.C) ?*c_void;
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
const Unit = extern struct {};
pub export fn main() u8 {
const stdout = std.io.getStdOut().writer();
const size = @intCast(usize, roc__mainForHost_1_size());
const raw_output = std.heap.c_allocator.alloc(u8, size) catch unreachable;
var output = @ptrCast([*]u8, raw_output);
defer {
std.heap.c_allocator.free(raw_output);
}
roc__mainForHost_1_exposed(output);
const elements = @ptrCast([*]u64, @alignCast(8, output));
var flag = elements[0];
if (flag == 0) {
// all is well
const closure_data_pointer = @ptrCast([*]u8, output[8..size]);
call_the_closure(closure_data_pointer);
} else {
unreachable;
}
return 0;
}
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
const stdout = std.io.getStdOut().writer();
// Perform the actual malloc
const startNs = std.time.nanoTimestamp();
const ptr = malloc(size);
const endNs = std.time.nanoTimestamp();
const totalMs = @divTrunc(endNs - startNs, 1000);
stdout.print("\x1B[36m{} | \x1B[39m Custom malloc allocated {} bytes in {} ms!\n", .{ startNs, size, totalMs }) catch unreachable;
return ptr;
}
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void {
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
}
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
const stdout = std.io.getStdOut().writer();
// Perform the actual free
const startNs = std.time.nanoTimestamp();
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
const endNs = std.time.nanoTimestamp();
const totalMs = @divTrunc(endNs - startNs, 1000);
stdout.print("\x1B[36m{} | \x1B[39m Custom dealloc ran in {} ms!\n", .{ startNs, totalMs }) catch unreachable;
}
fn call_the_closure(closure_data_pointer: [*]u8) void {
const size = roc__mainForHost_1_Fx_result_size();
const raw_output = std.heap.c_allocator.alloc(u8, @intCast(usize, size)) catch unreachable;
var output = @ptrCast([*]u8, raw_output);
defer {
std.heap.c_allocator.free(raw_output);
}
const flags: u8 = 0;
roc__mainForHost_1_Fx_caller(&flags, closure_data_pointer, output);
const elements = @ptrCast([*]u64, @alignCast(8, output));
var flag = elements[0];
if (flag == 0) {
return;
} else {
unreachable;
}
}
pub export fn roc_fx_putLine(rocPath: str.RocStr) i64 {
const stdout = std.io.getStdOut().writer();
const u8_ptr = rocPath.asU8ptr();
var i: usize = 0;
while (i < rocPath.len()) {
stdout.print("{c}", .{u8_ptr[i]}) catch unreachable;
i += 1;
}
stdout.print("\n", .{}) catch unreachable;
return 0;
}
pub const ReadResult = extern struct {
bytes: RocStr, // TODO RocList<u8> once Roc supports U8
errno: i64, // TODO i32 when Roc supports I32
};
pub const WriteResult = extern struct {
errno: i64,
};
pub export fn roc_fx_readAllUtf8(rocPath: RocStr) callconv(.C) ReadResult {
var dir = std.fs.cwd();
var content = dir.readFileAlloc(testing.allocator, rocPath.asSlice(), 1024) catch |e| switch (e) {
error.FileNotFound => return .{ .bytes = RocStr.empty(), .errno = 2 },
error.IsDir => return .{ .bytes = RocStr.empty(), .errno = 19 },
else => return .{ .bytes = RocStr.empty(), .errno = 9999 },
};
var str_ptr = @ptrCast([*]u8, content);
var roc_str3 = RocStr.init(str_ptr, content.len);
return .{ .bytes = roc_str3, .errno = 0 };
}
pub export fn roc_fx_writeAllUtf8(filePath: RocStr, content: RocStr) callconv(.C) WriteResult {
var dir = std.fs.cwd();
dir.writeFile(filePath.asSlice(), content.asSlice()) catch |e| switch (e) {
else => return .{ .errno = 1 },
};
return .{ .errno = 0 };
}