Search results

There are no results.

std.map.Map

class pub Map[K: Equal[ref K] + Hash, V]

A hash map using linear probing and Robin Hood hashing.

A Map preserves the order in which values are inserted, even when entries are removed.

Performance

Preserving the insertion order makes it easier to use a Map (e.g. when writing tests or when serialising it), but comes with the trade-off that removals are more expensive. Our implementation simply shifts values when removing them. This makes removals more expensive compared to traditional maps (O(n) in the worst case, with n being the number of entries), but removes the need for using tombstones and extra indirection.

If you find yourself in a situation where you need to remove many entries from a Map, it may be faster to construct a new Map that only contains the key/value pairs you are interested in.

Algorithm

Map uses Robin Hood hashing, with the necessary changes to make this work while preserving insertion order. For more information on these algorithms you can refer to the following resources:

Static methods

new

Show source code
Hide source code
fn pub static new -> Map[K, V] {
  with_capacity(DEFAULT_CAPACITY)
}
fn pub static new -> Map[K, V]

Returns a new empty Map.

with_capacity

Show source code
Hide source code
fn pub static with_capacity(amount: Int) -> Map[K, V] {
  let size = if amount <= 0 {
    DEFAULT_CAPACITY
  } else {
    amount.nearest_power_of_two
  }
  let slots = Array.filled(with: EMPTY, times: size)
  let resize_at = resize_threshold(size)

  Map(slots: slots, entries: [], resize_at: resize_at)
}
fn pub static with_capacity(amount: Int) -> Map[K, V]

Returns a new Map with space for at least the given number of values.

The actual size may be larger.

Examples

let map = Map.with_capacity(32)

map.set('name', 'Alice')

Instance methods

!=

Show source code
Hide source code
fn pub !=(other: T) -> Bool {
  (self == other).false?
}
fn pub !=(other: T) -> Bool

Returns true if self and the given object are not equal to each other.

==

Show source code
Hide source code
fn pub ==(other: ref Map[K, V]) -> Bool {
  if size != other.size { return false }

  iter.all?(fn (ours) {
    match other.entries_index(ours.key) {
      case EMPTY -> false
      case index -> other.entries.get(index).value == ours.value
    }
  })
}
fn pub ==(other: ref Map[K, V]) -> Bool
if
  V: Equal[ref V]

Returns true if self and the given Map are identical to each other.

Examples

Comparing two Map instances:

let map1 = Map.new
let map2 = Map.new

map1.set('name', 'Alice')
map2.set('name', 'Alice')

map1 == map2 # => true

capacity

Show source code
Hide source code
fn pub capacity -> Int {
  @slots.size
}
fn pub capacity -> Int

Returns the number of entries this map can store before needing a resize.

Examples

Map.new.capacity              # => 4
Map.with_capacity(8).capacity # => 8

clone

Show source code
Hide source code
fn pub clone -> Map[K, V] {
  Map(slots: @slots.clone, entries: @entries.clone, resize_at: @resize_at)
}
fn pub clone -> Map[K, V]
if
  K: Equal[ref K] + Hash + Clone[K],
  V: Clone[V]

Creates a clone of self.

contains?

Show source code
Hide source code
fn pub contains?(value: ref K) -> Bool {
  entries_index(value) > EMPTY
}
fn pub contains?(value: ref K) -> Bool

Returns true if self contains the key key.

Examples

Checking if a Map defines a key:

let map = Map.new

map.set('name', 'Alice')
map.contains?('name') # => true
map.contains?('city') # => false

fmt

Show source code
Hide source code
fn pub fmt(formatter: mut Formatter) {
  formatter.write('{')

  iter.each_with_index(fn (index, entry) {
    if index > 0 { formatter.write(', ') }

    entry.key.fmt(formatter)
    formatter.write(': ')
    entry.value.fmt(formatter)
  })

  formatter.write('}')
}
fn pub fmt(formatter: mut Formatter)
if
  K: Equal[ref K] + Hash + Format,
  V: Format

Formats self in a human-readable format for debugging purposes.

get

Show source code
Hide source code
fn pub get(index: ref K) -> ref V {
  match entries_index(index) {
    case EMPTY -> panic("The key doesn't exist")
    case index -> @entries.get(index).value
  }
}
fn pub get(index: ref K) -> ref V

