feat(cpp/core): añadir file_poll_diff pure

This commit is contained in:
2026-04-28 23:53:49 +02:00
parent 90e9593b20
commit 02c9dd93e3
5 changed files with 159 additions and 1 deletions
+2 -1
View File
@@ -17,9 +17,10 @@ add_imgui_app(primitives_gallery
${CMAKE_SOURCE_DIR}/functions/core/timeline.cpp
demos_sql.cpp
demos_scientific.cpp
# text_editor + file_watcher (issue 0025)
# text_editor + file_watcher (issue 0025) + file_poll_diff pure (issue 0045)
${CMAKE_SOURCE_DIR}/functions/core/text_editor.cpp
${CMAKE_SOURCE_DIR}/functions/core/file_watcher.cpp
${CMAKE_SOURCE_DIR}/functions/core/file_poll_diff.cpp
${CMAKE_SOURCE_DIR}/vendor/imgui_text_edit/TextEditor.cpp
# sql_workbench (issue 0032) + sql_parse pure (issue 0045)
${CMAKE_SOURCE_DIR}/functions/core/sql_workbench.cpp
@@ -7,6 +7,7 @@ add_imgui_app(text_editor_smoke
main.cpp
${CMAKE_SOURCE_DIR}/functions/core/text_editor.cpp
${CMAKE_SOURCE_DIR}/functions/core/file_watcher.cpp
${CMAKE_SOURCE_DIR}/functions/core/file_poll_diff.cpp
${CMAKE_SOURCE_DIR}/vendor/imgui_text_edit/TextEditor.cpp
)
target_include_directories(text_editor_smoke PRIVATE
+45
View File
@@ -0,0 +1,45 @@
#include "core/file_poll_diff.h"
#include <unordered_map>
#include <unordered_set>
namespace fn_ui {
FileDiff file_poll_diff(const std::vector<FileEntry>& before,
const std::vector<FileEntry>& after) {
FileDiff out;
// Index before by path para lookup O(1).
std::unordered_map<std::string, const FileEntry*> idx_before;
idx_before.reserve(before.size());
for (const auto& e : before) {
idx_before[e.path] = &e;
}
// Recorrer after: clasificar added/modified.
std::unordered_set<std::string> seen_in_after;
seen_in_after.reserve(after.size());
for (const auto& e : after) {
seen_in_after.insert(e.path);
auto it = idx_before.find(e.path);
if (it == idx_before.end()) {
out.added.push_back(e.path);
} else {
const FileEntry* prev = it->second;
if (prev->size != e.size || prev->mtime != e.mtime) {
out.modified.push_back(e.path);
}
}
}
// Recorrer before: detectar removed (paths que no estan en after).
for (const auto& e : before) {
if (seen_in_after.find(e.path) == seen_in_after.end()) {
out.removed.push_back(e.path);
}
}
return out;
}
} // namespace fn_ui
+34
View File
@@ -0,0 +1,34 @@
#pragma once
// file_poll_diff — diff puro entre dos snapshots de filesystem.
//
// Pareja natural de file_watcher: en plataformas sin inotify/RDCW (o cuando
// se quiere fallback portable), el caller toma snapshots periodicos via
// stat()/opendir() y los compara con esta funcion para emitir eventos
// added/modified/removed. Sin I/O, sin estado.
#include <cstdint>
#include <string>
#include <vector>
namespace fn_ui {
struct FileEntry {
std::string path;
uint64_t size = 0;
int64_t mtime = 0; // unix seconds
};
struct FileDiff {
std::vector<std::string> added;
std::vector<std::string> modified; // size o mtime distinto
std::vector<std::string> removed;
};
// Pura: calcula diff entre dos snapshots por path. Asume entries con paths
// unicos en cada snapshot. Orden de los vectores: el orden en que aparecen
// los paths en `after` (added/modified) y en `before` (removed).
FileDiff file_poll_diff(const std::vector<FileEntry>& before,
const std::vector<FileEntry>& after);
} // namespace fn_ui
+77
View File
@@ -0,0 +1,77 @@
---
name: file_poll_diff
kind: function
lang: cpp
domain: core
version: "1.0.0"
purity: pure
signature: "fn_ui::FileDiff fn_ui::file_poll_diff(const std::vector<fn_ui::FileEntry>& before, const std::vector<fn_ui::FileEntry>& after)"
description: "Diff puro entre dos snapshots de filesystem (path/size/mtime). Devuelve vectores added/modified/removed. Sin I/O. Pareja del file_watcher para fallback portable basado en polling."
tags: [filesystem, diff, poll, snapshot, pure]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
tested: true
tests: ["file_poll_diff detects added/modified/removed", "file_poll_diff: empty inputs", "file_poll_diff: identical snapshots"]
test_file_path: "cpp/tests/test_file_poll_diff.cpp"
file_path: "cpp/functions/core/file_poll_diff.cpp"
params:
- name: before
desc: "Snapshot anterior. Vector de FileEntry {path, size, mtime}, paths unicos"
- name: after
desc: "Snapshot actual. Mismo formato. Paths unicos"
output: "FileDiff con tres vectores de paths: added (en after y no en before), modified (path comun pero size o mtime distinto), removed (en before y no en after)."
---
# file_poll_diff
Logica pura para calcular cambios de filesystem entre dos snapshots. Sin
I/O, sin estado: el caller hace `stat()`/`opendir()` por su lado, construye
los `FileEntry`, y esta funcion los compara.
## API
```cpp
namespace fn_ui {
struct FileEntry {
std::string path;
uint64_t size = 0;
int64_t mtime = 0; // unix seconds
};
struct FileDiff {
std::vector<std::string> added;
std::vector<std::string> modified;
std::vector<std::string> removed;
};
FileDiff file_poll_diff(const std::vector<FileEntry>& before,
const std::vector<FileEntry>& after);
}
```
## Reglas
- Comparacion por `path` exacto.
- "Modified": al menos uno de `size` o `mtime` cambia.
- Asume paths unicos por snapshot (la funcion no deduplica).
- Complejidad: O(N+M) con un `unordered_map<string, const FileEntry*>` para
indexar `before`.
## Cuando usar
- En plataformas donde `file_watcher` no tiene backend nativo (stub) y se
necesita un fallback basado en polling.
- Para consolidar bursts de eventos: tomar dos snapshots en el tiempo y
reportar solo el cambio neto (sin los intermedios).
- Tests del watcher: simular cambios de FS sin tocar disco.
## Por que pura
No abre archivos, no llama `stat`, no usa el reloj. Misma entrada produce la
misma salida — testeable sin fixtures de FS.