PR: rename to List.concatUtf8

This commit is contained in:
shua 2024-06-08 13:36:20 +02:00
parent 33e8a7a439
commit f7bec802c0
No known key found for this signature in database
GPG key ID: 73387DA37055770F
18 changed files with 81 additions and 89 deletions

View file

@ -80,7 +80,7 @@ It's one thing to actually write these functions, it's _another_ thing to let th
## Specifying how we pass args to the function ## Specifying how we pass args to the function
### builtins/mono/src/borrow.rs ### builtins/mono/src/inc_dec.rs
After we have all of this, we need to specify if the arguments we're passing are owned, borrowed or irrelevant. Towards the bottom of this file, add a new case for your builtin and specify each arg. Be sure to read the comment, as it explains this in more detail. After we have all of this, we need to specify if the arguments we're passing are owned, borrowed or irrelevant. Towards the bottom of this file, add a new case for your builtin and specify each arg. Be sure to read the comment, as it explains this in more detail.

View file

@ -1,5 +1,6 @@
const std = @import("std"); const std = @import("std");
const utils = @import("utils.zig"); const utils = @import("utils.zig");
const str = @import("str.zig");
const UpdateMode = utils.UpdateMode; const UpdateMode = utils.UpdateMode;
const mem = std.mem; const mem = std.mem;
const math = std.math; const math = std.math;
@ -1033,3 +1034,34 @@ test "listConcat: non-unique with unique overlapping" {
try expect(concatted.eql(wanted)); try expect(concatted.eql(wanted));
} }
pub fn listConcatUtf8(
list: RocList,
string: str.RocStr,
) callconv(.C) RocList {
if (string.len() == 0) {
return list;
} else {
const combined_length = list.len() + string.len();
// List U8 has alignment 1 and element_width 1
var result = list.reallocate(1, combined_length, 1);
// We just allocated combined_length, which is > 0 because string.len() > 0
var bytes = result.bytes orelse unreachable;
@memcpy(bytes[list.len()..combined_length], string.asU8ptr()[0..string.len()]);
return result;
}
}
test "listConcatUtf8" {
const list = RocList.fromSlice(u8, &[_]u8{ 1, 2, 3, 4 });
defer list.decref(1);
const string_bytes = "🐦";
const string = str.RocStr.init(string_bytes, string_bytes.len);
defer string.decref();
const ret = listConcatUtf8(list, string);
const expected = RocList.fromSlice(u8, &[_]u8{ 1, 2, 3, 4, 240, 159, 144, 166 });
defer expected.decref(1);
try expect(ret.eql(expected));
}

View file

@ -85,6 +85,7 @@ comptime {
exportListFn(list.listCapacity, "capacity"); exportListFn(list.listCapacity, "capacity");
exportListFn(list.listAllocationPtr, "allocation_ptr"); exportListFn(list.listAllocationPtr, "allocation_ptr");
exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity"); exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity");
exportListFn(list.listConcatUtf8, "concat_utf8");
} }
// Num Module // Num Module
@ -210,7 +211,6 @@ comptime {
exportStrFn(str.withCapacityC, "with_capacity"); exportStrFn(str.withCapacityC, "with_capacity");
exportStrFn(str.strAllocationPtr, "allocation_ptr"); exportStrFn(str.strAllocationPtr, "allocation_ptr");
exportStrFn(str.strReleaseExcessCapacity, "release_excess_capacity"); exportStrFn(str.strReleaseExcessCapacity, "release_excess_capacity");
exportStrFn(str.strConcatUtf8, "concat_utf8");
inline for (INTEGERS) |T| { inline for (INTEGERS) |T| {
str.exportFromInt(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_int."); str.exportFromInt(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_int.");

View file

@ -2390,34 +2390,3 @@ pub fn strReleaseExcessCapacity(
return output; return output;
} }
} }
pub fn strConcatUtf8(
list: RocList,
string: RocStr,
) callconv(.C) RocList {
if (string.len() == 0) {
return list;
} else {
const combined_length = list.len() + string.len();
// XXX: I assume List U8 has alignment 1 and element_width 1?
var result = list.reallocate(1, combined_length, 1);
// We just allocated combined_length, which is > 0 because string.len() > 0
var bytes = result.bytes orelse unreachable;
@memcpy(bytes[list.len()..combined_length], string.asU8ptr()[0..string.len()]);
return result;
}
}
test "strConcatUtf8" {
const list = RocList.fromSlice(u8, &[_]u8{ 1, 2, 3, 4 });
defer list.decref(1);
const string_bytes = "🐦";
const string = RocStr.init(string_bytes, string_bytes.len);
defer string.decref();
const ret = strConcatUtf8(list, string);
const expected = RocList.fromSlice(u8, &[_]u8{ 1, 2, 3, 4, 240, 159, 144, 166 });
defer expected.decref(1);
try expect(ret.eql(expected));
}

