You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
🚀 Semantic-Cpp: Un marco de procesamiento de flujos inteligente orientado al futuro para C++
Semantic-Cpp es una biblioteca moderna de procesamiento de flujos en C++, rediseñada desde cero, que presenta una arquitectura modular de "múltiples encabezados, cero dependencias externas". Cada archivo de encabezado tiene una responsabilidad clara y única, y es probable de forma independiente; juntos forman un ecosistema completo de procesamiento de flujos. Esta biblioteca combina de manera innovadora la esencia de múltiples paradigmas de programación:
La elegancia y fluidez de Java Stream API: Llamadas encadenadas, programación declarativa, haciendo que el código sea tan elegante como la poesía ✨
La pereza y flexibilidad de los Generadores de JavaScript: Evaluación perezosa, generación bajo demanda, amigable con la memoria 🌱
La eficiencia y orden de la indexación de bases de datos: Clasificación inteligente, impulsada por índices, una herramienta poderosa para el procesamiento de datos de series temporales ⏱️
La filosofía de procesamiento por lotes de "Contenedor-como-Elemento": Vectores, listas, mapas... Cualquier contenedor puede ser un ciudadano de primera clase en el flujo, fluyendo libremente 📦
¿Está cansado de escribir bucles for para iterar sobre un vector, anidar un if para filtrar, y llamar manualmente a push_back en otro contenedor? 😩
¿Alguna vez ha depurado un error de índice fuera de límites hasta altas horas de la noche, solo porque quería el "tercer elemento desde el final" al iterar hacia atrás? 😵💫
¿Anhela manipular datos como una base de datos: localizar con precisión por índice, analizar con ventanas deslizantes, completar todo el viaje desde los datos hasta las estadísticas con una única cadena de llamadas? 🤔
Semantic-Cpp nació con este propósito. 🔧
Abstrae el procesamiento de datos como operaciones sobre "elementos" y sus "posiciones lógicas (índices)", similar a "filas" y "claves primarias" en una base de datos. Puede reorganizar, desplazar e invertir índices libremente sin tocar los datos en sí; también puede pasar cualquier contenedor (vector, map, array...) como un todo indivisible dentro del flujo, y "desempaquetarlo" de nuevo a nivel de elemento en cualquier momento. Esta capacidad de cambiar libremente entre dos granularidades falta en los marcos de flujos tradicionales. 🎯
🏗️ Arquitectura del Proyecto: Diseño modular de siete capas
Semantic-Cpp consta de siete archivos de encabezado principales, construidos en capas progresivas. Cada archivo tiene una única responsabilidad y es probado de forma independiente. Cinco espacios de nombres, cada uno con su propio ámbito, trabajan juntos para formar una canalización completa desde la fuente de datos hasta el resultado final:
La cadena de dependencias es clara y lógica, como un diagrama de circuitos diseñado meticulosamente: la corriente fluye desde las definiciones de tipo fundamentales hacia arriba, donde cada capa depende solo de las capas inferiores. Finalmente, todas las rutas convergen en semantic.h y semantics.h, formando la capacidad completa de procesamiento de flujos.
Semantic-Cpp diseña meticulosamente cinco espacios de nombres, cada uno como un "departamento" independiente, con responsabilidades distintas pero colaborando estrechamente:
Espacio de nombres
Archivo de encabezado
Responsabilidad
Tipos/Funciones principales
function
function.h
Base del sistema de tipos
Timestamp, Module, Generator<T>, Supplier<R>, Consumer<T>, Predicate<T> etc.
pool
pool.h
Motor de ejecución concurrente
pool::pool (grupo de hilos global), submit(), emergencyShutdown()
charsequence
charsequence.h
Procesamiento de cadenas Unicode
charset, Meta, Point, Charsequence, Builder, Buffer etc.
collector
collector.h
Ejecución de colección terminal
Collector<E,A,R>, Identity<A>, Accumulator<A,E> etc.
collectable
semantic.h
Contenedores de datos materializados
Collectable<E>, OrderedCollectable<E>, UnorderedCollectable<E> etc.
semantic
semantic.h semantics.h
Construcción de flujo y operaciones intermedias
Semantic<E>, useRange(), useFrom() etc.
🔁 Flujo de colaboración entre espacios de nombres
El flujo de datos entre espacios de nombres es como una línea de montaje en una fábrica: la materia prima entra desde semantic, pasa por procesamiento capa por capa, y finalmente se empaqueta y envía desde collector. Cada paso tiene un límite de responsabilidad claro:
semantic::useRange(0, 100) // ← espacio de nombres semantic: crear flujo
.map(int x { return x * 2; }) // ← espacio de nombres semantic: transformación intermedia
.filter(int x { return x > 50; }) // ← espacio de nombres semantic: filtro intermedio
.toUnordered() // ← Convertir al espacio de nombres collectable
.toVector(); // ← Invocar colector del espacio de nombres collector
📦 Capa 1: function.h — Base de tipos
function.h define el sistema de tipos para todo el marco, la base común para todos los módulos. 🔑
namespacefunction {
using Timestamp = longlong; // Tipo de índice, la "marca de tiempo" de los datos en el flujousing Module = unsignedlonglong; // Tipo de módulo/conteotemplate <typename T>
using Generator = std::function<void(
std::function<void(T, Timestamp)>, // accept — recibir un elemento
std::function<bool(T, Timestamp)> // interrupt — ¿deberíamos detenernos?
)>;
}
Generator es la abstracción central de todo el sistema de flujos. 🌀 No devuelve datos; en cambio, acepta dos callbacks: accept ("Estoy listo, por favor acepta este elemento") e interrupt ("¿deberíamos detenernos?"). Este diseño de inversión de control significa que el productor de datos no tiene conocimiento del consumidor; simplemente "empuja" datos en el momento apropiado. Esta es la esencia de la evaluación perezosa: los datos solo "fluyen" realmente cuando se llama a accept; antes de eso, todo es meramente una descripción.
pool.h proporciona el grupo de hilos global pool::pool, el motor de concurrencia para todo el marco. 🚀 Emplea un diseño de paralelismo declarativo; cuando escribe .parallel(4), no lanza inmediatamente cuatro hilos para comenzar el procesamiento. Esta línea de código es meramente una "declaración": le dice al marco que "tengo la intención de usar 4 hilos para el procesamiento paralelo". La ejecución paralela real ocurre cuando se invoca una operación terminal; es decir, cuando llama a métodos de colección como toVector(), findFirst(), count(), etc.
Característica
Descripción
Paralelismo declarativo
.parallel(4) solo declara "quiero usar 4 hilos", no comienza inmediatamente
Apagado de emergencia
Manejador incorporado emergencyShutdown() y std::set_terminate
Propagación de excepciones
submit() devuelve std::future, propagando excepciones de manera segura al hilo principal
🔤 Capa 3: charsequence.h — Secuencias de caracteres Unicode
charsequence.h es un módulo completo de procesamiento Unicode, que proporciona funcionalidad para crear, convertir y manipular secuencias de caracteres. 🌍 Admite varias codificaciones como UTF-8, UTF-16 (LE/BE), UTF-32 (LE/BE), ASCII y Latin1. Detecta y maneja correctamente pares sustitutos, devolviendo el carácter de reemplazo estándar U+FFFD para puntos de código no válidos.
Regla importante: Un Semantic<E> primero debe convertirse en un Collectable<E> a través de toUnordered(), toOrdered(), toWindow(), toStatistics() o sort() antes de que se puedan llamar métodos terminales.
🧭 Cinco caminos de materialización
Método de conversión
Tipo objetivo
Estructura de datos subyacente
Característica de rendimiento
toUnordered()
UnorderedCollectable
unordered_map
Búsqueda promedio O(1)
toOrdered()
OrderedCollectable
map
Búsqueda O(log n)
sort()
OrderedCollectable
map (ordenado por valor)
Búsqueda O(log n)
toWindow()
WindowCollectable
Hereda colección ordenada
Admite slide/tumble
toStatistics<D>()
Statistics<E,D>
Hereda colección ordenada
30+ métodos estadísticos
📋 Collectable — Todos los métodos terminales (orden alfabético)
Método
Tipo de retorno
Descripción
allMatch(predicate)
bool
Todos los elementos cumplen la condición
anyMatch(predicate)
bool
Algún elemento cumple la condición
average<D>()
D
Promedio
average<D>(mapper)
D
Promedio después del mapeo
collect(identity, acc, comb, fin)
R
Colección personalizada de cuatro etapas
collect(identity, interrupt, acc, comb, fin)
R
Colección interrumpible personalizada
count()
Module
Número total de elementos
empty()
bool
¿Está el flujo vacío?
error()
void
Salida a stderr (admite delimiter/prefix/suffix/converter)
findAny()
std::optional<E>
Encuentra cualquier elemento (aleatorio)
findAt(index)
std::optional<E>
Encuentra elemento en índice específico (admite negativo)
findFirst()
std::optional<E>
Encuentra el primer elemento
findLast()
std::optional<E>
Encuentra el último elemento
findMaximum()
std::optional<E>
Encuentra el elemento máximo
findMaximum(comparator)
std::optional<E>
Encuentra máximo con comparador personalizado
findMinimum()
std::optional<E>
Encuentra el elemento mínimo
findMinimum(comparator)
std::optional<E>
Encuentra mínimo con comparador personalizado
forEach(consumer)
void
Ejecuta efecto secundario para cada elemento
group(keyExtractor)
unordered_map<K, vector<E>>
Agrupa por clave
groupBy(keyExtractor, valueExtractor)
unordered_map<K, vector<V>>
Agrupa por clave y extrae valor
join()
Charsequence
Une con formato predeterminado
join(delimiter)
Charsequence
Une con delimitador personalizado
join(prefix, delimiter, suffix)
Charsequence
Une con formato completamente personalizado
noneMatch(predicate)
bool
Ningún elemento cumple la condición
out()
Charsequence
Salida a stdout (admite delimiter/prefix/suffix/converter)
partition(size)
vector<vector<E>>
Particiona por tamaño fijo
partitionBy(keyExtractor)
vector<vector<E>>
Particiona por clave de índice
partitionBy(keyExtractor, valueExtractor)
vector<vector<V>>
Particiona por clave de índice y extrae valor
range<D>()
D
Rango numérico (max - min)
range<D>(mapper)
D
Rango numérico después del mapeo
reduce(accumulator)
std::optional<E>
Reducción sin identidad
reduce(identity, accumulator)
E
Reducción con identidad
reduce(identity, acc, comb)
R
Reducción completamente personalizada
summate<D>()
D
Sumatoria
summate<D>(mapper)
D
Sumatoria después del mapeo
toArray<N>()
std::array<E, N>
Recoge en array de tamaño fijo
toDeque()
std::deque<E>
Recoge en deque
toForwardList()
std::forward_list<E>
Recoge en forward_list
toList()
std::list<E>
Recoge en list
toMap(keyExtractor)
std::map<K, E>
Recoge en map por clave
toMap(keyExtractor, valueExtractor)
std::map<K, V>
Recoge en map con clave y valor personalizados
toMultimap(keyExtractor)
std::multimap<K, E>
Recoge en multimap por clave
toMultimap(keyExtractor, valueExtractor)
std::multimap<K, V>
Recoge en multimap con clave y valor personalizados
toMultiset()
std::multiset<E>
Recoge en multiset
toPriorityQueue()
std::priority_queue<E>
Recoge en priority_queue
toQueue()
std::queue<E>
Recoge en queue
toSet()
std::set<E>
Recoge en set (único y ordenado)
toStack()
std::stack<E>
Recoge en stack
toUnorderedMap(keyExtractor, valueExtractor)
std::unordered_map<K, V>
Recoge en unordered_map
toUnorderedMultimap(keyExtractor)
std::unordered_multimap<K, E>
Recoge en unordered_multimap por clave
toUnorderedMultimap(keyExtractor, valueExtractor)
std::unordered_multimap<K, V>
Recoge en unordered_multimap con clave y valor personalizados
toUnorderedMultiset()
std::unordered_multiset<E>
Recoge en unordered_multiset
toUnorderedSet()
std::unordered_set<E>
Recoge en unordered_set
toVector()
std::vector<E>
Recoge en vector
📈 Statistics<E,D> — Métodos estadísticos
Método
Tipo de retorno
Descripción
summate()
D
Sumatoria
average()
D
Promedio
minimum()
std::optional<D>
Valor mínimo
maximum()
std::optional<D>
Valor máximo
range()
D
Rango (max - min)
variance()
D
Varianza de la población
standardDeviation()
D
Desviación estándar de la población
median()
std::optional<D>
Mediana
mode()
std::optional<E>
Moda
percentile(p)
std::optional<D>
Percentil p-ésimo
firstQuartile()
std::optional<D>
Primer cuartil (Q1)
thirdQuartile()
std::optional<D>
Tercer cuartil (Q3)
interquartileRange()
std::optional<D>
Rango intercuartílico (IQR)
skewness()
D
Asimetría
kurtosis()
D
Curtosis
frequency()
map<E, complex>
Características del dominio de frecuencia
distribute()
map<E, complex>
Características de distribución espacial
dft()
vector<complex<double>>
Transformada Discreta de Fourier
idft()
vector<complex<double>>
Transformada Discreta Inversa de Fourier
fft()
vector<complex<double>>
Transformada Rápida de Fourier
ifft()
vector<complex<double>>
Transformada Rápida Inversa de Fourier
gradient(...)
vector<double>
Descenso de gradiente
Todos los métodos anteriores también admiten una versión de parámetro mapper opcional.
🔧 Métodos de operaciones intermedias de Semantic
Categoría
Método
Descripción
Transformación de elementos
map
Transformación de mapeo uno a uno
flatMap
Mapeo uno a muchos y aplanamiento
flat
Aplanar flujos anidados (admite Semantic y contenedores)
🔧 Capa 6: semantics.h — Fábricas de construcción de flujos
🔢 Generación de rangos numéricos
Método
Descripción
useRange(start, end)
Generar rango [start, end)
useRange(start, end, step)
Rango con tamaño de paso (admite negativo)
useRangeClosed(start, end)
Generar rango cerrado [start, end]
useRangeClosed(start, end, step)
Rango cerrado con tamaño de paso
♾️ Generación de flujos infinitos
Método
Descripción
useInfinite(seed, generator)
Iteración infinita desde valor inicial
useGenerate(supplier)
Llamadas infinitas al proveedor
useGenerate(supplier, limit)
Número limitado de llamadas al proveedor
useIterate(seed, generator)
Iteración infinita desde valor inicial
useIterate(seed, generator, limit)
Número limitado de iteraciones
useRandom()
Flujo infinito de enteros aleatorios
useRandom(min, max)
Flujo de números aleatorios en rango especificado
useRandom(min, max, count)
Flujo de números aleatorios con rango y número especificados
📦 Construcción de contenedores y elementos
Método
Descripción
useEmpty()
Crear un flujo vacío
useOf(element)
Crear flujo a partir de un solo elemento
useOf(e1, e2)
Crear flujo a partir de dos elementos
useOf(e1, e2, e3)
Crear flujo a partir de tres elementos
useOf({...})
Crear flujo a partir de lista de inicialización
useFrom(container)
Crear flujo a partir de contenedor estándar
useFrom({...})
Crear flujo a partir de lista de inicialización
useRepeat(element, count)
Repetir elemento n veces
📄 Procesamiento de texto y Unicode
Método
Descripción
useBlob(text)
Dividir cadena byte a byte en flujo de char
useBlob(text, start, end)
Dividir rango específico byte a byte
useBlob(istream)
Leer línea por línea desde flujo de entrada
useBlob(istream, delimiter)
Leer por delimitador desde flujo de entrada
useText(text)
Flujo de texto completo (Charsequence)
useText(text, delimiter)
Dividir texto por delimitador
useText(istream)
Leer contenido completo desde flujo de entrada
useSequence(charsequence)
Crear flujo de puntos de código a partir de secuencia de caracteres
useSequence(text, encoding)
Crear flujo de puntos de código a partir de texto con codificación especificada
useCharsequence(charsequence)
Secuencia de caracteres como flujo completo
useCharsequence(charsequence, delimiter)
Dividir secuencia de caracteres por delimitador
🔐 Capa 7: hash.h / less.h — El lenguaje universal del mundo de los contenedores
Proporciona soporte completo de hash y comparación para todos los contenedores de la biblioteca estándar (incluidos contenedores anidados), pair, tuple, optional, variant, tipos de tiempo chrono, números complex, y más. Los contenedores anidados en cualquier profundidad y combinación ahora pueden usarse como claves en unordered_set o elementos en set. 🌉
🚀 Consejos de optimización de rendimiento
Elija el contenedor correcto: Use toUnordered() si el orden no importa, toOrdered() o sort() si se necesita ordenación.
Aproveche el paralelismo: Use parallel() para conjuntos de datos grandes.
Optimice el orden de las operaciones: Filtre temprano, ordene sabiamente.
Utilice la evaluación perezosa: takeWhile y limit pueden terminar temprano.
Semantic-Cpp — Construyendo canalizaciones de procesamiento de datos eficientes y claras con C++ moderno. 🚀🎯✨