add display-grouped to hover

This commit is contained in:
silverweed 2024-09-12 11:56:12 +02:00
parent 7385210e66
commit fdbfcbc3a6
2 changed files with 156 additions and 59 deletions

View file

@ -14,14 +14,14 @@ template <> u64 bswap_if_needed(u64 x) { return bswap(x); }
template <typename T> template <typename T>
String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val) String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val)
{ {
static_assert(!std::is_same_v<T, String8>);
val = bswap_if_needed(val); val = bswap_if_needed(val);
return push_str8_node_child(arena, prev, fmt, val); return push_str8_node_child(arena, prev, fmt, val);
} }
template <> String8_Node *hover_display_val_str8(Arena *arena, String8_Node *prev, const char *fmt, String8 val)
String8_Node *hover_display_val_be(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 <typename T> template <typename T>
@ -86,6 +86,16 @@ String8_Node *display_val_rootzip(Arena *arena, String8_Node *prev, const char *
template <typename T> template <typename T>
using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T); using Display_Fn = String8_Node *(*)(Arena *, String8_Node *, const char *, T);
template <typename T>
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. // Functor used by get_section_hover_info to describe the structure of a section and print data about it.
struct Sec_Hover_Fn { struct Sec_Hover_Fn {
u64 start; u64 start;
@ -94,6 +104,7 @@ struct Sec_Hover_Fn {
Arena *arena; Arena *arena;
Sec_Hover_Info &info; Sec_Hover_Info &info;
u64 &cur_field_off; u64 &cur_field_off;
b8 display_grouped;
template <typename F> template <typename F>
b8 titled_section(const char *title, F &&fn) const b8 titled_section(const char *title, F &&fn) const
@ -110,6 +121,31 @@ struct Sec_Hover_Fn {
return ok; return ok;
} }
template <typename T>
T add_to_desc(const char *fmt, Display_Fn<T> display_val = hover_display_val_le<T>) const
{
static_assert(!std::is_same_v<T, String8>, "use add_to_desc_str8 instead.");
T val = read_buf<T>(data + start, cur_field_off);
display_val(arena, info.desc, fmt, val);
return val;
}
template <typename TStrSize>
String8 add_to_desc_str8(const char *fmt, Display_Fn<String8> display_val = hover_display_val_str8) const
{
TStrSize str_size = read_buf<TStrSize>(data + start, cur_field_off);
u8 *buf = nullptr;
if (str_size > 0) {
buf = arena_push_array_nozero<u8>(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 <typename T> template <typename T>
b8 field(const char *desc_fmt, Display_Fn<T> display_val) const b8 field(const char *desc_fmt, Display_Fn<T> display_val) const
{ {
@ -117,9 +153,7 @@ struct Sec_Hover_Fn {
u64 field_len = sizeof(T); u64 field_len = sizeof(T);
if (roff < cur_field_off + field_len) { if (roff < cur_field_off + field_len) {
info.rng = { start + cur_field_off, field_len }; info.rng = { start + cur_field_off, field_len };
T val; add_to_desc<T>(desc_fmt, display_val);
memcpy(&val, data + info.rng.start, info.rng.len);
display_val(arena, info.desc, desc_fmt, val);
return true; return true;
} }
cur_field_off += field_len; cur_field_off += field_len;
@ -139,14 +173,11 @@ struct Sec_Hover_Fn {
} }
template <typename TStrSize> template <typename TStrSize>
b8 field_str8(const char *desc_fmt, Display_Fn<String8> display_val = hover_display_val_be<String8>) const b8 field_str8(const char *desc_fmt, Display_Fn<String8> 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). // String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple).
TStrSize str_size; TStrSize str_size;
memcpy(&str_size, data + start + cur_field_off, sizeof(TStrSize)); 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) { if (roff < cur_field_off + sizeof(TStrSize) + str_size) {
info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size }; info.rng = { start + cur_field_off, sizeof(TStrSize) + (u64)str_size };
u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1); u8 *buf = arena_push_array_nozero<u8>(arena, str_size + 1);
@ -279,61 +310,124 @@ struct Sec_Hover_Fn {
static const char *const field_struct_names[] = { static const char *const field_struct_names[] = {
"Leaf", "Collection", "Record", "Variant", "Unsplit" "Leaf", "Collection", "Record", "Variant", "Unsplit"
}; };
return titled_section("Field", [this] {
u64 flags_off = start + cur_field_off + 22; if (display_grouped) {
u16 flags; i64 size;
memcpy(&flags, data + flags_off, sizeof(flags)); memcpy(&size, data + start + cur_field_off, sizeof(size));
b8 ok = field_le<i64>("Size: %" PRIi64) u64 field_desc_len = (u64)std::abs(size);
|| field_le<u32>("Field version: %u") if (roff < cur_field_off + field_desc_len) {
|| field_le<u32>("Type version: %u") return titled_section("Field", [this, field_desc_len] {
|| field_le<u32>("On-disk parent id: %u") info.rng = { start + cur_field_off, (u64)field_desc_len };
|| field<u16>("Field structure: %s", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 type) { add_to_desc<i64>("Size: %" PRIi64);
add_to_desc<u32>("Field version: %u");
add_to_desc<u32>("Type version: %u");
add_to_desc<u32>("On-disk parent id: %u");
add_to_desc<u16>("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]; const char *name = (type >= countof(field_struct_names)) ? "Unknown" : field_struct_names[type];
return push_str8_node_child(arena, prev, fmt, name); return push_str8_node_child(arena, prev, fmt, name);
}) });
|| field_le<u16>("Flags: 0b%b") u16 flags = add_to_desc<u16>("Flags: 0b%b");
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64)) if (flags & RNTupleSerializer::kFlagRepetitiveField)
return true; add_to_desc<u64>("N Repetitions: %" PRIu64);
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u")) if (flags & RNTupleSerializer::kFlagProjectedField)
return true; add_to_desc<u32>("On disk proj.src id: %u");
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u")) if (flags & RNTupleSerializer::kFlagHasTypeChecksum)
return true; add_to_desc<u32>("Checksum: %u");
return field_str8<u32>("Name: %s") add_to_desc_str8<u32>("Name: %s");
|| field_str8<u32>("Type Name: %s") add_to_desc_str8<u32>("Type Name: %s");
|| field_str8<u32>("Type Alias: %s") add_to_desc_str8<u32>("Type Alias: %s");
|| field_str8<u32>("Description: %s") add_to_desc_str8<u32>("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<i64>("Size: %" PRIi64)
|| field_le<u32>("Field version: %u")
|| field_le<u32>("Type version: %u")
|| field_le<u32>("On-disk parent id: %u")
|| field<u16>("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<u16>("Flags: 0b%b")
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagRepetitiveField) && field_le<u64>("N Repetitions: %" PRIu64))
return true;
if ((flags & RNTupleSerializer::kFlagProjectedField) && field_le<u32>("On disk proj.src id: %u"))
return true;
if ((flags & RNTupleSerializer::kFlagHasTypeChecksum) && field_le<u32>("Checksum: %u"))
return true;
return field_str8<u32>("Name: %s")
|| field_str8<u32>("Type Name: %s")
|| field_str8<u32>("Type Alias: %s")
|| field_str8<u32>("Description: %s")
;
});
}
} }
b8 column_desc() const b8 column_desc() const
{ {
return titled_section("Column", [this] { if (display_grouped) {
u64 flags_off = start + cur_field_off + 16; i64 size;
u16 flags; memcpy(&size, data + start + cur_field_off, sizeof(size));
memcpy(&flags, data + flags_off, sizeof(flags)); u64 col_desc_len = (u64)std::abs(size);
b8 ok = field_le<i64>("Size: %" PRIi64) if (roff < cur_field_off + col_desc_len) {
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name return titled_section("Column", [this, col_desc_len] {
|| field_le<u16>("Bits on storage: %u") info.rng = { start + cur_field_off, col_desc_len };
|| field_le<u32>("Field ID: %u") add_to_desc<i64>("Size: %" PRIi64 " B");
|| field_le<u16>("Flags: 0b%b") add_to_desc<u16>("Column type: %u"); // TODO: human-readable type
|| field_le<u16>("Representation idx: %u") add_to_desc<u16>("Bits on storage: %u");
; add_to_desc<u32>("Field ID: %u");
if (ok) u16 flags = add_to_desc<u16>("Flags: 0b%b");
return ok; add_to_desc<u16>("Representation idx: %u");
if (flags & RNTupleSerializer::kFlagDeferredColumn)
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64)) add_to_desc<u64>("First element: %" PRIu64);
return true; // if (flags & RNTupleSerializer::kFlagHasValueRange) {
if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f"))) // add_to_desc<double>("Value Min: %f");
return true; // add_to_desc<double>("Value Max: %f");
// }
return true;
});
}
cur_field_off += col_desc_len;
return false; 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<i64>("Size: %" PRIi64)
|| field_le<u16>("Column Type: 0x%X") // TODO: prettify name
|| field_le<u16>("Bits on storage: %u")
|| field_le<u32>("Field ID: %u")
|| field_le<u16>("Flags: 0b%b")
|| field_le<u16>("Representation idx: %u")
;
if (ok)
return ok;
if ((flags & RNTupleSerializer::kFlagDeferredColumn) && field_le<u64>("First element: %" PRIu64))
return true;
// if ((flags & RNTupleSerializer::kFlagHasValueRange) && (field_le<double>("Value Min: %f") || field_le<double>("Value Max: %f")))
// return true;
return false;
});
}
} }
b8 schema_description() const b8 schema_description() const
@ -369,7 +463,7 @@ struct Sec_Hover_Fn {
// `off` is the absolute offset into `data`. // `off` is the absolute offset into `data`.
internal 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 {}; 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 start = section.range.start - section.pre_size;
u64 roff = off - start; // offset relative to `section` u64 roff = off - start; // offset relative to `section`
u64 cur_field_off = 0; 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) { switch (section.id) {
case Sec_RNTuple_Anchor: { case Sec_RNTuple_Anchor: {

View file

@ -387,7 +387,10 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms)
if (hovered_off) if (hovered_off)
{ {
Section hovered_section = find_section(app, hovered_off - 1); 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); imgui_render_string_tree(scratch.arena, hover_info.desc->head);
app.viewer.hovered_range = hover_info.rng; app.viewer.hovered_range = hover_info.rng;
} else { } else {