Версия 1.6.1.
В этой библиотеке содержится современная реализация нескольких видов строковых объектов и различных алгоритмов для работы со строками.
Цель библиотеки - сделать работу со строками в С++ такой же простой и лёгкой, как во множестве других языков, особенно скриптовых, но при этом сохранив оптимальность и производительность на уровне С и C++, и даже улучшив их.
Не секрет, что работа со строками в С++ зачастую доставляет боль. Класс std::string часто неудобен либо неэффективен. Многих функций, обычно необходимых при работе со строками, просто нет, и их каждому приходится писать самому. Даже элементарно конкатенировать std::string и std::string_view стало возможно только с C++26. Именно поэтому я начал примерно в 2012 году создавать для себя эту библиотеку, и теперь готов поделится ею со всеми C++ разработчиками.
Эта библиотека не делалась как универсальный комбайн, который "может всё", я реализовывал то, что мне приходилось использовать в работе, стараясь сделать это наиболее эффективным способом, и скромно надеюсь, что кое-что у меня получилось и пригодится другим людям, либо напрямую, либо как источник идей.
Библиотека содержит две части:
"include/simstr/strexpr.h" и написать в своём коде std::basic_string, std::basic_string_view) использовать мощные и быстрые "строковые выражения" для конкатенации и построения строк, а также упрощенные варианты классов simple_str и simple_str_nt, которые реализуют все те строковые алгоритмы библиотеки, которые не требуют хранения или модификации строк. Так как это header-only часть, она не включает в себя работу с UTF-кодировками и упрощённый Unicode."include/simstr/sstring.h"), добавляет свои строковые типы с возможностями хранения и модификации строк, работает с UTF-кодировками и упрощённым Unicode.Библиотека не претендует на роль "поменял хедер и всё заработало лучше" - она прекрасно уживается вместе со стандартными строками и не меняет поведение уже существующего кода, работающего с ними. Многие методы в ней я старался делать совместимыми с std::string и std::string_view, но особо с этим не заморачивался. Переписывание вашего кода на работу с simstr потребует некоторых усилий, но уверяю, что они окупятся. А благодаря совместимости со стандартными строками эту работу можно делать поэтапно, небольшими кусками. Новый же код работы со строками создавать с её применением легко и доставляет удовольствие :)
Основное отличие simstr от std::string - для работы со строками используется не единый универсальный класс, а несколько видов объектов, каждый из которых хорош для своих целей, и при этом хорошо взаимодействующих друг с другом. Если вы активно использовали std::string_view и понимали, в чём его преимущества и недостатки по сравнению с std::string, то подход simstr вам также будет понятен.
При использовании только #include "simstr/strexpr.h":
char, char8_t, char16_t, char32_t, wchar_t.simstr, так и со стандартными строками (std::basic_string, std::basic_string_view), что позволяет применять быструю конкатенацию и там, где пока не получается отказаться от стандартных строк. Тоже позволяет смешивать в операциях строки совместимых типов символов.Splitter.str::append(text, "count = "_ss + count).0x, 0, 0b, 0o, допустимость знака +. Парсинг реализован для всех видов строк и символов.char и wchar_t, а также совместимых с ними по размеру типов символов.При использовании полной версии библиотеки:
sstring (shared string), lstring (local string).lstring - поддерживает множество мутабельных операций со строками - различные замены, вставки, удаления и т.п. Позволяет задавать размер для внутреннего буфера символов, что может превращать Small String Optimization в Big String Optimization :).char <-> char8_t, wchar_t <-> char32_t в Linux, wchar_t <-> char16_t в Windows.format и sprintf (с автоматическим увеличением буфера). Форматирование возможно для строк char, wchar_t и строк, совместимых с ними по размеру. То есть под Windows это char8_t, char16_t, под Linux - char8_t, char32_t (писать свою библиотеку форматирования для всех видов символов не входило в мои замыслы).upper, lower и регистро-независимом сравнении строк. Работает только для символов первой плоскости Unicode (до 0xFFFF), а при смене регистра не учитываются случаи, когда один code point может преобразовываться в несколько, то есть преобразование регистра символов соответствует std::towupper, std::towlower для unicode локали, только быстрее и может работать с любым видом символов.hash map для ключей строкового типа, на базе std::unordered_map, с возможностью более эффективного хранения и сравнения ключей по сравнению с ключами std::string. Поддерживается возможность регистро-независимого сравнения ключей (Ascii или минимальный Unicode (см. предыдущий пункт)).Бенчмарки производятся с использованием фреймворка Google benchmark. Постарался сделать замеры для наиболее типичных операций, встречающихся в обычной работе. Я проводил замеры на своём оборудовании, под Windows и Linux (в WSL), с использованием компиляторов MSVC, Clang, GCC. Сторонние результаты приветствуются. Также проводил замеры в WASM, сборка в Emscripten. Обращаю внимание, что под WASM в Emscripten собирается 32-битная сборка, а значит, размеры буферов SSO в объектах меньше.
На странице релизов вы можете скачать бинарные сборки бенчмарков и запустить их на своём оборудовании.
Также вы можете запустить Emscripten сборку бенчмарков прямо в браузере. (Перед переходом по ссылке лучше предварительно откройте "Инструменты разработчика" (обычно F12), чтобы видеть консоль Javascript, так как до окончания бенчмарков страница не будет обновляться, а весь вывод будет виден в консоли).
Это специальные объекты, которые эффективно реализуют конкатенацию строк, с помощью operator+. Главный принцип, за счёт которого достигается эффективная работа - сколько бы операндов не входило во всё выражение, никаких временных (промежуточных) строк не создаётся, общая длина всего результата подсчитывается только один раз, один раз выделяется память под буфер символов результата, после чего символы копируются сразу в буфер результата на своё место. Никаких перевыделений памяти, никакого передвигания символов в различных промежуточных буферах - всё максимально эффективно. Благодаря возможностям шаблонов C++ и перегрузке операторов, выражение пишется максимально приближённо к обычному синтаксису сложения строк. Кроме того, есть специальные перегрузки для сложения строковых объектов и строковых литералов, строк и чисел, для копирования с заменой, для слияния контейнеров строк и многое другое. Благодаря расширяемости этой системы - возможно создание новых вариантов построения строк, развитие постоянно продолжается.
Все строковые объекты из simstr - сами являются строковыми выражениями, то есть их можно использовать в операциях конкатенации строковых выражений напрямую. Стандартные строки (std::basic_string, std::basic_string_view) - тоже могут служить операндами в операциях сложения со строковыми выражениями. Либо их можно легко преобразовать в строковое выражение, поставив перед ними унарный +.
+s1 - преобразует std::string в объект - строковое выражение, для которого есть эффективная конкатенация с числами и строковыми литералами.
По бенчмаркам ускорение 1.6 - 2 раза.
Ускорение в 9 - 14 раз!!!
std::string_view ssa - псевдоним для simple_str<char> - аналог std::string_view, позволяет с минимальными расходами принимать параметром функции любой строковый объект, который не нужно модифицировать или передавать в C-API: std::string, std::string_view, "строковый литерал", simple_str_nt, sstring, lstring. Также так как он при этом является ещё и "строковым выражением", то позволяет легко строить конкатенации с его участием.
По замерам ускорение 1.5 - 9 раз.
При prec != 0, ускорение 1.5 - 2.2 раза.
Ускорение от 1.5 раз и выше - в зависимости от содержимого строк.
Помимо приведённых здесь отдельных примеров, можно посмотреть исходники:
Доступны при любом использовании:
simple_str<K> - самая простая строка (или кусок строки), иммутабельная, не владеющая, аналог std::string_view.simple_str_nt<K> - то же самое, только заявляет, что заканчивается 0. Для работы со сторонними C-API.Доступны при использовании всей библиотеки:
sstring<K> - shared string, иммутабельная, владеющая, с разделяемым буфером символов, поддержка SSO.lstring<K, N> - local string, мутабельная, владеющая, с задаваемым размером SSO буфера.При подключении только strexpr.h - типы simple_str<K> и simple_str_nt<K> не содержат методов для работы с UTF и Unicode.
Библиотеку можно использовать частично, просто взяв файл "include/simstr/strexpr.h" и включив в свои исходники
Это подключит только строковые выражения и упрощённые реализации simple_str и simple_str_nt, без функций работы с UTF и Unicode.
Полная же версия библиотеки simstr состоит из трёх заголовочных файлов и двух исходников. Можно подключать как CMake проект через add_subdirectory (библиотека simstr), можно просто включить файлы в свой проект. Для сборки также требуется simdutf (при использовании CMake скачивается автоматически).
Библиотека также включена в vcpkg, подключается как orefkov-simstr.
Для работы simstr требуется компилятор стандарта не ниже С++20 - используются концепты и std::format. Работа проверялась под Windows на MSVC-19 и Clang-19, под Linux - на GCC-13 и Clang-21. Также проверялась работа в WASM, сборка в Emscripten 4.0.6, Clang-21.
Вместе с библиотекой поставляются два файла, делающие просмотр simstr строковых объектов в отладчиках более удобным.\ Более подробно описано здесь.
Также simstr используется в моих проектах: