toUpper

@trusted
toUpper
()
(
const SSOString x
)

Return Value

Type: SSOString

x uppercased.

Examples

construct from non-immutable source is allowed in non-@nogc-scope

alias S = SSOString;

scope const char[] x0;
const s0 = SSOString(x0);           // no .idup

scope const char[] x16 = new char[16];
const s16 = SSOString(x16);         // will call .idup

construct from non-immutable source is not allowed in @nogc-scope

scope const char[] s;
// TODO: why does this fail? static assert(!__traits(compiles, { const _ = SSOString(s); }));

verify isNull when @nogc constructing from small static array of chars

static foreach (const n; 0 .. SSOString.smallCapacity + 1)
{
    {
        immutable(char)[n] x;
        assert(!SSOString(x).isNull);
    }
}

verify isNull when constructing from large static array of chars

static foreach (const n; SSOString.smallCapacity + 1 .. 32)
{
    {
        immutable(char)[n] x;
        assert(!SSOString(x).isNull);
    }
}

verify isNull when constructing from dynamic array of chars

foreach (const n; 0 .. 32)
{
    scope x = new immutable(char)[n];
    assert(!SSOString(x).isNull);
}

test behaviour of == and is operator

const SSOString x = "42";
assert(!x.isNull);
assert(x == "42");

const SSOString y = "42";
assert(!y.isNull);
assert(y == "42");

assert(x == y);
assert(x == y[]);
assert(x[] == y);
assert(x[] == y[]);
assert(x[] is x[]);
assert(y[] is y[]);
assert(x[] !is y[]);
assert(x.ptr !is y.ptr);

const SSOString z = "43";
assert(!z.isNull);
assert(z == "43");
assert(x != z);
assert(x[] != z[]);
assert(x !is z);
assert(x[] !is z[]);
1 static assert(SSOString.smallCapacity == 15);
2 
3 import nxt.gc_traits : mustAddGCRange;
4 static assert(mustAddGCRange!SSOString); // `Large large.ptr` must be scanned
5 
6 static assert(__traits(isZeroInit, SSOString));
7 // TODO: assert(SSOString.init == SSOString.nullValue);
8 
9 auto s0 = SSOString.init;
10 assert(s0.isNull);
11 assert(s0.length == 0);
12 assert(s0.isLarge);
13 assert(s0[] == []);
14 
15 char[SSOString.smallCapacity] charsSmallCapacity = "123456789_12345"; // fits in small string
16 const sSmallCapacity = SSOString(charsSmallCapacity);
17 assert(!sSmallCapacity.isLarge);
18 assert(sSmallCapacity.length == SSOString.smallCapacity);
19 assert(sSmallCapacity == charsSmallCapacity);
20 
21 const s0_ = SSOString("");
22 assert(!s0_.isNull);         // cannot distinguish
23 assert(s0 == s0_);
24 
25 const s7 = SSOString("0123456");
26 assert(!s7.isNull);
27 
28 const s7_ = SSOString("0123456_"[0 .. $ - 1]);
29 assert(s7.ptr !is s7_.ptr); // string data shall not overlap
30 assert(s7 == s7_);
31 
32 const _s7 = SSOString("_0123456"[1 .. $]); // source from other string literal
33 assert(s7.ptr !is _s7.ptr); // string data shall not overlap
34 assert(s7 == _s7);
35 
36 assert(!s7.isLarge);
37 assert(s7.length == 7);
38 assert(s7[] == "0123456");
39 assert(s7[] == "_0123456"[1 .. $]);
40 assert(s7[] == "0123456_"[0 .. $ - 1]);
41 assert(s7[0 .. 4] == "0123");
42 
43 const s15 = SSOString("0123456789abcde");
44 assert(!s15.isNull);
45 static assert(is(typeof(s15[]) == const(char)[]));
46 assert(!s15.isLarge);
47 assert(s15.length == 15);
48 assert(s15[] == "0123456789abcde");
49 assert(s15[0 .. 4] == "0123");
50 assert(s15[10 .. 15] == "abcde");
51 assert(s15[10 .. $] == "abcde");
52 
53 const s16 = SSOString("0123456789abcdef");
54 assert(!s16.isNull);
55 static assert(is(typeof(s16[]) == const(char)[]));
56 assert(s16.isLarge);
57 
58 const s16_ = SSOString("0123456789abcdef_"[0 .. s16.length]);
59 assert(s16.length == s16_.length);
60 assert(s16[] == s16_[]);
61 assert(s16.ptr !is s16_.ptr); // string data shall not overlap
62 assert(s16 == s16_);              // but contents is equal
63 
64 const _s16 = SSOString("_0123456789abcdef"[1 .. $]);
65 assert(s16.length == _s16.length);
66 assert(s16[] == _s16[]);    // contents is equal
67 assert(s16 == _s16);        // contents is equal
68 
69 assert(s16.length == 16);
70 assert(s16[] == "0123456789abcdef");
71 assert(s16[0] == '0');
72 assert(s16[10] == 'a');
73 assert(s16[15] == 'f');
74 assert(s16[0 .. 4] == "0123");
75 assert(s16[10 .. 16] == "abcdef");
76 assert(s16[10 .. $] == "abcdef");

