mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +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 std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const unicode = std.unicode;
|
const unicode = std.unicode;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const expectEqual = testing.expectEqual;
|
const expectEqual = testing.expectEqual;
|
||||||
const expect = testing.expect;
|
const expect = testing.expect;
|
||||||
|
|
||||||
|
const InPlace = packed enum(u8) {
|
||||||
|
InPlace,
|
||||||
|
Clone,
|
||||||
|
};
|
||||||
|
|
||||||
const RocStr = extern struct {
|
const RocStr = extern struct {
|
||||||
str_bytes: ?[*]u8,
|
str_bytes: ?[*]u8,
|
||||||
str_len: usize,
|
str_len: usize,
|
||||||
|
@ -49,7 +55,7 @@ const RocStr = extern struct {
|
||||||
|
|
||||||
return ret_small_str;
|
return ret_small_str;
|
||||||
} else {
|
} 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);
|
@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
|
// 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.
|
// small string, and returns a (pointer, len) tuple which points to them.
|
||||||
pub fn withCapacity(length: usize) RocStr {
|
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 {
|
pub fn eq(self: RocStr, other: RocStr) bool {
|
||||||
const self_bytes_ptr: ?[*]const u8 = self.str_bytes;
|
const self_bytes_ptr: ?[*]const u8 = self.str_bytes;
|
||||||
const other_bytes_ptr: ?[*]const u8 = other.str_bytes;
|
const other_bytes_ptr: ?[*]const u8 = other.str_bytes;
|
||||||
|
@ -122,6 +146,22 @@ const RocStr = extern struct {
|
||||||
return true;
|
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 {
|
pub fn isSmallStr(self: RocStr) bool {
|
||||||
return @bitCast(isize, self.str_len) < 0;
|
return @bitCast(isize, self.str_len) < 0;
|
||||||
}
|
}
|
||||||
|
@ -178,8 +218,7 @@ const RocStr = extern struct {
|
||||||
const str2_ptr: [*]u8 = &str2;
|
const str2_ptr: [*]u8 = &str2;
|
||||||
var roc_str2 = RocStr.init(testing.allocator, str2_ptr, str2_len);
|
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_str1.deinit(testing.allocator);
|
||||||
roc_str2.deinit(testing.allocator);
|
roc_str2.deinit(testing.allocator);
|
||||||
|
@ -220,8 +259,7 @@ const RocStr = extern struct {
|
||||||
roc_str2.deinit(testing.allocator);
|
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);
|
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
|
// 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 {
|
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
|
// Str.split
|
||||||
// When we actually use this in Roc, libc will be linked so we have access to std.heap.c_allocator
|
// 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 {
|
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 ret_array_index: usize = 0;
|
||||||
var slice_start_index: usize = 0;
|
var slice_start_index: usize = 0;
|
||||||
var str_index: usize = 0;
|
var str_index: usize = 0;
|
||||||
|
@ -765,10 +803,10 @@ test "endsWith: hello world ends with world" {
|
||||||
// Str.concat
|
// Str.concat
|
||||||
// When we actually use this in Roc, libc will be linked so we have access to std.heap.c_allocator
|
// 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 {
|
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) {
|
return switch (ptr_size) {
|
||||||
4 => strConcatHelp(allocator, i32, result_in_place, arg1, arg2),
|
4 => strConcatHelp(allocator, i32, result_in_place, arg1, arg2),
|
||||||
8 => strConcatHelp(allocator, i64, 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 {
|
fn strConcatHelp(allocator: *Allocator, comptime T: type, result_in_place: InPlace, arg1: RocStr, arg2: RocStr) RocStr {
|
||||||
if (arg1.isEmpty()) {
|
if (arg1.isEmpty()) {
|
||||||
return cloneStr(allocator, T, result_in_place, arg2);
|
return RocStr.clone(allocator, T, result_in_place, arg2);
|
||||||
} else if (arg2.isEmpty()) {
|
} else if (arg2.isEmpty()) {
|
||||||
return cloneStr(allocator, T, result_in_place, arg1);
|
return RocStr.clone(allocator, T, result_in_place, arg1);
|
||||||
} else {
|
} else {
|
||||||
const combined_length = arg1.len() + arg2.len();
|
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;
|
const result_is_big = combined_length >= small_str_bytes;
|
||||||
|
|
||||||
if (result_is_big) {
|
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);
|
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" {
|
test "RocStr.concat: small concat small" {
|
||||||
const str1_len = 3;
|
const str1_len = 3;
|
||||||
var str1: [str1_len]u8 = "foo".*;
|
var str1: [str1_len]u8 = "foo".*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue