sq_detailed_metrics 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/extconf.rb +26 -0
  3. data/include/half.hpp +4575 -0
  4. data/include/msgpack.h +24 -0
  5. data/include/msgpack/fbuffer.h +42 -0
  6. data/include/msgpack/gcc_atomic.h +25 -0
  7. data/include/msgpack/object.h +118 -0
  8. data/include/msgpack/pack.h +174 -0
  9. data/include/msgpack/pack_define.h +18 -0
  10. data/include/msgpack/pack_template.h +952 -0
  11. data/include/msgpack/sbuffer.h +115 -0
  12. data/include/msgpack/sysdep.h +221 -0
  13. data/include/msgpack/timestamp.h +58 -0
  14. data/include/msgpack/unpack.h +281 -0
  15. data/include/msgpack/unpack_define.h +89 -0
  16. data/include/msgpack/unpack_template.h +471 -0
  17. data/include/msgpack/util.h +15 -0
  18. data/include/msgpack/version.h +38 -0
  19. data/include/msgpack/version_master.h +3 -0
  20. data/include/msgpack/vrefbuffer.h +144 -0
  21. data/include/msgpack/zbuffer.h +205 -0
  22. data/include/msgpack/zone.h +163 -0
  23. data/include/rapidjson/allocators.h +271 -0
  24. data/include/rapidjson/document.h +2575 -0
  25. data/include/rapidjson/encodedstream.h +299 -0
  26. data/include/rapidjson/encodings.h +716 -0
  27. data/include/rapidjson/error/en.h +74 -0
  28. data/include/rapidjson/error/error.h +155 -0
  29. data/include/rapidjson/filereadstream.h +99 -0
  30. data/include/rapidjson/filewritestream.h +104 -0
  31. data/include/rapidjson/fwd.h +151 -0
  32. data/include/rapidjson/internal/biginteger.h +290 -0
  33. data/include/rapidjson/internal/diyfp.h +258 -0
  34. data/include/rapidjson/internal/dtoa.h +245 -0
  35. data/include/rapidjson/internal/ieee754.h +78 -0
  36. data/include/rapidjson/internal/itoa.h +304 -0
  37. data/include/rapidjson/internal/meta.h +181 -0
  38. data/include/rapidjson/internal/pow10.h +55 -0
  39. data/include/rapidjson/internal/regex.h +701 -0
  40. data/include/rapidjson/internal/stack.h +230 -0
  41. data/include/rapidjson/internal/strfunc.h +55 -0
  42. data/include/rapidjson/internal/strtod.h +269 -0
  43. data/include/rapidjson/internal/swap.h +46 -0
  44. data/include/rapidjson/istreamwrapper.h +115 -0
  45. data/include/rapidjson/memorybuffer.h +70 -0
  46. data/include/rapidjson/memorystream.h +71 -0
  47. data/include/rapidjson/msinttypes/inttypes.h +316 -0
  48. data/include/rapidjson/msinttypes/stdint.h +300 -0
  49. data/include/rapidjson/ostreamwrapper.h +81 -0
  50. data/include/rapidjson/pointer.h +1358 -0
  51. data/include/rapidjson/prettywriter.h +255 -0
  52. data/include/rapidjson/rapidjson.h +615 -0
  53. data/include/rapidjson/reader.h +1879 -0
  54. data/include/rapidjson/schema.h +2006 -0
  55. data/include/rapidjson/stream.h +179 -0
  56. data/include/rapidjson/stringbuffer.h +117 -0
  57. data/include/rapidjson/writer.h +610 -0
  58. data/include/xxhash.h +328 -0
  59. data/json_conv.cpp +284 -0
  60. data/json_conv.hpp +17 -0
  61. data/metrics.cpp +239 -0
  62. data/metrics.hpp +84 -0
  63. data/msgpack/objectc.c +482 -0
  64. data/msgpack/unpack.c +703 -0
  65. data/msgpack/version.c +22 -0
  66. data/msgpack/vrefbuffer.c +250 -0
  67. data/msgpack/zone.c +222 -0
  68. data/sq_detailed_metrics.cpp +248 -0
  69. metadata +199 -0
