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:
- http://codecapsule.com/2013/11/11/robin-hood-hashing/
- http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
- https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/
Static methods
new
Show source codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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 codeHide 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
Clone
impl Clone[Map[K, V]] for Map
if
K: Equal[ref K] + Hash + Clone[K],
V: Clone[V]
Contains
impl Contains[K] for Map
Equal
impl Equal[ref Map[K, V]] for Map
if
V: Equal[ref V]
Format
impl Format for Map
if
K: Equal[ref K] + Hash + Format,
V: Format
Hash
impl Hash for Map
if
K: Equal[ref K] + Hash + Hash,
V: Hash