metadata for null string

auto s = SSOString.init;
assert(s.isNull);
foreach (const i; 0 .. 8)
{
    s.metadata = i;
    assert(s.metadata == i);
    assert(s.length == 0);
}

metadata for small string

auto s = SSOString("0123456");
assert(!s.isNull);
assert(!s.isLarge);
foreach (const i; 0 .. 8)
{
    s.metadata = i;
    assert(s.metadata == i);
    assert(s.length == 7);
    assert(!s.isLarge);
    assert(!s.isNull);
}

metadata for small string with maximum length

auto s = SSOString("0123456789abcde");
assert(s.length == SSOString.smallCapacity);
assert(!s.isNull);
assert(!s.isLarge);
foreach (const i; 0 .. 8)
{
    s.metadata = i;
    assert(s.metadata == i);
    assert(s.length == 15);
    assert(!s.isLarge);
    assert(!s.isNull);
}

metadata for large string with minimum length

auto s = SSOString("0123456789abcdef");
assert(s.length == SSOString.smallCapacity + 1);
assert(!s.isNull);
assert(s.isLarge);
assert(!s.empty);
foreach (const i; 0 .. 8)
{
    s.metadata = i;
    assert(s.metadata == i);
    assert(s.length == 16);
    assert(s.isLarge);
    assert(!s.isNull);
}

equality and equivalence

assert(SSOString() == SSOString(""));
assert(SSOString() !is SSOString(""));

hashing of null, empty and non-empty

assert(SSOString().toHash == 0);
assert(SSOString("").toHash == 0);
assert(SSOString("a").toHash != 0);
assert(SSOString("0123456789abcdef").toHash != 0);

construct from static array larger than smallCapacity

char[SSOString.smallCapacity + 1] charsMinLargeCapacity;
const _ = SSOString(charsMinLargeCapacity);

hole handling

assert(!SSOString.init.isHole);
assert(!SSOString("").isHole);
assert(!SSOString("a").isHole);
assert(SSOString.asHole.isHole);

DIP-1000 return ref escape analysis

static if (hasPreviewDIP1000)
{
    static assert(!__traits(compiles, { immutable(char)* f1() @safe pure nothrow { SSOString x; return x.ptr; } }));
    static assert(!__traits(compiles, { string f1() @safe pure nothrow { SSOString x; return x[]; } }));
    static assert(!__traits(compiles, { string f2() @safe pure nothrow { SSOString x; return x.toString; } }));
    static assert(!__traits(compiles, { ref immutable(char) g() @safe pure nothrow @nogc { SSOString x; return x[0]; } }));
}

ASCII purity and case-conversion