@@ -0,0 +1,17 @@
1
+ #ifndef JSON_CONV_HPP
2
+ #define JSON_CONV_HPP
3
+
4
+ #include <iostream>
5
+
6
+ namespace sq_detailed_metrics
7
+ {
8
+ class JsonConv {
9
+ std::ostream& os;
10
+ public:
11
+ JsonConv(std::ostream& os_) : os(os_) {}
12
+
13
+ void parse(const char *src, size_t size);
14
+ };
15
+ }
16
+
17
+ #endif // JSON_CONV_HPP
@@ -0,0 +1,239 @@
1
+ #include "metrics.hpp"
2
+ #include <msgpack.h>
3
+ #define LZ4LIB_VISIBILITY
4
+
5
+ namespace sq_detailed_metrics {
6
+
7
+ struct MsgpackPacker
8
+ {
9
+ MsgpackPacker() {
10
+ msgpack_packer_init(&packer, &output, &MsgpackPacker::std_string_write);
11
+ }
12
+
13
+ void start_map(size_t num_keys) {
14
+ msgpack_pack_map(&packer, num_keys);
15
+ }
16
+
17
+ void start_array(size_t num_elements) {
18
+ msgpack_pack_array(&packer, num_elements);
19
+ }
20
+
21
+ void start_bin(size_t size) {
22
+ msgpack_pack_bin(&packer, size);
23
+ }
24
+
25
+ void add_bin_portion(const char *data, size_t size) {
26
+ msgpack_pack_bin_body(&packer, data, size);
27
+ }
28
+
29
+ MsgpackPacker& operator<<(const std::string& str) {
30
+ const char *c_str = str.c_str();
31
+ msgpack_pack_str_with_body(&packer, c_str, str.size());
32
+ return *this;
33
+ }
34
+
35
+ MsgpackPacker& operator<<(index_t value) {
36
+ msgpack_pack_uint8(&packer, value);
37
+ return *this;
38
+ }
39
+
40
+ MsgpackPacker& operator<<(uint16_t value) {
41
+ msgpack_pack_uint16(&packer, value);
42
+ return *this;
43
+ }
44
+
45
+ MsgpackPacker& operator<<(half_float::half& value) {
46
+ msgpack_pack_fix_uint16(&packer, *reinterpret_cast<uint16_t *>(&value));
47
+ return *this;
48
+ }
49
+
50
+ std::string move_output() {
51
+ return std::move(output);
52
+ }
53
+
54
+ MsgpackPacker(const MsgpackPacker&) = delete;
55
+ MsgpackPacker& operator=(const MsgpackPacker&) = delete;
56
+ private:
57
+ // must be of type msgpack_packer_write
58
+ static int std_string_write(void* data, const char* buf, size_t len) {
59
+ std::string *str = static_cast<std::string*>(data);
60
+ try {
61
+ str->append(buf, len);
62
+ } catch (std::bad_alloc&) {
63
+ return -1;
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ std::string output;
69
+ msgpack_packer packer;
70
+ };
71
+
72
+ struct MetricsIndex {
73
+ index_t index_of(const std::string& meas_type) {
74
+ lock_guard lock_guard(m);
75
+
76
+ index_t& t = meas_type_index[meas_type];
77
+ if (t == undef_index_t) {
78
+ t = next;
79
+ if (next < max_index_t) {
80
+ next++;
81
+ }
82
+ }
83
+ return t;
84
+ }
85
+
86
+ void serialize(MsgpackPacker& packer, const index_t_set& used_meas) {
87
+ lock_guard lock_guard(m);
88
+
89
+ // indexes 0 (undefined) and 255 (others) are not sent
90
+ packer.start_map(used_meas.count() -
91
+ (used_meas[undef_index_t] ? 1 : 0) -
92
+ (used_meas[max_index_t] ? 1 : 0));
93
+
94
+ std::for_each(meas_type_index.begin(), meas_type_index.end(),
95
+ [&packer, &used_meas](std::pair<std::string, index_t> entry) {
96
+ index_t i = entry.second;
97
+ if (i == max_index_t || i == undef_index_t || !used_meas[i]) {
98
+ return;
99
+ }
100
+ packer << i << entry.first; // index, string
101
+ });
102
+ }
103
+
104
+ MetricsIndex() {}
105
+ ~MetricsIndex() = default;
106
+ MetricsIndex(const MetricsIndex&) = delete;
107
+ MetricsIndex& operator= (const MetricsIndex&) = delete;
108
+
109
+ private:
110
+ std::map<std::string, index_t> meas_type_index;
111
+ index_t next = 1;
112
+ std::mutex m;
113
+ };
114
+
115
+
116
+ void Request::set_overtime_cb(const std::string& cb) {
117
+ if (cb.size() != 0) {
118
+ overtime_cb = metrics_index->index_of(cb);
119
+ } else {
120
+ overtime_cb = undef_index_t;
121
+ }
122
+ }
123
+
124
+ void Request::add(const std::string& meas_type, double value) {
125
+ index_t t = metrics_index->index_of(meas_type);
126
+ // the max half float is only 65504. Since we're storing
127
+ // ms, this is about 65 s. While this is a large quantity,
128
+ // larger ones have been seen in practice. Extend this range
129
+ // to almost 9 minutes by diving by 8. The minumum (normal)
130
+ // value becomes about 0.5 us, which is still good enough
131
+ float fval = static_cast<float>(value) / 8.0f;
132
+ half_float::half val{fval};
133
+
134
+ measurements.push_back(meas_entry_t{t, val});
135
+ }
136
+
137
+ void Request::mark_used_meas_types(index_t_set& bitset) const {
138
+ bitset[this->overtime_cb] = true;
139
+ for (const meas_entry_t& m: measurements) {
140
+ index_t i = m.first;
141
+ bitset[i] = true;
142
+ }
143
+ }
144
+
145
+ void Request::serialize(MsgpackPacker& packer,
146
+ req_index_t idx,
147
+ std::map<std::string, req_index_t>& prev_routes) const {
148
+ packer.start_array(3);
149
+
150
+ auto route_prev_idx_it = prev_routes.find(route);
151
+ if (route_prev_idx_it == prev_routes.end()) {
152
+ packer << route;
153
+ prev_routes[route] = idx;
154
+ } else {
155
+ req_index_t prev_idx = route_prev_idx_it->second;
156
+ packer << prev_idx;
157
+ }
158
+
159
+ packer << overtime_cb;
160
+
161
+ // encode as binary to encode pairs in 3 bytes
162
+ packer.start_bin(measurements.size() *
163
+ (sizeof(index_t) + sizeof(half_float::half)));
164
+ std::for_each(measurements.begin(), measurements.end(),
165
+ [&packer](meas_entry_t entry) {
166
+ packer.add_bin_portion(
167
+ reinterpret_cast<const char *>(&entry.first),
168
+ sizeof(index_t));
169
+ packer.add_bin_portion(
170
+ reinterpret_cast<const char *>(&entry.second),
171
+ sizeof(half_float::half));
172
+ });
173
+ }
174
+
175
+ size_t Request::mem_size() const {
176
+ return sizeof(Request) + route.length() +
177
+ sizeof(meas_entry_t) * this->measurements.size();
178
+ }
179
+
180
+ void RequestCollection::operator<<(Request request) {
181
+ lock_guard lock_guard{m};
182
+
183
+ if (completed_requests.size() == max_req_per_coll) {
184
+ return;
185
+ }
186
+
187
+ completed_requests.push_back(std::move(request));
188
+ }
189
+
190
+ bool RequestCollection::flush(std::string& out) {
191
+ std::list<Request> requests;
192
+ {
193
+ lock_guard lock_guard{m};
194
+ std::swap(requests, completed_requests);
195
+ }
196
+
197
+ if (requests.size() == 0) {
198
+ return false;
199
+ }
200
+
201
+ MsgpackPacker packer;
202
+
203
+ packer.start_array(2);
204
+ index_t_set meas_types_used;
205
+ for (const Request& req: requests) {
206
+ req.mark_used_meas_types(meas_types_used);
207
+ }
208
+ metrics_index->serialize(packer, meas_types_used);
209
+
210
+ packer.start_array(requests.size());
211
+ {
212
+ std::map<std::string, req_index_t> seen_routes;
213
+ req_index_t i = 0;
214
+ for (const Request &r: requests) {
215
+ r.serialize(packer, i, seen_routes);
216
+ i++;
217
+ }
218
+ }
219
+
220
+ out = packer.move_output(); // should select move assignment
221
+
222
+ return true;
223
+ }
224
+
225
+ size_t RequestCollection::mem_size() const {
226
+ size_t size = sizeof(RequestCollection);
227
+ for (const Request& req: completed_requests) {
228
+ size += req.mem_size();
229
+ }
230
+ return size;
231
+ }
232
+
233
+ MetricsIndex *MetricsIndex_create() {
234
+ return new MetricsIndex();
235
+ }
236
+ void MetricsIndex_free(MetricsIndex *idx) {
237
+ delete idx;
238
+ }
239
+ }
@@ -0,0 +1,84 @@
1
+ #ifndef METRICS_HPP
2
+ #define METRICS_HPP
3
+
4
+ #include <memory>
5
+ #include <map>
6
+ #include <set>
7
+ #include <string>
8
+ #include <list>
9
+ #include <mutex>
10
+ #include <bitset>
11
+ #include <half.hpp>
12
+ #include <limits>
13
+
14
+ #include <memory>
15
+ namespace sq_detailed_metrics
16
+ {
17
+ struct MetricsIndex;
18
+ MetricsIndex *MetricsIndex_create();
19
+ void MetricsIndex_free(MetricsIndex *idx);
20
+
21
+ extern MetricsIndex *metrics_index;
22
+
23
+ using index_t = uint8_t;
24
+ constexpr index_t max_index_t = std::numeric_limits<index_t>::max();
25
+ constexpr index_t undef_index_t = 0; // must be 0
26
+ using index_t_set = std::bitset<max_index_t - 0 /* min */ + 1>;
27
+ using lock_guard = std::lock_guard<std::mutex>;
28
+ typedef std::pair<index_t, half_float::half> meas_entry_t;
29
+
30
+ using req_index_t = uint16_t;
31
+ constexpr auto max_req_per_coll = std::numeric_limits<req_index_t>::max();
32
+
33
+ struct MsgpackPacker;
34
+
35
+ // XXX: we require here that Request objects be modified only
36
+ // in one thread and that this be the thread that submits them to
37
+ // the request collection. This holds for Ruby, but may not hold
38
+ // e.g. for Java.
39
+ struct Request {
40
+ public:
41
+ void add(const std::string& meas_type, double value);
42
+ void set_route(std::string route_arg) {
43
+ this->route = std::move(route_arg);
44
+ }
45
+ void set_overtime_cb(const std::string& cb);
46
+
47
+ void mark_used_meas_types(index_t_set& set) const;
48
+
49
+ /*
50
+ * ["route"/<prev req index>, "overtime callback", b"<metric index 1><measurement 1>..."]]
51
+ */
52
+ void serialize(MsgpackPacker& packer,
53
+ req_index_t idx,
54
+ std::map<std::string, req_index_t>& prev_routes) const;
55
+
56
+ size_t mem_size() const;
57
+
58
+ Request() = default;
59
+ Request(const Request&) = delete;
60
+ Request(Request&&) = default;
61
+ Request& operator=(const Request&) = delete;
62
+
63
+ private:
64
+ std::string route;
65
+ index_t overtime_cb = undef_index_t;
66
+ std::list<meas_entry_t> measurements;
67
+ };
68
+
69
+ class RequestCollection {
70
+ public:
71
+ void operator<<(Request request);
72
+ bool flush(std::string& out);
73
+ size_t mem_size() const;
74
+
75
+ RequestCollection() = default;
76
+ RequestCollection(const RequestCollection&) = delete;
77
+ RequestCollection& operator=(const RequestCollection&) = delete;
78
+ private:
79
+ std::mutex m;
80
+ std::list<Request> completed_requests;
81
+ };
82
+ }
83
+
84
+ #endif // METRICS_HPP
@@ -0,0 +1,482 @@
1
+ /*
2
+ * MessagePack for C dynamic typing routine
3
+ *
4
+ * Copyright (C) 2008-2009 FURUHASHI Sadayuki
5
+ *
6
+ * Distributed under the Boost Software License, Version 1.0.
7
+ * (See accompanying file LICENSE_1_0.txt or copy at
8
+ * http://www.boost.org/LICENSE_1_0.txt)
9
+ */
10
+ #if defined(_KERNEL_MODE)
11
+ # undef _NO_CRT_STDIO_INLINE
12
+ # define _NO_CRT_STDIO_INLINE
13
+ #endif
14
+
15
+ #include "msgpack/object.h"
16
+ #include "msgpack/pack.h"
17
+ #include <ctype.h>
18
+
19
+ #include <stdio.h>
20
+ #include <string.h>
21
+
22
+ #if defined(_MSC_VER)
23
+ #if _MSC_VER >= 1800
24
+ #include <inttypes.h>
25
+ #else
26
+ #define PRIu64 "I64u"
27
+ #define PRIi64 "I64i"
28
+ #define PRIi8 "i"
29
+ #endif
30
+ #else
31
+ #include <inttypes.h>
32
+ #endif
33
+
34
+ #if defined(_KERNEL_MODE)
35
+ # undef snprintf
36
+ # define snprintf _snprintf
37
+ #endif
38
+
39
+ int msgpack_pack_object(msgpack_packer* pk, msgpack_object d)
40
+ {
41
+ switch(d.type) {
42
+ case MSGPACK_OBJECT_NIL:
43
+ return msgpack_pack_nil(pk);
44
+
45
+ case MSGPACK_OBJECT_BOOLEAN:
46
+ if(d.via.boolean) {
47
+ return msgpack_pack_true(pk);
48
+ } else {
49
+ return msgpack_pack_false(pk);
50
+ }
51
+
52
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
53
+ return msgpack_pack_uint64(pk, d.via.u64);
54
+
55
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
56
+ return msgpack_pack_int64(pk, d.via.i64);
57
+
58
+ case MSGPACK_OBJECT_FLOAT32:
59
+ return msgpack_pack_float(pk, (float)d.via.f64);
60
+
61
+ case MSGPACK_OBJECT_FLOAT64:
62
+ return msgpack_pack_double(pk, d.via.f64);
63
+
64
+ case MSGPACK_OBJECT_STR:
65
+ {
66
+ int ret = msgpack_pack_str(pk, d.via.str.size);
67
+ if(ret < 0) { return ret; }
68
+ return msgpack_pack_str_body(pk, d.via.str.ptr, d.via.str.size);
69
+ }
70
+
71
+ case MSGPACK_OBJECT_BIN:
72
+ {
73
+ int ret = msgpack_pack_bin(pk, d.via.bin.size);
74
+ if(ret < 0) { return ret; }
75
+ return msgpack_pack_bin_body(pk, d.via.bin.ptr, d.via.bin.size);
76
+ }
77
+
78
+ case MSGPACK_OBJECT_EXT:
79
+ {
80
+ int ret = msgpack_pack_ext(pk, d.via.ext.size, d.via.ext.type);
81
+ if(ret < 0) { return ret; }
82
+ return msgpack_pack_ext_body(pk, d.via.ext.ptr, d.via.ext.size);
83
+ }
84
+
85
+ case MSGPACK_OBJECT_ARRAY:
86
+ {
87
+ int ret = msgpack_pack_array(pk, d.via.array.size);
88
+ if(ret < 0) {
89
+ return ret;
90
+ }
91
+ else {
92
+ msgpack_object* o = d.via.array.ptr;
93
+ msgpack_object* const oend = d.via.array.ptr + d.via.array.size;
94
+ for(; o != oend; ++o) {
95
+ ret = msgpack_pack_object(pk, *o);
96
+ if(ret < 0) { return ret; }
97
+ }
98
+
99
+ return 0;
100
+ }
101
+ }
102
+
103
+ case MSGPACK_OBJECT_MAP:
104
+ {
105
+ int ret = msgpack_pack_map(pk, d.via.map.size);
106
+ if(ret < 0) {
107
+ return ret;
108
+ }
109
+ else {
110
+ msgpack_object_kv* kv = d.via.map.ptr;
111
+ msgpack_object_kv* const kvend = d.via.map.ptr + d.via.map.size;
112
+ for(; kv != kvend; ++kv) {
113
+ ret = msgpack_pack_object(pk, kv->key);
114
+ if(ret < 0) { return ret; }
115
+ ret = msgpack_pack_object(pk, kv->val);
116
+ if(ret < 0) { return ret; }
117
+ }
118
+
119
+ return 0;
120
+ }
121
+ }
122
+
123
+ default:
124
+ return -1;
125
+ }
126
+ }
127
+
128
+ #if !defined(_KERNEL_MODE)
129
+
130
+ static void msgpack_object_bin_print(FILE* out, const char *ptr, size_t size)
131
+ {
132
+ size_t i;
133
+ for (i = 0; i < size; ++i) {
134
+ if (ptr[i] == '"') {
135
+ fputs("\\\"", out);
136
+ } else if (isprint((unsigned char)ptr[i])) {
137
+ fputc(ptr[i], out);
138
+ } else {
139
+ fprintf(out, "\\x%02x", (unsigned char)ptr[i]);
140
+ }
141
+ }
142
+ }
143
+
144
+ void msgpack_object_print(FILE* out, msgpack_object o)
145
+ {
146
+ switch(o.type) {
147
+ case MSGPACK_OBJECT_NIL:
148
+ fprintf(out, "nil");
149
+ break;
150
+
151
+ case MSGPACK_OBJECT_BOOLEAN:
152
+ fprintf(out, (o.via.boolean ? "true" : "false"));
153
+ break;
154
+
155
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
156
+ #if defined(PRIu64)
157
+ fprintf(out, "%" PRIu64, o.via.u64);
158
+ #else
159
+ if (o.via.u64 > ULONG_MAX)
160
+ fprintf(out, "over 4294967295");
161
+ else
162
+ fprintf(out, "%lu", (unsigned long)o.via.u64);
163
+ #endif
164
+ break;
165
+
166
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
167
+ #if defined(PRIi64)
168
+ fprintf(out, "%" PRIi64, o.via.i64);
169
+ #else
170
+ if (o.via.i64 > LONG_MAX)
171
+ fprintf(out, "over +2147483647");
172
+ else if (o.via.i64 < LONG_MIN)
173
+ fprintf(out, "under -2147483648");
174
+ else
175
+ fprintf(out, "%ld", (signed long)o.via.i64);
176
+ #endif
177
+ break;
178
+
179
+ case MSGPACK_OBJECT_FLOAT32:
180
+ case MSGPACK_OBJECT_FLOAT64:
181
+ fprintf(out, "%f", o.via.f64);
182
+ break;
183
+
184
+ case MSGPACK_OBJECT_STR:
185
+ fprintf(out, "\"");
186
+ fwrite(o.via.str.ptr, o.via.str.size, 1, out);
187
+ fprintf(out, "\"");
188
+ break;
189
+
190
+ case MSGPACK_OBJECT_BIN:
191
+ fprintf(out, "\"");
192
+ msgpack_object_bin_print(out, o.via.bin.ptr, o.via.bin.size);
193
+ fprintf(out, "\"");
194
+ break;
195
+
196
+ case MSGPACK_OBJECT_EXT:
197
+ #if defined(PRIi8)
198
+ fprintf(out, "(ext: %" PRIi8 ")", o.via.ext.type);
199
+ #else
200
+ fprintf(out, "(ext: %d)", (int)o.via.ext.type);
201
+ #endif
202
+ fprintf(out, "\"");
203
+ msgpack_object_bin_print(out, o.via.ext.ptr, o.via.ext.size);
204
+ fprintf(out, "\"");
205
+ break;
206
+
207
+ case MSGPACK_OBJECT_ARRAY:
208
+ fprintf(out, "[");
209
+ if(o.via.array.size != 0) {
210
+ msgpack_object* p = o.via.array.ptr;
211
+ msgpack_object* const pend = o.via.array.ptr + o.via.array.size;
212
+ msgpack_object_print(out, *p);
213
+ ++p;
214
+ for(; p < pend; ++p) {
215
+ fprintf(out, ", ");
216
+ msgpack_object_print(out, *p);
217
+ }
218
+ }
219
+ fprintf(out, "]");
220
+ break;
221
+
222
+ case MSGPACK_OBJECT_MAP:
223
+ fprintf(out, "{");
224
+ if(o.via.map.size != 0) {
225
+ msgpack_object_kv* p = o.via.map.ptr;
226
+ msgpack_object_kv* const pend = o.via.map.ptr + o.via.map.size;
227
+ msgpack_object_print(out, p->key);
228
+ fprintf(out, "=>");
229
+ msgpack_object_print(out, p->val);
230
+ ++p;
231
+ for(; p < pend; ++p) {
232
+ fprintf(out, ", ");
233
+ msgpack_object_print(out, p->key);
234
+ fprintf(out, "=>");
235
+ msgpack_object_print(out, p->val);
236
+ }
237
+ }
238
+ fprintf(out, "}");
239
+ break;
240
+
241
+ default:
242
+ // FIXME
243
+ #if defined(PRIu64)
244
+ fprintf(out, "#<UNKNOWN %i %" PRIu64 ">", o.type, o.via.u64);
245
+ #else
246
+ if (o.via.u64 > ULONG_MAX)
247
+ fprintf(out, "#<UNKNOWN %i over 4294967295>", o.type);
248
+ else
249
+ fprintf(out, "#<UNKNOWN %i %lu>", o.type, (unsigned long)o.via.u64);
250
+ #endif
251
+
252
+ }
253
+ }
254
+
255
+ #endif
256
+
257
+ #define MSGPACK_CHECKED_CALL(ret, func, aux_buffer, aux_buffer_size, ...) \
258
+ ret = func(aux_buffer, aux_buffer_size, __VA_ARGS__); \
259
+ if (ret <= 0 || ret >= (int)aux_buffer_size) return 0; \
260
+ aux_buffer = aux_buffer + ret; \
261
+ aux_buffer_size = aux_buffer_size - ret \
262
+
263
+ static int msgpack_object_bin_print_buffer(char *buffer, size_t buffer_size, const char *ptr, size_t size)
264
+ {
265
+ size_t i;
266
+ char *aux_buffer = buffer;
267
+ size_t aux_buffer_size = buffer_size;
268
+ int ret;
269
+
270
+ for (i = 0; i < size; ++i) {
271
+ if (ptr[i] == '"') {
272
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\\\"");
273
+ } else if (isprint((unsigned char)ptr[i])) {
274
+ if (aux_buffer_size > 0) {
275
+ memcpy(aux_buffer, ptr + i, 1);
276
+ aux_buffer = aux_buffer + 1;
277
+ aux_buffer_size = aux_buffer_size - 1;
278
+ }
279
+ } else {
280
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\\x%02x", (unsigned char)ptr[i]);
281
+ }
282
+ }
283
+
284
+ return (int)(buffer_size - aux_buffer_size);
285
+ }
286
+
287
+ int msgpack_object_print_buffer(char *buffer, size_t buffer_size, msgpack_object o)
288
+ {
289
+ char *aux_buffer = buffer;
290
+ size_t aux_buffer_size = buffer_size;
291
+ int ret;
292
+ switch(o.type) {
293
+ case MSGPACK_OBJECT_NIL:
294
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "nil");
295
+ break;
296
+
297
+ case MSGPACK_OBJECT_BOOLEAN:
298
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, (o.via.boolean ? "true" : "false"));
299
+ break;
300
+
301
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
302
+ #if defined(PRIu64)
303
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%" PRIu64, o.via.u64);
304
+ #else
305
+ if (o.via.u64 > ULONG_MAX) {
306
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "over 4294967295");
307
+ } else {
308
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%lu", (unsigned long)o.via.u64);
309
+ }
310
+ #endif
311
+ break;
312
+
313
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
314
+ #if defined(PRIi64)
315
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%" PRIi64, o.via.i64);
316
+ #else
317
+ if (o.via.i64 > LONG_MAX) {
318
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "over +2147483647");
319
+ } else if (o.via.i64 < LONG_MIN) {
320
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "under -2147483648");
321
+ } else {
322
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%ld", (signed long)o.via.i64);
323
+ }
324
+ #endif
325
+ break;
326
+
327
+ case MSGPACK_OBJECT_FLOAT32:
328
+ case MSGPACK_OBJECT_FLOAT64:
329
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%f", o.via.f64);
330
+ break;
331
+
332
+ case MSGPACK_OBJECT_STR:
333
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
334
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "%.*s", (int)o.via.str.size, o.via.str.ptr);
335
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
336
+ break;
337
+
338
+ case MSGPACK_OBJECT_BIN:
339
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
340
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_bin_print_buffer, aux_buffer, aux_buffer_size, o.via.bin.ptr, o.via.bin.size);
341
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
342
+ break;
343
+
344
+ case MSGPACK_OBJECT_EXT:
345
+ #if defined(PRIi8)
346
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "(ext: %" PRIi8 ")", o.via.ext.type);
347
+ #else
348
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "(ext: %d)", (int)o.via.ext.type);
349
+ #endif
350
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
351
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_bin_print_buffer, aux_buffer, aux_buffer_size, o.via.ext.ptr, o.via.ext.size);
352
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "\"");
353
+ break;
354
+
355
+ case MSGPACK_OBJECT_ARRAY:
356
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "[");
357
+ if(o.via.array.size != 0) {
358
+ msgpack_object* p = o.via.array.ptr;
359
+ msgpack_object* const pend = o.via.array.ptr + o.via.array.size;
360
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, *p);
361
+ ++p;
362
+ for(; p < pend; ++p) {
363
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, ", ");
364
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, *p);
365
+ }
366
+ }
367
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "]");
368
+ break;
369
+
370
+ case MSGPACK_OBJECT_MAP:
371
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "{");
372
+ if(o.via.map.size != 0) {
373
+ msgpack_object_kv* p = o.via.map.ptr;
374
+ msgpack_object_kv* const pend = o.via.map.ptr + o.via.map.size;
375
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, p->key);
376
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "=>");
377
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, p->val);
378
+ ++p;
379
+ for(; p < pend; ++p) {
380
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, ", ");
381
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, p->key);
382
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "=>");
383
+ MSGPACK_CHECKED_CALL(ret, msgpack_object_print_buffer, aux_buffer, aux_buffer_size, p->val);
384
+ }
385
+ }
386
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "}");
387
+ break;
388
+
389
+ default:
390
+ // FIXME
391
+ #if defined(PRIu64)
392
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "#<UNKNOWN %i %" PRIu64 ">", o.type, o.via.u64);
393
+ #else
394
+ if (o.via.u64 > ULONG_MAX) {
395
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "#<UNKNOWN %i over 4294967295>", o.type);
396
+ } else {
397
+ MSGPACK_CHECKED_CALL(ret, snprintf, aux_buffer, aux_buffer_size, "#<UNKNOWN %i %lu>", o.type, (unsigned long)o.via.u64);
398
+ }
399
+ #endif
400
+ }
401
+
402
+ return (int)(buffer_size - aux_buffer_size);
403
+ }
404
+
405
+ #undef MSGPACK_CHECKED_CALL
406
+
407
+ bool msgpack_object_equal(const msgpack_object x, const msgpack_object y)
408
+ {
409
+ if(x.type != y.type) { return false; }
410
+
411
+ switch(x.type) {
412
+ case MSGPACK_OBJECT_NIL:
413
+ return true;
414
+
415
+ case MSGPACK_OBJECT_BOOLEAN:
416
+ return x.via.boolean == y.via.boolean;
417
+
418
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
419
+ return x.via.u64 == y.via.u64;
420
+
421
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
422
+ return x.via.i64 == y.via.i64;
423
+
424
+ case MSGPACK_OBJECT_FLOAT32:
425
+ case MSGPACK_OBJECT_FLOAT64:
426
+ return x.via.f64 == y.via.f64;
427
+
428
+ case MSGPACK_OBJECT_STR:
429
+ return x.via.str.size == y.via.str.size &&
430
+ memcmp(x.via.str.ptr, y.via.str.ptr, x.via.str.size) == 0;
431
+
432
+ case MSGPACK_OBJECT_BIN:
433
+ return x.via.bin.size == y.via.bin.size &&
434
+ memcmp(x.via.bin.ptr, y.via.bin.ptr, x.via.bin.size) == 0;
435
+
436
+ case MSGPACK_OBJECT_EXT:
437
+ return x.via.ext.size == y.via.ext.size &&
438
+ x.via.ext.type == y.via.ext.type &&
439
+ memcmp(x.via.ext.ptr, y.via.ext.ptr, x.via.ext.size) == 0;
440
+
441
+ case MSGPACK_OBJECT_ARRAY:
442
+ if(x.via.array.size != y.via.array.size) {
443
+ return false;
444
+ } else if(x.via.array.size == 0) {
445
+ return true;
446
+ } else {
447
+ msgpack_object* px = x.via.array.ptr;
448
+ msgpack_object* const pxend = x.via.array.ptr + x.via.array.size;
449
+ msgpack_object* py = y.via.array.ptr;
450
+ do {
451
+ if(!msgpack_object_equal(*px, *py)) {
452
+ return false;
453
+ }
454
+ ++px;
455
+ ++py;
456
+ } while(px < pxend);
457
+ return true;
458
+ }
459
+
460
+ case MSGPACK_OBJECT_MAP:
461
+ if(x.via.map.size != y.via.map.size) {
462
+ return false;
463
+ } else if(x.via.map.size == 0) {
464
+ return true;
465
+ } else {
466
+ msgpack_object_kv* px = x.via.map.ptr;
467
+ msgpack_object_kv* const pxend = x.via.map.ptr + x.via.map.size;
468
+ msgpack_object_kv* py = y.via.map.ptr;
469
+ do {
470
+ if(!msgpack_object_equal(px->key, py->key) || !msgpack_object_equal(px->val, py->val)) {
471
+ return false;
472
+ }
473
+ ++px;
474
+ ++py;
475
+ } while(px < pxend);
476
+ return true;
477
+ }
478
+
479
+ default:
480
+ return false;
481
+ }
482
+ }