Skip to content

Commit 534843f

Browse files
authored
Merge pull request #95 from Electrostat-Lab/arithmos-eca
Arithmos Maps: Hashmaps library and Map ADT
2 parents 5ee9ba0 + 79890e8 commit 534843f

15 files changed

Lines changed: 1202 additions & 105 deletions

File tree

.github/workflows/build-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ jobs:
7979
- name: Testing "hello_contiguous_buffer.c"
8080
run: ./helper-scripts/ci-cd/test-electrostatic.sh "hello_lists.c" "hello-listadt"
8181

82+
- name: Testing "hello_hashmaps.c"
83+
run: ./helper-scripts/ci-cd/test-electrostatic.sh "hello_hashmaps.c" "hello-hashmaps"
84+
8285
- name: Testing "hello_unittest.c"
8386
run: ./helper-scripts/ci-cd/test-electrostatic.sh "hello_unittest.c" "hello-unittest"
8487

sdk/core/src/include/electronetsoft/arithmos/adt/list.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,35 @@ struct list_element {
4747
void *data;
4848
void *metadata;
4949
size_t size;
50+
element_type type;
5051
};
5152

5253
struct list_info {
53-
uint64_t start_index;
54+
uint64_t index;
5455
uint64_t length;
5556
uint64_t rate;
57+
void *metadata;
5658
};
5759

5860
struct list {
5961
list_element **elements;
6062
list_function_table *function_table;
6163
list_type type;
6264
memory_partition elements_memory;
63-
uint64_t length;
65+
uint64_t position;
6466
uint64_t limit;
67+
uint64_t hash_key;
6568
};
6669

6770
struct list_function_table {
6871
status_code (*contains)(list *, list_element *);
69-
status_code (*iterator)(list *, list_info, void (*callback)(list *, list_element *));
72+
status_code (*iterator)(list *, list_info,
73+
status_code (*callback)(list *, list_info, list_element *));
7074
status_code (*add)(list *, list_element *);
75+
status_code (*insert)(list *, list_element *, uint64_t);
76+
status_code (*on_collision)(list *, uint64_t, list_element *);
77+
status_code (*insert_overwrite)(list *, list_element *, uint64_t);
78+
status_code (*on_collision_overwrite)(list *, uint64_t, list_element *);
7179
status_code (*get)(list *, uint64_t, list_element **);
7280
status_code (*index_of)(list *, list_element *, uint64_t *);
7381
status_code (*resize)(list *, uint16_t);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef _MAP_H_
2+
#define _MAP_H_
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
#include <inttypes.h>
7+
#include <stddef.h>
8+
#include <electronetsoft/arithmos/adt/list.h>
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
struct map_element {
15+
char *key;
16+
list_element *value;
17+
};
18+
19+
struct map_processors {
20+
status_code (*on_initialization)(map *);
21+
status_code (*on_deinitialization)(map *);
22+
status_code (*on_insertion)(map *, map_element *, uint64_t);
23+
status_code (*on_resize_dispatch)(map *, list_element **);
24+
status_code (*on_removal)(map *, list *, uint64_t);
25+
status_code (*on_collision)(list *,
26+
uint64_t,
27+
list_element *);
28+
status_code (*on_collision_resolution)(list *,
29+
uint64_t,
30+
list_element *);
31+
};
32+
33+
struct map {
34+
map_function_table *function_table;
35+
map_type type;
36+
list *adt;
37+
map_processors *processors;
38+
uint64_t count;
39+
};
40+
41+
struct map_function_table {
42+
status_code (*insert)(map *, map_element *);
43+
status_code (*insert_all)(map *, map_element **);
44+
status_code (*remove)(map *, const char *);
45+
status_code (*remove_all)(map *, const char **);
46+
status_code (*resize)(map *, uint64_t);
47+
status_code (*contains)(map *, const char *);
48+
status_code (*contains_all)(map *, const char **);
49+
status_code (*get)(map *, const char *key, map_element *);
50+
status_code (*iterator)(map *, status_code (*callback)(map *, map_element *));
51+
};
52+
53+
status_code init_map_function_table(map *, map_function_table *,
54+
api_lifecycle *);
55+
56+
status_code map_get_lambda_factor(map *, float *);
57+
58+
status_code deinit_map_function_table(map *, api_lifecycle *);
59+
60+
#ifdef __cplusplus
61+
};
62+
#endif
63+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef _HASH_MAP_H_
2+
#define _HASH_MAP_H_
3+
4+
#include <electronetsoft/arithmos/adt/map.h>
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
status_code hashmap_init(map *, map_function_table *,
11+
api_lifecycle *);
12+
13+
14+
status_code hashmap_deinit(map *, api_lifecycle *);
15+
16+
#ifdef __cplusplus
17+
};
18+
#endif
19+
#endif

sdk/core/src/include/electronetsoft/util/types.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ typedef enum status_code {
7070
EDLLSYMFAIL = (EDLLOPENFAIL + 1),
7171
EDLLCONVENTIONCALLRETURN = (EDLLSYMFAIL + 1),
7272
UNEXPECTED_ERROR = (EDLLCONVENTIONCALLRETURN + 1),
73+
EBUFFER_EXISTS = (UNEXPECTED_ERROR + 1),
74+
INVALID_OP = (EBUFFER_EXISTS + 1),
7375
ASSERTION_SUCCESS = 1,
7476
ASSERTION_FAILURE = 0
7577
} status_code;
@@ -119,6 +121,27 @@ typedef struct mat3_processors (mat3_processors);
119121

