From fdbfcbc3a6339968ece0a93922f1fca357150087 Mon Sep 17 00:00:00 2001 From: silverweed Date: Thu, 12 Sep 2024 11:56:12 +0200 Subject: [PATCH] add display-grouped to hover --- src/hover.cpp | 210 +++++++++++++++++++++++++++++++++++-------------- src/render.cpp | 5 +- 2 files changed, 156 insertions(+), 59 deletions(-) diff --git a/src/hover.cpp b/src/hover.cpp index d673837..3cb85ab 100644 --- a/src/hover.cpp +++ b/src/hover.cpp @@ -14,14 +14,14 @@ template <> u64 bswap_if_needed(u64 x) { return bswap(x); } template String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val) { + static_assert(!std::is_same_v); val = bswap_if_needed(val); return push_str8_node_child(arena, prev, fmt, val); } -template <> -String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, String8 val) +String8_Node *hover_display_val_str8(Arena *arena, String8_Node *prev, const char *fmt, String8 val) { - return push_str8_node_child(arena, prev, fmt, val.c()); + return push_str8_node_child(arena, prev, fmt, val.str ? val.c() : ""); } template @@ -86,6 +86,16 @@ String8_Node *display_val_rootzip(Arena *arena, String8_Node *prev, const char * template using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T); +template +internal +T read_buf(const void *buf, u64 &off) +{ + T val; + memcpy(&val, (u8 *)buf + off, sizeof(val)); + off += sizeof(val); + return val; +} + // Functor used by get_section_hover_info to describe the structure of a section and print data about it. struct Sec_Hover_Fn { u64 start; @@ -94,6 +104,7 @@ struct Sec_Hover_Fn { Arena *arena; Sec_Hover_Info &info; u64 &cur_field_off; + b8 display_grouped; template b8 titled_section(const char *title, F &&fn) const @@ -110,6 +121,31 @@ struct Sec_Hover_Fn { return ok; } + template + T add_to_desc(const char *fmt, Display_Fn display_val = hover_display_val_le) const + { + static_assert(!std::is_same_v, "use add_to_desc_str8 instead."); + T val = read_buf(data + start, cur_field_off); + display_val(arena, info.desc, fmt, val); + return val; + } + + template + String8 add_to_desc_str8(const char *fmt, Display_Fn display_val = hover_display_val_str8) const + { + TStrSize str_size = read_buf(data + start, cur_field_off); + u8 *buf = nullptr; + if (str_size > 0) { + buf = arena_push_array_nozero(arena, str_size + 1); + memcpy(buf, data + start + cur_field_off, str_size); + buf[str_size] = 0; + cur_field_off += str_size; + } + String8 s = { buf, str_size }; + display_val(arena, info.desc, fmt, s); + return s; + } + template b8 field(const char *desc_fmt, Display_Fn display_val) const { @@ -117,9 +153,7 @@ struct Sec_Hover_Fn { u64 field_len = sizeof(T); if (roff < cur_field_off + field_len) { info.rng = { start + cur_field_off, field_len }; - T val; - memcpy(&val, data + info.rng.start, info.rng.len); - display_val(arena, info.desc, desc_fmt, val); + add_to_desc(desc_fmt, display_val); return true; } cur_field_off += field_len; @@ -139,14 +173,11 @@ struct Sec_Hover_Fn { } template - b8 field_str8(const char *desc_fmt, Display_Fn display_val = hover_display_val_be) const + b8 field_str8(const char *desc_fmt, Display_Fn display_val = hover_display_val_str8) const { // String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple). TStrSize str_size; memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize)); - // TEMP DEBUG - if (str_size > 1000) - return false; if (roff < cur_field_off + sizeof(TStrSize) + str_size) { info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size }; u8 *buf = arena_push_array_nozero(arena, str_size + 1); @@ -279,61 +310,124 @@ struct Sec_Hover_Fn { static const char *const field_struct_names[] = { "Leaf", "Collection", "Record", "Variant", "Unsplit" }; - return titled_section("Field", [this] { - u64 flags_off = start + cur_field_off + 22; - u16 flags; - memcpy(&flags, data + flags_off, sizeof(flags)); - b8 ok = field_le("Size: %" PRIi64) - || field_le("Field version: %u") - || field_le("Type version: %u") - || field_le("On-disk parent id: %u") - || field("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { + + if (display_grouped) { + i64 size; + memcpy(&size, data + start + cur_field_off, sizeof(size)); + u64 field_desc_len = (u64)std::abs(size); + if (roff < cur_field_off + field_desc_len) { + return titled_section("Field", [this, field_desc_len] { + info.rng = { start + cur_field_off, (u64)field_desc_len }; + add_to_desc("Size: %" PRIi64); + add_to_desc("Field version: %u"); + add_to_desc("Type version: %u"); + add_to_desc("On-disk parent id: %u"); + add_to_desc("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type]; return push_str8_node_child(arena, prev, fmt, name); - }) - || field_le("Flags: 0b%b") - ; - if (ok) - return ok; + }); + u16 flags = add_to_desc("Flags: 0b%b"); - if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le("N Repetitions: %" PRIu64)) - return true; - if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le("On disk proj.src id: %u")) - return true; - if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le("Checksum: %u")) - return true; + if (flags & RNTupleSerializer::kFlagRepetitiveField) + add_to_desc("N Repetitions: %" PRIu64); + if (flags & RNTupleSerializer::kFlagProjectedField) + add_to_desc("On disk proj.src id: %u"); + if (flags & RNTupleSerializer::kFlagHasTypeChecksum) + add_to_desc("Checksum: %u"); - return field_str8("Name: %s") - || field_str8("Type Name: %s") - || field_str8("Type Alias: %s") - || field_str8("Description: %s") - ; - }); + add_to_desc_str8("Name: %s"); + add_to_desc_str8("Type Name: %s"); + add_to_desc_str8("Type Alias: %s"); + add_to_desc_str8("Description: %s"); + + return true; + }); + } + cur_field_off += field_desc_len; + return false; + } else { + return titled_section("Field", [this] { + u64 flags_off = start + cur_field_off + 22; + u16 flags; + memcpy(&flags, data + flags_off, sizeof(flags)); + b8 ok = field_le("Size: %" PRIi64) + || field_le("Field version: %u") + || field_le("Type version: %u") + || field_le("On-disk parent id: %u") + || field("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { + const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type]; + return push_str8_node_child(arena, prev, fmt, name); + }) + || field_le("Flags: 0b%b") + ; + if (ok) + return ok; + + if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le("N Repetitions: %" PRIu64)) + return true; + if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le("On disk proj.src id: %u")) + return true; + if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le("Checksum: %u")) + return true; + + return field_str8("Name: %s") + || field_str8("Type Name: %s") + || field_str8("Type Alias: %s") + || field_str8("Description: %s") + ; + }); + } } b8 column_desc() const { - return titled_section("Column", [this] { - u64 flags_off = start + cur_field_off + 16; - u16 flags; - memcpy(&flags, data + flags_off, sizeof(flags)); - b8 ok = field_le("Size: %" PRIi64) - || field_le("Column Type: 0x%X") // TODO: prettify name - || field_le("Bits on storage: %u") - || field_le("Field ID: %u") - || field_le("Flags: 0b%b") - || field_le("Representation idx: %u") - ; - if (ok) - return ok; - - if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le("First element: %" PRIu64)) - return true; - if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le("Value Min: %f") || field_le("Value Max: %f"))) - return true; - + if (display_grouped) { + i64 size; + memcpy(&size, data + start + cur_field_off, sizeof(size)); + u64 col_desc_len = (u64)std::abs(size); + if (roff < cur_field_off + col_desc_len) { + return titled_section("Column", [this, col_desc_len] { + info.rng = { start + cur_field_off, col_desc_len }; + add_to_desc("Size: %" PRIi64 " B"); + add_to_desc("Column type: %u"); // TODO: human-readable type + add_to_desc("Bits on storage: %u"); + add_to_desc("Field ID: %u"); + u16 flags = add_to_desc("Flags: 0b%b"); + add_to_desc("Representation idx: %u"); + if (flags & RNTupleSerializer::kFlagDeferredColumn) + add_to_desc("First element: %" PRIu64); + // if (flags & RNTupleSerializer::kFlagHasValueRange) { + // add_to_desc("Value Min: %f"); + // add_to_desc("Value Max: %f"); + // } + return true; + }); + } + cur_field_off += col_desc_len; return false; - }); + } else { + return titled_section("Column", [this] { + u64 flags_off = start + cur_field_off + 16; + u16 flags; + memcpy(&flags, data + flags_off, sizeof(flags)); + b8 ok = field_le("Size: %" PRIi64) + || field_le("Column Type: 0x%X") // TODO: prettify name + || field_le("Bits on storage: %u") + || field_le("Field ID: %u") + || field_le("Flags: 0b%b") + || field_le("Representation idx: %u") + ; + if (ok) + return ok; + + if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le("First element: %" PRIu64)) + return true; + // if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le("Value Min: %f") || field_le("Value Max: %f"))) + // return true; + + return false; + }); + } } b8 schema_description() const @@ -369,7 +463,7 @@ struct Sec_Hover_Fn { // `off` is the absolute offset into `data`. internal -Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data) +Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, const u8 *data, b8 display_grouped) { Sec_Hover_Info info {}; @@ -393,7 +487,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co u64 start = section.range.start - section.pre_size; u64 roff = off - start; // offset relative to `section` u64 cur_field_off = 0; - Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off }; + Sec_Hover_Fn hover { start, roff, data, arena, info, cur_field_off, display_grouped }; switch (section.id) { case Sec_RNTuple_Anchor: { diff --git a/src/render.cpp b/src/render.cpp index fce40bb..97fa745 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -387,7 +387,10 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) if (hovered_off) { Section hovered_section = find_section(app, hovered_off - 1); - Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, app.inspected_file.mem); + b8 hover_display_grouped = !(app.user_input.key_state[KEY_ALT] & KEY_STATE_IS_DOWN); + Sec_Hover_Info hover_info = get_section_hover_info(scratch.arena, hovered_section, hovered_off - 1, + app.inspected_file.mem, hover_display_grouped); + ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "(Hint: press Alt for single-field hover information)"); imgui_render_string_tree(scratch.arena, hover_info.desc->head); app.viewer.hovered_range = hover_info.rng; } else {