prometheus-client-mmap 0.7.0.beta32 → 0.7.0.beta33
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/fast_mmaped_file/extconf.rb +2 -4
- data/ext/fast_mmaped_file/fast_mmaped_file.c +0 -107
- data/lib/fast_mmaped_file.bundle +0 -0
- data/lib/prometheus/client/helper/entry_parser.rb +5 -53
- data/lib/prometheus/client/helper/metrics_processing.rb +14 -31
- data/lib/prometheus/client/helper/metrics_representation.rb +3 -4
- data/lib/prometheus/client/helper/mmaped_file.rb +1 -1
- data/lib/prometheus/client/helper/plain_file.rb +1 -1
- data/lib/prometheus/client/mmaped_value.rb +8 -8
- data/lib/prometheus/client/version.rb +1 -1
- metadata +15 -3
- data/ext/fast_mmaped_file/jsmn.c +0 -313
- data/ext/fast_mmaped_file/jsmn.h +0 -76
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a7956684dd9781b3ca54566d1822574a9efaba7
|
4
|
+
data.tar.gz: b1673743af7ef8d4cbe1f1fa40d2da9560ed4f98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20ca0cf0603f45196a403348f8db23f5fb2b1d64fa0855c966e3448908eec3254b492670d219faa4f1040ab3f5c674a00eb34621729a38c34378641257c02e1f
|
7
|
+
data.tar.gz: c35c741b2a573826d3ac3096c14cf8e92a475f894bab7097404340161f37010e8703866424253ab2cb06871658105a9a7ba53136350ef07ce23c8e54f849d1b4
|
@@ -3,7 +3,5 @@ $CFLAGS << ' -std=c11 -Wall -Wextra -Werror'
|
|
3
3
|
|
4
4
|
CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
dir_config(extension_name)
|
9
|
-
create_makefile(extension_name)
|
6
|
+
dir_config('fast_mmaped_file')
|
7
|
+
create_makefile('fast_mmaped_file')
|
@@ -7,15 +7,6 @@
|
|
7
7
|
|
8
8
|
#include "mmap.h"
|
9
9
|
|
10
|
-
#ifdef UNUSED
|
11
|
-
#elif defined(__GNUC__)
|
12
|
-
#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
13
|
-
#elif defined(__LCLINT__)
|
14
|
-
#define UNUSED(x) /*@unused@*/ x
|
15
|
-
#else
|
16
|
-
#define UNUSED(x) x
|
17
|
-
#endif
|
18
|
-
|
19
10
|
VALUE MMAPED_FILE = Qnil;
|
20
11
|
|
21
12
|
#define START_POSITION 8
|
@@ -146,106 +137,8 @@ VALUE method_get_double(VALUE self, VALUE index) {
|
|
146
137
|
return DBL2NUM(tmp);
|
147
138
|
}
|
148
139
|
|
149
|
-
#include <jsmn.h>
|
150
|
-
|
151
|
-
#define min(a,b) \
|
152
|
-
({ __typeof__ (a) _a = (a); \
|
153
|
-
__typeof__ (b) _b = (b); \
|
154
|
-
_a < _b ? _a : _b; })
|
155
|
-
|
156
|
-
VALUE token_to_s(char* json, jsmntok_t *t){
|
157
|
-
int len = t->end - t->start;
|
158
|
-
if (len == 0) {
|
159
|
-
return rb_str_new_literal("");
|
160
|
-
} else {
|
161
|
-
return rb_str_new(json + t->start, t->end - t->start);
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
VALUE fast_json_parse(char* json, size_t json_size){
|
166
|
-
jsmn_parser parser;
|
167
|
-
jsmn_init(&parser);
|
168
|
-
|
169
|
-
jsmntok_t t[128];
|
170
|
-
int r = jsmn_parse(&parser, json, json_size, t, sizeof(t)/sizeof(t[0]));
|
171
|
-
|
172
|
-
if (r < 3) {
|
173
|
-
return Qnil;
|
174
|
-
}
|
175
|
-
|
176
|
-
VALUE labels = rb_hash_new();
|
177
|
-
int label_cnt = (r-5)/2;
|
178
|
-
//TODO: (r - 4) % 2 == 0
|
179
|
-
|
180
|
-
for(int i = 0; i < label_cnt; i++){
|
181
|
-
int key = 4 + i;
|
182
|
-
int val = 5 + label_cnt + i;
|
183
|
-
//TODO: add type checks
|
184
|
-
|
185
|
-
if (strncmp("null", json + t[val].start, min(4, t[val].end - t[val].start)) == 0) {
|
186
|
-
rb_hash_aset(labels, token_to_s(json, &t[key]), Qnil);
|
187
|
-
} else {
|
188
|
-
rb_hash_aset(labels, token_to_s(json, &t[key]), token_to_s(json, &t[val]));
|
189
|
-
}
|
190
|
-
}
|
191
|
-
|
192
|
-
return rb_ary_new_from_args(3, token_to_s(json, &t[1]), token_to_s(json, &t[2]), labels);
|
193
|
-
}
|
194
|
-
|
195
|
-
|
196
|
-
VALUE method_fast_json_parse(VALUE UNUSED(self), VALUE source){
|
197
|
-
Check_Type(source, T_STRING);
|
198
|
-
|
199
|
-
return fast_json_parse(StringValuePtr(source), RSTRING_LEN(source));
|
200
|
-
}
|
201
|
-
|
202
|
-
VALUE method_fast_entries(VALUE UNUSED(self), VALUE _data){
|
203
|
-
Check_Type(_data, T_STRING);
|
204
|
-
|
205
|
-
char *data = StringValuePtr(_data);
|
206
|
-
uint64_t data_len = RSTRING_LEN(_data);
|
207
|
-
|
208
|
-
uint32_t used;
|
209
|
-
memcpy(&used, data, sizeof(uint32_t));
|
210
|
-
|
211
|
-
uint32_t pos = START_POSITION;
|
212
|
-
|
213
|
-
while (pos < used && (pos + 2*sizeof(uint32_t)) < data_len) {
|
214
|
-
uint32_t encoded_len, first_bytes;
|
215
|
-
memcpy(&encoded_len, data + pos, sizeof(uint32_t));
|
216
|
-
pos += sizeof(uint32_t);
|
217
|
-
|
218
|
-
memcpy(&first_bytes, data + pos, sizeof(uint32_t));
|
219
|
-
if (encoded_len == 0 || first_bytes == 0){
|
220
|
-
pos += 8;
|
221
|
-
continue; // do not parse empty data
|
222
|
-
}
|
223
|
-
|
224
|
-
uint32_t value_offset = encoded_len + padding_length(encoded_len);
|
225
|
-
VALUE metric_name_labels = fast_json_parse(data + pos, encoded_len);
|
226
|
-
|
227
|
-
double value;
|
228
|
-
pos += value_offset;
|
229
|
-
memcpy(&value, data + pos, sizeof(double));
|
230
|
-
|
231
|
-
rb_yield_values(4, rb_ary_entry(metric_name_labels, 0),
|
232
|
-
rb_ary_entry(metric_name_labels, 1),
|
233
|
-
rb_ary_entry(metric_name_labels, 2),
|
234
|
-
DBL2NUM(value)
|
235
|
-
);
|
236
|
-
|
237
|
-
pos += sizeof(double);
|
238
|
-
}
|
239
|
-
|
240
|
-
return Qnil;
|
241
|
-
}
|
242
|
-
|
243
140
|
void Init_fast_mmaped_file() {
|
244
|
-
|
245
141
|
MMAPED_FILE = rb_define_module("FastMmapedFile");
|
246
|
-
rb_define_singleton_method(MMAPED_FILE, "fast_json_parse", method_fast_json_parse, 1);
|
247
|
-
rb_define_singleton_method(MMAPED_FILE, "fast_entries", method_fast_entries, 1);
|
248
|
-
|
249
142
|
rb_define_method(MMAPED_FILE, "get_double", method_get_double, 1);
|
250
143
|
rb_define_method(MMAPED_FILE, "add_entry", method_add_entry, 3);
|
251
144
|
}
|
data/lib/fast_mmaped_file.bundle
CHANGED
Binary file
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'prometheus/client/helper/json_parser'
|
2
|
-
require 'fast_mmaped_file'
|
3
2
|
|
4
3
|
module Prometheus
|
5
4
|
module Client
|
@@ -78,20 +77,21 @@ module Prometheus
|
|
78
77
|
end
|
79
78
|
|
80
79
|
def to_metrics(metrics = {}, ignore_errors = false)
|
81
|
-
|
80
|
+
parsed_entries(ignore_errors).each do |key, value|
|
82
81
|
begin
|
82
|
+
metric_name, name, labelnames, labelvalues = JsonParser.load(key)
|
83
83
|
metric = metrics.fetch(metric_name,
|
84
84
|
metric_name: metric_name,
|
85
85
|
help: 'Multiprocess metric',
|
86
86
|
type: type,
|
87
|
-
samples:
|
87
|
+
samples: []
|
88
88
|
)
|
89
89
|
if type == :gauge
|
90
90
|
metric[:multiprocess_mode] = multiprocess_mode
|
91
|
-
|
91
|
+
metric[:samples] += [[name, labelnames.zip(labelvalues) + [['pid', pid]], value]]
|
92
92
|
else
|
93
|
-
merge_samples(name, labels, value, metric[:samples])
|
94
93
|
# The duplicates and labels are fixed in the next for.
|
94
|
+
metric[:samples] += [[name, labelnames.zip(labelvalues), value]]
|
95
95
|
end
|
96
96
|
metrics[metric_name] = metric
|
97
97
|
rescue JSON::ParserError => e
|
@@ -103,54 +103,6 @@ module Prometheus
|
|
103
103
|
metrics
|
104
104
|
end
|
105
105
|
|
106
|
-
|
107
|
-
def min(a, b)
|
108
|
-
if a < b
|
109
|
-
a
|
110
|
-
else
|
111
|
-
b
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def max(a, b)
|
116
|
-
if a > b
|
117
|
-
a
|
118
|
-
else
|
119
|
-
b
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def merge_samples(name, labels, value, samples)
|
124
|
-
samples ||= {}
|
125
|
-
case type
|
126
|
-
when :gauge
|
127
|
-
case multiprocess_mode
|
128
|
-
when 'min'
|
129
|
-
key = labels.merge!(__key_name: name)
|
130
|
-
s = samples.fetch(key, value)
|
131
|
-
samples[key] = min(s, value)
|
132
|
-
when 'max'
|
133
|
-
key = labels.merge!(__key_name: name)
|
134
|
-
s = samples.fetch(key, value)
|
135
|
-
samples[key] = max(s, value)
|
136
|
-
when 'livesum'
|
137
|
-
key = labels.merge!(__key_name: name)
|
138
|
-
s = samples.fetch(key, 0.0)
|
139
|
-
samples[key] = s + value
|
140
|
-
else # all/liveall
|
141
|
-
key = labels.merge!(pid: pid, __key_name: name)
|
142
|
-
samples[key] = value
|
143
|
-
end
|
144
|
-
else
|
145
|
-
key = labels.merge!(__key_name: name)
|
146
|
-
# Counter, Histogram and Summary.
|
147
|
-
s = samples.fetch(key, 0.0)
|
148
|
-
samples[key] = s + value
|
149
|
-
end
|
150
|
-
|
151
|
-
samples
|
152
|
-
end
|
153
|
-
|
154
106
|
private
|
155
107
|
|
156
108
|
def bin_to_hex(s)
|
@@ -3,54 +3,37 @@ module Prometheus
|
|
3
3
|
module Helper
|
4
4
|
module MetricsProcessing
|
5
5
|
def self.merge_metrics(metrics)
|
6
|
-
metrics
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
if a < b
|
11
|
-
a
|
12
|
-
else
|
13
|
-
b
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.max(a, b)
|
18
|
-
if a > b
|
19
|
-
a
|
20
|
-
else
|
21
|
-
b
|
6
|
+
metrics.each_value do |metric|
|
7
|
+
metric[:samples] = merge_samples(metric[:samples], metric[:type], metric[:multiprocess_mode]).map do |(name, labels), value|
|
8
|
+
[name, labels.to_h, value]
|
9
|
+
end
|
22
10
|
end
|
23
11
|
end
|
24
12
|
|
25
13
|
def self.merge_samples(raw_samples, metric_type, multiprocess_mode)
|
26
14
|
samples = {}
|
27
15
|
raw_samples.each do |name, labels, value|
|
28
|
-
|
29
|
-
# without_pid = labels.delete(:pid)
|
16
|
+
without_pid = labels.reject { |l| l[0] == 'pid' }
|
30
17
|
|
31
18
|
case metric_type
|
32
19
|
when :gauge
|
33
20
|
case multiprocess_mode
|
34
21
|
when 'min'
|
35
|
-
|
36
|
-
|
37
|
-
samples[key] = min(s, value)
|
22
|
+
s = samples.fetch([name, without_pid], value)
|
23
|
+
samples[[name, without_pid]] = [s, value].min
|
38
24
|
when 'max'
|
39
|
-
|
40
|
-
|
41
|
-
samples[key] = max(s, value)
|
25
|
+
s = samples.fetch([name, without_pid], value)
|
26
|
+
samples[[name, without_pid]] = [s, value].max
|
42
27
|
when 'livesum'
|
43
|
-
|
44
|
-
|
45
|
-
samples[key] = s + value
|
28
|
+
s = samples.fetch([name, without_pid], 0.0)
|
29
|
+
samples[[name, without_pid]] = s + value
|
46
30
|
else # all/liveall
|
47
|
-
samples[
|
31
|
+
samples[[name, labels]] = value
|
48
32
|
end
|
49
33
|
else
|
50
|
-
labels.delete(:pid)
|
51
34
|
# Counter, Histogram and Summary.
|
52
|
-
s = samples.fetch(
|
53
|
-
samples[
|
35
|
+
s = samples.fetch([name, without_pid], 0.0)
|
36
|
+
samples[[name, without_pid]] = s + value
|
54
37
|
end
|
55
38
|
end
|
56
39
|
|
@@ -19,9 +19,8 @@ module Prometheus
|
|
19
19
|
metrics.each do |name, metric|
|
20
20
|
lines << format(HELP_LINE, name, escape(metric[:help]))
|
21
21
|
lines << format(TYPE_LINE, name, metric[:type])
|
22
|
-
metric[:samples].each do |labels, value|
|
23
|
-
|
24
|
-
lines << metric(key, format_labels(labels), value)
|
22
|
+
metric[:samples].each do |metric_name, labels, value|
|
23
|
+
lines << metric(metric_name, format_labels(labels), value)
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
@@ -33,7 +32,7 @@ module Prometheus
|
|
33
32
|
format(METRIC_LINE, name, labels, value)
|
34
33
|
end
|
35
34
|
|
36
|
-
def self.format_labels(set)
|
35
|
+
def self.format_labels(set)
|
37
36
|
return if set.empty?
|
38
37
|
|
39
38
|
strings = set.each_with_object([]) do |(key, value), memo|
|
@@ -19,8 +19,6 @@ module Prometheus
|
|
19
19
|
@file_prefix += '_' + multiprocess_mode.to_s
|
20
20
|
end
|
21
21
|
|
22
|
-
self.class.reset_on_pid_change
|
23
|
-
# initialize_file
|
24
22
|
@pid = -1
|
25
23
|
|
26
24
|
@mutex = Mutex.new
|
@@ -65,6 +63,7 @@ module Prometheus
|
|
65
63
|
def initialize_file
|
66
64
|
VALUE_LOCK.synchronize do
|
67
65
|
return if @file && !pid_changed?
|
66
|
+
self.class.reset_on_pid_change
|
68
67
|
|
69
68
|
@pid = Process.pid
|
70
69
|
unless @@files.has_key?(@file_prefix)
|
@@ -90,16 +89,17 @@ module Prometheus
|
|
90
89
|
end
|
91
90
|
|
92
91
|
def self.reset_on_pid_change
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
@@files = {}
|
97
|
-
end
|
92
|
+
if pid_changed?
|
93
|
+
@@pid = Process.pid
|
94
|
+
@@files = {}
|
98
95
|
end
|
99
96
|
end
|
100
97
|
|
101
98
|
def self.reinitialize_on_pid_change
|
102
|
-
|
99
|
+
VALUE_LOCK.synchronize do
|
100
|
+
reset_on_pid_change
|
101
|
+
end
|
102
|
+
|
103
103
|
ObjectSpace.each_object(MmapedValue, &:reinitialize)
|
104
104
|
end
|
105
105
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-client-mmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.0.
|
4
|
+
version: 0.7.0.beta33
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Schmidt
|
@@ -59,6 +59,20 @@ dependencies:
|
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 1.0.4
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: ruby-prof
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.16.2
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.16.2
|
62
76
|
description:
|
63
77
|
email:
|
64
78
|
- ts@soundcloud.com
|
@@ -71,8 +85,6 @@ files:
|
|
71
85
|
- README.md
|
72
86
|
- ext/fast_mmaped_file/extconf.rb
|
73
87
|
- ext/fast_mmaped_file/fast_mmaped_file.c
|
74
|
-
- ext/fast_mmaped_file/jsmn.c
|
75
|
-
- ext/fast_mmaped_file/jsmn.h
|
76
88
|
- ext/fast_mmaped_file/mmap.h
|
77
89
|
- lib/fast_mmaped_file.bundle
|
78
90
|
- lib/prometheus.rb
|
data/ext/fast_mmaped_file/jsmn.c
DELETED
@@ -1,313 +0,0 @@
|
|
1
|
-
#include "jsmn.h"
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Allocates a fresh unused token from the token pull.
|
5
|
-
*/
|
6
|
-
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
7
|
-
jsmntok_t *tokens, size_t num_tokens) {
|
8
|
-
jsmntok_t *tok;
|
9
|
-
if (parser->toknext >= num_tokens) {
|
10
|
-
return NULL;
|
11
|
-
}
|
12
|
-
tok = &tokens[parser->toknext++];
|
13
|
-
tok->start = tok->end = -1;
|
14
|
-
tok->size = 0;
|
15
|
-
#ifdef JSMN_PARENT_LINKS
|
16
|
-
tok->parent = -1;
|
17
|
-
#endif
|
18
|
-
return tok;
|
19
|
-
}
|
20
|
-
|
21
|
-
/**
|
22
|
-
* Fills token type and boundaries.
|
23
|
-
*/
|
24
|
-
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
25
|
-
int start, int end) {
|
26
|
-
token->type = type;
|
27
|
-
token->start = start;
|
28
|
-
token->end = end;
|
29
|
-
token->size = 0;
|
30
|
-
}
|
31
|
-
|
32
|
-
/**
|
33
|
-
* Fills next available token with JSON primitive.
|
34
|
-
*/
|
35
|
-
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
36
|
-
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
37
|
-
jsmntok_t *token;
|
38
|
-
int start;
|
39
|
-
|
40
|
-
start = parser->pos;
|
41
|
-
|
42
|
-
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
43
|
-
switch (js[parser->pos]) {
|
44
|
-
#ifndef JSMN_STRICT
|
45
|
-
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
46
|
-
case ':':
|
47
|
-
#endif
|
48
|
-
case '\t' : case '\r' : case '\n' : case ' ' :
|
49
|
-
case ',' : case ']' : case '}' :
|
50
|
-
goto found;
|
51
|
-
}
|
52
|
-
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
53
|
-
parser->pos = start;
|
54
|
-
return JSMN_ERROR_INVAL;
|
55
|
-
}
|
56
|
-
}
|
57
|
-
#ifdef JSMN_STRICT
|
58
|
-
/* In strict mode primitive must be followed by a comma/object/array */
|
59
|
-
parser->pos = start;
|
60
|
-
return JSMN_ERROR_PART;
|
61
|
-
#endif
|
62
|
-
|
63
|
-
found:
|
64
|
-
if (tokens == NULL) {
|
65
|
-
parser->pos--;
|
66
|
-
return 0;
|
67
|
-
}
|
68
|
-
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
69
|
-
if (token == NULL) {
|
70
|
-
parser->pos = start;
|
71
|
-
return JSMN_ERROR_NOMEM;
|
72
|
-
}
|
73
|
-
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
74
|
-
#ifdef JSMN_PARENT_LINKS
|
75
|
-
token->parent = parser->toksuper;
|
76
|
-
#endif
|
77
|
-
parser->pos--;
|
78
|
-
return 0;
|
79
|
-
}
|
80
|
-
|
81
|
-
/**
|
82
|
-
* Fills next token with JSON string.
|
83
|
-
*/
|
84
|
-
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
85
|
-
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
86
|
-
jsmntok_t *token;
|
87
|
-
|
88
|
-
int start = parser->pos;
|
89
|
-
|
90
|
-
parser->pos++;
|
91
|
-
|
92
|
-
/* Skip starting quote */
|
93
|
-
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
94
|
-
char c = js[parser->pos];
|
95
|
-
|
96
|
-
/* Quote: end of string */
|
97
|
-
if (c == '\"') {
|
98
|
-
if (tokens == NULL) {
|
99
|
-
return 0;
|
100
|
-
}
|
101
|
-
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
102
|
-
if (token == NULL) {
|
103
|
-
parser->pos = start;
|
104
|
-
return JSMN_ERROR_NOMEM;
|
105
|
-
}
|
106
|
-
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
107
|
-
#ifdef JSMN_PARENT_LINKS
|
108
|
-
token->parent = parser->toksuper;
|
109
|
-
#endif
|
110
|
-
return 0;
|
111
|
-
}
|
112
|
-
|
113
|
-
/* Backslash: Quoted symbol expected */
|
114
|
-
if (c == '\\' && parser->pos + 1 < len) {
|
115
|
-
int i;
|
116
|
-
parser->pos++;
|
117
|
-
switch (js[parser->pos]) {
|
118
|
-
/* Allowed escaped symbols */
|
119
|
-
case '\"': case '/' : case '\\' : case 'b' :
|
120
|
-
case 'f' : case 'r' : case 'n' : case 't' :
|
121
|
-
break;
|
122
|
-
/* Allows escaped symbol \uXXXX */
|
123
|
-
case 'u':
|
124
|
-
parser->pos++;
|
125
|
-
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
|
126
|
-
/* If it isn't a hex character we have an error */
|
127
|
-
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
128
|
-
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
129
|
-
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
130
|
-
parser->pos = start;
|
131
|
-
return JSMN_ERROR_INVAL;
|
132
|
-
}
|
133
|
-
parser->pos++;
|
134
|
-
}
|
135
|
-
parser->pos--;
|
136
|
-
break;
|
137
|
-
/* Unexpected symbol */
|
138
|
-
default:
|
139
|
-
parser->pos = start;
|
140
|
-
return JSMN_ERROR_INVAL;
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
parser->pos = start;
|
145
|
-
return JSMN_ERROR_PART;
|
146
|
-
}
|
147
|
-
|
148
|
-
/**
|
149
|
-
* Parse JSON string and fill tokens.
|
150
|
-
*/
|
151
|
-
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
152
|
-
jsmntok_t *tokens, unsigned int num_tokens) {
|
153
|
-
int r;
|
154
|
-
int i;
|
155
|
-
jsmntok_t *token;
|
156
|
-
int count = parser->toknext;
|
157
|
-
|
158
|
-
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
159
|
-
char c;
|
160
|
-
jsmntype_t type;
|
161
|
-
|
162
|
-
c = js[parser->pos];
|
163
|
-
switch (c) {
|
164
|
-
case '{': case '[':
|
165
|
-
count++;
|
166
|
-
if (tokens == NULL) {
|
167
|
-
break;
|
168
|
-
}
|
169
|
-
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
170
|
-
if (token == NULL)
|
171
|
-
return JSMN_ERROR_NOMEM;
|
172
|
-
if (parser->toksuper != -1) {
|
173
|
-
tokens[parser->toksuper].size++;
|
174
|
-
#ifdef JSMN_PARENT_LINKS
|
175
|
-
token->parent = parser->toksuper;
|
176
|
-
#endif
|
177
|
-
}
|
178
|
-
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
179
|
-
token->start = parser->pos;
|
180
|
-
parser->toksuper = parser->toknext - 1;
|
181
|
-
break;
|
182
|
-
case '}': case ']':
|
183
|
-
if (tokens == NULL)
|
184
|
-
break;
|
185
|
-
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
186
|
-
#ifdef JSMN_PARENT_LINKS
|
187
|
-
if (parser->toknext < 1) {
|
188
|
-
return JSMN_ERROR_INVAL;
|
189
|
-
}
|
190
|
-
token = &tokens[parser->toknext - 1];
|
191
|
-
for (;;) {
|
192
|
-
if (token->start != -1 && token->end == -1) {
|
193
|
-
if (token->type != type) {
|
194
|
-
return JSMN_ERROR_INVAL;
|
195
|
-
}
|
196
|
-
token->end = parser->pos + 1;
|
197
|
-
parser->toksuper = token->parent;
|
198
|
-
break;
|
199
|
-
}
|
200
|
-
if (token->parent == -1) {
|
201
|
-
if(token->type != type || parser->toksuper == -1) {
|
202
|
-
return JSMN_ERROR_INVAL;
|
203
|
-
}
|
204
|
-
break;
|
205
|
-
}
|
206
|
-
token = &tokens[token->parent];
|
207
|
-
}
|
208
|
-
#else
|
209
|
-
for (i = parser->toknext - 1; i >= 0; i--) {
|
210
|
-
token = &tokens[i];
|
211
|
-
if (token->start != -1 && token->end == -1) {
|
212
|
-
if (token->type != type) {
|
213
|
-
return JSMN_ERROR_INVAL;
|
214
|
-
}
|
215
|
-
parser->toksuper = -1;
|
216
|
-
token->end = parser->pos + 1;
|
217
|
-
break;
|
218
|
-
}
|
219
|
-
}
|
220
|
-
/* Error if unmatched closing bracket */
|
221
|
-
if (i == -1) return JSMN_ERROR_INVAL;
|
222
|
-
for (; i >= 0; i--) {
|
223
|
-
token = &tokens[i];
|
224
|
-
if (token->start != -1 && token->end == -1) {
|
225
|
-
parser->toksuper = i;
|
226
|
-
break;
|
227
|
-
}
|
228
|
-
}
|
229
|
-
#endif
|
230
|
-
break;
|
231
|
-
case '\"':
|
232
|
-
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
233
|
-
if (r < 0) return r;
|
234
|
-
count++;
|
235
|
-
if (parser->toksuper != -1 && tokens != NULL)
|
236
|
-
tokens[parser->toksuper].size++;
|
237
|
-
break;
|
238
|
-
case '\t' : case '\r' : case '\n' : case ' ':
|
239
|
-
break;
|
240
|
-
case ':':
|
241
|
-
parser->toksuper = parser->toknext - 1;
|
242
|
-
break;
|
243
|
-
case ',':
|
244
|
-
if (tokens != NULL && parser->toksuper != -1 &&
|
245
|
-
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
246
|
-
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
247
|
-
#ifdef JSMN_PARENT_LINKS
|
248
|
-
parser->toksuper = tokens[parser->toksuper].parent;
|
249
|
-
#else
|
250
|
-
for (i = parser->toknext - 1; i >= 0; i--) {
|
251
|
-
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
252
|
-
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
253
|
-
parser->toksuper = i;
|
254
|
-
break;
|
255
|
-
}
|
256
|
-
}
|
257
|
-
}
|
258
|
-
#endif
|
259
|
-
}
|
260
|
-
break;
|
261
|
-
#ifdef JSMN_STRICT
|
262
|
-
/* In strict mode primitives are: numbers and booleans */
|
263
|
-
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
264
|
-
case '5': case '6': case '7' : case '8': case '9':
|
265
|
-
case 't': case 'f': case 'n' :
|
266
|
-
/* And they must not be keys of the object */
|
267
|
-
if (tokens != NULL && parser->toksuper != -1) {
|
268
|
-
jsmntok_t *t = &tokens[parser->toksuper];
|
269
|
-
if (t->type == JSMN_OBJECT ||
|
270
|
-
(t->type == JSMN_STRING && t->size != 0)) {
|
271
|
-
return JSMN_ERROR_INVAL;
|
272
|
-
}
|
273
|
-
}
|
274
|
-
#else
|
275
|
-
/* In non-strict mode every unquoted value is a primitive */
|
276
|
-
default:
|
277
|
-
#endif
|
278
|
-
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
279
|
-
if (r < 0) return r;
|
280
|
-
count++;
|
281
|
-
if (parser->toksuper != -1 && tokens != NULL)
|
282
|
-
tokens[parser->toksuper].size++;
|
283
|
-
break;
|
284
|
-
|
285
|
-
#ifdef JSMN_STRICT
|
286
|
-
/* Unexpected char in strict mode */
|
287
|
-
default:
|
288
|
-
return JSMN_ERROR_INVAL;
|
289
|
-
#endif
|
290
|
-
}
|
291
|
-
}
|
292
|
-
|
293
|
-
if (tokens != NULL) {
|
294
|
-
for (i = parser->toknext - 1; i >= 0; i--) {
|
295
|
-
/* Unmatched opened object or array */
|
296
|
-
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
297
|
-
return JSMN_ERROR_PART;
|
298
|
-
}
|
299
|
-
}
|
300
|
-
}
|
301
|
-
|
302
|
-
return count;
|
303
|
-
}
|
304
|
-
|
305
|
-
/**
|
306
|
-
* Creates a new parser based over a given buffer with an array of tokens
|
307
|
-
* available.
|
308
|
-
*/
|
309
|
-
void jsmn_init(jsmn_parser *parser) {
|
310
|
-
parser->pos = 0;
|
311
|
-
parser->toknext = 0;
|
312
|
-
parser->toksuper = -1;
|
313
|
-
}
|
data/ext/fast_mmaped_file/jsmn.h
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
#ifndef __JSMN_H_
|
2
|
-
#define __JSMN_H_
|
3
|
-
|
4
|
-
#include <stddef.h>
|
5
|
-
|
6
|
-
#ifdef __cplusplus
|
7
|
-
extern "C" {
|
8
|
-
#endif
|
9
|
-
|
10
|
-
/**
|
11
|
-
* JSON type identifier. Basic types are:
|
12
|
-
* o Object
|
13
|
-
* o Array
|
14
|
-
* o String
|
15
|
-
* o Other primitive: number, boolean (true/false) or null
|
16
|
-
*/
|
17
|
-
typedef enum {
|
18
|
-
JSMN_UNDEFINED = 0,
|
19
|
-
JSMN_OBJECT = 1,
|
20
|
-
JSMN_ARRAY = 2,
|
21
|
-
JSMN_STRING = 3,
|
22
|
-
JSMN_PRIMITIVE = 4
|
23
|
-
} jsmntype_t;
|
24
|
-
|
25
|
-
enum jsmnerr {
|
26
|
-
/* Not enough tokens were provided */
|
27
|
-
JSMN_ERROR_NOMEM = -1,
|
28
|
-
/* Invalid character inside JSON string */
|
29
|
-
JSMN_ERROR_INVAL = -2,
|
30
|
-
/* The string is not a full JSON packet, more bytes expected */
|
31
|
-
JSMN_ERROR_PART = -3
|
32
|
-
};
|
33
|
-
|
34
|
-
/**
|
35
|
-
* JSON token description.
|
36
|
-
* type type (object, array, string etc.)
|
37
|
-
* start start position in JSON data string
|
38
|
-
* end end position in JSON data string
|
39
|
-
*/
|
40
|
-
typedef struct {
|
41
|
-
jsmntype_t type;
|
42
|
-
int start;
|
43
|
-
int end;
|
44
|
-
int size;
|
45
|
-
#ifdef JSMN_PARENT_LINKS
|
46
|
-
int parent;
|
47
|
-
#endif
|
48
|
-
} jsmntok_t;
|
49
|
-
|
50
|
-
/**
|
51
|
-
* JSON parser. Contains an array of token blocks available. Also stores
|
52
|
-
* the string being parsed now and current position in that string
|
53
|
-
*/
|
54
|
-
typedef struct {
|
55
|
-
unsigned int pos; /* offset in the JSON string */
|
56
|
-
unsigned int toknext; /* next token to allocate */
|
57
|
-
int toksuper; /* superior token node, e.g parent object or array */
|
58
|
-
} jsmn_parser;
|
59
|
-
|
60
|
-
/**
|
61
|
-
* Create JSON parser over an array of tokens
|
62
|
-
*/
|
63
|
-
void jsmn_init(jsmn_parser *parser);
|
64
|
-
|
65
|
-
/**
|
66
|
-
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
|
67
|
-
* a single JSON object.
|
68
|
-
*/
|
69
|
-
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
70
|
-
jsmntok_t *tokens, unsigned int num_tokens);
|
71
|
-
|
72
|
-
#ifdef __cplusplus
|
73
|
-
}
|
74
|
-
#endif
|
75
|
-
|
76
|
-
#endif /* __JSMN_H_ */
|