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: Высокоинтеллектуальный фреймворк потоковой обработки данных на современном C++
Semantic-Cpp — это полностью переосмысленная современная библиотека для потоковой обработки данных на C++, построенная по модульному принципу «множество заголовочных файлов, ноль внешних зависимостей». Каждый заголовочный файл наделен четко очерченной зоной ответственности и может тестироваться независимо, формируя вместе с остальными полноценную экосистему обработки потоков.
Эта библиотека творчески объединяет в себе лучшие черты различных парадигм программирования:
Элегантность и гибкость Java Stream API: цепочки вызовов и декларативное программирование делают ваш код изящным, словно стихи ✨
Отложенность и гибкость JavaScript Generator: ленивые вычисления, генерация данных по требованию и бережное отношение к памяти 🌱
Эффективность и упорядоченность баз данных: интеллектуальная сортировка, работа на основе индексов — мощный инструмент для обработки временных рядов ⏱️
Философия пакетной обработки с контейнерами в качестве элементов: векторы, связные списки, словари... любые контейнеры становятся «гражданами первого класса» в потоке и перемещаются абсолютно свободно 📦
💡 Зачем это нужно?
Вы тоже устали вручную писать циклы for для обхода vector, затем фильтровать данные через if, а после вручную вызывать push_back для заполнения другого контейнера? 😩
Случалось ли вам засиживаться допоздна, отлаживая баг с ошибкой на единицу (off-by-one) из-за того, что при обратном обходе вы пытались получить «третий элемент с конца»? 😵💫
Хотели бы вы работать с данными так же точно, как в базах данных (используя индексы), анализировать их с помощью скользящего окна и превращать сырой набор данных в готовую статистику всего одной цепочкой вызовов? 🤔
Semantic-Cpp создан именно для этого. 🔧
Фреймворк абстрагирует обработку данных до операций над «элементом» и его «логической позицией (индексом)». Подобно «строкам» и «первичным ключам» в базах данных, вы можете свободно переставлять, смещать и инвертировать индексы, вообще не затрагивая сами данные. Более того, любой контейнер (vector, map, array...) можно передать в поток как неделимое целое, а затем в любой момент снова «распаковать» до уровня отдельных элементов. Способность так легко переключаться между двумя уровнями детализации (гранулярности) — уникальная черта, которой нет в традиционных потоковых фреймворках. 🎯
🏗️ Архитектура проекта: 7-уровневая модульная структура
Semantic-Cpp состоит из 7 ключевых заголовочных файлов, плавно развивающихся от уровня к уровню. 5 пространств имен распределяют обязанности между собой, формируя сквозной конвейер (pipeline) от источника данных до финального результата:
Цепочка зависимостей прозрачна, как схема четко спроектированной электронной платы. Ток зарождается в базовых определениях типов на самом нижнем уровне и поднимается вверх шаг за шагом — каждый уровень зависит строго от нижележащего. В итоге все линии сходятся в semantic.h и semantics.h, формируя монолитную функциональность потоковой обработки.
В Semantic-Cpp четко выстроена структура из 5 пространств имен. Каждое из них работает как автономный «департамент», выполняющий свою задачу, но при этом они тесно взаимодействуют друг с другом:
Пространство имен
Файл
Обязанности
Ключевые типы / функции
function
function.h
Фундамент системы типов
Timestamp, Module, Generator, Supplier, Consumer, Predicate и др.
charset, Meta, Point, Charsequence, Builder, Buffer и др.
collector
collector.h
Финальный сбор данных
Collector<E,A,R>, Identity, Accumulator<A,E> и др.
collectable
semantic.h
Материализованные контейнеры данных
Collectable, OrderedCollectable, UnorderedCollectable и др.
semantic
semantic.h
semantics.h
Создание потока и промежуточные операции
Semantic, useRange(), useFrom() и др.
🔁 Схема взаимодействия пространств имен
Потоки данных между пространствами имен напоминают сборочный конвейер на заводе. Сырье поступает в semantic, проходит через несколько стадий обработки и трансформации, после чего упаковывается в collector и отгружается. На каждом этапе границы ответственности строго разграничены:
semantic::useRange(0, 100) // ← Пространство semantic: создание потока
.map(int x { return x * 2; }) // ← Пространство semantic: промежуточное преобразование
.filter(int x { return x > 50; }) // ← Пространство semantic: промежуточная фильтрация
.toUnordered() // ← Переход в пространство collectable
.toVector(); // ← Вызов коллектора из пространства collector
📦 Уровень 1: function.h — Основа системы типов
Файл function.h задает систему типов для всего фреймворка и служит общим фундаментом для всех без исключения модулей. 🔑
namespacefunction {
using Timestamp = longlong; // Тип индекса, «таймстамп» данных внутри потокаusing Module = unsignedlonglong; // Тип счетчика / объема / модуляtemplate <typename T>
using Generator = std::function<void(
std::function<void(T, Timestamp)>, // accept — принимает один элемент
std::function<bool(T, Timestamp)> // interrupt — нужно ли прервать поток?
)>;
}
Generator — это главная абстракция всей потоковой системы. 🌀 Он не возвращает данные напрямую, а принимает два колбэка: accept («все готово, прими этот элемент») и interrupt («надо ли остановиться?»).
Благодаря архитектуре инверсии управления (Inversion of Control) поставщик данных вообще ничего не знает о потребителе — ему достаточно «проталкивать» (Push) данные в нужный момент. В этом и заключается суть ленивых вычислений (Lazy Evaluation). Данные начинают «течь» только тогда, когда вызывается accept. До этого моменты весь код — лишь декларативное описание.
Файл pool.h предоставляет глобальный пул потоков pool::pool, который выступает многопоточным движком фреймворка. 🚀
Здесь применяется концепция декларативного параллелизма (Declarative Parallelism). Когда вы пишете .parallel(4), четыре потока не запускаются сию же секунду. Эта строка кода — всего лишь намерение. Вы сообщаете фреймворку: «Я планирую обработать это в 4 потока».
Реальное параллельное выполнение начнется только в момент вызова терминальной (финальной) операции — то есть при вызове методов сбора данных, таких как toVector(), findFirst(), count().
Возможность
Описание
Декларативный параллелизм
.parallel(4) — это декларация намерения выделить 4 потока; мгновенного старта не происходит
Аварийный останов
Встроенный метод emergencyShutdown() и хэндлер std::set_terminate
Проброс исключений
Метод submit() возвращает std::future, безопасно транслируя исключения в главный поток
🔤 Уровень 3: charsequence.h — Unicode-последовательности
Модуль charsequence.h представляет собой полноценный инструмент для работы с Unicode, обеспечивающий создание, конвертацию и манипулирование символьными последовательностями. 🌍
Он поддерживает кодировки UTF-8, UTF-16(LE/BE), UTF-32(LE/BE), ASCII, Latin1, корректно определяет суррогатные пары (Surrogate Pairs) и возвращает стандартный символ замены U+FFFD в случае обнаружения некорректных кодовых точек (Code Points).
Двунаправленный итератор по кодовым точкам Unicode
encode()
Кодирует одну кодовую точку в байтовую последовательность заданной кодировки
decode()
Декодирует следующую кодовую точку из байтового потока и автоматически сдвигает указатель
convert()
Конвертация кодировок (поддерживает вывод в string, vector, deque)
⚙️ Уровень 4: collector.h — Архитектура коллекторов и фабрика
Файл collector.h содержит в себе ядро системы сборщиков данных Semantic-Cpp, объединяя в одном месте общую инфраструктуру коллекторов и фабричные функции.
⚠️Главное правило: Сначала необходимо преобразовать Semantic в Collectable с помощью методов toUnordered(), toOrdered(), toWindow(), toStatistics() или sort(), и только после этого можно вызывать финальные (терминальные) методы.
🧭 5 путей материализации
Метод трансформации
Целевой тип
Базовая структура данных
Характеристики производительности
toUnordered()
UnorderedCollectable
unordered_map
Поиск в среднем за O(1)
toOrdered()
OrderedCollectable
map
Поиск за O(\log n)
sort()
OrderedCollectable
map (сортировка по значению)
Поиск за O(\log n)
toWindow()
WindowCollectable
Наследует упорядоченную коллекцию
Поддержка slide/tumble окон
toStatistics()
Statistics<E,D>
Наследует упорядоченную коллекцию
Более 30 статистических методов
📋 Collectable — Все терминальные методы (в алфавитном порядке)
Метод
Возвращаемый тип
Описание
allMatch(predicate)
bool
Все элементы удовлетворяют условию
anyMatch(predicate)
bool
Хотя бы один элемент удовлетворяет условию
average()
D
Среднее значение
average(mapper)
D
Среднее значение после маппинга
collect(identity, acc, comb, fin)
R
Кастомный 4-стадийный сбор
collect(identity, interrupt, acc, comb, fin)
R
Кастомный сбор с возможностью прерывания
count()
Module
Общее количество элементов
empty()
bool
Проверка, пуст ли поток
error()
void
Вывод в stderr (поддерживает delimiter/prefix/suffix/converter)
findAny()
std::optional
Поиск любого элемента
findAt(index)
std::optional
Поиск по индексу (включая отрицательные значения)
findFirst()
std::optional
Поиск первого элемента
findLast()
std::optional
Поиск последнего элемента
findMaximum()
std::optional
Поиск максимума
findMaximum(comparator)
std::optional
Поиск максимума с пользовательским компаратором
findMinimum()
std::optional
Поиск минимума
findMinimum(comparator)
std::optional
Поиск минимума с пользовательским компаратором
forEach(consumer)
void
Обход элементов с выполнением сайд-эффектов
group(keyExtractor)
unordered_map<K, vector>
Группировка по ключу
groupBy(keyExtractor, valueExtractor)
unordered_map<K, vector>
Группировка по ключу с извлечением значений
join()
Charsequence
Соединение в строку в дефолтном формате
join(delimiter)
Charsequence
Соединение строк через разделитель
join(prefix, delimiter, suffix)
Charsequence
Соединение строк в полностью кастомном формате
noneMatch(predicate)
bool
Ни один элемент не удовлетворяет условию
out()
Charsequence
Вывод в stdout (поддерживает delimiter/prefix/suffix/converter)
partition(size)
vector<vector>
Разбиение на блоки фиксированного размера
partitionBy(keyExtractor)
vector<vector>
Разбиение на блоки по индексному ключу
partitionBy(keyExtractor, valueExtractor)
vector<vector>
Разбиение по ключу с извлечением значений
range()
D
Числовой диапазон (макс. - мин.)
range(mapper)
D
Числовой диапазон после маппинга
reduce(accumulator)
std::optional
Свёртка без начального значения
reduce(identity, accumulator)
E
Свёртка с начальным значением
reduce(identity, acc, comb)
R
Полностью настраиваемая свёртка
summate()
D
Сумма
summate(mapper)
D
Сумма после маппинга
toArray()
std::array<E, N>
Сбор в array фиксированного размера
toDeque()
std::deque
Сбор в deque
toForwardList()
std::forward_list
Сбор в forward_list
toList()
std::list
Сбор в list
toMap(keyExtractor)
std::map<K, E>
Сбор в map на основе ключа
toMap(keyExtractor, valueExtractor)
std::map<K, V>
Сбор в map с кастомными парами ключ-значение
toMultimap(keyExtractor)
std::multimap<K, E>
Сбор в multimap по ключу
toMultimap(keyExtractor, valueExtractor)
std::multimap<K, V>
Сбор в multimap с кастомными парами ключ-значение
toMultiset()
std::multiset
Сбор в multiset
toPriorityQueue()
std::priority_queue
Сбор в priority_queue
toQueue()
std::queue
Сбор в queue
toSet()
std::set
Сбор в set (с сортировкой и удалением дубликатов)
toStack()
std::stack
Сбор в stack
toUnorderedMap(keyExtractor, valueExtractor)
std::unordered_map<K, V>
Сбор в unordered_map
toUnorderedMultimap(keyExtractor)
std::unordered_multimap<K, E>
Сбор в unordered_multimap по ключу
toUnorderedMultimap(keyExtractor, valueExtractor)
std::unordered_multimap<K, V>
Сбор в unordered_multimap с кастомными парами
toUnorderedMultiset()
std::unordered_multiset
Сбор в unordered_multiset
toUnorderedSet()
std::unordered_set
Сбор в unordered_set
toVector()
std::vector
Сбор в vector
📈 Statistics<E,D> — Статистические методы
Метод
Возвращаемый тип
Описание
summate()
D
Сумма
average()
D
Среднее значение
minimum()
std::optional
Минимальное значение
maximum()
std::optional
Максимальное значение
range()
D
Диапазон
variance()
D
Дисперсия выборки
standardDeviation()
D
Стандартное отклонение
median()
std::optional
Медиана
mode()
std::optional
Мода
percentile(p)
std::optional
p-й процентиль
firstQuartile()
std::optional
Первый квартиль (Q1)
thirdQuartile()
std::optional
Третий квартиль (Q3)
interquartileRange()
std::optional
Межквартильный размах (IQR)
skewness()
D
Асимметрия
kurtosis()
D
Эксцесс
frequency()
map<E, complex>
Частотные характеристики
distribute()
map<E, complex>
Пространственное распределение
dft()
vector<complex>
Дискретное преобразование Фурье
idft()
vector<complex>
Обратное дискретное преобразование Фурье
fft()
vector<complex>
Быстрое преобразование Фурье
ifft()
vector<complex>
Обратное быстрое преобразование Фурье
gradient(...)
vector
Градиентный спуск
💡 Все вышеперечисленные методы поддерживают альтернативные версии с необязательным аргументом mapper.
🔧 Semantic Методы промежуточных операций
Категория
Метод
Описание
Трансформация
map
Преобразование «один к одному»
flatMap
Преобразование «один ко многим» со сглаживанием
flat
Сглаживание вложенных потоков (поддержка контейнеров и Semantic)
Фильтрация
filter
Фильтрация по условию
takeWhile
Получение элементов, пока выполняется условие
dropWhile
Пропуск элементов, пока выполняется условие
distinct
Удаление дубликатов (с кастомным компаратором)
Контроль объема
limit
Ограничение количества элементов
skip
Пропуск первых n элементов
sub
Извлечение поддиапазона [start, end)
Индексация
redirect
Перемаппинг индексов
reverse
Инверсия индексов (разворот)
translate
Смещение индексов
Наблюдение
peek
Просмотр элементов (без модификации потока)
Параллелизм
parallel(n)
Объявление уровня многопоточности
Слияние
concatenate
Объединение Semantic / элементов / генераторов / контейнеров
🔧 Уровень 6: semantics.h — Фабрика конвейеров потока
🔢 Генерация числовых диапазонов
Метод
Описание
useRange(start, end)
Создание диапазона вида [start, end)
useRange(start, end, step)
Числовой диапазон с шагом (поддерживается отрицательный шаг)
useRangeClosed(start, end)
Создание замкнутого диапазона вида [start, end]
useRangeClosed(start, end, step)
Замкнутый числовой диапазон с шагом
♾️ Генерация бесконечных потоков
Метод
Описание
useInfinite(seed, generator)
Бесконечный поток на основе начального значения и генератора
useGenerate(supplier)
Бесконечный вызов поставщика данных
useGenerate(supplier, limit)
Вызов поставщика фиксированное число раз
useIterate(seed, generator)
Бесконечная итерация начиная с seed
useIterate(seed, generator, limit)
Итерация фиксированное число раз
useRandom()
Бесконечный поток случайных чисел
useRandom(min, max)
Поток случайных чисел в заданном диапазоне
useRandom(min, max, count)
Поток случайных чисел заданного объема в диапазоне
📦 Потоки из контейнеров и элементов
Метод
Описание
useEmpty()
Создание пустого потока
useOf(element)
Поток из одного элемента
useOf(e1, e2)
Поток из двух элементов
useOf(e1, e2, e3)
Поток из трех элементов
useOf({...})
Поток из списка инициализации
useFrom(container)
Поток из стандартного STL-контейнера
useFrom({...})
Поток из списка инициализации
useRepeat(element, count)
Повторение элемента n раз
📄 Обработка текста и Unicode
Метод
Описание
useBlob(text)
Разделение строки на поток char побайтово
useBlob(text, start, end)
Побайтовое разделение указанного диапазона строки
useBlob(istream)
Построчное чтение из входного потока
useBlob(istream, delimiter)
Чтение из входного потока по разделителю
useText(text)
Полноценный текстовый поток (Charsequence)
useText(text, delimiter)
Разделение текста по разделителю
useText(istream)
Чтение всего содержимого из входного потока
useSequence(charsequence)
Поток кодовых точек из символьной последовательности
useSequence(text, encoding)
Поток кодовых точек заданной кодировки из текста
useCharsequence(charsequence)
Символьная последовательность как единый поток
useCharsequence(charsequence, delimiter)
Разделение последовательности по разделителю
🔐 Уровень 7: hash.h / less.h — Общий язык для мира контейнеров
Предоставляет полноценную поддержку хэширования и сравнения для всех контейнеров стандартной библиотеки (включая контейнеры любой глубины вложенности), а также для pair, tuple, optional, variant, типов времени chrono, комплексных чисел complex и многого другого. Теперь вложенные контейнеры произвольной структуры можно напрямую использовать в качестве ключей в unordered_set или элементов в set. 🌉
🚀 Советы по оптимизации производительности
Выбирайте правильный тип материализации: Если порядок элементов не важен, используйте toUnordered(). Если нужна сортировка — вызывайте toOrdered() или sort().
Используйте многопоточность с умом: При работе с большими массивами данных подключайте метод parallel().
Оптимизируйте порядок вызовов: Старайтесь вызывать фильтрацию (filter) как можно раньше, а к сортировке (sort) прибегайте только при явной необходимости.
Используйте преимущества ленивых вычислений: Методы takeWhile и limit позволяют завершить обработку потока досрочно (Early Exit).
Semantic-Cpp — создавайте эффективные и прозрачные конвейеры обработки данных на современном C++. 🚀🎯✨