Generated reference › API — ICoreEssentials/Text
kind: generated#api#icoreessentials-text

API — ICoreEssentials/Text

The public contract of 8 header(s) under src/ICoreEssentials/Text — 8 class/struct definition(s), 417 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreByteArray.h#

src/ICoreEssentials/Text/ICoreByteArray.h

ICoreByteArray#

ICoreByteArray.h:64 · class · 105 declaration(s)

ICoreByteArray -- the project's own byte buffer.

class ICoreByteArray {
public:
    using value_type     = char;
    using iterator       = QByteArray::iterator;
    using const_iterator = QByteArray::const_iterator;

    // Task Q4.6 re-pointed these at the project's own value-pinned enums
    // (Text/ICoreTextEnums.h). A call site spelling ICoreByteArray::
    // Base64UrlEncoding is untouched -- see the constants below, which did not
    // exist before and are what makes the alias usable without naming Qt.
    using Base64Option  = ICoreBase64Option;
    using Base64Options = ICoreBase64Options;

    static constexpr Base64Option Base64Encoding              = ICoreBase64Option::Base64Encoding;
    static constexpr Base64Option Base64UrlEncoding           = ICoreBase64Option::Base64UrlEncoding;
    static constexpr Base64Option KeepTrailingEquals          = ICoreBase64Option::KeepTrailingEquals;
    static constexpr Base64Option OmitTrailingEquals          = ICoreBase64Option::OmitTrailingEquals;
    static constexpr Base64Option IgnoreBase64DecodingErrors  = ICoreBase64Option::IgnoreBase64DecodingErrors;
    static constexpr Base64Option AbortOnBase64DecodingErrors = ICoreBase64Option::AbortOnBase64DecodingErrors;

    // --- construction ------------------------------------------------------
    // The storage: one QByteArray, measured at 24 bytes / align 8 on this
    // tree's Qt 6.10.2 -- a QArrayDataPointer, not a single d-pointer. Pinned
    // by static_asserts in the .cpp.
    static constexpr std::size_t kNativeStorageSize  = 24;
    static constexpr std::size_t kNativeStorageAlign = 8;

    // ⚠ NONE OF THESE CAN BE `= default` ANY MORE -- a defaulted special member
    // would copy the raw bytes of the buffer and never touch the refcount.
    ICoreByteArray();
    ICoreByteArray(const ICoreByteArray&);
    ICoreByteArray(ICoreByteArray&&) noexcept;
    ICoreByteArray& operator=(const ICoreByteArray&);
    ICoreByteArray& operator=(ICoreByteArray&&) noexcept;
    ~ICoreByteArray();

    // Implicit on purpose -- see the note at the top of the file.
    ICoreByteArray(const QByteArray& b);
    ICoreByteArray(QByteArray&& b) noexcept;
    ICoreByteArray(const char* s);
    ICoreByteArray(const char* s, qsizetype n);
    ICoreByteArray(qsizetype n, char fill);

    // --- named constructors ------------------------------------------------
    static ICoreByteArray fromStdString(const std::string& s);
    static ICoreByteArray fromBase64(const ICoreByteArray& b);
    static ICoreByteArray fromHex(const ICoreByteArray& b);
    static ICoreByteArray fromRawData(const char* s, qsizetype n);

    static ICoreByteArray number(int n, int base = 10);
    static ICoreByteArray number(uint n, int base = 10);
    static ICoreByteArray number(long n, int base = 10);
    static ICoreByteArray number(ulong n, int base = 10);
    static ICoreByteArray number(qlonglong n, int base = 10);
    static ICoreByteArray number(qulonglong n, int base = 10);
    static ICoreByteArray number(double n, char format = 'g', int precision = 6);

    // --- interop with the Qt backing store ---------------------------------
    operator const QByteArray&() const noexcept;
    const QByteArray& toQByteArray() const noexcept;

    // --- size and state ----------------------------------------------------
    bool isEmpty() const noexcept;
    bool isNull() const noexcept;
    qsizetype size() const noexcept;
    qsizetype length() const noexcept;
    void clear();
    void resize(qsizetype n);
    void reserve(qsizetype n);
    void squeeze();
    void truncate(qsizetype n);
    void chop(qsizetype n);
    ICoreByteArray& fill(char c, qsizetype n = -1);

    // --- element access ----------------------------------------------------
    char at(qsizetype i) const;
    char operator[](qsizetype i) const;
    char& operator[](qsizetype i);
    char front() const;
    char back() const;
    char* data() noexcept;
    const char* data() const noexcept;
    const char* constData() const noexcept;

    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;
    const_iterator cbegin() const;
    const_iterator cend() const;
    const_iterator constBegin() const;
    const_iterator constEnd() const;

    // --- non-mutating transforms -------------------------------------------
    ICoreByteArray trimmed() const;
    ICoreByteArray simplified() const;
    ICoreByteArray toLower() const;
    ICoreByteArray toUpper() const;
    ICoreByteArray left(qsizetype n) const;
    ICoreByteArray right(qsizetype n) const;
    ICoreByteArray mid(qsizetype pos, qsizetype n = -1) const;
    ICoreByteArray sliced(qsizetype pos) const;
    ICoreByteArray sliced(qsizetype pos, qsizetype n) const;
    ICoreByteArray chopped(qsizetype n) const;
    ICoreByteArray first(qsizetype n) const;
    ICoreByteArray last(qsizetype n) const;
    ICoreByteArray repeated(qsizetype times) const;
    ICoreByteArray toBase64(Base64Options options = ICoreBase64Option::Base64Encoding) const;
    ICoreByteArray toHex(char separator = '\0') const;
    ICoreByteArray toPercentEncoding() const;

    // H8: a container of the wrapper is not a container of the Qt
    // type, so this returns QList<ICoreByteArray> and the mechanical rename of
    // the call site's declaration lands on the same type.
    QList<ICoreByteArray> split(char sep) const;

