Serene Runtime 1.0.0
C runtime for the Serene programming language
Loading...
Searching...
No Matches
hashmap.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21/// @file
22/// This is an implementation of Compressed Hash-Array Mapped Prefix-tree,
23/// which is a bit-partitioned, persistent, immutable Hashed array mapped trie.
24///
25/// For more information, have a look at the `Optimizing Hash-Array Mapped Tries
26/// for Fast and Lean Immutable JVM Collections` paper.
27///
28///
29/// TL;DR:
30/// - Every struct is immutable
31/// - Nodes are persistent and immutable.
32/// - Nodes are heap allocated
33/// - Heads can be stack allocated
34/// - We create a new head for any change and probably will create inner nodes
35/// as well depending on the change
36/// - New heads will share structure with the older version
37/// - This is not a ordered hashmap
38/// - The hashing function HAS TO BE DETERMINISTIC
39/// - Don't use pointers value as the data to hash, use the data that they
40/// point
41/// to instead.
42
43#include <stddef.h>
44#include <stdint.h>
45
46#include "serene/rt/errors.h"
47
48typedef struct srn_context_t srn_context_t;
49
50// -----------------------------------------------------------------------------
51// Tunables
52// -----------------------------------------------------------------------------
53/// branching factor (power of two)
54#define HMAP_BR 32u
55#define HMAP_SHIFT 5u
56#define HMAP_MASK (HMAP_BR - 1u)
57#define HMAP_HASH_SIZE 32u ///< By default we use 32bit hashes
58#define HMAP_HASH_TYPE uint32_t
59#define HMAP_BITMAP_TYPE uint32_t
60
63typedef void *hmap_data_t;
64
65/// Note: For key equality we use the memcpy function
66typedef struct hmap_key_t {
67 /// len 0 -> data == nullptr
68 void *data;
69 size_t len;
71
77
78typedef struct hmap_node_t {
81 /// This is really a (void **) which each entry in the array
82 /// will be either (mutually exclusive):
83 /// - A pointer to a hmap_kv_entry_t (or a collision node), which mean the
84 /// actual key/value is in that slot.
85 /// - A pointer to the next hmap_node_t (a child of the current node)
86 /// that is determined by the corresponding bit in the `datamap` and `nodemap`
87 /// bitmaps.
88 ///
89 /// For example, if datamap is `0b...110` and nodemap is `0b...001` then
90 /// the first entry, is a child node (a pointer to hmap_node_t) and second and
91 /// third entries are pointers to `hmap_kv_entry_t` or simply the key/value
94
95typedef struct hmap_t {
96 /// Number of key/value pairs in the map
97 size_t len;
100
101/// If we ever want to modify some of these behaviours for a new instance
102/// of hashmap, we should use this control type.
103typedef struct hmap_control_t {
104 bool (*cmp)(srn_context_t *ctx, const hmap_key_t *a, const hmap_key_t *b);
106 hmap_t (*insert)(const struct hmap_control_t *ctl, srn_context_t *ctx,
107 const hmap_t *hmap, hmap_key_t *k, void *v);
108 void *(*lookup)(const struct hmap_control_t *ctl, srn_context_t *ctx,
109 const hmap_t *hmap, const hmap_key_t *k, void *default_value);
110
112
114
115/// Create, initialize and return a new hashmap
116[[nodiscard]] [[gnu::nonnull(1)]] hmap_t hmap_empty(srn_context_t *ctx);
117/// Insert the given key `k` with the value `v` in the given hash `hmap` and
118/// return the new map.
119/// The new map will share parts of its structure with the old map and never
120/// mutate the old map.
121[[nodiscard]] [[gnu::nonnull(1, 2, 3)]] hmap_t
122hmap_insert(srn_context_t *ctx, const hmap_t *hmap, hmap_key_t *k, void *v);
123
124/// Just like the `hmap_insert` function but, it receives a `hmap_control_t` to
125/// customize the comparison and hashing function.
126[[nodiscard]] [[gnu::nonnull(1, 2, 3)]]
128 const hmap_t *hmap, hmap_key_t *k, void *v);
129
130/// Lookup the given `k` in the given `hmap` and return the value if it's been
131/// found. Otherwise return the `default_value` value. Since a `nullptr` is a
132/// valid value for any keys, returning a `nullptr` is not a good option to
133/// indicate that the key does not exist, So it's safer to use explicit values
134/// to differenciate between a missing key and a legit nullptr as a value.
135[[nodiscard]] [[gnu::nonnull(1, 2, 3)]]
136void *hmap_lookup(srn_context_t *ctx, const hmap_t *hmap, const hmap_key_t *k,
137 void *default_value);
138
139/// Just like the `hmap_lookup` function but, it receives a `hmap_control_t` to
140/// customize the comparison and hashing function.
141void *hmap_lookup_ctl(const hmap_control_t *ctl, srn_context_t *ctx,
142 const hmap_t *hmap, const hmap_key_t *k,
143 void *default_value);
144/// This is a simple hack to mock the hash function during tests to force a high
145/// collision hashing function. Outside of tests, this will be a wrapper around
146/// `srn_hash`.
147[[gnu::nonnull(1)]]
148hmap_hash_t hmap_hash(srn_context_t *ctx, const void *data, size_t len);
149
150/// Create a new key out of the given `data`, with the given len.
151[[gnu::nonnull(1, 2)]]
152hmap_key_t *hmap_make_key(srn_context_t *ctx, void *data, size_t len);
hmap_control_t hmap_default_control
Definition hashmap.c:636
#define HMAP_BITMAP_TYPE
Definition hashmap.h:59
void * hmap_data_t
Definition hashmap.h:63
#define HMAP_HASH_TYPE
Definition hashmap.h:58
hmap_t hmap_empty(srn_context_t *ctx)
Create, initialize and return a new hashmap.
Definition hashmap.c:612
void * hmap_lookup(srn_context_t *ctx, const hmap_t *hmap, const hmap_key_t *k, void *default_value)
Lookup the given k in the given hmap and return the value if it's been found.
Definition hashmap.c:622
hmap_hash_t hmap_hash(srn_context_t *ctx, const void *data, size_t len)
This is a simple hack to mock the hash function during tests to force a high collision hashing functi...
Definition hashmap.c:78
hmap_t hmap_insert(srn_context_t *ctx, const hmap_t *hmap, hmap_key_t *k, void *v)
Insert the given key k with the value v in the given hash hmap and return the new map.
Definition hashmap.c:618
struct hmap_t hmap_t
void * hmap_lookup_ctl(const hmap_control_t *ctl, srn_context_t *ctx, const hmap_t *hmap, const hmap_key_t *k, void *default_value)
Just like the hmap_lookup function but, it receives a hmap_control_t to customize the comparison and ...
Definition hashmap.c:597
hmap_key_t * hmap_make_key(srn_context_t *ctx, void *data, size_t len)
Create a new key out of the given data, with the given len.
Definition hashmap.c:627
HMAP_BITMAP_TYPE hmap_bitmap_t
Definition hashmap.h:62
HMAP_HASH_TYPE hmap_hash_t
Definition hashmap.h:61
hmap_t hmap_insert_ctl(const hmap_control_t *ctl, srn_context_t *ctx, const hmap_t *hmap, hmap_key_t *k, void *v)
Just like the hmap_insert function but, it receives a hmap_control_t to customize the comparison and ...
Definition hashmap.c:559
If we ever want to modify some of these behaviours for a new instance of hashmap, we should use this ...
Definition hashmap.h:103
hmap_hash_t(* hash)(srn_context_t *ctx, const hmap_key_t *k)
Definition hashmap.h:105
bool(* cmp)(srn_context_t *ctx, const hmap_key_t *a, const hmap_key_t *b)
Definition hashmap.h:104
hmap_t(* insert)(const struct hmap_control_t *ctl, srn_context_t *ctx, const hmap_t *hmap, hmap_key_t *k, void *v)
Definition hashmap.h:106
Note: For key equality we use the memcpy function.
Definition hashmap.h:66
void * data
len 0 -> data == nullptr
Definition hashmap.h:68
size_t len
Definition hashmap.h:69
Definition hashmap.h:72
hmap_key_t * k
Definition hashmap.h:74
void * v
Definition hashmap.h:75
hmap_hash_t hash
Definition hashmap.h:73
hmap_data_t * entries
This is really a (void **) which each entry in the array will be either (mutually exclusive):
Definition hashmap.h:92
hmap_bitmap_t datamap
Definition hashmap.h:79
hmap_bitmap_t nodemap
Definition hashmap.h:80
hmap_node_t * root
Definition hashmap.h:98
size_t len
Number of key/value pairs in the map.
Definition hashmap.h:97