// these are all small ASCII
assert( SSOString("a").isSmallASCII);
assert( SSOString("b").isSmallASCII);
assert( SSOString("z").isSmallASCII);
assert( SSOString("_").isSmallASCII);
assert( SSOString("abcd").isSmallASCII);
assert( SSOString("123456789_12345").isSmallASCII);

// these are not
assert(!SSOString("123456789_123456").isSmallASCII); // too large
assert(!SSOString("123456789_123ö").isSmallASCII);
assert(!SSOString("ö").isSmallASCII);
assert(!SSOString("Ö").isSmallASCII);
assert(!SSOString("åäö").isSmallASCII);
assert(!SSOString("ö-värld").isSmallASCII);

ASCII purity and case-conversion

assert(SSOString("A").toLower[] == "a");
assert(SSOString("a").toUpper[] == "A");
assert(SSOString("ABCDEFGHIJKLMNO").toLower[] == "abcdefghijklmno"); // small
assert(SSOString("abcdefghijklmno").toUpper[] == "ABCDEFGHIJKLMNO"); // small
assert(SSOString("ÅÄÖ").toLower[] == "åäö");
assert(SSOString("åäö").toUpper[] == "ÅÄÖ");
assert(SSOString("ABCDEFGHIJKLMNOP").toLower[] == "abcdefghijklmnop"); // large
assert(SSOString("abcdefghijklmnop").toUpper[] == "ABCDEFGHIJKLMNOP"); // large

char[6] x = "ÅÄÖ";
import std.uni : toLowerInPlace;
auto xref = x[];
toLowerInPlace(xref);
assert(x == "åäö");
assert(xref == "åäö");

lexicographic comparison

const SSOString a = SSOString("a");
assert(a == SSOString("a"));

immutable SSOString b = SSOString("b");

assert(a < b);
assert(b > a);
assert(a[] < b[]);

assert("a" < "b");
assert("a" < "å");
assert("Å" < "å");
assert(SSOString("a") < SSOString("å"));
assert(SSOString("ÅÄÖ") < SSOString("åäö"));

cast to bool

// mimics behaviour of casting of `string` to `bool`
assert(!SSOString());
assert(SSOString(""));
assert(SSOString("abc"));

to string conversion

// mutable small will GC-allocate
{
    SSOString s = SSOString("123456789_12345");
    assert(s.ptr is &s.opSlice()[0]);
    assert(s.ptr !is &s.toString()[0]);
}

// const small will GC-allocate
{
    const SSOString s = SSOString("123456789_12345");
    assert(s.ptr is &s.opSlice()[0]);
    assert(s.ptr !is &s.toString()[0]);
}

// immutable small will not allocate
{
    immutable SSOString s = SSOString("123456789_12345");
    assert(s.ptr is &s.opSlice()[0]);
    assert(s.ptr is &s.toString()[0]);
    // TODO: check return via -dip1000
}

/* Forbid return of possibly locally scoped `Smll` small stack object
 * regardless of head-mutability.
 */
static if (hasPreviewDIP1000)
{
    static assert(!__traits(compiles, { immutable(char)* f1() @safe pure nothrow { SSOString x; return x.ptr; } }));
    static assert(!__traits(compiles, { immutable(char)* f1() @safe pure nothrow { const SSOString x; return x.ptr; } }));
    static assert(!__traits(compiles, { immutable(char)* f1() @safe pure nothrow { immutable SSOString x; return x.ptr; } }));

    /** TODO: Enable the following line when DIP-1000 works for opSlice()
     *
     * See_Also: https://issues.dlang.org/show_bug.cgi?id=18792
     */
    // static assert(!__traits(compiles, { string f1() @safe pure nothrow { immutable SSOString x; return x[]; } }));
}

// large will never allocate regardless of head-mutability
{
    SSOString s = SSOString("123456789_123456");
    assert(s.ptr is &s.opSlice()[0]);
    assert(s.ptr is &s.toString()[0]); // shouldn't this change?
}

Meta