Returns an immutable reference to the value of the given key.

Panics

This method panics if the key doesn't exist.

Examples

Getting the value of an existing key:

let mut map = Map.new

map.set('name', 'Alice')
map.get('name') # => 'Alice'

get_mut

Show source code
Hide source code
fn pub mut get_mut(index: ref K) -> mut V {
  match entries_index(index) {
    case EMPTY -> panic("The key doesn't exist")
    case index -> @entries.get_mut(index).value
  }
}
fn pub mut get_mut(index: ref K) -> mut V: mut
if
  V: mut

Returns a mutable reference to the value of the given key.

Panics

This method panics if the key doesn't exist.

hash

Show source code
Hide source code
fn pub hash[H: mut + Hasher](hasher: mut H) {
  iter.each(fn (entry) {
    entry.key.hash(hasher)
    entry.value.hash(hasher)
  })
}
fn pub hash[H: mut + Hasher](hasher: mut H: mut)
if
  K: Equal[ref K] + Hash + Hash,
  V: Hash

Writes the hash for self into the given Hasher.

into_iter

Show source code
Hide source code
fn pub move into_iter -> IntoIter[Entry[K, V]] {
  @entries.into_iter
}
fn pub move into_iter -> IntoIter[Entry[K, V]]

Returns an Iter that iterates over all key-value pairs in this Map, yielding them by value.

Examples

let mut map = Map.new

map.set('name', 'Alice')

map.into_iter.each fn (e) {
  e.key   # => 'name'
  e.value # => 'Alice'
}

iter

Show source code
Hide source code
fn pub iter -> Stream[ref Entry[K, V]] {
  @entries.iter
}
fn pub iter -> Stream[ref Entry[K, V]]

Returns an iterator of immutable key-value pairs.

Examples

Iterating over all the key-value pairs:

let mut map = Map.new

map.set('name', 'Alice')

map.iter.each fn (entry) {
  entry.key   # => 'name'
  entry.value # => 'Alice'
}

iter_mut

Show source code
Hide source code
fn pub mut iter_mut -> Stream[mut Entry[K, V]] {
  @entries.iter_mut
}
fn pub mut iter_mut -> Stream[mut Entry[K, V]]

Returns an iterator of mutable key-value pairs.

Examples

Iterating over all the key-value pairs:

let mut map = Map.new

map.set('name', 'Alice')

map.iter_mut.each fn (entry) {
  entry.key   # => 'name'
  entry.value # => 'Alice'
}

keys

Show source code
Hide source code
fn pub keys -> Stream[ref K] {
  iter.map(fn (e) { e.key })
}
fn pub keys -> Stream[ref K]

Returns an Iter visiting all the keys in this Map.

Examples

Iterating over the keys in a Map:

let mut map = Map.new

map.set('name', 'Alice')

map.keys.each fn (key) {
  key # => 'name'
}

merge

Show source code
Hide source code
fn pub mut merge(other: Map[K, V]) {
  other.into_iter.each(fn (entry) {
    entry.distance = 0
    entry.hash = hash_key(entry.key)

    insert_entry(entry)
  })
}
fn pub mut merge(other: Map[K, V])

Merges two Map objects together.

Examples

let map1 = Map.new
let map2 = Map.new

map1.set('name', 'Alice')
map2.set('city', 'Amsterdam')

map1.merge(map2)

map1['name'] # => 'Alice'
map2['city'] # => 'Amsterdam'

opt

Show source code
Hide source code
fn pub opt(key: ref K) -> Option[ref V] {
  match entries_index(key) {
    case EMPTY -> Option.None
    case index -> Option.Some(@entries.get(index).value)
  }
}
fn pub opt(key: ref K) -> Option[ref V]

Returns an optional immutable reference to the key's value.

Examples

Getting the value of a non-existing key:

let map = Map.new

map.opt('name') # => Option.None

Getting the value of an existing key:

let mut map = Map.new

map.set('name', 'Alice')

map.opt('name') # => Option.Some('Alice')

opt_mut

Show source code
Hide source code
fn pub mut opt_mut(key: ref K) -> Option[mut V] {
  match entries_index(key) {
    case EMPTY -> Option.None
    case index -> Option.Some(@entries.get_mut(index).value)
  }
}
fn pub mut opt_mut(key: ref K) -> Option[mut V: mut]
if
  V: mut

