asegurate de que subimos todo
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,89 +1,175 @@
|
||||
// Playground tables: iterador de la fn `data_table` antes de promoverla al
|
||||
// registry y migrar las apps C++ que hoy usan `ImGui::BeginTable` raw.
|
||||
|
||||
#include "app_base.h"
|
||||
#include "imgui.h"
|
||||
#include "core/logger.h"
|
||||
#include "data_table.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
struct Row {
|
||||
const char* name;
|
||||
const char* lang;
|
||||
const char* domain;
|
||||
const char* purity;
|
||||
const char* description;
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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<std::string> backing; // dynamic strings (name, version, deps, size, cov, date)
|
||||
std::vector<const char*> cells; // row-major pointers
|
||||
};
|
||||
|
||||
const std::vector<Row>& sample_rows() {
|
||||
static const std::vector<Row> rows = {
|
||||
{"filter_slice", "go", "core", "pure", "Filtra slice con predicado"},
|
||||
{"map_slice", "go", "core", "pure", "Aplica f a cada elemento"},
|
||||
{"reduce_slice", "go", "core", "pure", "Fold con acumulador"},
|
||||
{"sma", "py", "finance", "pure", "Simple moving average"},
|
||||
{"ema", "py", "finance", "pure", "Exponential moving average"},
|
||||
{"rsi", "py", "finance", "pure", "Relative strength index"},
|
||||
{"table_view", "cpp", "viz", "pure", "Tabla ImGui actual del registry"},
|
||||
{"line_plot", "cpp", "viz", "pure", "ImPlot line wrapper"},
|
||||
{"scatter_plot", "cpp", "viz", "pure", "ImPlot scatter wrapper"},
|
||||
{"bar_chart", "cpp", "viz", "pure", "ImPlot bar wrapper"},
|
||||
{"heatmap", "cpp", "viz", "pure", "ImPlot heatmap wrapper"},
|
||||
{"sqlite_open", "go", "infra", "impure", "Open SQLite con WAL+FK"},
|
||||
{"http_json_response", "go", "infra", "impure", "Helper JSON response"},
|
||||
{"http_parse_body", "go", "infra", "impure", "Parse JSON body"},
|
||||
{"rsync_deploy", "bash", "infra", "impure", "rsync local -> remoto"},
|
||||
{"systemd_install", "go", "infra", "impure", "Sube unit + enable + start"},
|
||||
{"systemd_restart", "go", "infra", "impure", "Restart servicio remoto"},
|
||||
{"jupyter_discover", "py", "notebook", "impure", "Descubre instancias Jupyter"},
|
||||
{"jupyter_exec", "py", "notebook", "impure", "Ejecuta celda y vuelca output"},
|
||||
{"docker_pull_image", "go", "infra", "impure", "docker pull con timeout"},
|
||||
{"graph_force_layout", "cpp", "viz", "pure", "Force-directed CPU"},
|
||||
{"graph_force_layout_gpu","cpp", "viz", "pure", "Force-directed GPU (compute)"},
|
||||
{"sql_workbench", "cpp", "core", "impure", "Workbench SQL embebido"},
|
||||
{"text_editor", "cpp", "core", "impure", "Editor de texto con highlighting"},
|
||||
{"icon_font", "cpp", "core", "impure", "Carga tabler-icons.ttf"},
|
||||
const char* const* dataset_cells(const Dataset& d) { return d.cells.data(); }
|
||||
|
||||
std::shared_ptr<Dataset> build_dataset(int rows) {
|
||||
auto d = std::make_shared<Dataset>();
|
||||
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();
|
||||
};
|
||||
return rows;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const char* const* flatten_cells(int& rows, int& cols) {
|
||||
static std::vector<const char*> flat;
|
||||
static bool built = false;
|
||||
if (!built) {
|
||||
const auto& src = sample_rows();
|
||||
flat.reserve(src.size() * 5);
|
||||
for (const auto& r : src) {
|
||||
flat.push_back(r.name);
|
||||
flat.push_back(r.lang);
|
||||
flat.push_back(r.domain);
|
||||
flat.push_back(r.purity);
|
||||
flat.push_back(r.description);
|
||||
}
|
||||
built = true;
|
||||
}
|
||||
rows = (int)sample_rows().size();
|
||||
cols = 5;
|
||||
return flat.data();
|
||||
std::shared_ptr<Dataset>& current_dataset() {
|
||||
static std::shared_ptr<Dataset> 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.1")) {
|
||||
if (ImGui::Begin("Tables Playground - data_table v0.5")) {
|
||||
ImGui::TextWrapped(
|
||||
"Iteracion 1: sort real al pulsar header, click en celda -> popup operador "
|
||||
"(=, !=, >, >=, <, <=) -> chip removible. Click derecho header: filter input, "
|
||||
"conditional color, hide column, show/hide columns.");
|
||||
"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", "description"};
|
||||
int rows = 0, cols = 0;
|
||||
const char* const* cells = flatten_cells(rows, cols);
|
||||
data_table::render("##registry_sample", headers, cols, cells, rows, st);
|
||||
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<data_table::ColumnType>(types, types + 10);
|
||||
main_t.cells = dataset_cells(d);
|
||||
main_t.rows = d.rows;
|
||||
main_t.cols = d.cols;
|
||||
|
||||
std::vector<data_table::TableInput> tables = { main_t, lang_info };
|
||||
data_table::render("##bigdata", tables, st);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -92,11 +178,12 @@ void render() {
|
||||
int main() {
|
||||
return fn::run_app({
|
||||
.title = "Tables Playground",
|
||||
.width = 1280,
|
||||
.height = 800,
|
||||
.width = 1400,
|
||||
.height = 900,
|
||||
.about = {.name = "tables_playground",
|
||||
.version = "0.2.0",
|
||||
.description = "Playground para iterar mejoras sobre table_view antes de promover al registry."},
|
||||
.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<int>(fn_log::Level::Info)}
|
||||
}, render);
|
||||
|
||||
Reference in New Issue
Block a user