diff --git a/nostrdb/flatcc/builder.c b/nostrdb/flatcc/builder.c index c5155a85e..74535fb1c 100644 --- a/nostrdb/flatcc/builder.c +++ b/nostrdb/flatcc/builder.c @@ -177,7 +177,7 @@ int flatcc_builder_default_alloc(void *alloc_context, iovec_t *b, size_t request return 0; } -#define T_ptr(base, pos) ((void *)((uint8_t *)(base) + (uoffset_t)(pos))) +#define T_ptr(base, pos) ((void *)((size_t)(base) + (size_t)(pos))) #define ds_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_ds].iov_base, (pos))) #define vs_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vs].iov_base, (pos))) #define pl_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_pl].iov_base, (pos))) @@ -698,7 +698,8 @@ static inline flatcc_builder_ref_t emit_back(flatcc_builder_t *B, iov_state_t *i return ref + 1; } -static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_align, int is_nested) +/* If nested we cannot pad the end of the buffer without moving the entire buffer, so we don't. */ +static int align_buffer_end(flatcc_builder_t *B, uint16_t *align, uint16_t block_align, int is_nested) { size_t end_pad; iov_state_t iov; @@ -708,7 +709,7 @@ static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_a get_min_align(align, block_align); /* Pad end of buffer to multiple. */ if (!is_nested) { - end_pad = back_pad(B, block_align); + end_pad = back_pad(B, *align); if (end_pad) { init_iov(); push_iov(_pad, end_pad); @@ -723,13 +724,13 @@ static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_a flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, uint16_t block_align, - const void *data, size_t size, uint16_t align, int flags) + const void *data, size_t size, uint16_t align, flatcc_builder_buffer_flags_t flags) { uoffset_t size_field, pad; iov_state_t iov; - int with_size = flags & flatcc_builder_with_size; + int with_size = (flags & flatcc_builder_with_size) != 0; - if (align_to_block(B, &align, block_align, !is_top_buffer(B))) { + if (align_buffer_end(B, &align, block_align, !is_top_buffer(B))) { return 0; } pad = front_pad(B, (uoffset_t)(size + (with_size ? field_size : 0)), align); @@ -744,7 +745,7 @@ flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, const char identifier[identifier_size], uint16_t block_align, - flatcc_builder_ref_t object_ref, uint16_t align, int flags) + flatcc_builder_ref_t object_ref, uint16_t align, flatcc_builder_buffer_flags_t flags) { flatcc_builder_ref_t buffer_ref; uoffset_t header_pad, id_size = 0; @@ -754,7 +755,7 @@ flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, int is_nested = (flags & flatcc_builder_is_nested) != 0; int with_size = (flags & flatcc_builder_with_size) != 0; - if (align_to_block(B, &align, block_align, is_nested)) { + if (align_buffer_end(B, &align, block_align, is_nested)) { return 0; } set_min_align(B, align); @@ -808,7 +809,7 @@ flatcc_builder_ref_t flatcc_builder_create_struct(flatcc_builder_t *B, const voi } int flatcc_builder_start_buffer(flatcc_builder_t *B, - const char identifier[identifier_size], uint16_t block_align, int flags) + const char identifier[identifier_size], uint16_t block_align, flatcc_builder_buffer_flags_t flags) { /* * This saves the parent `min_align` in the align field since we @@ -820,7 +821,11 @@ int flatcc_builder_start_buffer(flatcc_builder_t *B, return -1; } /* B->align now has parent min_align, and child frames will save it. */ - B->min_align = 1; + /* Since we allow objects to be created before the buffer at top level, + we need to respect min_align in that case. */ + if (!is_top_buffer(B) || B->min_align == 0) { + B->min_align = 1; + } /* Save the parent block align, and set proper defaults for this buffer. */ frame(container.buffer.block_align) = B->block_align; B->block_align = block_align; @@ -845,9 +850,9 @@ int flatcc_builder_start_buffer(flatcc_builder_t *B, flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_builder_ref_t root) { flatcc_builder_ref_t buffer_ref; - int flags; + flatcc_builder_buffer_flags_t flags; - flags = B->buffer_flags & flatcc_builder_with_size; + flags = (flatcc_builder_buffer_flags_t)B->buffer_flags & flatcc_builder_with_size; flags |= is_top_buffer(B) ? 0 : flatcc_builder_is_nested; check(frame(type) == flatcc_builder_buffer, "expected buffer frame"); set_min_align(B, B->block_align); @@ -859,6 +864,8 @@ flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_build B->nest_id = frame(container.buffer.nest_id); B->identifier = frame(container.buffer.identifier); B->buffer_flags = frame(container.buffer.flags); + B->block_align = frame(container.buffer.block_align); + exit_frame(B); return buffer_ref; } @@ -1327,6 +1334,7 @@ flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B) flatcc_builder_ref_t table_ref, vt_ref; int pl_count; voffset_t *pl; + size_t tsize; check(frame(type) == flatcc_builder_table, "expected table frame"); @@ -1341,7 +1349,14 @@ flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B) * initial vtable offset field. Therefore `field_size` is added here * to the total table size in the vtable. */ - vt[1] = (voffset_t)(B->ds_offset + field_size); + tsize = (size_t)(B->ds_offset + field_size); + /* + * Tables are limited to 64K in standard FlatBuffers format due to the voffset + * 16 bit size, but we must also be able to store the table size, so the + * table payload has to be slightly less than that. + */ + check(tsize <= FLATBUFFERS_VOFFSET_MAX, "table too large"); + vt[1] = (voffset_t)tsize; FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)vt[0], (uint32_t)vt[1]); /* Find already emitted vtable, or emit a new one. */ if (!(vt_ref = flatcc_builder_create_cached_vtable(B, vt, vt_size, B->vt_hash))) { diff --git a/nostrdb/flatcc/flatcc_builder.h b/nostrdb/flatcc/flatcc_builder.h index 3871b1d07..2e84d2979 100644 --- a/nostrdb/flatcc/flatcc_builder.h +++ b/nostrdb/flatcc/flatcc_builder.h @@ -710,10 +710,13 @@ static inline void flatcc_builder_refmap_reset(flatcc_builder_t *B) } -enum flatcc_builder_buffer_flags { - flatcc_builder_is_nested = 1, - flatcc_builder_with_size = 2, -}; +typedef uint16_t flatcc_builder_buffer_flags_t; +static const flatcc_builder_buffer_flags_t flatcc_builder_is_nested = 1; +static const flatcc_builder_buffer_flags_t flatcc_builder_with_size = 2; + +/* The flag size in the API needs to match the internal size. */ +static_assert(sizeof(flatcc_builder_buffer_flags_t) == + sizeof(((flatcc_builder_t *)0)->buffer_flags), "flag size mismatch"); /** * An alternative to start buffer, start struct/table ... end buffer. @@ -776,7 +779,7 @@ enum flatcc_builder_buffer_flags { flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, const char identifier[FLATBUFFERS_IDENTIFIER_SIZE], uint16_t block_align, - flatcc_builder_ref_t ref, uint16_t align, int flags); + flatcc_builder_ref_t ref, uint16_t align, flatcc_builder_buffer_flags_t flags); /** * Creates a struct within the current buffer without using any @@ -867,7 +870,7 @@ flatcc_builder_ref_t flatcc_builder_end_struct(flatcc_builder_t *B); */ int flatcc_builder_start_buffer(flatcc_builder_t *B, const char identifier[FLATBUFFERS_IDENTIFIER_SIZE], - uint16_t block_align, int flags); + uint16_t block_align, flatcc_builder_buffer_flags_t flags); /** * The root object should be a struct or a table to conform to the @@ -923,7 +926,7 @@ flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_build */ flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, uint16_t block_align, - const void *data, size_t size, uint16_t align, int flags); + const void *data, size_t size, uint16_t align, flatcc_builder_buffer_flags_t flags); /** * Applies to the innermost open buffer. The identifier may be null or diff --git a/nostrdb/flatcc/flatcc_json_parser.h b/nostrdb/flatcc/flatcc_json_parser.h index 1d4a1f8ab..1fa13764f 100644 --- a/nostrdb/flatcc/flatcc_json_parser.h +++ b/nostrdb/flatcc/flatcc_json_parser.h @@ -22,13 +22,12 @@ extern "C" { #define PDIAGNOSTIC_IGNORE_UNUSED #include "portable/pdiagnostic_push.h" -enum flatcc_json_parser_flags { - flatcc_json_parser_f_skip_unknown = 1, - flatcc_json_parser_f_force_add = 2, - flatcc_json_parser_f_with_size = 4, - flatcc_json_parser_f_skip_array_overflow = 8, - flatcc_json_parser_f_reject_array_underflow = 16 -}; +typedef uint32_t flatcc_json_parser_flags_t; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_skip_unknown = 1; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_force_add = 2; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_with_size = 4; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_skip_array_overflow = 8; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_reject_array_underflow = 16; #define FLATCC_JSON_PARSE_ERROR_MAP(XX) \ XX(ok, "ok") \ @@ -92,7 +91,7 @@ typedef struct flatcc_json_parser_ctx flatcc_json_parser_t; struct flatcc_json_parser_ctx { flatcc_builder_t *ctx; const char *line_start; - int flags; + flatcc_json_parser_flags_t flags; #if FLATCC_JSON_PARSE_ALLOW_UNQUOTED int unquoted; #endif @@ -111,7 +110,7 @@ static inline int flatcc_json_parser_get_error(flatcc_json_parser_t *ctx) return ctx->error; } -static inline void flatcc_json_parser_init(flatcc_json_parser_t *ctx, flatcc_builder_t *B, const char *buf, const char *end, int flags) +static inline void flatcc_json_parser_init(flatcc_json_parser_t *ctx, flatcc_builder_t *B, const char *buf, const char *end, flatcc_json_parser_flags_t flags) { memset(ctx, 0, sizeof(*ctx)); ctx->ctx = B; @@ -237,30 +236,45 @@ static inline uint64_t flatcc_json_parser_symbol_part_ext(const char *buf, const { uint64_t w = 0; size_t n = (size_t)(end - buf); + const uint8_t *ubuf = (const uint8_t*)buf; if (n > 8) { n = 8; } /* This can bloat inlining for a rarely executed case. */ #if 1 - /* Fall through comments needed to silence gcc 7 warnings. */ switch (n) { - case 8: w |= ((uint64_t)buf[7]) << (0 * 8); - fallthrough; - case 7: w |= ((uint64_t)buf[6]) << (1 * 8); - fallthrough; - case 6: w |= ((uint64_t)buf[5]) << (2 * 8); - fallthrough; - case 5: w |= ((uint64_t)buf[4]) << (3 * 8); - fallthrough; - case 4: w |= ((uint64_t)buf[3]) << (4 * 8); - fallthrough; - case 3: w |= ((uint64_t)buf[2]) << (5 * 8); - fallthrough; - case 2: w |= ((uint64_t)buf[1]) << (6 * 8); - fallthrough; - case 1: w |= ((uint64_t)buf[0]) << (7 * 8); - fallthrough; + case 8: + w |= ((uint64_t)ubuf[7]) << (0 * 8); + goto lbl_n_7; + case 7: +lbl_n_7: + w |= ((uint64_t)ubuf[6]) << (1 * 8); + goto lbl_n_6; + case 6: +lbl_n_6: + w |= ((uint64_t)ubuf[5]) << (2 * 8); + goto lbl_n_5; + case 5: +lbl_n_5: + w |= ((uint64_t)ubuf[4]) << (3 * 8); + goto lbl_n_4; + case 4: +lbl_n_4: + w |= ((uint64_t)ubuf[3]) << (4 * 8); + goto lbl_n_3; + case 3: +lbl_n_3: + w |= ((uint64_t)ubuf[2]) << (5 * 8); + goto lbl_n_2; + case 2: +lbl_n_2: + w |= ((uint64_t)ubuf[1]) << (6 * 8); + goto lbl_n_1; + case 1: +lbl_n_1: + w |= ((uint64_t)ubuf[0]) << (7 * 8); + break; case 0: break; } @@ -872,10 +886,10 @@ const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx, * `buf`, `bufsiz` may be larger than the parsed json if trailing * space or zeroes are expected, but they must represent a valid memory buffer. * `fid` must be null, or a valid file identifier. - * `flags` default to 0. See also `flatcc_json_parser_flags`. + * `flags` default to 0. See also `flatcc_json_parser_f_` constants. */ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser); /* @@ -883,7 +897,7 @@ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t * * root. */ int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_struct_f *parser); #include "portable/pdiagnostic_pop.h" diff --git a/nostrdb/flatcc/flatcc_json_printer.h b/nostrdb/flatcc/flatcc_json_printer.h index 612a7ada5..4fb2a37af 100644 --- a/nostrdb/flatcc/flatcc_json_printer.h +++ b/nostrdb/flatcc/flatcc_json_printer.h @@ -243,14 +243,13 @@ static inline void flatcc_json_printer_set_nonstrict(flatcc_json_printer_t *ctx) flatcc_json_printer_set_noenum(ctx, 0); } -enum flatcc_json_printer_flags { - flatcc_json_printer_f_unquote = 1, - flatcc_json_printer_f_noenum = 2, - flatcc_json_printer_f_skip_default = 4, - flatcc_json_printer_f_force_default = 8, - flatcc_json_printer_f_pretty = 16, - flatcc_json_printer_f_nonstrict = 32, -}; +typedef uint32_t flatcc_json_printer_flags_t; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_unquote = 1; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_noenum = 2; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_skip_default = 4; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_force_default = 8; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_pretty = 16; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_nonstrict = 32; /* * May be called instead of setting operational modes individually. @@ -268,7 +267,7 @@ enum flatcc_json_printer_flags { * `pretty` flag sets indentation to 2. * `nonstrict` implies: `noenum`, `unquote`, `pretty`. */ -static inline void flatcc_json_printer_set_flags(flatcc_json_printer_t *ctx, int flags) +static inline void flatcc_json_printer_set_flags(flatcc_json_printer_t *ctx, flatcc_json_printer_flags_t flags) { ctx->unquote = !!(flags & flatcc_json_printer_f_unquote); ctx->noenum = !!(flags & flatcc_json_printer_f_noenum); diff --git a/nostrdb/flatcc/flatcc_version.h b/nostrdb/flatcc/flatcc_version.h index 0e677d1c1..78bc9c8d3 100644 --- a/nostrdb/flatcc/flatcc_version.h +++ b/nostrdb/flatcc/flatcc_version.h @@ -2,12 +2,12 @@ extern "C" { #endif -#define FLATCC_VERSION_TEXT "0.6.1" +#define FLATCC_VERSION_TEXT "0.6.2" #define FLATCC_VERSION_MAJOR 0 #define FLATCC_VERSION_MINOR 6 -#define FLATCC_VERSION_PATCH 1 +#define FLATCC_VERSION_PATCH 2 /* 1 or 0 */ -#define FLATCC_VERSION_RELEASED 1 +#define FLATCC_VERSION_RELEASED 0 #ifdef __cplusplus } diff --git a/nostrdb/flatcc/json_parser.c b/nostrdb/flatcc/json_parser.c index 06f778da3..1c0128fd2 100644 --- a/nostrdb/flatcc/json_parser.c +++ b/nostrdb/flatcc/json_parser.c @@ -141,11 +141,10 @@ const char *flatcc_json_parser_space_ext(flatcc_json_parser_t *ctx, const char * ++buf; } while (buf != end && *buf <= 0x20) { - /* Fall through comments needed to silence gcc 7 warnings. */ switch (*buf) { case 0x0d: buf += (end - buf > 1 && buf[1] == 0x0a); /* Consume following LF or treating CR as LF. */ - fallthrough; + ++ctx->line; ctx->line_start = ++buf; continue; case 0x0a: ++ctx->line; ctx->line_start = ++buf; continue; case 0x09: ++buf; continue; case 0x20: goto again; /* Don't consume here, sync with power of 2 spaces. */ @@ -880,7 +879,7 @@ const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx, if (ctx->flags & flatcc_json_parser_f_reject_array_underflow) { return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_underflow); } - memset(s, 0, n - k); + memset(s, 0, n); } return flatcc_json_parser_string_end(ctx, buf, end); } @@ -1258,12 +1257,12 @@ const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx, } int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser) { flatcc_json_parser_t _ctx; flatcc_builder_ref_t root; - int builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; + flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; ctx = ctx ? ctx : &_ctx; flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); @@ -1278,12 +1277,12 @@ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t * } int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser) { flatcc_json_parser_t _ctx; flatcc_builder_ref_t root; - int builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; + flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; ctx = ctx ? ctx : &_ctx; flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); diff --git a/nostrdb/flatcc/portable/paligned_alloc.h b/nostrdb/flatcc/portable/paligned_alloc.h index 3dcf4efcd..70b00b9ea 100644 --- a/nostrdb/flatcc/portable/paligned_alloc.h +++ b/nostrdb/flatcc/portable/paligned_alloc.h @@ -61,6 +61,8 @@ extern "C" { #define PORTABLE_C11_ALIGNED_ALLOC 0 #elif defined (__clang__) #define PORTABLE_C11_ALIGNED_ALLOC 0 +#elif defined (__APPLE__) +#define PORTABLE_C11_ALIGNED_ALLOC 0 #elif defined(__IBMC__) #define PORTABLE_C11_ALIGNED_ALLOC 0 #elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) diff --git a/nostrdb/flatcc/portable/pattributes.h b/nostrdb/flatcc/portable/pattributes.h index 30b3b23d3..9240fa319 100644 --- a/nostrdb/flatcc/portable/pattributes.h +++ b/nostrdb/flatcc/portable/pattributes.h @@ -40,7 +40,7 @@ extern "C" { #endif #ifndef PORTABLE_EXPOSE_ATTRIBUTES -#define PORTABLE_EXPOSE_ATTRIBUTES 1 +#define PORTABLE_EXPOSE_ATTRIBUTES 0 #endif #ifdef __has_c_attribute diff --git a/nostrdb/flatcc/portable/pparsefp.h b/nostrdb/flatcc/portable/pparsefp.h index 1d2b9da26..7fa1c247d 100644 --- a/nostrdb/flatcc/portable/pparsefp.h +++ b/nostrdb/flatcc/portable/pparsefp.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include /* memcpy */ + /* * Parses a float or double number and returns the length parsed if * successful. The length argument is of limited value due to dependency @@ -34,7 +36,7 @@ extern "C" { * Other compilers such as xlc may require linking with -lm which may not * be convienent so a default isinf is provided. If isinf is available * and there is a noticable performance issue, define - * `PORTABLE_USE_ISINF`. + * `PORTABLE_USE_ISINF`. This flag also affects isnan. */ #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(PORTABLE_USE_ISINF) #include @@ -44,12 +46,13 @@ extern "C" { #define isinf(x) (!_finite(x)) #endif /* - * clang-5 through clang-8 but not clang-9 issues incorrect precision + * clang-3 through clang-8 but not clang-9 issues incorrect precision * loss warning with -Wconversion flag when cast is absent. */ #if defined(__clang__) -#if __clang_major__ >= 5 && __clang_major__ <= 8 +#if __clang_major__ >= 3 && __clang_major__ <= 8 #define parse_double_isinf(x) isinf((float)x) +#define parse_double_isnan(x) isnan((float)x) #endif #endif #if !defined(parse_double_isinf) @@ -64,19 +67,29 @@ extern "C" { #endif /* Avoid linking with libmath but depends on float/double being IEEE754 */ -static inline int parse_double_isinf(double x) +static inline int parse_double_isinf(const double x) { - union { uint64_t u64; double f64; } v; - v.f64 = x; - return (v.u64 & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL; + uint64_t u64x; + + memcpy(&u64x, &x, sizeof(u64x)); + return (u64x & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL; } static inline int parse_float_isinf(float x) { - union { uint32_t u32; float f32; } v; - v.f32 = x; - return (v.u32 & 0x7fffffff) == 0x7f800000; + uint32_t u32x; + + memcpy(&u32x, &x, sizeof(u32x)); + return (u32x & 0x7fffffff) == 0x7f800000; } + +#endif + +#if !defined(parse_double_isnan) +#define parse_double_isnan isnan +#endif +#if !defined(parse_float_isnan) +#define parse_float_isnan isnan #endif /* Returns 0 when in range, 1 on overflow, and -1 on underflow. */ @@ -131,6 +144,79 @@ static inline const char *parse_float(const char *buf, size_t len, float *result return end; } +/* Inspired by https://bitbashing.io/comparing-floats.html */ + +/* Return signed ULP distance or INT64_MAX if any value is nan. */ +static inline int64_t parse_double_compare(const double x, const double y) +{ + int64_t i64x, i64y; + + if (x == y) return 0; + if (parse_double_isnan(x)) return INT64_MAX; + if (parse_double_isnan(y)) return INT64_MAX; + memcpy(&i64x, &x, sizeof(i64x)); + memcpy(&i64y, &y, sizeof(i64y)); + if ((i64x < 0) != (i64y < 0)) return INT64_MAX; + return i64x - i64y; +} + +/* Same as double, but INT32_MAX if nan. */ +static inline int32_t parse_float_compare(const float x, const float y) +{ + int32_t i32x, i32y; + + if (x == y) return 0; + if (parse_float_isnan(x)) return INT32_MAX; + if (parse_float_isnan(y)) return INT32_MAX; + memcpy(&i32x, &x, sizeof(i32x)); + memcpy(&i32y, &y, sizeof(i32y)); + if ((i32x < 0) != (i32y < 0)) return INT32_MAX; + return i32x - i32y; +} + +/* + * Returns the absolute distance in floating point ULP (representational bit difference). + * Uses signed return value so that INT64_MAX and INT32_MAX indicates NaN similar to + * the compare function. + */ +static inline int64_t parse_double_dist(const double x, const double y) +{ + uint64_t m64; + int64_t i64; + + i64 = parse_double_compare(x, y); + /* Absolute integer value of compare. */ + m64 = (uint64_t)-(i64 < 0); + return (int64_t)(((uint64_t)i64 + m64) ^ m64); +} + +/* Same as double, but INT32_MAX if NaN. */ +static inline int32_t parse_float_dist(const float x, const float y) +{ + uint32_t m32; + int32_t i32; + + i32 = parse_float_compare(x, y); + /* Absolute integer value of compare. */ + m32 = (uint32_t)-(i32 < 0); + return (int32_t)(((uint32_t)i32 + m32) ^ m32); +} + +/* + * Returns 1 if no value is NaN, and the difference is at most one ULP (1 bit), and the + * sign is the same, and 0 otherwise. + */ +static inline int parse_double_is_equal(const double x, const double y) +{ + return parse_double_dist(x, y) >> 1 == 0; +} + +/* Same as double, but at lower precision. */ +static inline int parse_float_is_equal(const float x, const float y) +{ + return parse_float_dist(x, y) >> 1 == 0; +} + #include "pdiagnostic_pop.h" #ifdef __cplusplus diff --git a/nostrdb/flatcc/reflection/flatbuffers_common_reader.h b/nostrdb/flatcc/reflection/flatbuffers_common_reader.h index 6379c5864..c57530868 100644 --- a/nostrdb/flatcc/reflection/flatbuffers_common_reader.h +++ b/nostrdb/flatcc/reflection/flatbuffers_common_reader.h @@ -64,7 +64,6 @@ static inline TK ## _option_t N ## _ ## NK ## _option(N ## _table_t t__tmp)\ #define __flatbuffers_offset_field(T, ID, t, r, adjust)\ {\ flatbuffers_uoffset_t *elem__tmp;\ - printf("got here\n"); __flatbuffers_read_vt(ID, offset__tmp, t)\ if (offset__tmp) {\ elem__tmp = (flatbuffers_uoffset_t *)((uint8_t *)(t) + offset__tmp);\