#include "app_base.h" #include "imgui.h" #include "core/logger.h" #include "data_table.h" #include #include #include #include #include #include namespace { // --------------------------------------------------------------------------- // Dataset generador. Filas se generan con valores deterministas en funcion del // indice (semilla = i). Strings repetidas (lang/domain/purity/tested) usan // interned literals -> sin coste de memoria por fila. // --------------------------------------------------------------------------- struct Dataset { int rows = 0; int cols = 10; std::vector backing; // dynamic strings (name, version, deps, size, cov, date) std::vector cells; // row-major pointers }; const char* const* dataset_cells(const Dataset& d) { return d.cells.data(); } std::shared_ptr build_dataset(int rows) { auto d = std::make_shared(); d->rows = rows; d->cols = 10; static const char* langs[] = {"go", "py", "cpp", "bash", "ts"}; static const char* domains[] = {"core", "viz", "infra", "finance", "notebook", "shell"}; static const char* puritys[] = {"pure", "impure"}; static const char* bools[] = {"true", "false"}; // Reserve antes de pushear -> punteros .c_str() estables. d->backing.reserve((size_t)rows * 6 + 16); d->cells.reserve((size_t)rows * 10); auto add = [&](const std::string& s) -> const char* { d->backing.push_back(s); return d->backing.back().c_str(); }; char buf[40]; for (int i = 0; i < rows; ++i) { std::snprintf(buf, sizeof(buf), "fn_%07d", i); const char* name = add(buf); const char* lang = langs[i % 5]; const char* domain = domains[i % 6]; const char* purity = puritys[i % 2]; std::snprintf(buf, sizeof(buf), "%d", (i % 5) + 1); const char* vmaj = add(buf); std::snprintf(buf, sizeof(buf), "%d", i % 7); const char* deps = add(buf); std::snprintf(buf, sizeof(buf), "%.2f", ((i * 31) % 10000) / 100.0); const char* size = add(buf); std::snprintf(buf, sizeof(buf), "%.1f", (i % 1001) / 10.0); const char* cov = add(buf); const char* tst = bools[(i * 3) % 2]; int y = 2024 + (i % 3); int m = 1 + (i % 12); int day = 1 + (i % 28); std::snprintf(buf, sizeof(buf), "%04d-%02d-%02d", y, m, day); const char* dt = add(buf); d->cells.push_back(name); d->cells.push_back(lang); d->cells.push_back(domain); d->cells.push_back(purity); d->cells.push_back(vmaj); d->cells.push_back(deps); d->cells.push_back(size); d->cells.push_back(cov); d->cells.push_back(tst); d->cells.push_back(dt); } return d; } std::shared_ptr& current_dataset() { static std::shared_ptr ds; if (!ds) ds = build_dataset(100); return ds; } } // namespace void render() { static data_table::State st; if (ImGui::Begin("Tables Playground - data_table v0.5")) { ImGui::TextWrapped( "v0.5: + en chip-row anade filtro a cualquier col. Show stats muestra " "0/uniq/mean/min/max por header. Clipper virtualiza render -> 1M filas a 60 FPS."); ImGui::Separator(); ImGui::Text("Dataset size:"); ImGui::SameLine(); const int sizes[] = {100, 10000, 100000, 1000000}; const char* labels[] = {"100", "10K", "100K", "1M"}; for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[0]); ++i) { if (i > 0) ImGui::SameLine(); bool is_active = (current_dataset()->rows == sizes[i]); if (is_active) ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(80, 120, 80, 255)); if (ImGui::SmallButton(labels[i])) { current_dataset() = build_dataset(sizes[i]); st = data_table::State{}; // reset filtros/sort/orden al cambiar dataset } if (is_active) ImGui::PopStyleColor(); } ImGui::SameLine(); ImGui::TextDisabled("(actual: %d filas)", current_dataset()->rows); ImGui::Separator(); static const char* headers[] = { "name", "lang", "domain", "purity", "version_major", "deps_count", "size_kb", "coverage_pct", "tested", "updated_at" }; static const data_table::ColumnType types[] = { data_table::ColumnType::String, // name data_table::ColumnType::String, // lang data_table::ColumnType::String, // domain data_table::ColumnType::String, // purity data_table::ColumnType::Int, // version_major data_table::ColumnType::Int, // deps_count data_table::ColumnType::Float, // size_kb data_table::ColumnType::Float, // coverage_pct data_table::ColumnType::Bool, // tested data_table::ColumnType::Date, // updated_at }; // Tabla extra para demo de joins (fase 9). static const char* lang_info_cells[] = { "go", "compiled", "2009", "py", "interp", "1991", "rust", "compiled", "2010", "ts", "interp", "2012", "bash", "shell", "1989", "lua", "interp", "1993", }; static data_table::TableInput lang_info; if (lang_info.name.empty()) { lang_info.name = "lang_info"; lang_info.headers = {"lang", "family", "year"}; lang_info.types = {data_table::ColumnType::String, data_table::ColumnType::String, data_table::ColumnType::Int}; lang_info.cells = lang_info_cells; lang_info.rows = 6; lang_info.cols = 3; } const auto& d = *current_dataset(); static data_table::TableInput main_t; main_t.name = "fn_registry"; main_t.headers = {"name", "lang", "domain", "purity", "version_major", "deps_count", "size_kb", "coverage_pct", "tested", "updated_at"}; main_t.types = std::vector(types, types + 10); main_t.cells = dataset_cells(d); main_t.rows = d.rows; main_t.cols = d.cols; std::vector tables = { main_t, lang_info }; data_table::render("##bigdata", tables, st); } ImGui::End(); } #ifndef FN_TEST_BUILD int main() { return fn::run_app({ .title = "Tables Playground", .width = 1400, .height = 900, .about = {.name = "tables_playground", .version = "0.5.0", .description = "Playground data_table: + add filter, stats por columna, " "clipper para datasets de millones."}, .log = {.file_path = "tables_playground.log", .level = static_cast(fn_log::Level::Info)} }, render); } #endif