    // --- mutating ----------------------------------------------------------
    //
    // ⚠ H11: every member below that is overloaded on BOTH
    // `const ICoreByteArray&` and `const char*` needs a third overload taking
    // `const QByteArray&`, and it is not redundant. QByteArray declares an
    // implicit `operator const char*()` (it is only suppressed by
    // QT_NO_CAST_FROM_BYTEARRAY, which this project does not define), so a
    // plain QByteArray argument -- one still coming out of Qt, or out of a
    // wrapper whose phase-1 signature has not been narrowed yet -- converts
    // equally well to both, and the call is ambiguous. `m_sseBuffer.append(
    // m_reply->readAll())` in ICoreLLMBackend.cpp is where it was found.
    // The QByteArray overload is an exact match on the reference and settles
    // it. This is H5's mechanism seen from the other side: there a QT method
    // went ambiguous for OUR argument, here OUR method goes ambiguous for a
    // Qt argument.
    ICoreByteArray& append(const ICoreByteArray& b);
    ICoreByteArray& append(const char* s);
    ICoreByteArray& append(char c);
    ICoreByteArray& prepend(const ICoreByteArray& b);
    ICoreByteArray& prepend(const char* s);
    ICoreByteArray& prepend(char c);
    ICoreByteArray& insert(qsizetype i, const ICoreByteArray& b);
    ICoreByteArray& remove(qsizetype pos, qsizetype n);
    ICoreByteArray& replace(const ICoreByteArray& before, const ICoreByteArray& after);
    ICoreByteArray& replace(const char* before, const ICoreByteArray& after);
    ICoreByteArray& replace(char before, char after);

    // --- searching ---------------------------------------------------------
    // Each of these carries the QByteArray overload for H11's reason -- see
    // the note above append().
    bool contains(const ICoreByteArray& b) const;
    bool contains(const char* s) const;
    bool contains(char c) const;
    bool startsWith(const ICoreByteArray& b) const;
    bool startsWith(const char* s) const;
    bool startsWith(char c) const;
    bool endsWith(const ICoreByteArray& b) const;
    bool endsWith(const char* s) const;
    bool endsWith(char c) const;
    qsizetype indexOf(const ICoreByteArray& b, qsizetype from = 0) const;
    qsizetype indexOf(const char* s, qsizetype from = 0) const;
    qsizetype indexOf(char c, qsizetype from = 0) const;
    qsizetype lastIndexOf(const ICoreByteArray& b) const;
    qsizetype lastIndexOf(char c) const;
    qsizetype count() const noexcept;
    qsizetype count(char c) const;

    // --- conversions out ---------------------------------------------------
    std::string toStdString() const;
    int toInt(bool* ok = nullptr, int base = 10) const;
    uint toUInt(bool* ok = nullptr, int base = 10) const;
    qlonglong toLongLong(bool* ok = nullptr, int base = 10) const;
    qulonglong toULongLong(bool* ok = nullptr, int base = 10) const;
    double toDouble(bool* ok = nullptr) const;
    float toFloat(bool* ok = nullptr) const;

    // --- compound assignment -----------------------------------------------
    ICoreByteArray& operator+=(const ICoreByteArray& b);
    ICoreByteArray& operator+=(const QByteArray& b);
    ICoreByteArray& operator+=(const char* s);
    ICoreByteArray& operator+=(char c);

};

ICoreChar.h#

src/ICoreEssentials/Text/ICoreChar.h

ICoreChar#

ICoreChar.h:48 · class · 20 declaration(s)

ICoreChar -- the project's own character.

class ICoreChar {
public:
    // ⚠ MEASURED: QChar is 2 bytes / align 2, TRIVIALLY COPYABLE and TRIVIALLY
    // DESTRUCTIBLE on this tree's Qt 6.10.2. Both of those matter here in a way
    // they did not for ICoreString:
    //
    //  * Trivially copyable means the implicit copy and move -- a two-byte
    //    memcpy of the buffer -- are CORRECT, so this type declares none of the
    //    five and stays trivially copyable itself. That is load-bearing: an
    //    ICoreChar is passed BY VALUE in ICoreString's signatures and in every
    //    operator below, and a user-declared copy constructor would move it out
    //    of a register and into memory at every one of those call sites.
    //  * Trivially destructible means no destructor is needed either.
    //
    // So only the three CONSTRUCTORS have bodies to move, and they are the only
    // members that touch the buffer through placement new. The .cpp pins all
    // four properties with static_asserts.
    static constexpr std::size_t kNativeStorageSize  = 2;
    static constexpr std::size_t kNativeStorageAlign = 2;

    // --- construction ------------------------------------------------------
    ICoreChar();
    // Implicit on purpose -- see the first design note.
    ICoreChar(QChar c) noexcept;
    // EXPLICIT, and it has to stay explicit -- plan §6 H4, the same rule that
    // makes ICoreString(QLatin1String) explicit and for the identical reason.
    // Qt already converts QLatin1Char to QChar implicitly, so an implicit one
    // here would give `qLatin1Char == qChar` two candidates each costing one
    // user-defined conversion (Qt's operator==(QChar, QChar) and our
    // operator==(ICoreChar, QChar)) and tie them -- in unmigrated files that
    // name neither ICoreChar nor this refactor. The five call sites that pass
    // a QLatin1Char to an ICoreChar parameter therefore spell it out; B20
    // absorbs QLatin1Char and retires them.
    explicit ICoreChar(QLatin1Char c) noexcept;

    // --- interop with the Qt backing store ---------------------------------
    operator QChar() const noexcept;
    QChar toQChar() const noexcept;

    // --- classification ----------------------------------------------------
    bool isNull() const noexcept;
    bool isDigit() const noexcept;
    bool isLetter() const noexcept;
    bool isLetterOrNumber() const noexcept;
    bool isNumber() const noexcept;
    bool isSpace() const noexcept;
    bool isPunct() const noexcept;
    bool isUpper() const noexcept;
    bool isLower() const noexcept;
    bool isPrint() const noexcept;

    // --- case --------------------------------------------------------------
    ICoreChar toUpper() const noexcept;
    ICoreChar toLower() const noexcept;

    // --- value -------------------------------------------------------------
    char16_t unicode() const noexcept;
    char toLatin1() const noexcept;
    int digitValue() const noexcept;

};

ICoreLocale.h#

src/ICoreEssentials/Text/ICoreLocale.h

ICoreLocale#

ICoreLocale.h:101 · class · 2 declaration(s)

ICoreLocale -- locale-aware number parsing.

class ICoreLocale {
public:
    // The invariant "C" locale: '.' decimal separator, no group separator.
    [[nodiscard]] static ICoreLocale c();

    // Parse a decimal number. `ok` is set false when `s` is not a complete,
    // valid, FINITE number -- callers rely on that to reject partial input
    // rather than silently taking the 0.0 that a failed parse also returns.
    // See the equivalence note above for what "complete" and "finite" mean and
    // where they differ from the QLocale version this replaced.
    double toDouble(const ICoreString& s, bool* ok = nullptr) const;

};

ICoreRegex.h#

src/ICoreEssentials/Text/ICoreRegex.h

ICoreRegexMatch#

ICoreRegex.h:81 · class · 17 declaration(s)

ICoreRegex / ICoreRegexMatch / ICoreRegexMatchIterator -- the project's own regular expressions.

class ICoreRegexMatch {
public:
    // One QRegularExpressionMatch, pinned by static_asserts in the .cpp.
    static constexpr std::size_t kNativeStorageSize  = 8;
    static constexpr std::size_t kNativeStorageAlign = 8;

    ICoreRegexMatch();
    ICoreRegexMatch(const QRegularExpressionMatch& m);
    ICoreRegexMatch(const ICoreRegexMatch& other);
    ICoreRegexMatch(ICoreRegexMatch&& other) noexcept;
    ICoreRegexMatch& operator=(const ICoreRegexMatch& other);
    ICoreRegexMatch& operator=(ICoreRegexMatch&& other) noexcept;
    ~ICoreRegexMatch();

    operator const QRegularExpressionMatch&() const noexcept;

    bool hasMatch() const;
    bool hasPartialMatch() const;
    bool isValid() const;

    ICoreString captured(qsizetype n = 0) const;
    ICoreString captured(const ICoreString& name) const;
    ICoreStringList capturedTexts() const;
    qsizetype capturedStart(qsizetype n = 0) const;
    qsizetype capturedEnd(qsizetype n = 0) const;
    qsizetype capturedLength(qsizetype n = 0) const;
    qsizetype lastCapturedIndex() const;

};

ICoreRegexMatchIterator#

ICoreRegex.h:113 · class · 11 declaration(s)

class ICoreRegexMatchIterator {
public:
    // One QRegularExpressionMatchIterator, pinned by static_asserts in the .cpp.
    static constexpr std::size_t kNativeStorageSize  = 8;
    static constexpr std::size_t kNativeStorageAlign = 8;

    ICoreRegexMatchIterator();
    ICoreRegexMatchIterator(const QRegularExpressionMatchIterator& it);
    ICoreRegexMatchIterator(const ICoreRegexMatchIterator& other);
    ICoreRegexMatchIterator(ICoreRegexMatchIterator&& other) noexcept;
    ICoreRegexMatchIterator& operator=(const ICoreRegexMatchIterator& other);
    ICoreRegexMatchIterator& operator=(ICoreRegexMatchIterator&& other) noexcept;
    ~ICoreRegexMatchIterator();

    bool isValid() const;
    bool hasNext() const;
    ICoreRegexMatch next();
    ICoreRegexMatch peekNext() const;

};

ICoreRegex#

ICoreRegex.h:136 · class · 21 declaration(s)

class ICoreRegex {
public:
    // Enum aliases. They USED to point at Qt's enums, so that the mechanical
    // rename did not have to special-case a qualified enumerator; task Q0.4
    // re-pointed them at the project's own value-pinned enums in
    // ICoreTextEnums.h. Both halves of that still hold -- a call site that
    // writes ICoreRegex::CaseInsensitiveOption compiles unchanged -- but the
    // parameter lists below no longer name a Qt type, which is the point.
    using PatternOption  = ICoreRegexPatternOption;
    using PatternOptions = ICoreRegexPatternOptions;
    using MatchType      = ICoreRegexMatchType;
    using MatchOption    = ICoreRegexMatchOption;
    using MatchOptions   = ICoreRegexMatchOptions;

    static constexpr PatternOption NoPatternOption            = ICoreRegexPatternOption::NoPatternOption;
    static constexpr PatternOption CaseInsensitiveOption      = ICoreRegexPatternOption::CaseInsensitiveOption;
    static constexpr PatternOption DotMatchesEverythingOption = ICoreRegexPatternOption::DotMatchesEverythingOption;
    static constexpr PatternOption MultilineOption            = ICoreRegexPatternOption::MultilineOption;
    static constexpr PatternOption ExtendedPatternSyntaxOption = ICoreRegexPatternOption::ExtendedPatternSyntaxOption;
    static constexpr PatternOption InvertedGreedinessOption   = ICoreRegexPatternOption::InvertedGreedinessOption;
    static constexpr PatternOption DontCaptureOption          = ICoreRegexPatternOption::DontCaptureOption;
    static constexpr PatternOption UseUnicodePropertiesOption = ICoreRegexPatternOption::UseUnicodePropertiesOption;

    static constexpr MatchType NormalMatch          = ICoreRegexMatchType::NormalMatch;
    static constexpr MatchType PartialPreferCompleteMatch = ICoreRegexMatchType::PartialPreferCompleteMatch;
    static constexpr MatchType PartialPreferFirstMatch    = ICoreRegexMatchType::PartialPreferFirstMatch;
    static constexpr MatchType NoMatch              = ICoreRegexMatchType::NoMatch;

    static constexpr MatchOption NoMatchOption        = ICoreRegexMatchOption::NoMatchOption;
    static constexpr MatchOption AnchorAtOffsetMatchOption = ICoreRegexMatchOption::AnchorAtOffsetMatchOption;
    static constexpr MatchOption DontCheckSubjectStringMatchOption = ICoreRegexMatchOption::DontCheckSubjectStringMatchOption;

    // One QRegularExpression, pinned by static_asserts in the .cpp.
    static constexpr std::size_t kNativeStorageSize  = 8;
    static constexpr std::size_t kNativeStorageAlign = 8;

    // --- construction ------------------------------------------------------
    ICoreRegex();
    // EXPLICIT, mirroring QRegularExpression's own explicit string constructor
    // -- see the second design note. This is not the H4 rule; it is Qt's rule.
    explicit ICoreRegex(const ICoreString& pattern, PatternOptions options = ICoreRegexPatternOption::NoPatternOption);
    ICoreRegex(const QRegularExpression& re);
    ICoreRegex(const ICoreRegex& other);
    ICoreRegex(ICoreRegex&& other) noexcept;
    ICoreRegex& operator=(const ICoreRegex& other);
    ICoreRegex& operator=(ICoreRegex&& other) noexcept;
    ~ICoreRegex();

    // --- interop with the Qt backing store ---------------------------------
    operator const QRegularExpression&() const noexcept;

    // --- pattern -----------------------------------------------------------
    ICoreString pattern() const;
    void setPattern(const ICoreString& pattern);
    PatternOptions patternOptions() const;
    void setPatternOptions(PatternOptions options);