Returns an optional mutable reference to the key's value.

remove

Show source code
Hide source code
fn pub mut remove(key: ref K) -> Option[V] {
  let mut slot = slot_index(hash_key(key))
  let mut dist = 0
  let mut index = @slots.get(slot)

  # For the removal we need both the slot and the entry index, so we have to
  # duplicate the logic of `entries_index()` here, as this is the only place
  # we need both.
  loop {
    if index == EMPTY { return Option.None }

    let entry = @entries.get(index)

    if dist > entry.distance { return Option.None }

    if entry.key == key { break }

    slot = slot_index(slot + 1)
    index = @slots.get(slot)
    dist += 1
  }

  let value = @entries.remove_at(index).into_value

  @slots.set(slot, EMPTY)

  # Because we shifted the entries to the left, any slots pointing to entries
  # _after_ the removed value have to be updated accordingly.
  @slots.iter.each_with_index(fn (slot, entry) {
    if entry > index { @slots.set(slot, entry - 1) }
  })

  let mut prev_slot = slot

  slot = slot_index(slot + 1)

  loop {
    let mut index = @slots.get(slot)

    if index == EMPTY { break }

    let entry = @entries.get_mut(index)

    if entry.distance > 0 {
      @slots.set(slot, EMPTY)
      @slots.set(prev_slot, index)

      entry.distance -= 1
    } else {
      break
    }

    prev_slot = slot
    slot = slot_index(slot + 1)
  }

  Option.Some(value)
}
fn pub mut remove(key: ref K) -> Option[V]

Removes the given key, returning its value if the key was present.

Examples

Removing a non-existing key:

let mut map = Map.new

map.remove('name') # => Option.None

Removing an existing key:

let mut map = Map.new

map.set('name', 'Alice')

map.remove('name') # => Option.Some('Alice')

set

Show source code
Hide source code
fn pub mut set(key: K, value: V) -> Option[V] {
  if size >= @resize_at { resize }

  let hash = hash_key(key)
  let entry = Entry(key: key, value: value, hash: hash, distance: 0)

  insert_entry(entry)
}
fn pub mut set(key: K, value: V) -> Option[V]

Inserts the key and value in this Map, returning the previous value (if any).

Examples

Inserting a new key-value pair:

let mut map = Map.new

map.set('name', 'Alice') # => 'Alice'

size

Show source code
Hide source code
fn pub size -> Int {
  @entries.size
}
fn pub size -> Int

Returns the number of key-value pairs in this map.

Examples

Using an empty map:

let map = Map.new

map.size # => 0

Using a map with one key-value pair:

let map = Map.new

map.set('name', 'Alice')

map.size # => 1

values

Show source code
Hide source code
fn pub values -> Stream[ref V] {
  iter.map(fn (e) { e.value })
}
fn pub values -> Stream[ref V]

Returns an iterator that yields immutable references to the values in self.

Examples

Iterating over the values in a Map:

let mut map = Map.new

map.set('name', 'Alice')

map.values.each fn (value) {
  value # => 'Alice'
}

values_mut

Show source code
Hide source code
fn pub mut values_mut -> Stream[mut V] {
  iter_mut.map(fn (e) { e.value })
}
fn pub mut values_mut -> Stream[mut V: mut]
if
  V: mut

Returns an iterator that yields mutable references to the values in self.

Examples

Iterating over the values in a Map:

let mut map = Map.new

map.set('name', 'Alice')

map.values_mut.each fn (value) {
  value # => 'Alice'
}

Implemented traits

std.clone.

Clone

impl Clone[Map[K, V]] for Map
if
  K: Equal[ref K] + Hash + Clone[K],
  V: Clone[V]
std.cmp.

Contains

impl Contains[K] for Map
std.cmp.

Equal

impl Equal[ref Map[K, V]] for Map
if
  V: Equal[ref V]
std.fmt.

Format

impl Format for Map
if
  K: Equal[ref K] + Hash + Format,
  V: Format
std.hash.

Hash

impl Hash for Map
if
  K: Equal[ref K] + Hash + Hash,
  V: Hash