Skip to content

Commit

Permalink
add map_entry procedure
Browse files Browse the repository at this point in the history
  • Loading branch information
laytan committed Nov 28, 2024
1 parent 2769281 commit 8050622
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
26 changes: 26 additions & 0 deletions base/runtime/core_builtin.odin
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,32 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
return
}

/*
Retrieves a pointer to the key and value for a possibly just inserted entry into the map.
If the `key` was not in the map `m`, an entry is inserted with the zero value and `just_inserted` will be `true`.
Otherwise the existing entry is left untouched and pointers to its key and value are returned.
If the map has to grow in order to insert the entry and the allocation fails, `err` is set and returned.
If `err` is `nil`, `key_ptr` and `value_ptr` are valid pointers and will not be `nil`.
WARN: User modification of the key pointed at by `key_ptr` should only be done if the new key is equal to (in hash) the old key.
If that is not the case you will corrupt the map.
*/
@(builtin, require_results)
map_entry :: proc(m: ^$T/map[$K]$V, key: K, loc := #caller_location) -> (key_ptr: ^K, value_ptr: ^V, just_inserted: bool, err: Allocator_Error) {
key := key
zero: V

_key_ptr, _value_ptr: rawptr
_key_ptr, _value_ptr, just_inserted, err = __dynamic_map_entry((^Raw_Map)(m), map_info(T), &key, &zero, loc)

key_ptr = (^K)(_key_ptr)
value_ptr = (^V)(_value_ptr)
return
}


@builtin
card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
Expand Down
23 changes: 23 additions & 0 deletions base/runtime/dynamic_map_internal.odin
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,29 @@ __dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
return nil, rawptr(result)
}

__dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key: rawptr, zero: rawptr, loc := #caller_location) -> (key_ptr: rawptr, value_ptr: rawptr, just_inserted: bool, err: Allocator_Error) {
hash := info.key_hasher(key, map_seed(m^))

if key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil {
return
}

has_grown: bool
if err, has_grown = __dynamic_map_check_grow(m, info, loc); err != nil {
return
} else if has_grown {
hash = info.key_hasher(key, map_seed(m^))
}

value_ptr = rawptr(map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(zero)))
assert(value_ptr != nil)
key_ptr = rawptr(map_cell_index_dynamic(map_data(m^), info.ks, map_desired_position(m^, hash)))

m.len += 1
just_inserted = true
return
}


// IMPORTANT: USED WITHIN THE COMPILER
@(private)
Expand Down

0 comments on commit 8050622

Please sign in to comment.