mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
PR: rename to List.concatUtf8
This commit is contained in:
parent
33e8a7a439
commit
f7bec802c0
18 changed files with 81 additions and 89 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue