mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
Merge pull request #6176 from roc-lang/set-perf
Improve perf of Dict and Set
This commit is contained in:
commit
81eff6a23f
@ -633,8 +633,8 @@ pub fn exportMulOrPanic(comptime T: type, comptime W: type, comptime name: []con
|
||||
|
||||
pub fn exportCountLeadingZeroBits(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(self: T) callconv(.C) usize {
|
||||
return @as(usize, @clz(self));
|
||||
fn func(self: T) callconv(.C) u8 {
|
||||
return @as(u8, @clz(self));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
@ -642,8 +642,8 @@ pub fn exportCountLeadingZeroBits(comptime T: type, comptime name: []const u8) v
|
||||
|
||||
pub fn exportCountTrailingZeroBits(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(self: T) callconv(.C) usize {
|
||||
return @as(usize, @ctz(self));
|
||||
fn func(self: T) callconv(.C) u8 {
|
||||
return @as(u8, @ctz(self));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
@ -651,8 +651,8 @@ pub fn exportCountTrailingZeroBits(comptime T: type, comptime name: []const u8)
|
||||
|
||||
pub fn exportCountOneBits(comptime T: type, comptime name: []const u8) void {
|
||||
comptime var f = struct {
|
||||
fn func(self: T) callconv(.C) usize {
|
||||
return @as(usize, @popCount(self));
|
||||
fn func(self: T) callconv(.C) u8 {
|
||||
return @as(u8, @popCount(self));
|
||||
}
|
||||
}.func;
|
||||
@export(f, .{ .name = name ++ @typeName(T), .linkage = .Strong });
|
||||
|
@ -102,7 +102,6 @@ Dict k v := {
|
||||
metadata : List I8,
|
||||
dataIndices : List Nat,
|
||||
data : List (k, v),
|
||||
size : Nat,
|
||||
} where k implements Hash & Eq
|
||||
implements [
|
||||
Eq {
|
||||
@ -137,6 +136,9 @@ toInspectorDict = \dict ->
|
||||
fmt <- Inspect.custom
|
||||
Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt
|
||||
|
||||
emptyMetadata = [emptySlot, emptySlot, emptySlot, emptySlot, emptySlot, emptySlot, emptySlot, emptySlot]
|
||||
emptyDataIndices = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
## Return an empty dictionary.
|
||||
## ```
|
||||
## emptyDict = Dict.empty {}
|
||||
@ -144,12 +146,41 @@ toInspectorDict = \dict ->
|
||||
empty : {} -> Dict * *
|
||||
empty = \{} ->
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot 8,
|
||||
dataIndices: List.repeat 0 8,
|
||||
metadata: emptyMetadata,
|
||||
dataIndices: emptyDataIndices,
|
||||
data: [],
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Dict * *
|
||||
withCapacity = \size ->
|
||||
if size == 0 then
|
||||
empty {}
|
||||
else
|
||||
# Max load is 7/8.
|
||||
# To avoid potential rehash, multiply size by 8/7.
|
||||
# Then map to containing power of 2 to make dict indices happy.
|
||||
cap =
|
||||
size
|
||||
|> Num.toU64
|
||||
|> Num.mul 8
|
||||
|> Num.divTrunc 7
|
||||
|> containingPowerOfTwo
|
||||
|> Num.max 8
|
||||
|> Num.toNat
|
||||
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot cap,
|
||||
dataIndices: List.repeat 0 cap,
|
||||
data: List.withCapacity cap,
|
||||
}
|
||||
|
||||
containingPowerOfTwo : U64 -> U64
|
||||
containingPowerOfTwo = \size ->
|
||||
Num.shiftLeftBy 1 (64 - Num.countLeadingZeroBits (size - 1))
|
||||
|
||||
## Returns the max number of elements the dictionary can hold before requiring a rehash.
|
||||
## ```
|
||||
## foodDict =
|
||||
@ -164,14 +195,6 @@ capacity = \@Dict { dataIndices } ->
|
||||
|
||||
Num.subWrap cap (Num.shiftRightZfBy cap 3)
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Dict * *
|
||||
withCapacity = \_ ->
|
||||
# TODO: power of 2 * 8 and actual implementation
|
||||
empty {}
|
||||
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
## ```
|
||||
## expect
|
||||
@ -193,8 +216,15 @@ single = \k, v ->
|
||||
## ```
|
||||
fromList : List (k, v) -> Dict k v where k implements Hash & Eq
|
||||
fromList = \data ->
|
||||
# TODO: make this efficient. Should just set data and then set all indicies in the hashmap.
|
||||
List.walk data (empty {}) (\dict, (k, v) -> insert dict k v)
|
||||
# TODO: make more efficient.
|
||||
# Want to just set the data and then set all indicies in the hashmap.
|
||||
# That said, we need to also deal with duplicates.
|
||||
|
||||
size = List.len data
|
||||
if size > 0 then
|
||||
List.walk data (withCapacity size) (\dict, (k, v) -> insert dict k v)
|
||||
else
|
||||
empty {}
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
## ```
|
||||
@ -207,8 +237,8 @@ fromList = \data ->
|
||||
## |> Bool.isEq 3
|
||||
## ```
|
||||
len : Dict * * -> Nat
|
||||
len = \@Dict { size } ->
|
||||
size
|
||||
len = \@Dict { data } ->
|
||||
List.len data
|
||||
|
||||
## Check if the dictinoary is empty.
|
||||
## ```
|
||||
@ -217,8 +247,8 @@ len = \@Dict { size } ->
|
||||
## Dict.isEmpty (Dict.empty {})
|
||||
## ```
|
||||
isEmpty : Dict * * -> Bool
|
||||
isEmpty = \@Dict { size } ->
|
||||
size == 0
|
||||
isEmpty = \@Dict { data } ->
|
||||
List.isEmpty data
|
||||
|
||||
## Clears all elements from a dictionary keeping around the allocation if it isn't huge.
|
||||
## ```
|
||||
@ -246,7 +276,6 @@ clear = \@Dict { metadata, dataIndices, data } ->
|
||||
dataIndices,
|
||||
# use takeFirst to keep around the capacity.
|
||||
data: List.takeFirst data 0,
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Convert each value in the dictionary to something new, by calling a conversion
|
||||
@ -424,7 +453,7 @@ contains = \@Dict { metadata, dataIndices, data }, key ->
|
||||
## |> Bool.isEq (Ok 12)
|
||||
## ```
|
||||
insert : Dict k v, k, v -> Dict k v where k implements Hash & Eq
|
||||
insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
insert = \@Dict { metadata, dataIndices, data }, key, value ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|> Hash.hash key
|
||||
@ -441,7 +470,6 @@ insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
metadata,
|
||||
dataIndices,
|
||||
data: List.set data dataIndex (key, value),
|
||||
size,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
@ -453,7 +481,6 @@ insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
metadata,
|
||||
dataIndices,
|
||||
data,
|
||||
size: Num.addWrap size 1,
|
||||
}
|
||||
)
|
||||
|
||||
@ -470,7 +497,7 @@ insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
## |> Bool.isEq 0
|
||||
## ```
|
||||
remove : Dict k v, k -> Dict k v where k implements Hash & Eq
|
||||
remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
||||
remove = \@Dict { metadata, dataIndices, data }, key ->
|
||||
# TODO: change this from swap remove to tombstone and test is performance is still good.
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
@ -490,13 +517,12 @@ remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
||||
metadata: List.set metadata index deletedSlot,
|
||||
dataIndices,
|
||||
data: List.dropLast data 1,
|
||||
size: Num.subWrap size 1,
|
||||
}
|
||||
else
|
||||
swapAndUpdateDataIndex (@Dict { metadata, dataIndices, data, size }) index last
|
||||
swapAndUpdateDataIndex (@Dict { metadata, dataIndices, data }) index last
|
||||
|
||||
Err NotFound ->
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
@Dict { metadata, dataIndices, data }
|
||||
|
||||
## Insert or remove a value for a specified key. This function enables a
|
||||
## performance optimization for the use case of providing a default when a value
|
||||
@ -596,36 +622,49 @@ values = \@Dict { data } ->
|
||||
## ```
|
||||
insertAll : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq
|
||||
insertAll = \xs, ys ->
|
||||
walk ys xs insert
|
||||
if len ys > len xs then
|
||||
insertAll ys xs
|
||||
else
|
||||
walk ys xs insert
|
||||
|
||||
## Combine two dictionaries by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory))
|
||||
## of all the key-value pairs. This means that we keep only those pairs
|
||||
## that are in both dictionaries. Note that where there are pairs with
|
||||
## the same key, the value contained in the first input will be retained,
|
||||
## and the value in the second input will be removed.
|
||||
## that are in both dictionaries. Both the key and value must match to be kept.
|
||||
## ```
|
||||
## first =
|
||||
## Dict.single 1 "Keep Me"
|
||||
## |> Dict.insert 2 "And Me"
|
||||
## |> Dict.insert 3 "Not this one"
|
||||
##
|
||||
## second =
|
||||
## Dict.single 1 "Keep Me"
|
||||
## |> Dict.insert 2 "And Me"
|
||||
## |> Dict.insert 3 "But Not Me"
|
||||
## |> Dict.insert 3 "This has a different value"
|
||||
## |> Dict.insert 4 "Or Me"
|
||||
##
|
||||
## expect Dict.keepShared first second == first
|
||||
## expected =
|
||||
## Dict.single 1 "Keep Me"
|
||||
## |> Dict.insert 2 "And Me"
|
||||
##
|
||||
## expect Dict.keepShared first second == expected
|
||||
## ```
|
||||
keepShared : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq
|
||||
keepShared = \xs, ys ->
|
||||
keepShared : Dict k v, Dict k v -> Dict k v where k implements Hash & Eq, v implements Eq
|
||||
keepShared = \xs0, ys0 ->
|
||||
(xs1, ys1) =
|
||||
if len ys0 < len xs0 then
|
||||
(ys0, xs0)
|
||||
else
|
||||
(xs0, ys0)
|
||||
walk
|
||||
xs
|
||||
(empty {})
|
||||
xs1
|
||||
(withCapacity (len xs1))
|
||||
(\state, k, v ->
|
||||
if contains ys k then
|
||||
insert state k v
|
||||
else
|
||||
state
|
||||
when get ys1 k is
|
||||
Ok yv if v == yv ->
|
||||
insert state k v
|
||||
|
||||
_ ->
|
||||
state
|
||||
)
|
||||
|
||||
## Remove the key-value pairs in the first input that are also in the second
|
||||
@ -653,7 +692,7 @@ removeAll = \xs, ys ->
|
||||
walk ys xs (\state, k, _ -> remove state k)
|
||||
|
||||
swapAndUpdateDataIndex : Dict k v, Nat, Nat -> Dict k v where k implements Hash & Eq
|
||||
swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIndex, lastIndex ->
|
||||
swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data }, removedIndex, lastIndex ->
|
||||
(key, _) = listGetUnsafe data lastIndex
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
@ -678,7 +717,6 @@ swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIn
|
||||
# Update index of swaped element.
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size: Num.subWrap size 1,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
@ -686,7 +724,7 @@ swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIn
|
||||
crash "unreachable state in dict swapAndUpdateDataIndex hit. Definitely a standard library bug."
|
||||
|
||||
insertNotFoundHelper : Dict k v, k, v, U64, I8 -> Dict k v
|
||||
insertNotFoundHelper = \@Dict { metadata, dataIndices, data, size }, key, value, h1Key, h2Key ->
|
||||
insertNotFoundHelper = \@Dict { metadata, dataIndices, data }, key, value, h1Key, h2Key ->
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
index = nextEmptyOrDeletedHelper metadata probe 0
|
||||
dataIndex = List.len data
|
||||
@ -696,7 +734,6 @@ insertNotFoundHelper = \@Dict { metadata, dataIndices, data, size }, key, value,
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size,
|
||||
}
|
||||
|
||||
nextEmptyOrDeletedHelper : List I8, Probe, Nat -> Nat
|
||||
@ -749,27 +786,26 @@ findIndexHelper = \metadata, dataIndices, data, h2Key, key, probe, offset ->
|
||||
# If we aren't to the load factor yet, just ignore this.
|
||||
# The container must have an updated size including any elements about to be inserted.
|
||||
maybeRehash : Dict k v -> Dict k v where k implements Hash & Eq
|
||||
maybeRehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
maybeRehash = \@Dict { metadata, dataIndices, data } ->
|
||||
cap = List.len dataIndices
|
||||
maxLoadCap =
|
||||
# This is 7/8 * capacity, which is the max load factor.
|
||||
Num.subWrap cap (Num.shiftRightZfBy cap 3)
|
||||
|
||||
if size > maxLoadCap then
|
||||
rehash (@Dict { metadata, dataIndices, data, size })
|
||||
if (List.len data + 1) > maxLoadCap then
|
||||
rehash (@Dict { metadata, dataIndices, data })
|
||||
else
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
@Dict { metadata, dataIndices, data }
|
||||
|
||||
# TODO: switch rehash to iterate data and eventually clear out tombstones as well.
|
||||
rehash : Dict k v -> Dict k v where k implements Hash & Eq
|
||||
rehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
rehash = \@Dict { metadata, dataIndices, data } ->
|
||||
newLen = 2 * List.len dataIndices
|
||||
newDict =
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot newLen,
|
||||
dataIndices: List.repeat 0 newLen,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
rehashHelper newDict metadata dataIndices data 0
|
||||
@ -796,7 +832,7 @@ rehashHelper = \dict, oldMetadata, oldDataIndices, oldData, index ->
|
||||
dict
|
||||
|
||||
insertForRehash : Dict k v, k, Nat -> Dict k v where k implements Hash & Eq
|
||||
insertForRehash = \@Dict { metadata, dataIndices, data, size }, key, dataIndex ->
|
||||
insertForRehash = \@Dict { metadata, dataIndices, data }, key, dataIndex ->
|
||||
hashKey =
|
||||
createLowLevelHasher PseudoRandSeed
|
||||
|> Hash.hash key
|
||||
@ -810,7 +846,6 @@ insertForRehash = \@Dict { metadata, dataIndices, data, size }, key, dataIndex -
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
emptySlot : I8
|
||||
|
@ -1112,7 +1112,7 @@ powInt : Int a, Int a -> Int a
|
||||
##
|
||||
## 8
|
||||
## ```
|
||||
countLeadingZeroBits : Int a -> Nat
|
||||
countLeadingZeroBits : Int a -> U8
|
||||
|
||||
## Counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.
|
||||
##
|
||||
@ -1125,7 +1125,7 @@ countLeadingZeroBits : Int a -> Nat
|
||||
##
|
||||
## 8
|
||||
## ```
|
||||
countTrailingZeroBits : Int a -> Nat
|
||||
countTrailingZeroBits : Int a -> U8
|
||||
|
||||
## Counts the number of set bits in an integer.
|
||||
##
|
||||
@ -1138,7 +1138,7 @@ countTrailingZeroBits : Int a -> Nat
|
||||
##
|
||||
## 0
|
||||
## ```
|
||||
countOneBits : Int a -> Nat
|
||||
countOneBits : Int a -> U8
|
||||
|
||||
addWrap : Int range, Int range -> Int range
|
||||
|
||||
|
@ -237,9 +237,10 @@ toList = \@Set dict ->
|
||||
## ```
|
||||
fromList : List k -> Set k where k implements Hash & Eq
|
||||
fromList = \list ->
|
||||
initial = @Set (Dict.withCapacity (List.len list))
|
||||
|
||||
List.walk list initial insert
|
||||
list
|
||||
|> List.map \k -> (k, {})
|
||||
|> Dict.fromList
|
||||
|> @Set
|
||||
|
||||
## Combine two `Set` collection by keeping the
|
||||
## [union](https://en.wikipedia.org/wiki/Union_(set_theory))
|
||||
|
@ -1765,6 +1765,21 @@ trait Backend<'a> {
|
||||
let intrinsic = bitcode::NUM_IS_MULTIPLE_OF[int_width].to_string();
|
||||
self.build_fn_call(sym, intrinsic, args, arg_layouts, ret_layout);
|
||||
}
|
||||
LowLevel::NumCountLeadingZeroBits => {
|
||||
let int_width = arg_layouts[0].try_int_width().unwrap();
|
||||
let intrinsic = bitcode::NUM_COUNT_LEADING_ZERO_BITS[int_width].to_string();
|
||||
self.build_fn_call(sym, intrinsic, args, arg_layouts, ret_layout);
|
||||
}
|
||||
LowLevel::NumCountTrailingZeroBits => {
|
||||
let int_width = arg_layouts[0].try_int_width().unwrap();
|
||||
let intrinsic = bitcode::NUM_COUNT_TRAILING_ZERO_BITS[int_width].to_string();
|
||||
self.build_fn_call(sym, intrinsic, args, arg_layouts, ret_layout);
|
||||
}
|
||||
LowLevel::NumCountOneBits => {
|
||||
let int_width = arg_layouts[0].try_int_width().unwrap();
|
||||
let intrinsic = bitcode::NUM_COUNT_ONE_BITS[int_width].to_string();
|
||||
self.build_fn_call(sym, intrinsic, args, arg_layouts, ret_layout);
|
||||
}
|
||||
LowLevel::ListSublist => {
|
||||
// list: RocList,
|
||||
// alignment: u32,
|
||||
|
@ -436,7 +436,7 @@ fn keep_shared() {
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn keep_shared_prefer_first() {
|
||||
fn keep_shared_value_must_match() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
@ -453,14 +453,14 @@ fn keep_shared_prefer_first() {
|
||||
dict2 =
|
||||
Dict.empty {}
|
||||
|> Dict.insert 0 100
|
||||
|> Dict.insert 2 200
|
||||
|> Dict.insert 2 2
|
||||
|> Dict.insert 4 300
|
||||
|
||||
Dict.keepShared dict1 dict2
|
||||
|> Dict.values
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[2, 4]),
|
||||
RocList::from_slice(&[2]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
@ -3869,30 +3869,30 @@ fn condition_polymorphic_num_becomes_float() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn num_count_leading_zero_bits() {
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u8"#, 2, usize);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u16"#, 10, usize);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u32"#, 26, usize);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u64"#, 58, usize);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u8"#, 2, u8);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u16"#, 10, u8);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u32"#, 26, u8);
|
||||
assert_evals_to!(r#"Num.countLeadingZeroBits 0b0010_1000u64"#, 58, u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn num_count_trailing_zero_bits() {
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1000u8"#, 3, usize);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_0000u16"#, 5, usize);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0u32"#, 32, usize);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1111u64"#, 0, usize);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1000u8"#, 3, u8);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_0000u16"#, 5, u8);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0u32"#, 32, u8);
|
||||
assert_evals_to!(r#"Num.countTrailingZeroBits 0b0010_1111u64"#, 0, u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn num_count_one_bits() {
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_1000u8"#, 2, usize);
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_0000u16"#, 1, usize);
|
||||
assert_evals_to!(r#"Num.countOneBits 0u32"#, 0, usize);
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_1111u64"#, 5, usize);
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_1000u8"#, 2, u8);
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_0000u16"#, 1, u8);
|
||||
assert_evals_to!(r#"Num.countOneBits 0u32"#, 0, u8);
|
||||
assert_evals_to!(r#"Num.countOneBits 0b0010_1111u64"#, 5, u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -120,7 +120,7 @@ fn union() {
|
||||
|> Set.toList
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[1, 2, 3, 4]),
|
||||
RocList::from_slice(&[1, 3, 4, 2]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
@ -1,93 +1,46 @@
|
||||
procedure Dict.1 (Dict.595):
|
||||
let Dict.605 : List {[], []} = Array [];
|
||||
let Dict.612 : U64 = 0i64;
|
||||
let Dict.613 : U64 = 8i64;
|
||||
let Dict.606 : List U64 = CallByName List.11 Dict.612 Dict.613;
|
||||
let Dict.609 : I8 = CallByName Dict.43;
|
||||
let Dict.610 : U64 = 8i64;
|
||||
let Dict.607 : List I8 = CallByName List.11 Dict.609 Dict.610;
|
||||
let Dict.608 : U64 = 0i64;
|
||||
let Dict.604 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.605, Dict.606, Dict.607, Dict.608};
|
||||
procedure Dict.1 (Dict.596):
|
||||
let Dict.606 : List {[], []} = Array [];
|
||||
let Dict.35 : List U64 = CallByName Dict.35;
|
||||
let Dict.34 : List I8 = CallByName Dict.34;
|
||||
let Dict.605 : {List {[], []}, List U64, List I8} = Struct {Dict.606, Dict.35, Dict.34};
|
||||
ret Dict.605;
|
||||
|
||||
procedure Dict.34 ():
|
||||
let Dict.608 : I8 = CallByName Dict.46;
|
||||
let Dict.609 : I8 = CallByName Dict.46;
|
||||
let Dict.610 : I8 = CallByName Dict.46;
|
||||
let Dict.611 : I8 = CallByName Dict.46;
|
||||
let Dict.612 : I8 = CallByName Dict.46;
|
||||
let Dict.613 : I8 = CallByName Dict.46;
|
||||
let Dict.614 : I8 = CallByName Dict.46;
|
||||
let Dict.615 : I8 = CallByName Dict.46;
|
||||
let Dict.607 : List I8 = Array [Dict.608, Dict.609, Dict.610, Dict.611, Dict.612, Dict.613, Dict.614, Dict.615];
|
||||
ret Dict.607;
|
||||
|
||||
procedure Dict.35 ():
|
||||
let Dict.617 : List U64 = Array [0i64, 0i64, 0i64, 0i64, 0i64, 0i64, 0i64, 0i64];
|
||||
ret Dict.617;
|
||||
|
||||
procedure Dict.4 (Dict.603):
|
||||
let Dict.114 : List {[], []} = StructAtIndex 0 Dict.603;
|
||||
let #Derived_gen.1 : List U64 = StructAtIndex 1 Dict.603;
|
||||
dec #Derived_gen.1;
|
||||
let #Derived_gen.0 : List I8 = StructAtIndex 2 Dict.603;
|
||||
dec #Derived_gen.0;
|
||||
let Dict.604 : U64 = CallByName List.6 Dict.114;
|
||||
dec Dict.114;
|
||||
ret Dict.604;
|
||||
|
||||
procedure Dict.4 (Dict.602):
|
||||
let Dict.108 : U64 = StructAtIndex 3 Dict.602;
|
||||
let #Derived_gen.8 : List {[], []} = StructAtIndex 0 Dict.602;
|
||||
dec #Derived_gen.8;
|
||||
let #Derived_gen.7 : List U64 = StructAtIndex 1 Dict.602;
|
||||
dec #Derived_gen.7;
|
||||
let #Derived_gen.6 : List I8 = StructAtIndex 2 Dict.602;
|
||||
dec #Derived_gen.6;
|
||||
ret Dict.108;
|
||||
procedure Dict.46 ():
|
||||
let Dict.616 : I8 = -128i64;
|
||||
ret Dict.616;
|
||||
|
||||
procedure Dict.43 ():
|
||||
let Dict.611 : I8 = -128i64;
|
||||
ret Dict.611;
|
||||
|
||||
procedure List.11 (List.133, List.134):
|
||||
let List.554 : List I8 = CallByName List.68 List.134;
|
||||
let List.553 : List I8 = CallByName List.86 List.133 List.134 List.554;
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.553 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.553;
|
||||
|
||||
procedure List.11 (List.133, List.134):
|
||||
let List.566 : List U64 = CallByName List.68 List.134;
|
||||
let List.565 : List U64 = CallByName List.86 List.133 List.134 List.566;
|
||||
ret List.565;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.564 : List I8 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.564;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.576 : List U64 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.576;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.561 : List I8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.561;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.573 : List U64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.573;
|
||||
|
||||
procedure List.86 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
|
||||
joinpoint List.555 List.135 List.136 List.137:
|
||||
let List.563 : U64 = 0i64;
|
||||
let List.557 : Int1 = CallByName Num.24 List.136 List.563;
|
||||
if List.557 then
|
||||
let List.562 : U64 = 1i64;
|
||||
let List.559 : U64 = CallByName Num.75 List.136 List.562;
|
||||
let List.560 : List I8 = CallByName List.71 List.137 List.135;
|
||||
jump List.555 List.135 List.559 List.560;
|
||||
else
|
||||
ret List.137;
|
||||
in
|
||||
jump List.555 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2;
|
||||
|
||||
procedure List.86 (#Derived_gen.3, #Derived_gen.4, #Derived_gen.5):
|
||||
joinpoint List.567 List.135 List.136 List.137:
|
||||
let List.575 : U64 = 0i64;
|
||||
let List.569 : Int1 = CallByName Num.24 List.136 List.575;
|
||||
if List.569 then
|
||||
let List.574 : U64 = 1i64;
|
||||
let List.571 : U64 = CallByName Num.75 List.136 List.574;
|
||||
let List.572 : List U64 = CallByName List.71 List.137 List.135;
|
||||
jump List.567 List.135 List.571 List.572;
|
||||
else
|
||||
ret List.137;
|
||||
in
|
||||
jump List.567 #Derived_gen.3 #Derived_gen.4 #Derived_gen.5;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.294 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.294;
|
||||
|
||||
procedure Num.75 (#Attr.2, #Attr.3):
|
||||
let Num.292 : U64 = lowlevel NumSubWrap #Attr.2 #Attr.3;
|
||||
ret Num.292;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : {} = Struct {};
|
||||
let Test.2 : {List {[], []}, List U64, List I8, U64} = CallByName Dict.1 Test.3;
|
||||
let Test.2 : {List {[], []}, List U64, List I8} = CallByName Dict.1 Test.3;
|
||||
let Test.1 : U64 = CallByName Dict.4 Test.2;
|
||||
ret Test.1;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,22 +3,22 @@
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
f = \{} ->
|
||||
#^{-1} <2846><117>{} -<120>[[f(1)]]-> <116>[Ok <2854>{}]<80>*
|
||||
#^{-1} <2826><117>{} -<120>[[f(1)]]-> <116>[Ok <2834>{}]<80>*
|
||||
when g {} is
|
||||
# ^ <2836><2854>{} -<2844>[[g(2)]]-> <72>[Ok <2854>{}]<102>*
|
||||
# ^ <2816><2834>{} -<2824>[[g(2)]]-> <72>[Ok <2834>{}]<102>*
|
||||
_ -> Ok {}
|
||||
|
||||
g = \{} ->
|
||||
#^{-1} <2836><2854>{} -<2844>[[g(2)]]-> <72>[Ok <2854>{}]<102>*
|
||||
#^{-1} <2816><2834>{} -<2824>[[g(2)]]-> <72>[Ok <2834>{}]<102>*
|
||||
when h {} is
|
||||
# ^ <2841><2854>{} -<2849>[[h(3)]]-> <94>[Ok <2854>{}]<124>*
|
||||
# ^ <2821><2834>{} -<2829>[[h(3)]]-> <94>[Ok <2834>{}]<124>*
|
||||
_ -> Ok {}
|
||||
|
||||
h = \{} ->
|
||||
#^{-1} <2841><2854>{} -<2849>[[h(3)]]-> <94>[Ok <2854>{}]<124>*
|
||||
#^{-1} <2821><2834>{} -<2829>[[h(3)]]-> <94>[Ok <2834>{}]<124>*
|
||||
when f {} is
|
||||
# ^ <2846><117>{} -<120>[[f(1)]]-> <116>[Ok <2854>{}]<80>*
|
||||
# ^ <2826><117>{} -<120>[[f(1)]]-> <116>[Ok <2834>{}]<80>*
|
||||
_ -> Ok {}
|
||||
|
||||
main = f {}
|
||||
# ^ <2856><133>{} -<136>[[f(1)]]-> <138>[Ok <2854>{}]<2855>w_a
|
||||
# ^ <2836><133>{} -<136>[[f(1)]]-> <138>[Ok <2834>{}]<2835>w_a
|
||||
|
Loading…
Reference in New Issue
Block a user