mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
add dict tests with string keys/values
This commit is contained in:
parent
7f8ca150f5
commit
02e161f839
3 changed files with 112 additions and 62 deletions
|
@ -5,8 +5,6 @@ const mem = std.mem;
|
|||
const Allocator = mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const level_size = 32;
|
||||
|
||||
const INITIAL_SEED = 0xc70f6907;
|
||||
const REFCOUNT_ONE_ISIZE: comptime isize = std.math.minInt(isize);
|
||||
const REFCOUNT_ONE: usize = @bitCast(usize, REFCOUNT_ONE_ISIZE);
|
||||
|
@ -31,10 +29,11 @@ const MaybeIndex = union(MaybeIndexTag) {
|
|||
};
|
||||
|
||||
fn nextSeed(seed: u64) u64 {
|
||||
// TODO is this a valid way to get a new seed? are there better ways?
|
||||
return seed + 1;
|
||||
}
|
||||
|
||||
fn total_slots_at_level(input: usize) usize {
|
||||
fn totalCapacityAtLevel(input: usize) usize {
|
||||
if (input == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,17 +105,6 @@ pub const RocDict = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: RocDict, allocator: *Allocator, key_size: usize, value_size: usize) void {
|
||||
if (!self.isEmpty()) {
|
||||
const slot_size = slotSize(key_size, value_size);
|
||||
|
||||
const dict_bytes_ptr: [*]u8 = self.dict_bytes orelse unreachable;
|
||||
|
||||
const dict_bytes: []u8 = dict_bytes_ptr[0..(self.number_of_levels)];
|
||||
allocator.free(dict_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
allocator: *Allocator,
|
||||
number_of_levels: usize,
|
||||
|
@ -125,7 +113,7 @@ pub const RocDict = extern struct {
|
|||
key_size: usize,
|
||||
value_size: usize,
|
||||
) RocDict {
|
||||
const number_of_slots = total_slots_at_level(number_of_levels);
|
||||
const number_of_slots = totalCapacityAtLevel(number_of_levels);
|
||||
const slot_size = slotSize(key_size, value_size);
|
||||
const data_bytes = number_of_slots * slot_size;
|
||||
|
||||
|
@ -147,7 +135,7 @@ pub const RocDict = extern struct {
|
|||
const slot_size = slotSize(key_width, value_width);
|
||||
|
||||
const old_capacity = self.capacity();
|
||||
const new_capacity = total_slots_at_level(new_level);
|
||||
const new_capacity = totalCapacityAtLevel(new_level);
|
||||
const delta_capacity = new_capacity - old_capacity;
|
||||
|
||||
const data_bytes = new_capacity * slot_size;
|
||||
|
@ -155,8 +143,7 @@ pub const RocDict = extern struct {
|
|||
|
||||
// transfer the memory
|
||||
|
||||
if (old_capacity > 0) {
|
||||
const source_ptr = self.dict_bytes orelse unreachable;
|
||||
if (self.dict_bytes) |source_ptr| {
|
||||
const dest_ptr = first_slot;
|
||||
|
||||
var source_offset: usize = 0;
|
||||
|
@ -208,10 +195,6 @@ pub const RocDict = extern struct {
|
|||
return @ptrCast([*]u8, self.dict_bytes);
|
||||
}
|
||||
|
||||
pub fn contains(self: RocDict, key_size: usize, key_ptr: *const c_void, hash_code: u64) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn len(self: RocDict) usize {
|
||||
return self.dict_entries_len;
|
||||
}
|
||||
|
@ -221,17 +204,18 @@ pub const RocDict = extern struct {
|
|||
}
|
||||
|
||||
pub fn isUnique(self: RocDict) bool {
|
||||
// the empty dict is unique (in the sense that copying it will not leak memory)
|
||||
if (self.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise, check if the refcount is one
|
||||
const ptr: [*]usize = @ptrCast([*]usize, @alignCast(8, self.dict_bytes));
|
||||
|
||||
return (ptr - 1)[0] == REFCOUNT_ONE;
|
||||
}
|
||||
|
||||
pub fn capacity(self: RocDict) usize {
|
||||
return total_slots_at_level(self.number_of_levels);
|
||||
return totalCapacityAtLevel(self.number_of_levels);
|
||||
}
|
||||
|
||||
pub fn makeUnique(self: RocDict, allocator: *Allocator, alignment: Alignment, key_width: usize, value_width: usize) RocDict {
|
||||
|
@ -264,21 +248,15 @@ pub const RocDict = extern struct {
|
|||
fn getSlot(self: *const RocDict, index: usize, key_width: usize, value_width: usize) Slot {
|
||||
const offset = self.capacity() * (key_width + value_width) + index * @sizeOf(Slot);
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
return @intToEnum(Slot, u8_ptr[offset]);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
return @intToEnum(Slot, ptr[offset]);
|
||||
}
|
||||
|
||||
fn setSlot(self: *RocDict, index: usize, key_width: usize, value_width: usize, slot: Slot) void {
|
||||
const offset = self.capacity() * (key_width + value_width) + index * @sizeOf(Slot);
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
u8_ptr[offset] = @enumToInt(slot);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
ptr[offset] = @enumToInt(slot);
|
||||
}
|
||||
|
||||
fn setKey(self: *RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize, data: Opaque) void {
|
||||
|
@ -290,12 +268,11 @@ pub const RocDict = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
|
||||
const source = data orelse unreachable;
|
||||
@memcpy(u8_ptr + offset, source, key_width);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const dest = ptr + offset;
|
||||
@memcpy(dest, source, key_width);
|
||||
}
|
||||
|
||||
fn getKey(self: *const RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize) Opaque {
|
||||
|
@ -307,11 +284,8 @@ pub const RocDict = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
return u8_ptr + offset;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
return ptr + offset;
|
||||
}
|
||||
|
||||
fn setValue(self: *RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize, data: Opaque) void {
|
||||
|
@ -323,12 +297,11 @@ pub const RocDict = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
|
||||
const source = data orelse unreachable;
|
||||
@memcpy(u8_ptr + offset, source, key_width);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const dest = ptr + offset;
|
||||
@memcpy(dest, source, value_width);
|
||||
}
|
||||
|
||||
fn getValue(self: *const RocDict, index: usize, alignment: Alignment, key_width: usize, value_width: usize) Opaque {
|
||||
|
@ -340,11 +313,8 @@ pub const RocDict = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
if (self.dict_bytes) |u8_ptr| {
|
||||
return u8_ptr + offset;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
const ptr = self.dict_bytes orelse unreachable;
|
||||
return ptr + offset;
|
||||
}
|
||||
|
||||
fn findIndex(self: *const RocDict, alignment: Alignment, key: Opaque, key_width: usize, value_width: usize, hash_fn: HashFn, is_eq: EqFn) MaybeIndex {
|
||||
|
|
|
@ -13,6 +13,8 @@ mod helpers;
|
|||
|
||||
#[cfg(test)]
|
||||
mod gen_dict {
|
||||
use roc_std::RocStr;
|
||||
|
||||
#[test]
|
||||
fn dict_empty_len() {
|
||||
assert_evals_to!(
|
||||
|
@ -233,4 +235,78 @@ mod gen_dict {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn small_str_keys() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
myDict : Dict Str I64
|
||||
myDict =
|
||||
Dict.empty
|
||||
|> Dict.insert "a" 100
|
||||
|> Dict.insert "b" 100
|
||||
|> Dict.insert "c" 100
|
||||
|
||||
|
||||
Dict.keys myDict
|
||||
"#
|
||||
),
|
||||
&[
|
||||
RocStr::from_str("c"),
|
||||
RocStr::from_str("a"),
|
||||
RocStr::from_str("b"),
|
||||
],
|
||||
&[RocStr]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_str_keys() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
myDict : Dict Str I64
|
||||
myDict =
|
||||
Dict.empty
|
||||
|> Dict.insert "Leverage agile frameworks to provide a robust" 100
|
||||
|> Dict.insert "synopsis for high level overviews. Iterative approaches" 200
|
||||
|> Dict.insert "to corporate strategy foster collaborative thinking to" 300
|
||||
|
||||
|
||||
Dict.keys myDict
|
||||
"#
|
||||
),
|
||||
&[
|
||||
RocStr::from_str("Leverage agile frameworks to provide a robust"),
|
||||
RocStr::from_str("to corporate strategy foster collaborative thinking to"),
|
||||
RocStr::from_str("synopsis for high level overviews. Iterative approaches"),
|
||||
],
|
||||
&[RocStr]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn big_str_values() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
myDict : Dict I64 Str
|
||||
myDict =
|
||||
Dict.empty
|
||||
|> Dict.insert 100 "Leverage agile frameworks to provide a robust"
|
||||
|> Dict.insert 200 "synopsis for high level overviews. Iterative approaches"
|
||||
|> Dict.insert 300 "to corporate strategy foster collaborative thinking to"
|
||||
|
||||
Dict.values myDict
|
||||
"#
|
||||
),
|
||||
&[
|
||||
RocStr::from_str("Leverage agile frameworks to provide a robust"),
|
||||
RocStr::from_str("to corporate strategy foster collaborative thinking to"),
|
||||
RocStr::from_str("synopsis for high level overviews. Iterative approaches"),
|
||||
],
|
||||
&[RocStr]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,6 +401,10 @@ impl RocStr {
|
|||
Self::from_slice_with_capacity_str(slice, slice.len())
|
||||
}
|
||||
|
||||
pub fn from_str(slice: &str) -> RocStr {
|
||||
Self::from_slice_with_capacity_str(slice.as_bytes(), slice.len())
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
if self.is_small_str() {
|
||||
unsafe { core::slice::from_raw_parts(self.get_small_str_ptr(), self.len()) }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue