lib: json: Efficiently pack field name, offset, alignment, type
This trades a little bit over 40 bytes (on x86) of text for a lot of savings in rodata. This is accomplished by using bitfields to pack the field name length, offset, alignment, and the type tag into a single 32-bit unsigned integer instead of scattering this information into four different integers. Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
This commit is contained in:
parent
1799cfdb2f
commit
0ec79d6853
|
@ -27,6 +27,11 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
enum json_tokens {
|
||||
/* Before changing this enum, ensure that its maximum
|
||||
* value is still within 7 bits. See comment next to the
|
||||
* declaration of `type` in struct json_obj_descr.
|
||||
*/
|
||||
|
||||
JSON_TOK_NONE = '_',
|
||||
JSON_TOK_OBJECT_START = '{',
|
||||
JSON_TOK_OBJECT_END = '}',
|
||||
|
@ -45,15 +50,28 @@ enum json_tokens {
|
|||
|
||||
struct json_obj_descr {
|
||||
const char *field_name;
|
||||
size_t field_name_len;
|
||||
size_t offset;
|
||||
size_t alignment;
|
||||
|
||||
/* Valid values here: JSON_TOK_STRING, JSON_TOK_NUMBER,
|
||||
* JSON_TOK_TRUE, JSON_TOK_FALSE, JSON_TOK_OBJECT_START,
|
||||
* JSON_TOK_LIST_START. (All others ignored.)
|
||||
/* Alignment can never be 0 or more than 4. The macros to create a
|
||||
* struct json_obj_descr will subtract 1 from the result of
|
||||
* __alignof__() calls in order to keep this value in the 0-3 range
|
||||
* and thus use only 2 bits. 1 is added back when rounding it up to
|
||||
* calculate the struct size while parsing an array or object.
|
||||
*/
|
||||
enum json_tokens type;
|
||||
u32_t alignment : 2;
|
||||
|
||||
/* 127 characters is more than enough for a field name. */
|
||||
u32_t field_name_len : 7;
|
||||
|
||||
/* Valid values here (enum json_tokens): JSON_TOK_STRING,
|
||||
* JSON_TOK_NUMBER, JSON_TOK_TRUE, JSON_TOK_FALSE,
|
||||
* JSON_TOK_OBJECT_START, JSON_TOK_LIST_START. (All others
|
||||
* ignored.) Maximum value is '}' (125), so this has to be 7 bits
|
||||
* long.
|
||||
*/
|
||||
u32_t type : 7;
|
||||
|
||||
/* 65535 bytes is more than enough for many JSON payloads. */
|
||||
u32_t offset : 16;
|
||||
|
||||
union {
|
||||
struct {
|
||||
|
@ -110,7 +128,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (#field_name_), \
|
||||
.field_name_len = sizeof(#field_name_) - 1, \
|
||||
.offset = offsetof(struct_, field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = type_, \
|
||||
}
|
||||
|
||||
|
@ -144,7 +162,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (#field_name_), \
|
||||
.field_name_len = (sizeof(#field_name_) - 1), \
|
||||
.offset = offsetof(struct_, field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_OBJECT_START, \
|
||||
.object = { \
|
||||
.sub_descr = sub_descr_, \
|
||||
|
@ -183,13 +201,13 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (#field_name_), \
|
||||
.field_name_len = sizeof(#field_name_) - 1, \
|
||||
.offset = offsetof(struct_, field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_LIST_START, \
|
||||
.array = { \
|
||||
.element_descr = &(struct json_obj_descr) { \
|
||||
.type = elem_type_, \
|
||||
.offset = offsetof(struct_, len_field_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
}, \
|
||||
.n_elements = (max_len_), \
|
||||
}, \
|
||||
|
@ -240,7 +258,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (#field_name_), \
|
||||
.field_name_len = sizeof(#field_name_) - 1, \
|
||||
.offset = offsetof(struct_, field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_LIST_START, \
|
||||
.array = { \
|
||||
.element_descr = &(struct json_obj_descr) { \
|
||||
|
@ -250,7 +268,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.sub_descr_len = elem_descr_len_, \
|
||||
}, \
|
||||
.offset = offsetof(struct_, len_field_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
}, \
|
||||
.n_elements = (max_len_), \
|
||||
}, \
|
||||
|
@ -279,7 +297,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (json_field_name_), \
|
||||
.field_name_len = sizeof(json_field_name_) - 1, \
|
||||
.offset = offsetof(struct_, struct_field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = type_, \
|
||||
}
|
||||
|
||||
|
@ -305,7 +323,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (json_field_name_), \
|
||||
.field_name_len = (sizeof(json_field_name_) - 1), \
|
||||
.offset = offsetof(struct_, struct_field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_OBJECT_START, \
|
||||
.object = { \
|
||||
.sub_descr = sub_descr_, \
|
||||
|
@ -341,13 +359,13 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = (json_field_name_), \
|
||||
.field_name_len = sizeof(json_field_name_) - 1, \
|
||||
.offset = offsetof(struct_, struct_field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_LIST_START, \
|
||||
.array = { \
|
||||
.element_descr = &(struct json_obj_descr) { \
|
||||
.type = elem_type_, \
|
||||
.offset = offsetof(struct_, len_field_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
}, \
|
||||
.n_elements = (max_len_), \
|
||||
}, \
|
||||
|
@ -407,7 +425,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.field_name = json_field_name_, \
|
||||
.field_name_len = sizeof(json_field_name_) - 1, \
|
||||
.offset = offsetof(struct_, struct_field_name_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
.type = JSON_TOK_LIST_START, \
|
||||
.element_descr = &(struct json_obj_descr) { \
|
||||
.type = JSON_TOK_OBJECT_START, \
|
||||
|
@ -416,7 +434,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
|
|||
.sub_descr_len = elem_descr_len_, \
|
||||
}, \
|
||||
.offset = offsetof(struct_, len_field_), \
|
||||
.alignment = __alignof__(struct_), \
|
||||
.alignment = __alignof__(struct_) - 1, \
|
||||
}, \
|
||||
.n_elements = (max_len_), \
|
||||
}
|
||||
|
|
|
@ -476,8 +476,6 @@ static int decode_value(struct json_obj *obj,
|
|||
|
||||
static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
|
||||
{
|
||||
assert(descr->alignment);
|
||||
|
||||
switch (descr->type) {
|
||||
case JSON_TOK_NUMBER:
|
||||
return sizeof(s32_t);
|
||||
|
@ -495,7 +493,7 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr)
|
|||
for (i = 0; i < descr->object.sub_descr_len; i++) {
|
||||
ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]);
|
||||
|
||||
total += ROUND_UP(s, descr->alignment);
|
||||
total += ROUND_UP(s, descr->alignment + 1);
|
||||
}
|
||||
|
||||
return total;
|
||||
|
|
Loading…
Reference in a new issue