    bool isValid() const;
    ICoreString errorString() const;
    qsizetype patternErrorOffset() const;
    int captureCount() const;
    ICoreStringList namedCaptureGroups() const;

    // --- matching ----------------------------------------------------------
    ICoreRegexMatch match(const ICoreString& subject,
                          qsizetype offset = 0,
                          MatchType type = ICoreRegexMatchType::NormalMatch,
                          MatchOptions options = ICoreRegexMatchOption::NoMatchOption) const;
    ICoreRegexMatchIterator globalMatch(const ICoreString& subject,
                                        qsizetype offset = 0,
                                        MatchType type = ICoreRegexMatchType::NormalMatch,
                                        MatchOptions options = ICoreRegexMatchOption::NoMatchOption) const;

    // --- statics -----------------------------------------------------------
    static ICoreString escape(const ICoreString& s);
    // A single character is the shape ICoreParityBlockFilter's wildcard builder
    // needs, and it cannot reach the overload above: ICoreChar -> QChar ->
    // ICoreString is two user-defined conversions. A static member joins no Qt
    // overload set (A14's rule), so this is free of H4 exposure.
    static ICoreString escape(ICoreChar c);
    static ICoreString anchoredPattern(const ICoreString& s);
    static ICoreString wildcardToRegularExpression(const ICoreString& s);

};

ICoreString.h#

src/ICoreEssentials/Text/ICoreString.h

ICoreString#

ICoreString.h:116 · class · 146 declaration(s)

class ICoreString {
public:
    using value_type     = QChar;
    using iterator       = QString::iterator;
    using const_iterator = QString::const_iterator;

    // Enum aliases. These exist so the mechanical `QString` -> `ICoreString`
    // rename does not have to special-case qualified enum names: a call site
    // written QString::SectionSkipEmpty becomes ICoreString::SectionSkipEmpty
    // and still compiles.
    //
    // Task Q4.4 re-pointed all five families at the project's own value-pinned
    // enums (Text/ICoreTextEnums.h). Every call site that spells one of the
    // constants below is untouched by that -- the ~34 sites writing
    // ICoreString::CaseInsensitive or ICoreString::SkipEmptyParts still
    // compile, and now they no longer resolve to a Qt type.
    using SectionFlag       = ICoreSectionFlag;
    using SectionFlags      = ICoreSectionFlags;
    using NormalizationForm = ICoreNormalizationForm;
    static constexpr SectionFlag SectionDefault              = ICoreSectionFlag::Default;
    static constexpr SectionFlag SectionSkipEmpty            = ICoreSectionFlag::SkipEmpty;
    static constexpr SectionFlag SectionIncludeLeadingSep    = ICoreSectionFlag::IncludeLeadingSep;
    static constexpr SectionFlag SectionIncludeTrailingSep   = ICoreSectionFlag::IncludeTrailingSep;
    static constexpr SectionFlag SectionCaseInsensitiveSeps  = ICoreSectionFlag::CaseInsensitiveSeps;
    static constexpr NormalizationForm NormalizationForm_D   = ICoreNormalizationForm::D;
    static constexpr NormalizationForm NormalizationForm_C   = ICoreNormalizationForm::C;
    static constexpr NormalizationForm NormalizationForm_KD  = ICoreNormalizationForm::KD;
    static constexpr NormalizationForm NormalizationForm_KC  = ICoreNormalizationForm::KC;

    // Same aliasing trick, for the two enums that searching/split members below
    // default to case-sensitive / keep-empty-parts. A call site that wants the
    // non-default value used to have to spell Qt:: itself; now it spells
    // ICoreString:: instead, same as every other enum on this type.
    using CaseSensitivity = ICoreCaseSensitivity;
    static constexpr CaseSensitivity CaseSensitive   = ICoreCaseSensitivity::Sensitive;
    static constexpr CaseSensitivity CaseInsensitive = ICoreCaseSensitivity::Insensitive;
    using SplitBehavior = ICoreSplitBehavior;
    static constexpr SplitBehavior KeepEmptyParts = ICoreSplitBehavior::KeepEmptyParts;
    static constexpr SplitBehavior SkipEmptyParts = ICoreSplitBehavior::SkipEmptyParts;

    // ⚠ MEASURED at 24 bytes / align 8 on this tree's Qt 6.10.2, macOS arm64 --
    // NOT one d-pointer. Qt 6's QString holds a QStringPrivate, which is three
    // words (the shared d, the data pointer and the size), where Qt 5's held a
    // single pointer. The first cut of this row assumed sizeof(void*) and the
    // static_assert in the .cpp caught it on the first build, which is exactly
    // what it is there for. See the buffer note at the top of the file for why
    // this is a buffer and not a heap Impl.
    static constexpr std::size_t kNativeStorageSize  = 24;
    static constexpr std::size_t kNativeStorageAlign = 8;

    // --- construction ------------------------------------------------------
    // ⚠ NONE OF THESE CAN BE `= default` ANY MORE. A defaulted special member
    // would copy the raw bytes of the buffer and never touch QString's
    // refcount; each one is written out in the .cpp, constructing or assigning
    // the QString in place. The move operations stay noexcept because QString's
    // are, and a moved-from ICoreString is a moved-from QString -- valid and
    // empty, exactly as before.
    ICoreString();
    ICoreString(const ICoreString&);
    ICoreString(ICoreString&&) noexcept;
    ICoreString& operator=(const ICoreString&);
    ICoreString& operator=(ICoreString&&) noexcept;
    ~ICoreString();

    // Implicit on purpose -- see the note at the top of the file.
    ICoreString(const QString& s);
    ICoreString(QString&& s) noexcept;
    ICoreString(const char* s);
    ICoreString(QChar c);
    // EXPLICIT, and it has to stay explicit. QLatin1String already converts
    // implicitly to QString, so an implicit ICoreString(QLatin1String) gives
    // every expression of the form `qstring + latin1` a second one-conversion
    // candidate (ours) that ties with Qt's, making it ambiguous -- in files
    // that have not been migrated and do not mention ICoreString at all.
    // That is how `builtInRoot + QLatin1Char('/') + QLatin1String(...)` in
    // ICoreTemplateLibrary.cpp broke. The comparison operators and the member
    // overloads below take QLatin1String directly, which covers the idiomatic
    // uses; anything else spells it ICoreString(QLatin1String(...)).
    explicit ICoreString(ICoreLatin1String s);
    explicit ICoreString(QStringView s);
    // EXPLICIT for the same reason QLatin1String is: Qt compares QString
    // against std::string through its own string-like overloads, and an
    // implicit ICoreString(std::string) adds a tying candidate that makes
    // `qstring == stdstring` ambiguous in unmigrated code -- it broke
    // ICoreGraphicsComboBoxDialog.cpp. Use ICoreString::fromStdString(s),
    // which is what the codebase already writes 551 times.
    explicit ICoreString(const std::string& s);
    ICoreString(qsizetype size, ICoreChar fill);

    // --- named constructors ------------------------------------------------
    static ICoreString fromStdString(const std::string& s);
    static ICoreString fromStdWString(const std::wstring& s);
    static ICoreString fromUtf8(const QByteArray& b);
    static ICoreString fromUtf8(const char* s, qsizetype n = -1);
    static ICoreString fromLatin1(const QByteArray& b);
    static ICoreString fromLatin1(const char* s, qsizetype n = -1);
    static ICoreString fromLocal8Bit(const QByteArray& b);
    static ICoreString fromLocal8Bit(const char* s, qsizetype n = -1);
    static ICoreString fromUcs4(const char32_t* s, qsizetype n = -1);

    static ICoreString number(int n, int base = 10);
    static ICoreString number(uint n, int base = 10);
    static ICoreString number(long n, int base = 10);
    static ICoreString number(ulong n, int base = 10);
    static ICoreString number(qlonglong n, int base = 10);
    static ICoreString number(qulonglong n, int base = 10);
    static ICoreString number(double n, char format = 'g', int precision = 6);

    // --- interop with the Qt backing store ---------------------------------
    // Implicit both ways. toQString() is the explicit spelling for the places
    // where an implicit conversion would be ambiguous or unclear -- and since
    // H1.1 it is also the seam every body in the .cpp reads the storage
    // through, which is why no accessor had to be added anywhere.
    operator const QString&() const noexcept;
    operator QAnyStringView() const noexcept;

    // Conversions to the Qt "sink" types that take a QString implicitly.
    // Without these, `jsonObject["k"] = icoreString` and
    // `settings.setValue(k, icoreString)` do not compile at all -- reaching
    // QJsonValue or QVariant through operator const QString& would be two
    // user-defined conversions in one sequence, and the language allows one.
    // These are the single viable path, so they add no ambiguity. They are
    // also the honest statement of where Qt still owns the data model; phase 3
    // replaces the sinks themselves and these two lines go with them.
    operator QVariant() const;
    operator QJsonValue() const;
    const QString& toQString() const noexcept;
    QString& toQString() noexcept;

    // --- size and state ----------------------------------------------------
    bool isEmpty() const noexcept;
    bool isNull() const noexcept;
    qsizetype size() const noexcept;
    qsizetype length() const noexcept;
    void clear();
    void resize(qsizetype n);
    void resize(qsizetype n, ICoreChar fill);
    void reserve(qsizetype n);
    void squeeze();
    void truncate(qsizetype n);
    void chop(qsizetype n);
    ICoreString& fill(ICoreChar c, qsizetype n = -1);

    // --- element access ----------------------------------------------------
    QChar at(qsizetype i) const;
    QChar operator[](qsizetype i) const;
    QChar front() const;
    QChar back() const;
    // NO data(). It is deliberately absent — see H5 in the refactor plan.
    // data() plus size() is exactly QStringView's "compatible container"
    // recipe, so having it let QStringView be constructed from ICoreString in
    // one user-defined conversion. Every QString member overloaded on both
    // (const QString&) and (QStringView) — contains, startsWith, endsWith,
    // indexOf, compare, … — then had two equally-good candidates for an
    // ICoreString argument and became ambiguous. constData() and unicode()
    // give the same pointer under names std::data() does not find; use
    // toQString().data() for the mutable one.
    const QChar* constData() const noexcept;
    const QChar* unicode() const noexcept;

    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;
    const_iterator cbegin() const;
    const_iterator cend() const;
    const_iterator constBegin() const;
    const_iterator constEnd() const;

    // --- non-mutating transforms -------------------------------------------
    ICoreString trimmed() const;
    ICoreString simplified() const;
    ICoreString toLower() const;
    ICoreString toUpper() const;
    ICoreString left(qsizetype n) const;
    ICoreString right(qsizetype n) const;
    ICoreString mid(qsizetype pos, qsizetype n = -1) const;
    ICoreString sliced(qsizetype pos) const;
    ICoreString sliced(qsizetype pos, qsizetype n) const;
    ICoreString chopped(qsizetype n) const;
    ICoreString first(qsizetype n) const;
    ICoreString last(qsizetype n) const;
    ICoreString repeated(qsizetype times) const;
    ICoreString leftJustified(qsizetype width, ICoreChar fill = QChar(u' '), bool truncate = false) const;
    ICoreString rightJustified(qsizetype width, ICoreChar fill = QChar(u' '), bool truncate = false) const;
    ICoreString toHtmlEscaped() const;
    ICoreString normalized(ICoreNormalizationForm form) const;
    ICoreString section(ICoreChar sep, qsizetype start, qsizetype end = -1, ICoreSectionFlags flags = ICoreSectionFlag::Default) const;
    ICoreString section(const ICoreString& sep, qsizetype start, qsizetype end = -1, ICoreSectionFlags flags = ICoreSectionFlag::Default) const;

    // --- mutating -----------------------------------------------------------
    ICoreString& append(const ICoreString& s);
    ICoreString& append(ICoreChar c);
    ICoreString& append(const char* s);
    ICoreString& append(ICoreLatin1String s);
    ICoreString& prepend(const ICoreString& s);
    ICoreString& prepend(ICoreLatin1String s);
    ICoreString& prepend(ICoreChar c);
    ICoreString& insert(qsizetype i, const ICoreString& s);
    ICoreString& insert(qsizetype i, ICoreChar c);
    ICoreString& remove(qsizetype pos, qsizetype n);
    ICoreString& remove(ICoreChar c, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreString& remove(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    // Defined in ICoreString.cpp -- see the note above the class.
    ICoreString& remove(const ICoreRegex& re);
    ICoreString& replace(qsizetype pos, qsizetype n, const ICoreString& after);
    ICoreString& replace(ICoreChar before, ICoreChar after, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreString& replace(const ICoreString& before, const ICoreString& after, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreString& replace(ICoreLatin1String before, ICoreLatin1String after, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    // Replacing ONE character with a longer literal — escaping a quote as "''",
    // a backslash as "\\\\". QString has this overload and the M-code codec
    // (A14) is built on it; without it the call site has to materialise an
    // ICoreString temporary per replacement, because ICoreString(QLatin1String)
    // is explicit (H4). Safe to add for the same reason every QLatin1String
    // overload above is: the receiver is an ICoreString, so this joins no Qt
    // overload set and cannot tie against one (that was H5's mechanism).
    ICoreString& replace(ICoreChar before, ICoreLatin1String after, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreString& remove(ICoreLatin1String s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreString& replace(const ICoreRegex& re, const ICoreString& after);
    void push_back(ICoreChar c);
    void push_back(const ICoreString& s);

    // --- searching ----------------------------------------------------------
    bool contains(ICoreChar c, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool contains(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool contains(ICoreLatin1String s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool contains(const ICoreRegex& re) const;
    // The (re, QRegularExpressionMatch*) overload is GONE, not swapped. It was
    // a Qt-declared POINTER out-parameter, which no conversion operator reaches
    // and which ICoreRegexMatch deliberately offers no mutable accessor for
    // (see ICoreRegex.h's third design note). It had no call site in the tree,
    // so Rule 3 retires it rather than inventing an accessor to preserve it:
    // `re.match(s).hasMatch()` is the spelling, and it is what the tree already
    // writes. Same for the indexOf/lastIndexOf out-params below.
    bool startsWith(ICoreChar c, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool startsWith(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool startsWith(ICoreLatin1String s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool endsWith(ICoreChar c, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool endsWith(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool endsWith(ICoreLatin1String s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype indexOf(ICoreChar c, qsizetype from = 0, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype indexOf(const ICoreString& s, qsizetype from = 0, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype indexOf(const ICoreRegex& re, qsizetype from = 0) const;
    qsizetype lastIndexOf(ICoreChar c, qsizetype from = -1, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype lastIndexOf(const ICoreString& s, qsizetype from = -1, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype lastIndexOf(const ICoreRegex& re) const;
    qsizetype count() const noexcept;
    qsizetype count(ICoreChar c, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype count(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    int compare(const ICoreString& other, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    // Case-insensitive comparison against a literal, without building a
    // temporary — the shape `value.compare(ICoreLatin1String("inf"), ICoreString::CaseInsensitive)`.
    // Same rationale and same safety argument as the QChar/QLatin1String
    // replace() above, and it matches contains/startsWith/endsWith/remove,
    // which already carry a QLatin1String overload each.
    int compare(ICoreLatin1String other, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;

    // Phase 1 returns QStringList; see the header note. Phase 3 replaces it.
    QStringList split(ICoreChar sep, ICoreSplitBehavior behavior = ICoreSplitBehavior::KeepEmptyParts, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    QStringList split(const ICoreString& sep, ICoreSplitBehavior behavior = ICoreSplitBehavior::KeepEmptyParts, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    QStringList split(const ICoreRegex& re, ICoreSplitBehavior behavior = ICoreSplitBehavior::KeepEmptyParts) const;

    // --- conversions out ----------------------------------------------------
    std::string toStdString() const;
    std::wstring toStdWString() const;
    QByteArray toUtf8() const;
    QByteArray toLatin1() const;
    QByteArray toLocal8Bit() const;
    int toInt(bool* ok = nullptr, int base = 10) const;
    uint toUInt(bool* ok = nullptr, int base = 10) const;
    short toShort(bool* ok = nullptr, int base = 10) const;
    ushort toUShort(bool* ok = nullptr, int base = 10) const;
    long toLong(bool* ok = nullptr, int base = 10) const;
    ulong toULong(bool* ok = nullptr, int base = 10) const;
    qlonglong toLongLong(bool* ok = nullptr, int base = 10) const;
    qulonglong toULongLong(bool* ok = nullptr, int base = 10) const;
    double toDouble(bool* ok = nullptr) const;
    float toFloat(bool* ok = nullptr) const;

    // --- formatting ---------------------------------------------------------
    // Forwards every argument to QString::arg, unwrapping ICoreString on the
    // way so both the single-argument overloads and the variadic one apply.
    //
    // ⚠ THIS ONE STAYS IN THE HEADER, and it is exemption 1, not an oversight:
    // a member template's body has to be visible where it is instantiated.
    // What DID change is that it no longer touches the storage -- it goes
    // through the public toQString(), so the buffer stays private to the .cpp.
    // It is also why this row banks 141->1 rather than 141->0; the guard's
    // template exemption is class-scoped, so a member template of a plain class
    // is always counted. Same shape as H2.22 (ICoreLog).
    template <typename... Args>
    ICoreString arg(Args&&... args) const
    {
        return ICoreString(toQString().arg(ICoreDetail::argAdapt(std::forward<Args>(args))...));
    }

    // --- compound assignment -------------------------------------------------
    ICoreString& operator+=(const ICoreString& s);
    ICoreString& operator+=(const QString& s);
    ICoreString& operator+=(const char* s);
    ICoreString& operator+=(ICoreChar c);
    ICoreString& operator+=(ICoreLatin1String s);

};

ICoreStringList.h#

src/ICoreEssentials/Text/ICoreStringList.h

ICoreStringList -- the project's own list of strings.

PHASE 1 (current): a thin value wrapper around QStringList. Every operation forwards.

⚠ THE BODIES ARE IN ICoreStringList.cpp (H1.3, 2026-08-14), and the storage is an OPAQUE BUFFER rather than a heap Impl, for the same reason ICoreString carries one: this is a value that crosses into Qt at ~100 boundaries and is copied at every one of them. QStringList measured 24 bytes / align 8 on this tree's Qt 6.10.2 -- a QArrayDataPointer, not a single d-pointer -- and the .cpp pins that with static_asserts.

DESIGN NOTES (load-bearing -- read before changing anything):

ICoreStringList#

ICoreStringList.h:85 · class · 95 declaration(s)

class ICoreStringList {
public:
    using value_type     = QString;
    using iterator       = QStringList::iterator;
    using const_iterator = QStringList::const_iterator;

    // Same alias trick as ICoreString (see its header note): contains()/sort()
    // below default to case-sensitive, so a call site that wants the
    // case-insensitive value spells ICoreStringList:: instead of naming Qt::.
    using CaseSensitivity = ICoreCaseSensitivity;
    static constexpr CaseSensitivity CaseSensitive   = ICoreCaseSensitivity::Sensitive;
    static constexpr CaseSensitivity CaseInsensitive = ICoreCaseSensitivity::Insensitive;

    // The storage. See the buffer note at the top of the file.
    static constexpr std::size_t kNativeStorageSize  = 24;
    static constexpr std::size_t kNativeStorageAlign = 8;

    // --- construction ------------------------------------------------------
    // ⚠ NONE OF THESE CAN BE `= default` ANY MORE -- a defaulted special member
    // would copy the raw bytes of the buffer and never touch the QStringList's
    // refcount. All six are written out in the .cpp.
    ICoreStringList();
    ICoreStringList(const ICoreStringList&);
    ICoreStringList(ICoreStringList&&) noexcept;
    ICoreStringList& operator=(const ICoreStringList&);
    ICoreStringList& operator=(ICoreStringList&&) noexcept;
    ~ICoreStringList();

    // Implicit on purpose -- QStringList arrives from Qt at ~100 boundaries.
    ICoreStringList(const QStringList& l);
    ICoreStringList(QStringList&& l) noexcept;
    ICoreStringList(const ICoreString& s);
    ICoreStringList(std::initializer_list<ICoreString> items);
    // Iterator pair, for building a list out of a set. RunnerSuites drains a
    // QSet<ICoreString> this way before sorting it; the element type there is
    // the wrapper, not QString, so the loop unwraps rather than copies through.
    //
    // ⚠ THIS ONE STAYS IN THE HEADER -- it is a constructor TEMPLATE, so its
    // body must be visible where it is instantiated (exemption 1). What changed
    // is that it no longer touches the storage: it delegates to the default
    // constructor and appends through the PUBLIC append(), which does exactly
    // what the old body did by hand. That is the narrowing answer -- no
    // accessor was added to reach the buffer from here.
    template <typename It>
    ICoreStringList(It first_, It last_) : ICoreStringList()
    {
        for (It it = first_; it != last_; ++it) append(ICoreString(*it));
    }
    // H8: QHash<ICoreString, T>::keys() hands back QList<ICoreString>,
    // which is not a QStringList and which Qt will not convert. A16 worked
    // around it by retyping the local and sorting by hand; with this
    // constructor the retyping is no longer needed.
    explicit ICoreStringList(const QList<ICoreString>& items);

    // --- interop with the Qt backing store ---------------------------------
    operator const QStringList&() const noexcept;
    const QStringList& toQStringList() const noexcept;

    // --- size and state ----------------------------------------------------
    bool isEmpty() const noexcept;
    qsizetype size() const noexcept;
    qsizetype count() const noexcept;
    qsizetype length() const noexcept;
    void clear();
    void reserve(qsizetype n);
    void resize(qsizetype n);
    void squeeze();

    // --- element access ----------------------------------------------------
    // These return QString& / const QString& rather than the wrapper, for the
    // reason in the header note: the store is a QStringList and handing back a
    // reference to a wrapper it does not contain is not possible. Call sites
    // that want the wrapper get it by assignment, which converts.
    const QString& at(qsizetype i) const;
    QString& operator[](qsizetype i);
    const QString& operator[](qsizetype i) const;
    QString& first();
    const QString& first() const;
    QString& last();
    const QString& last() const;
    const QString& constFirst() const;
    const QString& constLast() const;
    QString& front();
    const QString& front() const;
    QString& back();
    const QString& back() const;
    ICoreString value(qsizetype i) const;
    ICoreString value(qsizetype i, const ICoreString& fallback) const;

    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;
    const_iterator cbegin() const;
    const_iterator cend() const;
    const_iterator constBegin() const;
    const_iterator constEnd() const;
    // ⚠ SPELLED OUT, where they said `auto` before. A function with a DEDUCED
    // return type cannot have its body in a .cpp: a caller in another TU has
    // only the declaration and has nothing to deduce from. The deduced type was
    // always exactly these, so no call site changes -- every one spells `auto`
    // on its own side.
    QStringList::reverse_iterator rbegin();
    QStringList::reverse_iterator rend();
    QStringList::const_reverse_iterator rbegin() const;
    QStringList::const_reverse_iterator rend() const;

    // --- adding and removing -----------------------------------------------
    void append(const ICoreString& s);
    void append(const ICoreStringList& other);
    void append(const QStringList& other);
    void prepend(const ICoreString& s);
    void push_back(const ICoreString& s);
    void push_front(const ICoreString& s);
    void insert(qsizetype i, const ICoreString& s);
    iterator insert(const_iterator before, const ICoreString& s);
    void removeAt(qsizetype i);
    qsizetype removeAll(const ICoreString& s);
    bool removeOne(const ICoreString& s);
    void removeFirst();
    void removeLast();
    ICoreString takeAt(qsizetype i);
    ICoreString takeFirst();
    ICoreString takeLast();
    iterator erase(const_iterator pos);
    iterator erase(const_iterator first_, const_iterator last_);
    void swapItemsAt(qsizetype i, qsizetype j);
    void move(qsizetype from, qsizetype to);

    // --- searching ---------------------------------------------------------
    bool contains(const ICoreString& s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    bool contains(ICoreLatin1String s, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    qsizetype indexOf(const ICoreString& s, qsizetype from = 0) const;
    // QStringList's own case-insensitive search, which QList does not have --
    // ICoreParityCommands reads its --blocks/--seed flags with it.
    qsizetype indexOf(const ICoreString& s, qsizetype from, ICoreCaseSensitivity cs) const;
    // Defined at the foot of ICoreRegex.h -- see the note above ICoreString.
    qsizetype indexOf(const ICoreRegex& re, qsizetype from = 0) const;
    qsizetype lastIndexOf(const ICoreString& s, qsizetype from = -1) const;
    // No Qt::CaseSensitivity overload: QStringList has one for contains() and
    // deliberately none for count(), so neither does this.
    qsizetype count(const ICoreString& s) const;

    // --- QStringList's own vocabulary --------------------------------------
    ICoreString join(const ICoreString& sep) const;
    ICoreString join(ICoreChar sep) const;
    ICoreString join(ICoreLatin1String sep) const;
    ICoreStringList filter(const ICoreString& needle, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive) const;
    ICoreStringList filter(const ICoreRegex& re) const;
    ICoreStringList& replaceInStrings(const ICoreString& before, const ICoreString& after, ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    ICoreStringList& replaceInStrings(const ICoreRegex& re, const ICoreString& after);
    void sort(ICoreCaseSensitivity cs = ICoreCaseSensitivity::Sensitive);
    void removeDuplicates();
    ICoreStringList mid(qsizetype pos, qsizetype n = -1) const;
    ICoreStringList sliced(qsizetype pos) const;
    ICoreStringList sliced(qsizetype pos, qsizetype n) const;
    ICoreStringList first(qsizetype n) const;
    ICoreStringList last(qsizetype n) const;

    // --- compound operators (members, so they join no Qt overload set) ------
    ICoreStringList& operator<<(const ICoreString& s);
    ICoreStringList& operator<<(const ICoreStringList& other);
    ICoreStringList& operator<<(const QStringList& other);
    ICoreStringList& operator+=(const ICoreStringList& other);
    ICoreStringList& operator+=(const QStringList& other);
    ICoreStringList operator+(const ICoreStringList& other) const;

};

ICoreStringLiteral.h#

src/ICoreEssentials/Text/ICoreStringLiteral.h

ICoreStringLiteral / ICoreLatin1String / ICoreLatin1Char -- the project's own compile-time string literals.

PHASE 1 (current): ICoreStringLiteral is a MACRO producing an ICoreString; the other two are type ALIASES.

DESIGN NOTES (load-bearing -- read before changing anything):

  • ICoreStringLiteral is a macro and not a class, because QStringLiteral is

a macro: it builds a static QString::Data at compile time inside the expression, and nothing declared as a type can do that. The board row and README both specified this and both are right -- unlike B6, where the same instruction was wrong and had to be overturned. The difference is that B6 needed to NARROW two of its call sites and a macro cannot narrow;

File-scope declarations#

using ICoreLatin1String = QLatin1String;

using ICoreLatin1Char   = QLatin1Char;

ICoreTextEnums.h#

src/ICoreEssentials/Text/ICoreTextEnums.h

ICore names for the Qt:: / QString:: / QByteArray:: / QRegularExpression:: constants that the Text tier's signatures used to spell. Tasks Q0.3 and Q0.4 of QT_PARAM_SWAP.md.

SAME CONTRACT AS UI/Events/ICoreInputEnums.h, deliberately, so there is one rule to learn and not two: every enumerator's underlying value EQUALS its Qt counterpart, the wrapper headers translate with a static_cast, and that equality is not trusted to this comment -- it is pinned by static_asserts in ICoreTextEnumsVerify.cpp, which includes the real Qt headers and refuses to compile the moment Qt and this file disagree.

WHY A SECOND ENUM HEADER RATHER THAN MORE OF THE FIRST. ICoreInputEnums.h lives under UI/, and the types below are needed by Text/ -- ICoreString, ICoreStringList, ICoreByteArray and ICoreRegex are the whole non-UI half of

File-scope declarations#

// NOTE the enumerator names are Insensitive/Sensitive, not CaseInsensitive/
// CaseSensitive: the enum class already carries the word "Case", and
// ICoreCaseSensitivity::CaseInsensitive stutters. Call sites do not spell
// either one -- they write ICoreString::CaseInsensitive, which is a static
// constant on the wrapper and is what the ~34 existing sites already say.
enum class ICoreCaseSensitivity : int {
    Insensitive = 0,
    Sensitive   = 1,
};

enum class ICoreSplitBehavior : int {
    KeepEmptyParts = 0,
    SkipEmptyParts = 0x1,
};

// D/C/KD/KC are the Unicode standard's own names for the four forms
// (canonical/compatibility x decomposed/composed), so the Qt prefix carries no
// information the enum class name does not already give.
enum class ICoreNormalizationForm : int {
    D  = 0,
    C  = 1,
    KD = 2,
    KC = 3,
};

// The flag families below follow ICoreAlignment's shape, which is the pattern
// already in the tree: an or-able enum class plus a combining operator, and a
// plural ALIAS of the same type for the parameter position. There is
// deliberately no separate QFlags-style holder -- ICoreAlignment has done
// without one since it was written, and inventing a second flags mechanism for
// four enums would be a type nobody asked for.
enum class ICoreSectionFlag : unsigned int {
    Default             = 0x00,
    SkipEmpty           = 0x01,
    IncludeLeadingSep   = 0x02,
    IncludeTrailingSep  = 0x04,
    CaseInsensitiveSeps = 0x08,
};

using ICoreSectionFlags = ICoreSectionFlag;

// Three independent two-value choices packed into one flag set, exactly as Qt
// packs them, which is why three enumerators are 0: Base64Encoding,
// KeepTrailingEquals and IgnoreBase64DecodingErrors are the absence of their
// partners rather than values of their own. Duplicate enumerator values are
// legal and are what makes `Base64UrlEncoding | OmitTrailingEquals` mean what
// it says.
enum class ICoreBase64Option : unsigned int {
    Base64Encoding              = 0,
    Base64UrlEncoding           = 1,

    KeepTrailingEquals          = 0,
    OmitTrailingEquals          = 2,

    IgnoreBase64DecodingErrors  = 0,
    AbortOnBase64DecodingErrors = 4,
};

using ICoreBase64Options = ICoreBase64Option;

// The enumerators keep Qt's spelling, "Option" suffix and all, because
// ICoreRegex re-exports each one as a static constant and the ~12 call sites
// that name one write ICoreRegex::CaseInsensitiveOption today. Renaming them
// here would buy tidiness at the cost of every one of those sites.
enum class ICoreRegexPatternOption : unsigned int {
    NoPatternOption             = 0x0000,
    CaseInsensitiveOption       = 0x0001,
    DotMatchesEverythingOption  = 0x0002,
    MultilineOption             = 0x0004,
    ExtendedPatternSyntaxOption = 0x0008,
    InvertedGreedinessOption    = 0x0010,
    DontCaptureOption           = 0x0020,
    UseUnicodePropertiesOption  = 0x0040,
};

using ICoreRegexPatternOptions = ICoreRegexPatternOption;

// Not a flag set -- these four are alternatives, and Qt declares them without
// Q_DECLARE_FLAGS for that reason.
enum class ICoreRegexMatchType : int {
    NormalMatch                = 0,
    PartialPreferCompleteMatch = 1,
    PartialPreferFirstMatch    = 2,
    NoMatch                    = 3,
};

// Qt's AnchoredMatchOption is deliberately absent: it is a deprecated alias of
// AnchorAtOffsetMatchOption (renamed at Qt 6.0) and no call site names it.
enum class ICoreRegexMatchOption : unsigned int {
    NoMatchOption                     = 0x0000,
    AnchorAtOffsetMatchOption         = 0x0001,
    DontCheckSubjectStringMatchOption = 0x0002,
};

using ICoreRegexMatchOptions = ICoreRegexMatchOption;