Maps (Hash Maps)

  • Maps .

  • Zero value of a map is nil . A nil  map has no keys.

Maps Memory Layout

  • Always a copy

    m: map[string]int = ... 
    m2 := m 
    // points to the same data as m
    
    m2["foo"] = 123 
    // m is not aware of the new key that was added--it's in the data, but m has the wrong length 
    // worse, this could cause the map to reallocate, in which case m would point to freed memory 
    
    delete(m2) 
    // m is now definitely invalid
    
  • Are you trying to remove the entire map entry? if so: https://pkg.odin-lang.org/base/builtin/#delete_key  and then delete  the deleted_key  (and deleted_entry  if you allocated it) (edited)

  • Be consistent with your keys in the map--like I said, clone them all (and then you know you should delete them all when you delete the map) or don't clone any (and then you know not to delete any, but you also need to be careful with what you insert).

  • string s just happen to be particularly annoying to deal with because  they're pointers

  • Individual frees:

    • x[a] = b  gives me Mode_Not_Implemented  when using an vmem.Arena  as the backing allocator.

    • rats:

      • They're like a dynamic array in that regard.

      • when they get too big they move; I believe a map will resize once it's filled 75% of its space

  • 64bytes alignment:

    • I'm currently ignoring the problem by using arenas with 64bytes alignment.

    • rats:

      • Make sure the arena has 64byte alignment

      • should be an alignment argument when you make the arena, maps won't work without it.

    • Ginger Bill:

      • The map  type in Odin REQUIRES an allocator that can do 64-byte aligned allocations.

      • What you'll need to do is change the alignment when initializing the dynamic arena: dynamic_arena_init(&arena, alignment=64)

      • This does mean every allocation is a bit wasteful, unfortunately.

      • But that's the problem of custom allocators and trying to treat them "generally" any way.

    • (2025-11-23) Alignment confusion:

      • The vmem.Arena  doesn't have an option to change the alignment; it set as 0  as default.

      • The Dynamic_Arena  has this option:

        • dynamic_arena_init : "This procedure initializes a dynamic arena. The specified block_allocator  will be used to allocate arena blocks, and array_allocator  to allocate arrays of blocks and out-band blocks. The blocks have the default size of block_size  and out-band threshold will be out_band_size . All allocations will be aligned to a boundary specified by alignment ."

        • The default alignment is: DEFAULT_ALIGNMENT :: 2 * align_of(rawptr) , which seems to be equal to a total of 2 * 8 = 16 bytes  for 64bit systems.

          • x64 == 64bit?

            • Not always, but usually.

            • x64 is the common name for AMD64, the 64-bit extension of x86.

            • Most desktop/server โ€œ64-bitโ€ systems today use x64/AMD64.

            • But 64-bit is a broader category that also includes other 64-bit ISAs such as ARM64/AArch64, RISC-V RV64, PowerPC64, etc.

Create

  • Using make :

    • Uses the current context .

    m := make(map[string]int)
    
  • Map literals:

    m := map[string]int{
        "Bob" = 2,
        "Chloe" = 5,
    }
    

Delete

  • Using delete :

    delete(m)
    

Insert / update

m[key] = elem

Access

elem = m[key]
  • If an element for a key does not exist, the zero  value of the element will be returned.

elem, ok := m[key] // `ok` is true if the element for that key exists
    // โ€œcomma ok idiomโ€

//or 

ok := key in m     // `ok` is true if the element for that key exists

Remove element

delete_key :: proc(m: ^$T/map[$K]$V, key: $K) -> (deleted_key: $K, deleted_value: $V) {โ€ฆ}

Modify

Test :: struct {
    x: int,
    y: int,
}

m := map[string]Test{
    "Bob" = { 0, 0 },
    "Chloe" = { 1, 1 },
}

// Method 1
value, ok := &m["Bob"]
if ok {
    value^ = { 2, 2 }
}

// Method 2
m["Bob"] = { 3, 3 }

// Method 3 (Forbidden)
m["Chloe"].x = 0

"Compound Literals"

  • To enable compound literals for map s, #+feature dynamic-literals  must be enabled per file.

  • This is because dynamic literals will use the current context.allocator  and thus implicitly allocate.

  • The opt-in feature exists so that Odin does not implicitly allocate by default and give the user any surprises.

Container Calls

  • The built-in map also supports all the standard container calls that can be found with the dynamic array .

  • len(some_map)

    • Returns the number of slots used

  • clear(&some_map)

    • Clears the entire map - dynamically allocated content needs to be freed manually

  • cap(some_map)

    • Returns the capacity of the map - the map will reallocate when exceeded

  • shrink(&some_map)

    • Shrinks the capacity down to the current length

  • reserve(&some_map, capacity)

    • Reserves the requested number of elements