mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
Merge pull request #3369 from rtfeldman/pure-roc-list-walk
List.walk and friends in pure Roc
This commit is contained in:
commit
2a82d24847
39 changed files with 344 additions and 1630 deletions
|
@ -197,44 +197,6 @@ const Caller2 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
|||
const Caller3 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||
const Caller4 = fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
|
||||
|
||||
pub fn listReverse(list: RocList, alignment: u32, element_width: usize, update_mode: UpdateMode) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
var i: usize = 0;
|
||||
const end: usize = size - 1;
|
||||
|
||||
if (update_mode == .InPlace or list.isUnique()) {
|
||||
|
||||
// Working from the front and back so
|
||||
// we only need to go ~(n / 2) iterations.
|
||||
// If the length is an odd number the middle
|
||||
// element stays in the same place anyways.
|
||||
while (i < (end - i)) : (i += 1) {
|
||||
swapElements(source_ptr, element_width, i, end - i);
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
const output = RocList.allocate(alignment, size, element_width);
|
||||
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
while (i < size) : (i += 1) {
|
||||
const last_position = end - i;
|
||||
|
||||
@memcpy(target_ptr + (i * element_width), source_ptr + (last_position * element_width), element_width);
|
||||
}
|
||||
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listMap(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
|
@ -474,214 +436,6 @@ pub fn listMap4(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn listWalk(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
accum_width: usize,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
@memcpy(b2, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
var i: usize = 0;
|
||||
const size = list.len();
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, b2, element, b1);
|
||||
|
||||
std.mem.swap([*]u8, &b1, &b2);
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, b2, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
pub fn listWalkBackwards(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
accum_width: usize,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
@memcpy(b2, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = size;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, b2, element, b1);
|
||||
|
||||
std.mem.swap([*]u8, &b1, &b2);
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, b2, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
pub fn listWalkUntil(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
accum: Opaque,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
continue_stop_width: usize,
|
||||
accum_width: usize,
|
||||
has_tag_id: HasTagId,
|
||||
dec: Dec,
|
||||
output: Opaque,
|
||||
) callconv(.C) void {
|
||||
// [Continue a, Stop a]
|
||||
|
||||
if (accum_width == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty()) {
|
||||
@memcpy(output orelse unreachable, accum orelse unreachable, accum_width);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment) orelse unreachable;
|
||||
|
||||
// NOTE: assumes data bytes are the first bytes in a tag
|
||||
@memcpy(bytes_ptr, accum orelse unreachable, accum_width);
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
var i: usize = 0;
|
||||
const size = list.len();
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, 1);
|
||||
}
|
||||
|
||||
caller(data, bytes_ptr, element, bytes_ptr);
|
||||
|
||||
// [Continue ..., Stop]
|
||||
const tag_id = has_tag_id(0, bytes_ptr);
|
||||
|
||||
if (!tag_id.matched) {
|
||||
// decrement refcount of the remaining items
|
||||
i += 1;
|
||||
while (i < size) : (i += 1) {
|
||||
dec(source_ptr + i * element_width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@memcpy(output orelse unreachable, bytes_ptr, accum_width);
|
||||
utils.dealloc(bytes_ptr, alignment);
|
||||
}
|
||||
|
||||
// List.contains : List k, k -> Bool
|
||||
pub fn listContains(list: RocList, key: Opaque, key_width: usize, is_eq: EqFn) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * key_width;
|
||||
if (is_eq(element, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn listRepeat(count: usize, alignment: u32, element: Opaque, element_width: usize, inc_n_element: IncN) callconv(.C) RocList {
|
||||
if (count == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
var output = RocList.allocate(alignment, count, element_width);
|
||||
|
||||
if (output.bytes) |target_ptr| {
|
||||
// increment the element's RC N times
|
||||
inc_n_element(element, count);
|
||||
|
||||
var i: usize = 0;
|
||||
const source = element orelse unreachable;
|
||||
while (i < count) : (i += 1) {
|
||||
@memcpy(target_ptr + i * element_width, source, element_width);
|
||||
}
|
||||
|
||||
return output;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listSingle(alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
|
||||
var output = RocList.allocate(alignment, 1, element_width);
|
||||
|
||||
if (output.bytes) |target| {
|
||||
if (element) |source| {
|
||||
@memcpy(target, source, element_width);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
pub fn listWithCapacity(capacity: usize, alignment: u32, element_width: usize) callconv(.C) RocList {
|
||||
var output = RocList.allocate(alignment, capacity, element_width);
|
||||
output.length = 0;
|
||||
|
@ -934,66 +688,6 @@ pub fn listSortWith(
|
|||
return list;
|
||||
}
|
||||
|
||||
pub fn listAny(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
var satisfied = false;
|
||||
while (i < size) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, element, @ptrCast(?[*]u8, &satisfied));
|
||||
|
||||
if (satisfied) {
|
||||
return satisfied;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn listAll(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
) callconv(.C) bool {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var satisfied = false;
|
||||
const element = source_ptr + i * element_width;
|
||||
caller(data, element, @ptrCast(?[*]u8, &satisfied));
|
||||
|
||||
if (!satisfied) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// SWAP ELEMENTS
|
||||
|
||||
inline fn swapHelp(width: usize, temporary: [*]u8, ptr1: [*]u8, ptr2: [*]u8) void {
|
||||
|
@ -1127,41 +821,6 @@ inline fn listReplaceInPlaceHelp(
|
|||
return list;
|
||||
}
|
||||
|
||||
pub fn listFindUnsafe(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
element_width: usize,
|
||||
inc: Inc,
|
||||
dec: Dec,
|
||||
) callconv(.C) extern struct { value: Opaque, found: bool } {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var theOne = false;
|
||||
const element = source_ptr + (i * element_width);
|
||||
inc(element);
|
||||
caller(data, element, @ptrCast(?[*]u8, &theOne));
|
||||
|
||||
if (theOne) {
|
||||
return .{ .value = element, .found = true };
|
||||
} else {
|
||||
dec(element);
|
||||
}
|
||||
}
|
||||
return .{ .value = null, .found = false };
|
||||
} else {
|
||||
return .{ .value = null, .found = false };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listIsUnique(
|
||||
list: RocList,
|
||||
) callconv(.C) bool {
|
||||
|
|
|
@ -41,16 +41,9 @@ comptime {
|
|||
exportListFn(list.listMap3, "map3");
|
||||
exportListFn(list.listMap4, "map4");
|
||||
exportListFn(list.listMapWithIndex, "map_with_index");
|
||||
exportListFn(list.listWalk, "walk");
|
||||
exportListFn(list.listWalkUntil, "walkUntil");
|
||||
exportListFn(list.listWalkBackwards, "walk_backwards");
|
||||
exportListFn(list.listContains, "contains");
|
||||
exportListFn(list.listRepeat, "repeat");
|
||||
exportListFn(list.listAppend, "append");
|
||||
exportListFn(list.listPrepend, "prepend");
|
||||
exportListFn(list.listSingle, "single");
|
||||
exportListFn(list.listWithCapacity, "with_capacity");
|
||||
exportListFn(list.listReverse, "reverse");
|
||||
exportListFn(list.listSortWith, "sort_with");
|
||||
exportListFn(list.listConcat, "concat");
|
||||
exportListFn(list.listSublist, "sublist");
|
||||
|
@ -58,9 +51,6 @@ comptime {
|
|||
exportListFn(list.listReplace, "replace");
|
||||
exportListFn(list.listReplaceInPlace, "replace_in_place");
|
||||
exportListFn(list.listSwap, "swap");
|
||||
exportListFn(list.listAny, "any");
|
||||
exportListFn(list.listAll, "all");
|
||||
exportListFn(list.listFindUnsafe, "find_unsafe");
|
||||
exportListFn(list.listIsUnique, "is_unique");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue