mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Various small zig str changes
This commit is contained in:
parent
149d10ea0b
commit
784f299b43
1 changed files with 61 additions and 63 deletions
|
@ -1,11 +1,17 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||
const Allocator = mem.Allocator;
|
||||
const unicode = std.unicode;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
|
||||
const InPlace = packed enum(u8) {
|
||||
InPlace,
|
||||
Clone,
|
||||
};
|
||||
|
||||
const RocStr = extern struct {
|
||||
str_bytes: ?[*]u8,
|
||||
str_len: usize,
|
||||
|
@ -49,7 +55,7 @@ const RocStr = extern struct {
|
|||
|
||||
return ret_small_str;
|
||||
} else {
|
||||
var result = allocateStr(allocator, u64, InPlace.Clone, length);
|
||||
var result = RocStr.initBigStr(allocator, u64, InPlace.Clone, length);
|
||||
|
||||
@memcpy(@ptrCast([*]u8, result.str_bytes), bytes_ptr, length);
|
||||
|
||||
|
@ -57,6 +63,33 @@ const RocStr = extern struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn initBigStr(allocator: *Allocator, comptime T: type, in_place: InPlace, number_of_chars: u64) RocStr {
|
||||
const length = @sizeOf(T) + number_of_chars;
|
||||
var new_bytes: []T = allocator.alloc(T, length) catch unreachable;
|
||||
|
||||
if (in_place == InPlace.InPlace) {
|
||||
new_bytes[0] = @intCast(T, number_of_chars);
|
||||
} else {
|
||||
new_bytes[0] = std.math.minInt(T);
|
||||
}
|
||||
|
||||
var first_element = @ptrCast([*]align(@alignOf(T)) u8, new_bytes);
|
||||
first_element += @sizeOf(usize);
|
||||
|
||||
return RocStr{
|
||||
.str_bytes = first_element,
|
||||
.str_len = number_of_chars,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: RocStr, allocator: *Allocator) void {
|
||||
if (!self.isSmallStr() and !self.isEmpty()) {
|
||||
const str_bytes_ptr: [*]u8 = self.str_bytes orelse unreachable;
|
||||
const str_bytes: []u8 = str_bytes_ptr[0..self.str_len];
|
||||
allocator.free(str_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// This takes ownership of the pointed-to bytes if they won't fit in a
|
||||
// small string, and returns a (pointer, len) tuple which points to them.
|
||||
pub fn withCapacity(length: usize) RocStr {
|
||||
|
@ -76,15 +109,6 @@ const RocStr = extern struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: RocStr, allocator: *Allocator) void {
|
||||
if (!self.isSmallStr() and !self.isEmpty()) {
|
||||
const str_bytes_ptr: [*]u8 = self.str_bytes orelse unreachable;
|
||||
|
||||
const str_bytes: []u8 = str_bytes_ptr[0..self.str_len];
|
||||
allocator.free(str_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq(self: RocStr, other: RocStr) bool {
|
||||
const self_bytes_ptr: ?[*]const u8 = self.str_bytes;
|
||||
const other_bytes_ptr: ?[*]const u8 = other.str_bytes;
|
||||
|
@ -122,6 +146,22 @@ const RocStr = extern struct {
|
|||
return true;
|
||||
}
|
||||
|
||||
pub fn clone(allocator: *Allocator, comptime T: type, in_place: InPlace, str: RocStr) RocStr {
|
||||
if (str.isSmallStr() or str.isEmpty()) {
|
||||
// just return the bytes
|
||||
return str;
|
||||
} else {
|
||||
var new_str = RocStr.initBigStr(allocator, T, in_place, str.str_len);
|
||||
|
||||
var old_bytes: [*]u8 = @ptrCast([*]u8, str.str_bytes);
|
||||
var new_bytes: [*]u8 = @ptrCast([*]u8, new_str.str_bytes);
|
||||
|
||||
@memcpy(new_bytes, old_bytes, str.str_len);
|
||||
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isSmallStr(self: RocStr) bool {
|
||||
return @bitCast(isize, self.str_len) < 0;
|
||||
}
|
||||
|
@ -178,8 +218,7 @@ const RocStr = extern struct {
|
|||
const str2_ptr: [*]u8 = &str2;
|
||||
var roc_str2 = RocStr.init(testing.allocator, str2_ptr, str2_len);
|
||||
|
||||
// TODO: fix those tests
|
||||
// expect(roc_str1.eq(roc_str2));
|
||||
expect(roc_str1.eq(roc_str2));
|
||||
|
||||
roc_str1.deinit(testing.allocator);
|
||||
roc_str2.deinit(testing.allocator);
|
||||
|
@ -220,8 +259,7 @@ const RocStr = extern struct {
|
|||
roc_str2.deinit(testing.allocator);
|
||||
}
|
||||
|
||||
// TODO: fix those tests
|
||||
// expect(!roc_str1.eq(roc_str2));
|
||||
expect(!roc_str1.eq(roc_str2));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -236,9 +274,9 @@ pub fn strFromIntC(int: i64) callconv(.C) RocStr {
|
|||
return strFromInt(std.heap.c_allocator, int);
|
||||
}
|
||||
|
||||
inline fn strFromInt(allocator: *Allocator, int: i64) RocStr {
|
||||
fn strFromInt(allocator: *Allocator, int: i64) RocStr {
|
||||
// prepare for having multiple integer types in the future
|
||||
return strFromIntHelp(allocator, i64, int);
|
||||
return @call(.{ .modifier = always_inline }, strFromIntHelp, .{ allocator, i64, int });
|
||||
}
|
||||
|
||||
fn strFromIntHelp(allocator: *Allocator, comptime T: type, int: T) RocStr {
|
||||
|
@ -259,10 +297,10 @@ fn strFromIntHelp(allocator: *Allocator, comptime T: type, int: T) RocStr {
|
|||
// Str.split
|
||||
// When we actually use this in Roc, libc will be linked so we have access to std.heap.c_allocator
|
||||
pub fn strSplitInPlaceC(array: [*]RocStr, string: RocStr, delimiter: RocStr) callconv(.C) void {
|
||||
strSplitInPlace(std.heap.c_allocator, array, string, delimiter);
|
||||
return @call(.{ .modifier = always_inline }, strSplitInPlace, .{ std.heap.c_allocator, array, string, delimiter });
|
||||
}
|
||||
|
||||
inline fn strSplitInPlace(allocator: *Allocator, array: [*]RocStr, string: RocStr, delimiter: RocStr) void {
|
||||
fn strSplitInPlace(allocator: *Allocator, array: [*]RocStr, string: RocStr, delimiter: RocStr) void {
|
||||
var ret_array_index: usize = 0;
|
||||
var slice_start_index: usize = 0;
|
||||
var str_index: usize = 0;
|
||||
|
@ -765,10 +803,10 @@ test "endsWith: hello world ends with world" {
|
|||
// Str.concat
|
||||
// When we actually use this in Roc, libc will be linked so we have access to std.heap.c_allocator
|
||||
pub fn strConcatC(ptr_size: u32, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) callconv(.C) RocStr {
|
||||
return strConcat(std.heap.c_allocator, ptr_size, result_in_place, arg1, arg2);
|
||||
return @call(.{ .modifier = always_inline }, strConcat, .{ std.heap.c_allocator, ptr_size, result_in_place, arg1, arg2 });
|
||||
}
|
||||
|
||||
inline fn strConcat(allocator: *Allocator, ptr_size: u32, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
|
||||
fn strConcat(allocator: *Allocator, ptr_size: u32, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
|
||||
return switch (ptr_size) {
|
||||
4 => strConcatHelp(allocator, i32, result_in_place, arg1, arg2),
|
||||
8 => strConcatHelp(allocator, i64, result_in_place, arg1, arg2),
|
||||
|
@ -778,9 +816,9 @@ inline fn strConcat(allocator: *Allocator, ptr_size: u32, result_in_place: InPla
|
|||
|
||||
fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
|
||||
if (arg1.isEmpty()) {
|
||||
return cloneStr(allocator, T, result_in_place, arg2);
|
||||
return RocStr.clone(allocator, T, result_in_place, arg2);
|
||||
} else if (arg2.isEmpty()) {
|
||||
return cloneStr(allocator, T, result_in_place, arg1);
|
||||
return RocStr.clone(allocator, T, result_in_place, arg1);
|
||||
} else {
|
||||
const combined_length = arg1.len() + arg2.len();
|
||||
|
||||
|
@ -788,7 +826,7 @@ fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPla
|
|||
const result_is_big = combined_length >= small_str_bytes;
|
||||
|
||||
if (result_is_big) {
|
||||
var result = allocateStr(allocator, T, result_in_place, combined_length);
|
||||
var result = RocStr.initBigStr(allocator, T, result_in_place, combined_length);
|
||||
|
||||
{
|
||||
const old_if_small = &@bitCast([16]u8, arg1);
|
||||
|
@ -842,46 +880,6 @@ fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPla
|
|||
}
|
||||
}
|
||||
|
||||
const InPlace = packed enum(u8) {
|
||||
InPlace,
|
||||
Clone,
|
||||
};
|
||||
|
||||
fn cloneStr(allocator: *Allocator, comptime T: type, in_place: InPlace, str: RocStr) RocStr {
|
||||
if (str.isSmallStr() or str.isEmpty()) {
|
||||
// just return the bytes
|
||||
return str;
|
||||
} else {
|
||||
var new_str = allocateStr(allocator, T, in_place, str.str_len);
|
||||
|
||||
var old_bytes: [*]u8 = @ptrCast([*]u8, str.str_bytes);
|
||||
var new_bytes: [*]u8 = @ptrCast([*]u8, new_str.str_bytes);
|
||||
|
||||
@memcpy(new_bytes, old_bytes, str.str_len);
|
||||
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateStr(allocator: *Allocator, comptime T: type, in_place: InPlace, number_of_chars: u64) RocStr {
|
||||
const length = @sizeOf(T) + number_of_chars;
|
||||
var new_bytes: []T = allocator.alloc(T, length) catch unreachable;
|
||||
|
||||
if (in_place == InPlace.InPlace) {
|
||||
new_bytes[0] = @intCast(T, number_of_chars);
|
||||
} else {
|
||||
new_bytes[0] = std.math.minInt(T);
|
||||
}
|
||||
|
||||
var first_element = @ptrCast([*]align(@alignOf(T)) u8, new_bytes);
|
||||
first_element += @sizeOf(usize);
|
||||
|
||||
return RocStr{
|
||||
.str_bytes = first_element,
|
||||
.str_len = number_of_chars,
|
||||
};
|
||||
}
|
||||
|
||||
test "RocStr.concat: small concat small" {
|
||||
const str1_len = 3;
|
||||
var str1: [str1_len]u8 = "foo".*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue