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 | 18285 | for(const proto_field_info_t &f : FIELDS) | |
| 21 | 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 | 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 | 14941 | for(const proto_named_t &t : TYPES) | |
| 38 | 14751 | if(t.number == number) return t.name; | |
| 39 | 190 | return nullptr; | |
| 40 | } | ||
| 41 | 345 | proto_op_t protoOpKind(uint8_t type) { | |
| 42 | 17756 | for(const proto_named_t &t : TYPES) | |
| 43 | 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 | 126 | for(const proto_named_t &t : TYPES) | |
| 48 | 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 | 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 | 4 | if(hex[0]) return hex; | |
| 69 | 1 | uint32_t hash = 2166136261u; | |
| 70 | 67 | for(const proto_named_t &t : TYPES) hash = fnvNamed(hash, t); | |
| 71 | 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 | 8 | for(const proto_named_t &e : ERRORS) hash = fnvNamed(hash, e); | |
| 77 | 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 | 5779 | if(value == f.def) return; | |
| 84 | 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 | 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 |