Repository navigation
[Summary]
StormByte Base is the C++26 foundation of the StormByte suite.
Every other module links this library.
This repository is not Buffer, Config, Crypto, Database, Logger, Multimedia, Network or System — those live in their own repos and depend on Base.
Public headers under StormByte/ cover exceptions, Expected, little-endian Serializable, strings, paths, UUID v4, bitmasks, clonable types, ThreadLock, Size, and StormByte::Type concepts.
StormByte::Safe is the owned surface that crosses a DLL without the caller's CRT: collections, wait, and Safe::Thread.
If you landed here from a release link and have not read the tree:
- What this module is, how to build it, and short examples: README.md
- Since 2.0.0 license changed: original source in this repository is dual-licensed, LGPL v3 or later or a commercial license from the copyright holder. The grant does not cover other StormByte modules or
thirdparty/. LICENSE
Added
Safe::String::ImplodeandSafe::WString::Implodejoin aVectoror aQueueof text with astring_view/wstring_viewdelimiter. The containers are taken by const reference. The result size is counted first and reserved once, so a short join stays in SSO.std::numeric_limits<Size>andstd::numeric_limits<ByteSize>are specialized.min()is 0 andmax()is2^64 - 1, the storeduint64_trange, not the hoststd::size_trange.Safe::String::ReplaceTokenandSafe::WString::ReplaceTokenare static. There is no member and no in-place overload. The call isString::ReplaceToken(text, args...)/WString::ReplaceToken.textis a view, so a literal converts. One argument replaces the first literal{}; further arguments replace the following tokens in order. A missing token leaves the text unchanged. A view is used as-is and does not allocate. A number usesstd::to_string/std::to_wstring. Acharorwchar_tis that one character. Anything else is accepted when it converts tostd::string/std::wstringor toSafe::String/Safe::WString; an explicit conversion is enough, soSizeandByteSizeneed no cast. A result that fits SSO is written into the inline array and does not call SDS /wbuf. A longer result is one exact Base allocation.ENABLE_LTO, default ON. Link-time optimization follows this option for every build type, notRelease. It combines withENABLE_PGO.ENABLE_PGO. The build directory stays a normal build and is the onecmake --installships. Training is a separate tree,<build>/pgo-instr: instrumented library, tests andctest. This directory then compiles with that profile and without tests.install()rules are unchanged. The steps are incmake/pgo.cmake. The instrumented configure receives every project cache option (WITH_GPL,ENABLE_LTO, …) and prints each one. It uses the same C, C++ and linker flags as the final build, including-stdlib=and, on MSVC or clang-cl,/arch:AVX2and/DNDEBUG. On clang-cl the profile is applied at compile time. The instrumented link usesclang_rt.profile(underlib/windowsin the Windows LLVM layout) instead of a flag passed tolld-link. GCC names the.gcdafiles with-fprofile-prefix-pathsopgo-instris not part of the path the final build looks up. On Windows,ctestprepends<build>/pgo-instr/libtoPATH.- Release archives include
THIRD-PARTY(notTHIRDPARTY: on Windows and macOS that name is the same path as thethirdparty/directory, so the file never landed in those zips) andCOPYING.SDS. SDS commitcc59ce0b12e91521476ad54a1e069fb6fd933bbcis compiled into the shared library.COPYING.SDSreproduces the notice in those sources and the shorterLICENSEfrom the same commit.LICENSEin this repository still covers only original StormByte source.
Changed
- CI builds with
ENABLE_LTO=ON,ENABLE_PGO=OFFandENABLE_TEST=ON, then runs ctest. Profile-guided optimization stays on the release workflow. - Breaking:
- Container
size_typeisSize.Vector,Deque,List,Queue,Map,Set,UnorderedMap,UnorderedSet,IterableandBinaryno longer usestd::size_tassize_type. Counts convert implicitly tostd::size_twhen indexing memory.UnorderedMapkeeps its power-of-two mask onstd::size_t;Sizehas no bitwise operators. - Exception. Public constructors no longer take
std::format_string.Exception,Safe::Exception,DeserializeError,OperationError,Base64Error,ExpiredWeakPointerErrorandBadVariantAccesstakestd::string_view. ASafe::Stringconverts to that view and is copied; there is no move constructor. A derived class formats through a protected constructor that callsSafe::String::ReplaceToken, so it accepts the same fields as that function. A view is used as-is. A number, or anything that converts to a string, is converted inside the template. A throw site that is not a derived constructor builds the body withReplaceTokenand copies it in. Indexed arguments, fill characters and presentation types outsided,f,g,G,xandXare not fields. Safe::OutOfBoundsError. Constructors no longer take a message.OutOfBoundsError(Size)writesindex <n> is out of range.OutOfBoundsError()is the same text without a number, for a failure that has no numeric bound (a missing map key, an empty container).
- Container
PerformanceTestsalso trainsExplode,Implode,ReplaceToken,Split, case conversion, in-place edit, in-rangeatandByteSizetext.Safe::StringSSO capacity is 32 code units (48-byte Storage, 16-byte aligned).Safe::WStringis 11 units with 16-byte alignment: 32 units would make the object ~136 bytes on 64-bit and hurt cache density; 11 keeps it compact while covering typical short wide strings.- A public function that has to return a
std::object isSTORMBYTE_FORCE_INLINEin the header. The caller builds it; the DLL does not. That is the same rule asoperator std::string. It now also coversSafe::Binary::spanand itsstd::spanconversion,Error::make_error_code,Clock::Stop,Clock::Time,Clock::MeanDurationandClock::GetValues(the DLL returns a plain microsecond count), and theCodecreads ofstd::string,std::wstring,std::u16stringandstd::u32string. Those four are no longer explicit instantiations ofSerializable. The DLL side of a string read returnsSafe::StringorSafe::WString.std::error_category::messagestays on the category singleton: the standard virtual is bound to that object and cannot move into the caller. ReplaceTokenaccepts the fields Multimedia still writes withstd::format:{:.3f},{:.6f},{:.9f},{:.17g},{:6.2f},{:02},{:03}and{:016x}. A field is{, an optional colon, an optional0, an optional width, an optional.precision, an optional typed/f/g/G/x/X, then}. Width pads with spaces, or with zeros when0is set, and the sign stays in front of the zeros.fis fixed andg/Gis general, both throughstd::to_chars, so{:.3f}rounds the same waystd::formatdoes. A bare{}on a number is stillstd::to_string/std::to_wstring. Aboolistrueorfalseeven when the field has a numeric spec. A character pointer (char*/wchar_t*, including const) is text, the same as a literal; a null one inserts nothing. Any other raw pointer is0xplus lowercase hex of its address (0x0when null).Safe::UniqueandSafe::Sharedprintget(), the object they own, not the control block.{:016x}on a pointer, onSizeor onByteSizeis the integer form, without the0xprefix. A bare{}onSizeis its decimal text. A bare{}onByteSizeis the IEC length (12 B,1.50 KiB). A numeric field on either one formats the storeduint64_t. A brace run that is not one of these fields stays in the text and does not consume an argument. The replacement text is still built in the caller. Only the finished bytes cross intoReplaceTokens.
Fixed
FindStormByteaccepts theBasecomponent. That name is the installed core library, notlibStormByte-Base.find_package(StormByte REQUIRED Base Logger System)no longer fails withmissing: Basewhen StormByte is already installed. The imported targets areStormByte-BaseandStormByte::Base.-stdlib=libc++and-stdlib=libstdc++do not count as custom C++ flags. If either is the only extra flag, Release still gets-O2and the CPU baseline.Safe::Deque::backon an empty deque throwsOutOfBoundsError. It used to evaluatesize - 1first, andSizeasserts instead of wrapping when the count would go negative.Safe::Threadstarts a UNIX execution with an 8 MiB stack.std::threadleft the size to the libc, and musl's 128 KiB default overflowed when libaom ran its first encoder worker on that execution. Windows is unchanged.ThreadTestswalks a megabyte of stack on UNIX; a 128 KiB stack dies there.operator<=>no longer crosses the DLL.std::strong_orderingis not the same ABI in clang-cl and MSVC: the clang build writes the result through a hidden pointer and MSVC does not pass one, soi < sizewrote to address 0. MixedSize/ByteSizecomparisons are no longerextern templateexports.Safe::Binaryand every other three-way comparison areSTORMBYTE_FORCE_INLINEin the header, so the caller compiles them.- MSVC PGO links with
/LTCG:PGINSTRUMENTand/LTCG:PGOPTIMIZE./GENPROFILEand/USEPROFILEalone fail with LNK1220 on the currentlink.exe, because they require an/LTCGspecification. CMake's own/LTCGstays off so it does not replace the profile mode. The profile mode isadd_link_optionson this project, notCMAKE_EXE_LINKER_FLAGS. A nestedproject()inherits the cache and its compiler test linkscmTC_*.exe, which was never instrumented, so/LTCG:PGOPTIMIZEaborted with LNK1266 (cmTC_*.pgdmissing). The cache keeps a bare/LTCGso those/GLobjects still link. A static dependency stays LTCG and is optimized by the link that owns the.pgd. - Clang PGO drops
.profrawfiles left by compiler probes before ctest, andllvm-profdata mergeuses-failure-mode=all. A probe writes a few hundred bytes formain, with a padded empty symbol name. The default failure mode isany, so that one file aborted the merge even after the instrumented tests had passed.