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
### 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.

View file

@ -1,5 +1,6 @@
const std = @import("std");
const utils = @import("utils.zig");
const str = @import("str.zig");
const UpdateMode = utils.UpdateMode;
const mem = std.mem;
const math = std.math;
@ -1033,3 +1034,34 @@ test "listConcat: non-unique with unique overlapping" {
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.listAllocationPtr, "allocation_ptr");
exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity");
exportListFn(list.listConcatUtf8, "concat_utf8");
}
// Num Module
@ -210,7 +211,6 @@ comptime {
exportStrFn(str.withCapacityC, "with_capacity");
exportStrFn(str.strAllocationPtr, "allocation_ptr");
exportStrFn(str.strReleaseExcessCapacity, "release_excess_capacity");
exportStrFn(str.strConcatUtf8, "concat_utf8");
inline for (INTEGERS) |T| {
str.exportFromInt(T, ROC_BUILTINS ++ "." ++ STR ++ ".from_int.");

View file

@ -2390,34 +2390,3 @@ pub fn strReleaseExcessCapacity(
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,
countIf,
chunksOf,
concatUtf8,
]
import Bool exposing [Bool, Eq]
import Result exposing [Result]
import Num exposing [U64, Num]
import Num exposing [U64, Num, U8]
## ## Types
##
@ -1324,3 +1325,12 @@ iterBackwardsHelp = \list, state, f, prevIndex ->
Break b -> Break b
else
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,
withPrefix,
contains,
concatUtf8,
]
import Bool exposing [Bool]
@ -561,14 +560,6 @@ 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.
## ```roc
## 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_ALLOCATION_PTR: &str = "roc_builtins.str.allocation_ptr";
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_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_ALLOCATION_PTR: &str = "roc_builtins.list.allocation_ptr";
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_ACOS: &str = "roc_builtins.dec.acos";

View file

@ -128,7 +128,6 @@ map_symbol_to_lowlevel_and_arity! {
StrToNum; STR_TO_NUM; 1,
StrWithCapacity; STR_WITH_CAPACITY; 1,
StrReleaseExcessCapacity; STR_RELEASE_EXCESS_CAPACITY; 1,
StrConcatUtf8; STR_CONCAT_UTF8; 2,
ListLenUsize; LIST_LEN_USIZE; 1,
ListLenU64; LIST_LEN_U64; 1,
@ -151,6 +150,7 @@ map_symbol_to_lowlevel_and_arity! {
ListSwap; LIST_SWAP; 3,
ListGetCapacity; LIST_CAPACITY; 1,
ListReleaseExcessCapacity; LIST_RELEASE_EXCESS_CAPACITY; 1,
ListConcatUtf8; LIST_CONCAT_UTF8; 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)
}
LowLevel::StrConcatUtf8 => self.build_fn_call(
LowLevel::ListConcatUtf8 => self.build_fn_call(
sym,
bitcode::STR_CONCAT_UTF8.to_string(),
bitcode::LIST_CONCAT_UTF8.to_string(),
args,
arg_layouts,
ret_layout,

View file

@ -608,28 +608,6 @@ pub(crate) fn run_low_level<'a, 'ctx>(
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 => {
// List.len : List * -> U64
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 => {
// Num.toStr : Num a -> Str
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)
}
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
ListLenU64 => {
@ -482,6 +481,7 @@ impl<'a> LowLevelCall<'a> {
backend.call_host_fn_after_loading_args(bitcode::LIST_CONCAT);
}
ListConcatUtf8 => self.load_args_and_call_zig(backend, bitcode::LIST_CONCAT_UTF8),
ListReserve => {
// List.reserve : List elem, U64 -> List elem

View file

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

View file

@ -1440,7 +1440,6 @@ define_builtins! {
46 STR_REPLACE_FIRST: "replaceFirst"
47 STR_REPLACE_LAST: "replaceLast"
48 STR_RELEASE_EXCESS_CAPACITY: "releaseExcessCapacity"
49 STR_CONCAT_UTF8: "concatUtf8"
}
6 LIST: "List" => {
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"
87 LIST_CLONE: "clone"
88 LIST_LEN_USIZE: "lenUsize"
89 LIST_CONCAT_UTF8: "concatUtf8"
}
7 RESULT: "Result" => {
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,
ListConcat => RC::Rc,
StrConcat => RC::Rc,
StrConcatUtf8 => RC::Rc,
ListConcatUtf8 => RC::Rc,
StrSubstringUnsafe => RC::Rc,
StrReserve => 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],
ListConcat => &[OWNED, OWNED],
StrConcat => &[OWNED, BORROWED],
StrConcatUtf8 => &[OWNED, BORROWED],
ListConcatUtf8 => &[OWNED, BORROWED],
StrSubstringUnsafe => &[OWNED, IRRELEVANT, IRRELEVANT],
StrReserve => &[OWNED, IRRELEVANT],
StrTrim => &[OWNED],

View file

@ -170,11 +170,11 @@ mod solve_expr {
}
#[test]
fn string_concat_utf8() {
fn list_concat_utf8() {
infer_eq_without_problem(
indoc!(
r"
Str.concatUtf8
List.concatUtf8
"
),
"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
);
}
#[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>
)
}