feat(cpp/core): añadir file_poll_diff pure
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user