120122
typedef struct caller_graph (caller_graph);
121123

124+
typedef struct map (map);
125+
typedef struct map_element (map_element);
126+
typedef enum map_type {
127+
MAP_TYPE_HASHMAP = COLUMN_CONVENTION_ITERATOR - 1,
128+
MAP_TYPE_TREEMAP = MAP_TYPE_HASHMAP - 1
129+
} map_type;
130+
typedef struct map_function_table (map_function_table);
131+
typedef struct map_processors (map_processors);
132+
typedef struct hash_component (hash_component);
133+
134+
typedef struct automaton (automaton);
135+
typedef struct automaton_state (automaton_state);
136+
typedef struct automaton_input (automaton_input);
137+
typedef struct automaton_zeta (automaton_zeta);
138+
typedef struct automaton_component (automaton_component);
139+
140+
typedef enum {
141+
ELEMENT_LIST = MAP_TYPE_TREEMAP - 1,
142+
ELEMENT_MAP_ITEM = ELEMENT_LIST - 1,
143+
} element_type;
144+
122145
#ifdef __cplusplus
123146
};
124147
#endif

sdk/core/src/include/electronetsoft/util/utilities.h

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ struct api_lifecycle {
4141
void (*on_operation_failed)(void *api, void *caller, status_code cause);
4242
};
4343

44+
struct hash_component {
45+
char *key;
46+
uint64_t *hash;
47+
uint64_t user_key;
48+
};
49+
4450
/**
4551
* Uses a pointer as an r-value for safe
4652
* comparison reasons.
@@ -104,43 +110,86 @@ static inline typed_pointer get_typed_pointer(void *address, pointer_type type)
104110
return pointer;
105111
}
106112

107-
/**
108-
* @brief Improved spreading: uses a 64-bit Mixer (MurmurHash3 style)
109-
* to distribute entropy across the entire 64-bit range.
110-
*/
111113
static inline status_code spread_64(uint64_t in, uint64_t *out) {
112114
if (rvalue(out) == NULL) {
113115
return EUNDEFINEDBUFFER;
114116
}
115117

116-
in = (in ^ (in >> 30)) * 0xbf58476d1ce4e5b9ULL;
117-
in = (in ^ (in >> 27)) * 0x94d049bb133111ebULL;
118-
in = in ^ (in >> 31);
118+
in = in ^ ((in ^ (in >> 32)) >> 32);
119119
*out = in;
120120

121121
return PASS;
122122
}
123123

124-
static inline status_code hash_key(const char *key, uint64_t *hash) {
125-
if (rvalue((void *) key) == NULL || rvalue(hash) == NULL) {
124+
static inline status_code hash_key(hash_component hasher) {
125+
if (rvalue((void *) hasher.key) == NULL ||
126+
rvalue(hasher.hash) == NULL) {
126127
return EUNDEFINEDBUFFER;
127128
}
128129

129130
// Use a large prime constant to initialize (FNV-1a style)
130131
uint64_t h = 0xcbf29ce484222325ULL;
131132

132133
// Process every character
133-
for (const char *address = key; *address != '\0'; address++) {
134+
// Algorithm for polynomial hashing using Horner's rule
135+
for (const char *address = hasher.key; *address != '\0'; address++) {
136+
// use reverse Horner's Rule to compute the hash
134137
// 1. XOR the character into the hash
135-
h ^= (uint8_t) (*address);
136-
// 2. Multiply by a large prime (this spreads the bits)
137-
h *= 0x100000001b3ULL;
138+
h ^= (*address);
139+
// 2. Multiply by 2^5 (aka 32) which is the same as left-shifting by
140+
// 5 bits using Cyclic Shift Hashcode
141+
h = (h << 5) | (h >> (64 - 5));
142+
// 4. Combine MSB Component with LSB Component
143+
h = (h >> 32) ^ h;
138144
}
139145

140146
// Apply your spread_64 as a finalizer to ensure high entropy
141-
return spread_64(h, hash);
147+
return spread_64(h ^ hasher.user_key, hasher.hash);
142148
}
143149

150+
static inline uint64_t hash_compress(uint64_t hash,
151+
uint64_t limit) {
152+
// the equivalent of modulus operation
153+
// finds the remainder of an integer division operation
154+
return hash - (((uint64_t) (hash/limit)) * limit);
155+
}
156+
157+
static inline uint64_t generate_next_odd(uint64_t n) {
158+
return (n * 2) + 1;
159+
}
160+
161+
static inline status_code hashkey_compress64(hash_component hasher,
162+
uint64_t limit) {
163+
if (rvalue((void *) hasher.key) == NULL ||
164+
rvalue(hasher.hash) == NULL) {
165+
return EUNDEFINEDBUFFER;
166+
}
167+
168+
status_code __code = hash_key(hasher);
169+
if (PASS != __code) {
170+
return __code;
171+
}
172+
*(hasher.hash) = hash_compress(*(hasher.hash), limit);
173+
174+
return PASS;
175+
}
176+
177+
//static inline status_code is_prime(uint64_t n) {
178+
// return PASS;
179+
//}
180+
//
181+
//static inline uint64_t generate_next_prime(uint64_t n) {
182+
// uint64_t next_odd = n;
183+
//
184+
// while (1) {
185+
// next_odd = generate_next_odd(next_odd);
186+
// if (is_prime(next_odd)) {
187+
// return next_odd;
188+
// }
189+
// }
190+
// return n;
191+
//}
192+
144193
#ifdef __cplusplus
145194
};
146195
#endif

0 commit comments

Comments
 (0)