View file

@ -69,11 +69,12 @@ module [
walkBackwardsUntil, walkBackwardsUntil,
countIf, countIf,
chunksOf, chunksOf,
concatUtf8,
] ]
import Bool exposing [Bool, Eq] import Bool exposing [Bool, Eq]
import Result exposing [Result] import Result exposing [Result]
import Num exposing [U64, Num] import Num exposing [U64, Num, U8]
## ## Types ## ## Types
## ##
@ -1324,3 +1325,12 @@ iterBackwardsHelp = \list, state, f, prevIndex ->
Break b -> Break b Break b -> Break b
else else
Continue state Continue state
## Concatenates the bytes of a string encoded as utf8 to a list of bytes.
## ```roc
## expect (List.concatUtf8 [1, 2, 3, 4] "🐦") == [1, 2, 3, 4, 240, 159, 144, 166]
## ```
concatUtf8 : List U8, Str -> List U8
expect (List.concatUtf8 [1, 2, 3, 4] "🐦") == [1, 2, 3, 4, 240, 159, 144, 166]

View file

@ -367,7 +367,6 @@ module [
withCapacity, withCapacity,
withPrefix, withPrefix,
contains, contains,
concatUtf8,
] ]
import Bool exposing [Bool] import Bool exposing [Bool]
@ -561,14 +560,6 @@ FromUtf8Result : {
fromUtf8Lowlevel : List U8 -> FromUtf8Result fromUtf8Lowlevel : List U8 -> FromUtf8Result
## Concatenates the bytes of a string encoded as utf8 to a list of bytes.
## ```roc
## expect (Str.concatUtf8 [1, 2, 3, 4] "🐦") == [1, 2, 3, 4, 240, 159, 144, 166]
## ```
concatUtf8 : List U8, Str -> List U8
expect (Str.concatUtf8 [1, 2, 3, 4] "🐦") == [1, 2, 3, 4, 240, 159, 144, 166]
## Check if the given [Str] starts with a value. ## Check if the given [Str] starts with a value.
## ```roc ## ```roc
## expect Str.startsWith "ABC" "A" == Bool.true ## expect Str.startsWith "ABC" "A" == Bool.true

View file

@ -369,7 +369,6 @@ pub const STR_CLONE_TO: &str = "roc_builtins.str.clone_to";
pub const STR_WITH_CAPACITY: &str = "roc_builtins.str.with_capacity"; pub const STR_WITH_CAPACITY: &str = "roc_builtins.str.with_capacity";
pub const STR_ALLOCATION_PTR: &str = "roc_builtins.str.allocation_ptr"; pub const STR_ALLOCATION_PTR: &str = "roc_builtins.str.allocation_ptr";
pub const STR_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.str.release_excess_capacity"; pub const STR_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.str.release_excess_capacity";
pub const STR_CONCAT_UTF8: &str = "roc_builtins.str.concat_utf8";
pub const LIST_MAP: &str = "roc_builtins.list.map"; pub const LIST_MAP: &str = "roc_builtins.list.map";
pub const LIST_MAP2: &str = "roc_builtins.list.map2"; pub const LIST_MAP2: &str = "roc_builtins.list.map2";
@ -391,6 +390,7 @@ pub const LIST_RESERVE: &str = "roc_builtins.list.reserve";
pub const LIST_CAPACITY: &str = "roc_builtins.list.capacity"; pub const LIST_CAPACITY: &str = "roc_builtins.list.capacity";
pub const LIST_ALLOCATION_PTR: &str = "roc_builtins.list.allocation_ptr"; pub const LIST_ALLOCATION_PTR: &str = "roc_builtins.list.allocation_ptr";
pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess_capacity"; pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess_capacity";
pub const LIST_CONCAT_UTF8: &str = "roc_builtins.list.concat_utf8";
pub const DEC_ABS: &str = "roc_builtins.dec.abs"; pub const DEC_ABS: &str = "roc_builtins.dec.abs";
pub const DEC_ACOS: &str = "roc_builtins.dec.acos"; pub const DEC_ACOS: &str = "roc_builtins.dec.acos";

View file

@ -128,7 +128,6 @@ map_symbol_to_lowlevel_and_arity! {
StrToNum; STR_TO_NUM; 1, StrToNum; STR_TO_NUM; 1,
StrWithCapacity; STR_WITH_CAPACITY; 1, StrWithCapacity; STR_WITH_CAPACITY; 1,
StrReleaseExcessCapacity; STR_RELEASE_EXCESS_CAPACITY; 1, StrReleaseExcessCapacity; STR_RELEASE_EXCESS_CAPACITY; 1,
StrConcatUtf8; STR_CONCAT_UTF8; 2,
ListLenUsize; LIST_LEN_USIZE; 1, ListLenUsize; LIST_LEN_USIZE; 1,
ListLenU64; LIST_LEN_U64; 1, ListLenU64; LIST_LEN_U64; 1,
@ -151,6 +150,7 @@ map_symbol_to_lowlevel_and_arity! {
ListSwap; LIST_SWAP; 3, ListSwap; LIST_SWAP; 3,
ListGetCapacity; LIST_CAPACITY; 1, ListGetCapacity; LIST_CAPACITY; 1,
ListReleaseExcessCapacity; LIST_RELEASE_EXCESS_CAPACITY; 1, ListReleaseExcessCapacity; LIST_RELEASE_EXCESS_CAPACITY; 1,
ListConcatUtf8; LIST_CONCAT_UTF8; 2,
ListGetUnsafe; DICT_LIST_GET_UNSAFE; 2, ListGetUnsafe; DICT_LIST_GET_UNSAFE; 2,

View file

@ -1704,9 +1704,9 @@ trait Backend<'a> {
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout) self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
} }
LowLevel::StrConcatUtf8 => self.build_fn_call( LowLevel::ListConcatUtf8 => self.build_fn_call(
sym, sym,
bitcode::STR_CONCAT_UTF8.to_string(), bitcode::LIST_CONCAT_UTF8.to_string(),
args, args,
arg_layouts, arg_layouts,
ret_layout, ret_layout,

View file

@ -608,28 +608,6 @@ pub(crate) fn run_low_level<'a, 'ctx>(
bitcode::STR_WITH_CAPACITY, bitcode::STR_WITH_CAPACITY,
) )
} }
StrConcatUtf8 => {
// Str.concatUtf8: List U8, Str -> List U8
arguments!(list, string);
// XXX: I don't know why I need to call different functions based on the target pointer width, but the test_gen tests panic if I don't
match env.target.ptr_width() {
PtrWidth::Bytes4 => call_str_bitcode_fn(
env,
&[list, string],
&[],
BitcodeReturns::List,
bitcode::STR_CONCAT_UTF8,
),
PtrWidth::Bytes8 => call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[string],
BitcodeReturns::List,
bitcode::STR_CONCAT_UTF8,
),
}
}
ListLenU64 => { ListLenU64 => {
// List.len : List * -> U64 // List.len : List * -> U64
arguments!(list); arguments!(list);
@ -867,6 +845,18 @@ pub(crate) fn run_low_level<'a, 'ctx>(
} }
} }
} }
ListConcatUtf8 => {
// List.concatUtf8: List U8, Str -> List U8
arguments!(list, string);
call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[string],
BitcodeReturns::List,
bitcode::LIST_CONCAT_UTF8,
)
}
NumToStr => { NumToStr => {
// Num.toStr : Num a -> Str // Num.toStr : Num a -> Str
arguments_with_layouts!((num, num_layout)); arguments_with_layouts!((num, num_layout));

View file

@ -258,7 +258,6 @@ impl<'a> LowLevelCall<'a> {
self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE) self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE)
} }
StrWithCapacity => self.load_args_and_call_zig(backend, bitcode::STR_WITH_CAPACITY), StrWithCapacity => self.load_args_and_call_zig(backend, bitcode::STR_WITH_CAPACITY),
StrConcatUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_CONCAT_UTF8),
// List // List
ListLenU64 => { ListLenU64 => {
@ -482,6 +481,7 @@ impl<'a> LowLevelCall<'a> {
backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT); backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT);
} }
ListConcatUtf8 => self.load_args_and_call_zig(backend, bitcode::LIST_CONCAT_UTF8),
ListReserve => { ListReserve => {
// List.reserve : List elem, U64 -> List elem // List.reserve : List elem, U64 -> List elem

View file

@ -26,7 +26,6 @@ pub enum LowLevel {
StrReserve, StrReserve,
StrWithCapacity, StrWithCapacity,
StrReleaseExcessCapacity, StrReleaseExcessCapacity,
StrConcatUtf8,
ListLenUsize, ListLenUsize,
ListLenU64, ListLenU64,
ListWithCapacity, ListWithCapacity,
@ -48,6 +47,7 @@ pub enum LowLevel {
ListGetCapacity, ListGetCapacity,
ListIsUnique, ListIsUnique,
ListClone, ListClone,
ListConcatUtf8,
NumAdd, NumAdd,
NumAddWrap, NumAddWrap,
NumAddChecked, NumAddChecked,
@ -275,7 +275,6 @@ map_symbol_to_lowlevel! {
StrToNum <= STR_TO_NUM; StrToNum <= STR_TO_NUM;
StrWithCapacity <= STR_WITH_CAPACITY; StrWithCapacity <= STR_WITH_CAPACITY;
StrReleaseExcessCapacity <= STR_RELEASE_EXCESS_CAPACITY; StrReleaseExcessCapacity <= STR_RELEASE_EXCESS_CAPACITY;
StrConcatUtf8 <= STR_CONCAT_UTF8;
ListLenU64 <= LIST_LEN_U64; ListLenU64 <= LIST_LEN_U64;
ListLenUsize <= LIST_LEN_USIZE; ListLenUsize <= LIST_LEN_USIZE;
ListGetCapacity <= LIST_CAPACITY; ListGetCapacity <= LIST_CAPACITY;
@ -292,6 +291,7 @@ map_symbol_to_lowlevel! {
ListSublist <= LIST_SUBLIST_LOWLEVEL; ListSublist <= LIST_SUBLIST_LOWLEVEL;
ListDropAt <= LIST_DROP_AT; ListDropAt <= LIST_DROP_AT;
ListSwap <= LIST_SWAP; ListSwap <= LIST_SWAP;
ListConcatUtf8 <= LIST_CONCAT_UTF8;
NumAdd <= NUM_ADD; NumAdd <= NUM_ADD;
NumAddWrap <= NUM_ADD_WRAP; NumAddWrap <= NUM_ADD_WRAP;
NumAddChecked <= NUM_ADD_CHECKED_LOWLEVEL; NumAddChecked <= NUM_ADD_CHECKED_LOWLEVEL;

View file

@ -1440,7 +1440,6 @@ define_builtins! {
46 STR_REPLACE_FIRST: "replaceFirst" 46 STR_REPLACE_FIRST: "replaceFirst"
47 STR_REPLACE_LAST: "replaceLast" 47 STR_REPLACE_LAST: "replaceLast"
48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity" 48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity"
49 STR_CONCAT_UTF8: "concatUtf8"
} }
6 LIST: "List" => { 6 LIST: "List" => {
0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias 0 LIST_LIST: "List" exposed_apply_type=true // the List.List type alias
@ -1532,6 +1531,7 @@ define_builtins! {
86 LIST_WALK_WITH_INDEX_UNTIL: "walkWithIndexUntil" 86 LIST_WALK_WITH_INDEX_UNTIL: "walkWithIndexUntil"
87 LIST_CLONE: "clone" 87 LIST_CLONE: "clone"
88 LIST_LEN_USIZE: "lenUsize" 88 LIST_LEN_USIZE: "lenUsize"
89 LIST_CONCAT_UTF8: "concatUtf8"
} }
7 RESULT: "Result" => { 7 RESULT: "Result" => {
0 RESULT_RESULT: "Result" exposed_type=true // the Result.Result type alias 0 RESULT_RESULT: "Result" exposed_type=true // the Result.Result type alias

View file

@ -1539,7 +1539,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
StrGetUnsafe | ListGetUnsafe => RC::NoRc, StrGetUnsafe | ListGetUnsafe => RC::NoRc,
ListConcat => RC::Rc, ListConcat => RC::Rc,
StrConcat => RC::Rc, StrConcat => RC::Rc,
StrConcatUtf8 => RC::Rc, ListConcatUtf8 => RC::Rc,
StrSubstringUnsafe => RC::Rc, StrSubstringUnsafe => RC::Rc,
StrReserve => RC::Rc, StrReserve => RC::Rc,
StrTrim => RC::Rc, StrTrim => RC::Rc,

View file

@ -1288,7 +1288,7 @@ pub(crate) fn lowlevel_borrow_signature(op: LowLevel) -> &'static [Ownership] {
StrGetUnsafe | ListGetUnsafe => &[BORROWED, IRRELEVANT], StrGetUnsafe | ListGetUnsafe => &[BORROWED, IRRELEVANT],
ListConcat => &[OWNED, OWNED], ListConcat => &[OWNED, OWNED],
StrConcat => &[OWNED, BORROWED], StrConcat => &[OWNED, BORROWED],
StrConcatUtf8 => &[OWNED, BORROWED], ListConcatUtf8 => &[OWNED, BORROWED],
StrSubstringUnsafe => &[OWNED, IRRELEVANT, IRRELEVANT], StrSubstringUnsafe => &[OWNED, IRRELEVANT, IRRELEVANT],
StrReserve => &[OWNED, IRRELEVANT], StrReserve => &[OWNED, IRRELEVANT],
StrTrim => &[OWNED], StrTrim => &[OWNED],

View file

@ -170,11 +170,11 @@ mod solve_expr {
} }
#[test] #[test]
fn string_concat_utf8() { fn list_concat_utf8() {
infer_eq_without_problem( infer_eq_without_problem(
indoc!( indoc!(
r" r"
Str.concatUtf8 List.concatUtf8
" "
), ),
"List U8, Str -> List U8", "List U8, Str -> List U8",

View file

@ -4123,3 +4123,15 @@ mod pattern_match {
) )
} }
} }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_concat_utf8() {
assert_evals_to!(
r#"
List.concatUtf8 [1, 2, 3, 4] "🐦"
"#,
RocList::from_slice(&[1u8, 2, 3, 4, 240, 159, 144, 166]),
RocList<u8>
)
}

View file

@ -1988,15 +1988,3 @@ fn str_contains_self() {
bool bool
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn str_concat_utf8() {
assert_evals_to!(
r#"
Str.concatUtf8 [1, 2, 3, 4] "🐦"
"#,
RocList::from_slice(&[1u8, 2, 3, 4, 240, 159, 144, 166]),
RocList<u8>
)
}