[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.
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
STORMBYTE_FORCE_INLINE— inplatform.h.inlineplus__forceinlineoralways_inline, so the body is emitted in the caller.inlinealone is only a hint.- BinaryData — owned contiguous sequence of
std::byte, safe to use across a DLL boundary. Same kind of API asstd::vector<std::byte>(iterators,<algorithm>,std::ranges,std::span, insert / erase / assign /append/emplace_back/operator+=). Lengths and indices useStormByte::ByteSize. Storage lives on Base's heap; the public type is notstd::vector<std::byte>.at()throwsOutOfBoundsError. Construct fromspan, pointer+ByteSize, range, initializer list,string_view, and a caller-ownedstd::vector<std::byte>(lvalue copies and leaves the vector; rvalue copies onto Base's heap then clears the vector — looks like a move, not a heap steal). Convert out with implicitspanandexplicit operator std::vector<std::byte>(const&copies and leaves*this;&&copies onto the caller CRT then clears*this).append(BinaryData&&)/operator+=(BinaryData&&)are a real same-heap move when*thisis empty. Compare equal / unequal / three-way with anotherBinaryDataand withstd::span<const std::byte>(both operand orders).HexDump()andHexDump(std::size_t columns)return aCString: 8-digit offset, hex row, ASCII (non-printable as.).columnsis a row width, not a byte length — it isstd::size_t, notByteSize.0prints every byte on one line. DefaultHexDump()is 16 columns.Type::Container/Type::Sized/Type::HasPushBack/Type::ByteInputRangematch;Type::Stringdoes not.Serializable<BinaryData>uses the container path (same wire asstd::vector<std::byte>:uint64LE count + payload). Covered byBinaryDataTestsandSerializationTests. - CString — owned NUL-terminated buffer, safe to use across a DLL boundary. Not a
std::string. Copy, move,Reset,swap,Length(StormByte::Size), observeroperator[](indices[0, Length()];Length()is the trailing NUL; null or pastLength()is undefined andasserts when assertions are on), explicitoperator bool(non-null pointer;""is valid empty text), explicitconst char*(same lifetime asstd::string::c_str()), explicitstd::string_view(empty view when null;[0, Length()); same lifetime), implicitstd::string,operator<<, content==/!=/<=>, andstd::hash. Construct fromconst char*(null stays null),std::string_viewandconst std::string&(copy onto Base's heap, not a steal; empty yields"", not null). Covered byCStringTests. - WCString — wide counterpart of
CString(wchar_t/std::wstring/std::wstring_view/std::wostream). Same comparison, hash, subscript and lifetime rules asstd::wstring::c_str().Length()isStormByte::Size. Construct fromconst wchar_t*(null stays null),std::wstring_viewandconst std::wstring&(copy onto Base's heap; empty yieldsL""). Covered byWCStringTests. - Error —
Domain,Category,Code(Success,Unknown) andFault. Modules specializeDomainfor their enums;make_error_codelives next to the enum so ADL feedsstd::error_code. Category singletons stay in the module.cxx.Faultholds the code and aCString. Not thrown. Covered byErrorTests. - Shared — complements
std::shared_ptr(safe_pointers.hxx). It does not replace it. Exact type:Heap::MakeShared. Derived type:Shared<Base>::MakePointer<Derived>(the deleter still destroys the derived object). Daily operations matchstd::shared_ptr(copy,reset,swap, compare,use_count,owner_before). No constructor from a raw pointer or fromstd::shared_ptr, and norelease. Converts implicitly tostd::shared_ptr<T>(same control block, deleter stays Base). No conversion back.StaticPointerCast,DynamicPointerCast,ConstPointerCastandReinterpretPointerCastkeep that control block. Covered bySafePointersTests. - Unique — complements
std::unique_ptr(safe_pointers.hxx). It does not replace it. Exact type:Heap::MakeUnique. Derived type:Unique<Base>::MakePointer<Derived>, and~Basemust be virtual or the call does not compile. Noreleaseand no constructor from a raw pointer. Converts on move tostd::unique_ptr<T, Heap::ObjectDeleter>only. Astd::unique_ptr<T>parameter has to change.Heapstays private and is not installed. Covered bySafePointersTests. - Weak — complements
std::weak_ptr. Constructed only fromShared.lockreturnsShared, or empty when expired. No constructor fromstd::weak_ptr. Covered bySafePointersTests. - ClonableTests — clone / move /
MakePointercoverage forSharedandUnique.Derived::PointerTypeused as storage. Implicit conversion tostd::shared_ptr/unique_ptrwith Base deleter.ValidSmartPointerrejectsstd::shared_ptrand defaultstd::unique_ptr. - Size — abstract unit count (
uint64_tstorage), same width on every host and safe across a DLL. Not an octet length. Implicit conversion only tostd::size_t(clamp tosize_t::max); every other integral destination isexplicitand clamps toT::max. NoValue(), nooperator bool. Full arithmetic with anyType::Integraland with anotherSize; the result is alwaysSize. Mixed==/<=>with any integral and withByteSizeare hidden friends son == 5is not ambiguous. A negative integer operand is undefined andasserts when assertions are on. Overflow wraps in release.operator CString/operator WCStringprint the raw count (atoistyle). Explicit instantiations of the templates live in the StormByte DLL. Covered bySizeTests. - ByteSize — octet length (
uint64_tstorage), same width on every host and safe across a DLL. Implicit conversion only tostd::size_t(clamp); every other integral destination isexplicit. NoValue(), nooperator bool. Area products (ByteSize * ByteSize) are deleted. Scaling bySizeor by an integer is allowed and yieldsByteSize. Mixed==/<=>with any integral and withSize. IEC factories and free constants (B,KiB,MiB,GiB,TiB,PiB,EiB) so1 * KiBandByteSize::KiB(1)are 1024 octets. SI (KB…EB) likewise.operator CString/operator WCStringprint IEC text (0 B,1023 B,1.00 KiB,1.50 MiB). Explicit instantiations live in the StormByte DLL. Covered byByteSizeTests.
Changed
- License change — original source in this repository is dual-licensed: GNU LGPL v3 or later, or a commercial license from the copyright holder. The grant applies only to original StormByte source in this repository. It does not cover other StormByte modules or third-party material (including
thirdparty/). No patent rights are granted. - Visibility —
STORMBYTE_PUBLICcomes first on a function declaration (STORMBYTE_PUBLIC CString Foo();). clang-cl rejects__declspecafter a reference return.class STORMBYTE_PUBLICstays on the type. Exported templates are declaredextern template STORMBYTE_PUBLIC/extern template class STORMBYTE_PUBLICin the header and instantiated in the.cxxwithSTORMBYTE_INSTANTIATE(dllexporton Windows, empty on ELF so GCC does not warn-Wattributes). Theexternline in the header is what ELF uses to export; do not putSTORMBYTE_INSTANTIATEon that line. - Breaking: Exception.
StormByte::Componentis gone.what()isStormByte: <message>, orStormByte.<path>: <message>when a parent passes the segments underStormByte(Crypto.Crypter), joined with.. A parent passesException::Path(astd::string_viewof its segments) and forwards the format and the arguments. A bare string is not a path, because that is ambiguous with the format constructor. It does not format.Exceptioncallsstd::formatin the caller's translation unit and copies aconst char*into aCString. The view is not stored and nostd::stringenters the DLL. A final leaf inherits the parent constructors and adds no segment. A literal with no arguments is the message as-is.DeserializeError,OutOfBoundsErrorandBase64Errorare leaves of the root (StormByte: …). Each of those types, and the root, defines its destructor in Base's.cxxso thetypeinfois unique across a DLL. Named types in other modules do the same. - Expected — the error is a
Shared<E>, not astd::shared_ptrbuilt withstd::make_shared.UnexpectedusesHeap::MakeShared, orShared::MakePointerfor a derived error. The call staysUnexpected<E>("… {}", args…). Formatting runs in the caller;Eis constructed from the resulting string.Unexpected(result.error())forwards thatSharedand does not allocate.Shared<E>converts tostd::shared_ptr<E>. Astd::shared_ptris not accepted.Expected<T, E>is stillstd::expected. Covered byExpectedTests. - Breaking:
Clonable— polymorphicClone/Move. It is not an owner:MakePointerforwards toShared::MakePointerorUnique::MakePointer, which allocate the object and theshared_ptrcontrol block on Base's heap (Heap::Allocate/Heap::Freein a private TU that is not installed).Clonable<T>isClonable<T, Shared<T>>. Unique ownership isClonable<T, Unique<T>>.Clonable<T, std::shared_ptr<T>>andClonable<T, std::unique_ptr<T>>no longer compile.PointerTypeisShared<T>/Unique<T>; overrides that already returnPointerTypefromMakePointerdo not change. After construction,Sharedconverts implicitly tostd::shared_ptr<T>so existingshared_ptrcall sites keep working.Uniquedoes not convert tostd::unique_ptr<T>.ValidSmartPointerusesType::SameAs. Covered byClonableTests. - Type::String — also matches
StormByte::String::StringandStormByte::String::WString(forward-declared in Base). They stay out ofType::Container. - Type::Sized —
size()may be implicitly convertible tostd::size_t(STL containers) or beStormByte::Size/StormByte::ByteSize. Covered byTypeTraitsTests. - Type::Numeral — also matches
StormByte::SizeandStormByte::ByteSize. - Type::Array — StormByte flavor of a fixed-size sequence;
Serializableuses it instead of stockstd::is_same/tuple_sizeprobes.BinaryDatais not an array. - GenerateUUIDv4 — returns
CStringinstead ofstd::string. - Base64Encode — both overloads return
CStringinstead ofstd::string. Base64Decode returnsBinaryDataand still takesstd::string_view. - Size vs ByteSize everywhere — public Base APIs no longer take or return a raw
std::size_t/std::uint64_twhen the value is a count. Character counts (CString::Length,WCString::Length, subscripts) areSize. Octet counts (BinaryData::size/operator[]/ ctors /Serializable<T>::Size, wire lengths) areByteSize. Mixed arithmetic and comparison stay typed: aSizeresult stays aSize; aByteSizeresult stays aByteSize. - Serializable — container and string codecs use
ByteSizefor the on-wire length. Concepts used to branch (Type::Array,Type::Container,Type::String,Type::Numeral) are StormByte flavor, not stockstd::*traits. - Tests — suite section headers (
// -------------------) match in the body and inmain. UUID, Base64, Bitmask, Clonable, Exception, Expected, ThreadLock, TestHandlers, Iterable, Serialization, SafePointers, TypeTraits, Size, ByteSize and BinaryData cover the public surface (format, padding, invalid input, clone independence, non-owner unlock, bounds, wire, corruption, units,*///%,<algorithm>/ ranges / iterators,HexDumpcolumns, span comparison,operator+=, IEC text).Type::Sizedcovers a container whosesize()returnsStormByte::SizeorStormByte::ByteSize.Base64Decodeof an encode result uses an explicitstd::string_view.SerializationTestscoverBinaryDataroundtrip, the same wire asstd::vector<std::byte>, truncation, a huge size field, bit-flip / byte-overwrite / random corruption, trailing garbage andstd::optional<BinaryData>.
Removed
- String (
StormByte::Stringhelpers,string.hxx/string.cxx) — leaves Base. Helpers move to a new StormByte-String library. - System (
StormByte::Systemin Base:TempFileName,CurrentPath,ExecutablePath,Sleep) — leaves Base. Absorbed by the existing StormByte-System module. - UTF8Error / SystemError — leave Base with String and System. Derived exceptions that remain are
DeserializeError,OutOfBoundsErrorandBase64Error. - CoreApiTests — coverage lives in
ClonableTestsandErrorTests.
Fixed
FindStormByte.BufferpullsLogger,StringandSystem.LoggerandSystempullString.DatabasepullsLoggerandString.Crypto,MultimediaandNetworkname onlyBuffer; the closure still findsLogger,StringandSystem.ConfigandStringstill link only the core.ByteSize/Size. The integer constructors stay in the header. GCC does not emit aconstexprconstructor that is both anextern templateand an explicit instantiation, soSizeTestscrashed andByteSize(unsigned long long)was missing from the shared library. The operators are still one copy in the DLL.++/--build the step with the private constructor, so they do not instantiateunsigned intearly.Size/ByteSizetostd::string. The conversion callsoperator CString()by name. On GCC,static_cast<CString>picksCString(std::string)and that calls the same operator again until the stack dies.CString/WCString. Each constructs from the other. Narrow text is UTF-8.ByteSize's wide form uses that conversion.swprintfand%sis a narrow string on glibc and a wide string on the Windows CRT, so1.00 KiBdid not match.- Caller containers.
CString::operator std::string,WCString::operator std::wstring,Size/ByteSizeoperator std::string, theiroperator<<, andBinaryData::operator std::vectorareSTORMBYTE_FORCE_INLINE. On an exported class,inlinecan still be a call into the DLL, so the container was allocated here and freed by the caller. The vector operators were out of line; they now copy throughspan()in the caller, thenclear()on Base's heap.