src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
57 / 57
100.0%
Branches:
41 / 44
93.2%
Functions:
17 / 17
100.0%

ProtoSchema.cpp
Line Branch Exec Source
1 #include <stdio.h>
2 #include <string.h>
3 #include "ProtoSchema.h"
4
5 #define PROTO_FIELD_ROW(name, key, kind, def) {#name, key, kind, def},
6 static const proto_field_info_t FIELDS[] = { PROTO_FIELDS(PROTO_FIELD_ROW) };
7 #undef PROTO_FIELD_ROW
8 #define PROTO_TYPE_ROW(name, number, sender, op) {number, #name, sender, op},
9 static const proto_named_t TYPES[] = { PROTO_TYPES(PROTO_TYPE_ROW) };
10 #undef PROTO_TYPE_ROW
11 // Errors and feeds have no sender or op.
12 #define PROTO_NAMED_ROW(name, number) {number, #name, 0, 0},
13 static const proto_named_t ERRORS[] = { PROTO_ERRORS(PROTO_NAMED_ROW) };
14 static const proto_named_t FEEDS[] = { PROTO_FEEDS(PROTO_NAMED_ROW) };
15 #undef PROTO_NAMED_ROW
16 static_assert(sizeof(FIELDS) / sizeof(FIELDS[0]) == static_cast<size_t>(proto_field_t::count), "a field without a row");
17
18 8960 const proto_field_info_t &protoField(proto_field_t field) { return FIELDS[static_cast<uint8_t>(field)]; }
19 219 const proto_field_info_t *protoFieldByKey(const char *key) {
20
2/2
✓ Branch 0 taken 18280 times.
✓ Branch 1 taken 5 times.
18285 for(const proto_field_info_t &f : FIELDS)
21
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 18066 times.
18280 if(strcmp(f.key, key) == 0) return &f;
22 5 return nullptr;
23 }
24 217 bool protoFieldOfKey(const char *key, proto_field_t &out) {
25 217 const proto_field_info_t *f = protoFieldByKey(key);
26
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 213 times.
217 if(!f) return false;
27 213 out = static_cast<proto_field_t>(f - FIELDS);
28 213 return true;
29 }
30 203 uint8_t protoTypeCount() { return sizeof(TYPES) / sizeof(TYPES[0]); }
31 264 const proto_named_t &protoTypeAt(uint8_t index) { return TYPES[index]; }
32 10 uint8_t protoErrorCount() { return sizeof(ERRORS) / sizeof(ERRORS[0]); }
33 14 const proto_named_t &protoErrorAt(uint8_t index) { return ERRORS[index]; }
34 5 uint8_t protoFeedCount() { return sizeof(FEEDS) / sizeof(FEEDS[0]); }
35 4 const proto_named_t &protoFeedAt(uint8_t index) { return FEEDS[index]; }
36 256 const char *protoTypeName(uint8_t number) {
37
2/2
✓ Branch 0 taken 14751 times.
✓ Branch 1 taken 190 times.
14941 for(const proto_named_t &t : TYPES)
38
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 14685 times.
14751 if(t.number == number) return t.name;
39 190 return nullptr;
40 }
41 345 proto_op_t protoOpKind(uint8_t type) {
42
2/2
✓ Branch 0 taken 17565 times.
✓ Branch 1 taken 191 times.
17756 for(const proto_named_t &t : TYPES)
43
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 17411 times.
17565 if(t.number == type) return static_cast<proto_op_t>(t.op);
44 191 return proto_op_t::none;
45 }
46 5 bool protoClientMaySend(uint8_t type) {
47
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 1 time.
126 for(const proto_named_t &t : TYPES)
48
5/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
125 if(t.number == type) return t.sender == 'c' || t.sender == 'b';
49 1 return false;
50 }
51
52 373 static uint32_t fnv(uint32_t hash, const char *text) {
53
2/2
✓ Branch 0 taken 3354 times.
✓ Branch 1 taken 373 times.
3727 for(; *text; text++) {
54 3354 hash ^= (uint8_t)*text;
55 3354 hash *= 16777619u;
56 }
57 373 return hash;
58 }
59 75 static uint32_t fnvNamed(uint32_t hash, const proto_named_t &row) {
60 char num[12];
61 75 snprintf(num, sizeof(num), "%u:", row.number);
62 75 hash = fnv(hash, num);
63 75 hash = fnv(hash, row.name);
64 75 return fnv(hash, ";");
65 }
66 4 const char *protoSchemaHash() {
67 static char hex[9] = {0};
68
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if(hex[0]) return hex;
69 1 uint32_t hash = 2166136261u;
70
2/2
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 1 time.
67 for(const proto_named_t &t : TYPES) hash = fnvNamed(hash, t);
71
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 1 time.
149 for(const proto_field_info_t &f : FIELDS) {
72 char row[64];
73 148 snprintf(row, sizeof(row), "%s:%s:%c:%ld;", f.name, f.key, f.kind, (long)f.def);
74 148 hash = fnv(hash, row);
75 }
76
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
8 for(const proto_named_t &e : ERRORS) hash = fnvNamed(hash, e);
77
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
3 for(const proto_named_t &q : FEEDS) hash = fnvNamed(hash, q);
78 1 snprintf(hex, sizeof(hex), "%08lx", (unsigned long)hash);
79 1 return hex;
80 }
81
82 5779 void ProtoWriter::addInt(const proto_field_info_t &f, int64_t value) {
83
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 5657 times.
5779 if(value == f.def) return;
84
3/4
✓ Branch 0 taken 5657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4215 times.
✓ Branch 3 taken 1442 times.
5657 if(value >= INT32_MIN && value <= INT32_MAX) this->json.addElem(f.key, (int32_t)value);
85 1442 else this->json.addElem(f.key, (uint32_t)value);
86 }
87 1784 void ProtoWriter::item(int64_t value) {
88
3/4
✓ Branch 0 taken 1784 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1763 times.
✓ Branch 3 taken 21 times.
1784 if(value >= INT32_MIN && value <= INT32_MAX) this->json.addElem((int32_t)value);
89 21 else this->json.addElem((uint32_t)value);
90 1784 }
91