prometheus-client-mmap 0.28.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.tool-versions +1 -1
- data/README.md +2 -30
- data/ext/fast_mmaped_file_rs/extconf.rb +1 -3
- data/ext/fast_mmaped_file_rs/src/error.rs +8 -0
- data/ext/fast_mmaped_file_rs/src/mmap/inner.rs +38 -13
- data/ext/fast_mmaped_file_rs/src/mmap.rs +71 -5
- data/lib/prometheus/client/configuration.rb +1 -2
- data/lib/prometheus/client/formats/text.rb +1 -12
- data/lib/prometheus/client/helper/mmaped_file.rb +3 -14
- data/lib/prometheus/client/rack/exporter.rb +1 -3
- data/lib/prometheus/client/version.rb +1 -1
- metadata +4 -43
- data/ext/fast_mmaped_file/extconf.rb +0 -30
- data/ext/fast_mmaped_file/fast_mmaped_file.c +0 -122
- data/ext/fast_mmaped_file/file_format.c +0 -5
- data/ext/fast_mmaped_file/file_format.h +0 -11
- data/ext/fast_mmaped_file/file_parsing.c +0 -195
- data/ext/fast_mmaped_file/file_parsing.h +0 -27
- data/ext/fast_mmaped_file/file_reading.c +0 -102
- data/ext/fast_mmaped_file/file_reading.h +0 -30
- data/ext/fast_mmaped_file/globals.h +0 -14
- data/ext/fast_mmaped_file/mmap.c +0 -428
- data/ext/fast_mmaped_file/mmap.h +0 -61
- data/ext/fast_mmaped_file/rendering.c +0 -199
- data/ext/fast_mmaped_file/rendering.h +0 -8
- data/ext/fast_mmaped_file/utils.c +0 -56
- data/ext/fast_mmaped_file/utils.h +0 -22
- data/ext/fast_mmaped_file/value_access.c +0 -242
- data/ext/fast_mmaped_file/value_access.h +0 -15
- data/lib/prometheus/client/helper/loader.rb +0 -44
- data/vendor/c/hashmap/.gitignore +0 -52
- data/vendor/c/hashmap/LICENSE +0 -21
- data/vendor/c/hashmap/README.md +0 -90
- data/vendor/c/hashmap/_config.yml +0 -1
- data/vendor/c/hashmap/src/hashmap.c +0 -692
- data/vendor/c/hashmap/src/hashmap.h +0 -267
- data/vendor/c/hashmap/test/Makefile +0 -22
- data/vendor/c/hashmap/test/hashmap_test.c +0 -608
- data/vendor/c/jsmn/.travis.yml +0 -4
- data/vendor/c/jsmn/LICENSE +0 -20
- data/vendor/c/jsmn/Makefile +0 -41
- data/vendor/c/jsmn/README.md +0 -168
- data/vendor/c/jsmn/example/jsondump.c +0 -126
- data/vendor/c/jsmn/example/simple.c +0 -76
- data/vendor/c/jsmn/jsmn.c +0 -314
- data/vendor/c/jsmn/jsmn.h +0 -76
- data/vendor/c/jsmn/library.json +0 -16
- data/vendor/c/jsmn/test/test.h +0 -27
- data/vendor/c/jsmn/test/tests.c +0 -407
- data/vendor/c/jsmn/test/testutil.h +0 -94
@@ -1,56 +0,0 @@
|
|
1
|
-
#include "utils.h"
|
2
|
-
|
3
|
-
#include <errno.h>
|
4
|
-
|
5
|
-
static void rb_save_exception(VALUE exception, VALUE message) {
|
6
|
-
VALUE current_thread = rb_thread_current();
|
7
|
-
|
8
|
-
rb_thread_local_aset(current_thread, rb_intern("prometheus_last_exception"), exception);
|
9
|
-
rb_thread_local_aset(current_thread, rb_intern("prometheus_last_exception_message"), message);
|
10
|
-
}
|
11
|
-
/* @deprecated - use with_exception ignoring return value */
|
12
|
-
void save_exception(VALUE exception, const char *fmt, ...) {
|
13
|
-
va_list args;
|
14
|
-
|
15
|
-
va_start(args, fmt);
|
16
|
-
VALUE message = rb_vsprintf(fmt, args);
|
17
|
-
|
18
|
-
rb_save_exception(exception, message);
|
19
|
-
va_end(args);
|
20
|
-
}
|
21
|
-
|
22
|
-
int with_exception(VALUE exception, const char *fmt, ...) {
|
23
|
-
va_list args;
|
24
|
-
|
25
|
-
va_start(args, fmt);
|
26
|
-
VALUE message = rb_vsprintf(fmt, args);
|
27
|
-
|
28
|
-
rb_save_exception(exception, message);
|
29
|
-
va_end(args);
|
30
|
-
|
31
|
-
return FAILURE;
|
32
|
-
}
|
33
|
-
|
34
|
-
int with_exception_errno(VALUE exception, const char *fmt, ...) {
|
35
|
-
va_list args;
|
36
|
-
|
37
|
-
va_start(args, fmt);
|
38
|
-
VALUE message = rb_vsprintf(fmt, args);
|
39
|
-
rb_str_catf(message, " (%s)", strerror(errno));
|
40
|
-
|
41
|
-
rb_save_exception(exception, message);
|
42
|
-
va_end(args);
|
43
|
-
|
44
|
-
return FAILURE;
|
45
|
-
}
|
46
|
-
|
47
|
-
NORETURN(void raise_last_exception()) {
|
48
|
-
VALUE current_thread = rb_thread_current();
|
49
|
-
VALUE exception = rb_thread_local_aref(current_thread, rb_intern("prometheus_last_exception"));
|
50
|
-
VALUE message = rb_thread_local_aref(current_thread, rb_intern("prometheus_last_exception_message"));
|
51
|
-
if (exception != Qnil) {
|
52
|
-
rb_raise(exception, "%s", StringValueCStr(message));
|
53
|
-
} else {
|
54
|
-
rb_raise(rb_eRuntimeError, "no exception found in thread local");
|
55
|
-
}
|
56
|
-
}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
#ifndef UNUSED_H
|
2
|
-
#define UNUSED_H
|
3
|
-
#include <ruby.h>
|
4
|
-
|
5
|
-
#ifdef UNUSED
|
6
|
-
#elif defined(__GNUC__)
|
7
|
-
#define UNUSED(x) UNUSED_##x __attribute__((unused))
|
8
|
-
#elif defined(__LCLINT__)
|
9
|
-
#define UNUSED(x) /*@unused@*/ x
|
10
|
-
#else
|
11
|
-
#define UNUSED(x) x
|
12
|
-
#endif
|
13
|
-
|
14
|
-
#define SUCCESS 1
|
15
|
-
#define FAILURE 0
|
16
|
-
|
17
|
-
NORETURN(void raise_last_exception());
|
18
|
-
void save_exception(VALUE exception, const char *fmt, ...);
|
19
|
-
int with_exception(VALUE exception, const char *fmt, ...);
|
20
|
-
int with_exception_errno(VALUE exception, const char *fmt, ...);
|
21
|
-
|
22
|
-
#endif
|
@@ -1,242 +0,0 @@
|
|
1
|
-
#include "value_access.h"
|
2
|
-
|
3
|
-
#include <errno.h>
|
4
|
-
#include <fcntl.h>
|
5
|
-
#include <ruby/intern.h>
|
6
|
-
#include <sys/mman.h>
|
7
|
-
#include <unistd.h>
|
8
|
-
|
9
|
-
#include "file_format.h"
|
10
|
-
#include "mmap.h"
|
11
|
-
#include "utils.h"
|
12
|
-
|
13
|
-
static void close_file(mm_ipc *i_mm) {
|
14
|
-
close(i_mm->t->fd);
|
15
|
-
i_mm->t->fd = -1;
|
16
|
-
}
|
17
|
-
|
18
|
-
static int open_and_extend_file(mm_ipc *i_mm, size_t len) {
|
19
|
-
if (i_mm->t->fd < 0) {
|
20
|
-
int fd;
|
21
|
-
|
22
|
-
if ((fd = open(i_mm->t->path, i_mm->t->smode)) == -1) {
|
23
|
-
return with_exception_errno(rb_eArgError, "%s: Can't open %s", __FILE__, i_mm->t->path);
|
24
|
-
}
|
25
|
-
i_mm->t->fd = fd;
|
26
|
-
}
|
27
|
-
|
28
|
-
if (lseek(i_mm->t->fd, len - 1, SEEK_SET) == -1) {
|
29
|
-
close_file(i_mm);
|
30
|
-
return with_exception_errno(rb_eIOError, "Can't lseek %zu", len - 1);
|
31
|
-
}
|
32
|
-
|
33
|
-
if (write(i_mm->t->fd, "\000", 1) != 1) {
|
34
|
-
close_file(i_mm);
|
35
|
-
return with_exception_errno(rb_eIOError, "Can't extend %s", i_mm->t->path);
|
36
|
-
}
|
37
|
-
i_mm->t->len = len;
|
38
|
-
|
39
|
-
return SUCCESS;
|
40
|
-
}
|
41
|
-
|
42
|
-
static int perform_munmap(mm_ipc *i_mm) {
|
43
|
-
if (i_mm->t->addr != NULL && munmap(i_mm->t->addr, i_mm->t->len)) {
|
44
|
-
i_mm->t->addr = NULL;
|
45
|
-
return with_exception_errno(rb_eArgError, "munmap failed");
|
46
|
-
}
|
47
|
-
|
48
|
-
i_mm->t->addr = NULL;
|
49
|
-
i_mm->t->len = 0;
|
50
|
-
i_mm->t->real = 0;
|
51
|
-
|
52
|
-
return SUCCESS;
|
53
|
-
}
|
54
|
-
|
55
|
-
static int perform_mmap(mm_ipc *i_mm, size_t len) {
|
56
|
-
MMAP_RETTYPE addr = mmap(0, len, i_mm->t->pmode, i_mm->t->vscope, i_mm->t->fd, i_mm->t->offset);
|
57
|
-
|
58
|
-
if (addr == MAP_FAILED) {
|
59
|
-
return with_exception_errno(rb_eArgError, "mmap failed");
|
60
|
-
}
|
61
|
-
|
62
|
-
i_mm->t->addr = addr;
|
63
|
-
i_mm->t->len = len;
|
64
|
-
i_mm->t->real = len;
|
65
|
-
|
66
|
-
return SUCCESS;
|
67
|
-
}
|
68
|
-
|
69
|
-
static int expand(VALUE self, mm_ipc *i_mm, size_t len) {
|
70
|
-
if (len < i_mm->t->len) {
|
71
|
-
return with_exception(rb_eArgError, "Can't reduce the size of mmap");
|
72
|
-
}
|
73
|
-
|
74
|
-
if (!perform_munmap(i_mm)) {
|
75
|
-
return FAILURE;
|
76
|
-
}
|
77
|
-
|
78
|
-
if (!open_and_extend_file(i_mm, len)) {
|
79
|
-
return FAILURE;
|
80
|
-
}
|
81
|
-
|
82
|
-
if (!perform_mmap(i_mm, len)) {
|
83
|
-
close_file(i_mm);
|
84
|
-
return FAILURE;
|
85
|
-
}
|
86
|
-
|
87
|
-
if ((i_mm->t->flag & MM_LOCK) && mlock(i_mm->t->addr, len) == -1) {
|
88
|
-
return with_exception_errno(rb_eArgError, "mlock(%d)", errno);
|
89
|
-
}
|
90
|
-
|
91
|
-
mm_update(self);
|
92
|
-
|
93
|
-
return SUCCESS;
|
94
|
-
}
|
95
|
-
|
96
|
-
static void save_entry(mm_ipc *i_mm, size_t offset, VALUE key, VALUE value) {
|
97
|
-
uint32_t key_length = (uint32_t)RSTRING_LEN(key);
|
98
|
-
|
99
|
-
char *pos = (char *)i_mm->t->addr + offset;
|
100
|
-
|
101
|
-
memcpy(pos, &key_length, sizeof(uint32_t));
|
102
|
-
pos += sizeof(uint32_t);
|
103
|
-
|
104
|
-
memmove(pos, StringValuePtr(key), key_length);
|
105
|
-
pos += key_length;
|
106
|
-
|
107
|
-
memset(pos, ' ', padding_length(key_length)); // TODO: considder padding with /0
|
108
|
-
pos += padding_length(key_length);
|
109
|
-
|
110
|
-
double val = NUM2DBL(value);
|
111
|
-
memcpy(pos, &val, sizeof(double));
|
112
|
-
}
|
113
|
-
|
114
|
-
static void save_value(mm_ipc *i_mm, VALUE _offset, VALUE value) {
|
115
|
-
Check_Type(_offset, T_FIXNUM);
|
116
|
-
size_t offset = NUM2UINT(_offset);
|
117
|
-
if ((i_mm->t->real + sizeof(double)) <= offset) {
|
118
|
-
rb_raise(rb_eIndexError, "offset %zu out of string", offset);
|
119
|
-
}
|
120
|
-
|
121
|
-
if (i_mm->t->flag & MM_FROZEN) {
|
122
|
-
rb_error_frozen("mmap");
|
123
|
-
}
|
124
|
-
|
125
|
-
char *pos = (char *)i_mm->t->addr + offset;
|
126
|
-
|
127
|
-
double val = NUM2DBL(value);
|
128
|
-
memcpy(pos, &val, sizeof(double));
|
129
|
-
}
|
130
|
-
|
131
|
-
static VALUE load_value(mm_ipc *i_mm, VALUE _offset) {
|
132
|
-
Check_Type(_offset, T_FIXNUM);
|
133
|
-
size_t offset = NUM2UINT(_offset);
|
134
|
-
if ((i_mm->t->real + sizeof(double)) <= offset) {
|
135
|
-
rb_raise(rb_eIndexError, "offset %zu out of string", offset);
|
136
|
-
}
|
137
|
-
|
138
|
-
char *pos = (char *)i_mm->t->addr + offset;
|
139
|
-
|
140
|
-
double value;
|
141
|
-
memcpy(&value, pos, sizeof(double));
|
142
|
-
return DBL2NUM(value);
|
143
|
-
}
|
144
|
-
|
145
|
-
uint32_t load_used(mm_ipc *i_mm) {
|
146
|
-
uint32_t used = *((uint32_t *)i_mm->t->addr);
|
147
|
-
|
148
|
-
if (used == 0) {
|
149
|
-
used = START_POSITION;
|
150
|
-
}
|
151
|
-
return used;
|
152
|
-
}
|
153
|
-
|
154
|
-
void save_used(mm_ipc *i_mm, uint32_t used) { *((uint32_t *)i_mm->t->addr) = used; }
|
155
|
-
|
156
|
-
static VALUE initialize_entry(VALUE self, mm_ipc *i_mm, VALUE positions, VALUE key, VALUE value) {
|
157
|
-
if (i_mm->t->flag & MM_FROZEN) {
|
158
|
-
rb_error_frozen("mmap");
|
159
|
-
}
|
160
|
-
|
161
|
-
if (RSTRING_LEN(key) > INT32_MAX) {
|
162
|
-
rb_raise(rb_eArgError, "string length gt %d", INT32_MAX);
|
163
|
-
}
|
164
|
-
|
165
|
-
uint32_t key_length = (uint32_t)RSTRING_LEN(key);
|
166
|
-
uint32_t value_offset = sizeof(uint32_t) + key_length + padding_length(key_length);
|
167
|
-
uint32_t entry_length = value_offset + sizeof(double);
|
168
|
-
|
169
|
-
uint32_t used = load_used(i_mm);
|
170
|
-
while (i_mm->t->len < (used + entry_length)) {
|
171
|
-
if (!expand(self, i_mm, i_mm->t->len * 2)) {
|
172
|
-
raise_last_exception();
|
173
|
-
}
|
174
|
-
}
|
175
|
-
|
176
|
-
save_entry(i_mm, used, key, value);
|
177
|
-
save_used(i_mm, used + entry_length);
|
178
|
-
|
179
|
-
return rb_hash_aset(positions, key, INT2NUM(used + value_offset));
|
180
|
-
}
|
181
|
-
|
182
|
-
VALUE method_fetch_entry(VALUE self, VALUE positions, VALUE key, VALUE default_value) {
|
183
|
-
Check_Type(positions, T_HASH);
|
184
|
-
Check_Type(key, T_STRING);
|
185
|
-
|
186
|
-
mm_ipc *i_mm;
|
187
|
-
GET_MMAP(self, i_mm, MM_MODIFY);
|
188
|
-
|
189
|
-
VALUE position = rb_hash_lookup(positions, key);
|
190
|
-
|
191
|
-
if (position != Qnil) {
|
192
|
-
return load_value(i_mm, position);
|
193
|
-
}
|
194
|
-
|
195
|
-
position = initialize_entry(self, i_mm, positions, key, default_value);
|
196
|
-
return load_value(i_mm, position);
|
197
|
-
}
|
198
|
-
|
199
|
-
VALUE method_upsert_entry(VALUE self, VALUE positions, VALUE key, VALUE value) {
|
200
|
-
Check_Type(positions, T_HASH);
|
201
|
-
Check_Type(key, T_STRING);
|
202
|
-
|
203
|
-
mm_ipc *i_mm;
|
204
|
-
GET_MMAP(self, i_mm, MM_MODIFY);
|
205
|
-
|
206
|
-
VALUE position = rb_hash_lookup(positions, key);
|
207
|
-
|
208
|
-
if (position != Qnil) {
|
209
|
-
save_value(i_mm, position, value);
|
210
|
-
return load_value(i_mm, position);
|
211
|
-
}
|
212
|
-
|
213
|
-
position = initialize_entry(self, i_mm, positions, key, value);
|
214
|
-
return load_value(i_mm, position);
|
215
|
-
}
|
216
|
-
|
217
|
-
VALUE method_load_used(VALUE self) {
|
218
|
-
mm_ipc *i_mm;
|
219
|
-
|
220
|
-
GET_MMAP(self, i_mm, MM_MODIFY);
|
221
|
-
return UINT2NUM(load_used(i_mm));
|
222
|
-
}
|
223
|
-
|
224
|
-
VALUE method_save_used(VALUE self, VALUE value) {
|
225
|
-
Check_Type(value, T_FIXNUM);
|
226
|
-
mm_ipc *i_mm;
|
227
|
-
|
228
|
-
GET_MMAP(self, i_mm, MM_MODIFY);
|
229
|
-
|
230
|
-
if (i_mm->t->flag & MM_FROZEN) {
|
231
|
-
rb_error_frozen("mmap");
|
232
|
-
}
|
233
|
-
|
234
|
-
if (i_mm->t->len < INITIAL_SIZE) {
|
235
|
-
if (!expand(self, i_mm, INITIAL_SIZE)) {
|
236
|
-
raise_last_exception();
|
237
|
-
}
|
238
|
-
}
|
239
|
-
|
240
|
-
save_used(i_mm, NUM2UINT(value));
|
241
|
-
return value;
|
242
|
-
}
|
@@ -1,15 +0,0 @@
|
|
1
|
-
#ifndef VALUE_ACCESS_H
|
2
|
-
#define VALUE_ACCESS_H
|
3
|
-
#include <ruby.h>
|
4
|
-
|
5
|
-
VALUE method_load_used(VALUE self);
|
6
|
-
|
7
|
-
VALUE method_save_used(VALUE self, VALUE value);
|
8
|
-
|
9
|
-
VALUE method_get_double(VALUE self, VALUE index);
|
10
|
-
|
11
|
-
VALUE method_fetch_entry(VALUE self, VALUE positions, VALUE key, VALUE default_value);
|
12
|
-
|
13
|
-
VALUE method_upsert_entry(VALUE self, VALUE positions, VALUE key, VALUE value);
|
14
|
-
|
15
|
-
#endif
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Prometheus
|
2
|
-
module Client
|
3
|
-
module Helper
|
4
|
-
module Loader
|
5
|
-
class << self
|
6
|
-
def rust_impl_available?
|
7
|
-
return @rust_available unless @rust_available.nil?
|
8
|
-
|
9
|
-
check_for_rust
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def load_rust_extension
|
15
|
-
begin
|
16
|
-
ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION)
|
17
|
-
require_relative "../../../#{ruby_version}/fast_mmaped_file_rs"
|
18
|
-
rescue LoadError
|
19
|
-
require 'fast_mmaped_file_rs'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def check_for_rust
|
24
|
-
# This will be evaluated on each invocation even with `||=` if
|
25
|
-
# `@rust_available` if false. Running a `require` statement is slow,
|
26
|
-
# so the `rust_impl_available?` method memoizes the result, external
|
27
|
-
# callers can only trigger this method a single time.
|
28
|
-
@rust_available = begin
|
29
|
-
load_rust_extension
|
30
|
-
true
|
31
|
-
rescue LoadError
|
32
|
-
warn <<~WARN
|
33
|
-
WARNING: The Rust extension for prometheus-client-mmap is unavailable, falling back to the legacy C extension.
|
34
|
-
The Rust extension will be required in the next version. If you are compiling this gem from source,
|
35
|
-
ensure your build system has a Rust compiler and clang: https://gitlab.com/gitlab-org/ruby/gems/prometheus-client-mmap
|
36
|
-
WARN
|
37
|
-
false
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/vendor/c/hashmap/.gitignore
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# Prerequisites
|
2
|
-
*.d
|
3
|
-
|
4
|
-
# Object files
|
5
|
-
*.o
|
6
|
-
*.ko
|
7
|
-
*.obj
|
8
|
-
*.elf
|
9
|
-
|
10
|
-
# Linker output
|
11
|
-
*.ilk
|
12
|
-
*.map
|
13
|
-
*.exp
|
14
|
-
|
15
|
-
# Precompiled Headers
|
16
|
-
*.gch
|
17
|
-
*.pch
|
18
|
-
|
19
|
-
# Libraries
|
20
|
-
*.lib
|
21
|
-
*.a
|
22
|
-
*.la
|
23
|
-
*.lo
|
24
|
-
|
25
|
-
# Shared objects (inc. Windows DLLs)
|
26
|
-
*.dll
|
27
|
-
*.so
|
28
|
-
*.so.*
|
29
|
-
*.dylib
|
30
|
-
|
31
|
-
# Executables
|
32
|
-
*.exe
|
33
|
-
*.out
|
34
|
-
*.app
|
35
|
-
*.i*86
|
36
|
-
*.x86_64
|
37
|
-
*.hex
|
38
|
-
|
39
|
-
# Debug files
|
40
|
-
*.dSYM/
|
41
|
-
*.su
|
42
|
-
*.idb
|
43
|
-
*.pdb
|
44
|
-
|
45
|
-
# Kernel Module Compile Results
|
46
|
-
*.mod*
|
47
|
-
*.cmd
|
48
|
-
.tmp_versions/
|
49
|
-
modules.order
|
50
|
-
Module.symvers
|
51
|
-
Mkfile.old
|
52
|
-
dkms.conf
|
data/vendor/c/hashmap/LICENSE
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2016 David Leeds
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
data/vendor/c/hashmap/README.md
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# hashmap
|
2
|
-
Flexible hashmap implementation in C using open addressing and linear probing for collision resolution.
|
3
|
-
|
4
|
-
### Summary
|
5
|
-
This project came into existence because there are a notable lack of flexible and easy to use data structures available in C. Sure, higher level languages have built-in libraries, but plenty of embedded projects or higher level libraries start with core C code. It was undesirable to add a bulky library like Glib as a dependency to my projects, or grapple with a restrictive license agreement. Searching for "C hashmap" yielded results with questionable algorithms and code quality, projects with difficult or inflexible interfaces, or projects with less desirable licenses. I decided it was time to create my own.
|
6
|
-
|
7
|
-
|
8
|
-
### Goals
|
9
|
-
* **To scale gracefully to the full capacity of the numeric primitives in use.** E.g. on a 32-bit machine, you should be able to load a billion+ entries without hitting any bugs relating to integer overflows. Lookups on a hashtable with a billion entries should be performed in close to constant time, no different than lookups in a hashtable with 20 entries. Automatic rehashing occurs and maintains a load factor of 0.75 or less.
|
10
|
-
* **To provide a clean and easy-to-use interface.** C data structures often struggle to strike a balance between flexibility and ease of use. To this end, I provided a generic interface using void pointers for keys and data, and macros to generate type-specific wrapper functions, if desired.
|
11
|
-
* **To enable easy iteration and safe entry removal during iteration.** Applications often need these features, and the data structure should not hold them back. Both an iterator interface and a foreach function was provided to satisfy various use-cases. This hashmap also uses an open addressing scheme, which has superior iteration performance to a similar hashmap implemented using separate chaining (buckets with linked lists). This is because fewer instructions are needed per iteration, and array traversal has superior cache performance than linked list traversal.
|
12
|
-
* **To use a very unrestrictive software license.** Using no license was an option, but I wanted to allow the code to be tracked, simply for my own edification. I chose the MIT license because it is the most common open source license in use, and it grants full rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell the code. Basically, take this code and do what you want with it. Just be nice and leave the license comment and my name at top of the file. Feel free to add your name if you are modifying and redistributing.
|
13
|
-
|
14
|
-
### Code Example
|
15
|
-
```C
|
16
|
-
#include <stdlib.h>
|
17
|
-
#include <stdio.h>
|
18
|
-
|
19
|
-
#include <hashmap.h>
|
20
|
-
|
21
|
-
/* Some sample data structure with a string key */
|
22
|
-
struct blob {
|
23
|
-
char key[32];
|
24
|
-
size_t data_len;
|
25
|
-
unsigned char data[1024];
|
26
|
-
};
|
27
|
-
|
28
|
-
/* Declare type-specific blob_hashmap_* functions with this handy macro */
|
29
|
-
HASHMAP_FUNCS_CREATE(blob, const char, struct blob)
|
30
|
-
|
31
|
-
struct blob *blob_load(void)
|
32
|
-
{
|
33
|
-
struct blob *b;
|
34
|
-
/*
|
35
|
-
* Hypothetical function that allocates and loads blob structures
|
36
|
-
* from somewhere. Returns NULL when there are no more blobs to load.
|
37
|
-
*/
|
38
|
-
return b;
|
39
|
-
}
|
40
|
-
|
41
|
-
/* Hashmap structure */
|
42
|
-
struct hashmap map;
|
43
|
-
|
44
|
-
int main(int argc, char **argv)
|
45
|
-
{
|
46
|
-
struct blob *b;
|
47
|
-
struct hashmap_iter *iter;
|
48
|
-
|
49
|
-
/* Initialize with default string key functions and init size */
|
50
|
-
hashmap_init(&map, hashmap_hash_string, hashmap_compare_string, 0);
|
51
|
-
|
52
|
-
/* Load some sample data into the map and discard duplicates */
|
53
|
-
while ((b = blob_load()) != NULL) {
|
54
|
-
if (blob_hashmap_put(&map, b->key, b) != b) {
|
55
|
-
printf("discarding blob with duplicate key: %s\n", b->key);
|
56
|
-
free(b);
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
/* Lookup a blob with key "AbCdEf" */
|
61
|
-
b = blob_hashmap_get(&map, "AbCdEf");
|
62
|
-
if (b) {
|
63
|
-
printf("Found blob[%s]\n", b->key);
|
64
|
-
}
|
65
|
-
|
66
|
-
/* Iterate through all blobs and print each one */
|
67
|
-
for (iter = hashmap_iter(&map); iter; iter = hashmap_iter_next(&map, iter)) {
|
68
|
-
printf("blob[%s]: data_len %zu bytes\n", blob_hashmap_iter_get_key(iter),
|
69
|
-
blob_hashmap_iter_get_data(iter)->data_len);
|
70
|
-
}
|
71
|
-
|
72
|
-
/* Remove all blobs with no data */
|
73
|
-
iter = hashmap_iter(&map);
|
74
|
-
while (iter) {
|
75
|
-
b = blob_hashmap_iter_get_data(iter);
|
76
|
-
if (b->data_len == 0) {
|
77
|
-
iter = hashmap_iter_remove(&map, iter);
|
78
|
-
free(b);
|
79
|
-
} else {
|
80
|
-
iter = hashmap_iter_next(&map, iter);
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
/* Free all allocated resources associated with map and reset its state */
|
85
|
-
hashmap_destroy(&map);
|
86
|
-
|
87
|
-
return 0;
|
88
|
-
}
|
89
|
-
|
90
|
-
```
|
@@ -1 +0,0 @@
|
|
1
|
-
theme: jekyll-theme-slate
|