Wolfgang Thallergcc16 merge934c3885 months agoHistory
2593 lines · 99.3 KB · D
RawDownload
/** * D header file for interaction with C++ std::string. * * Copyright: Copyright (c) 2019 D Language Foundation * License: Distributed under the *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). *    (See accompanying file LICENSE) * Authors:   Guillaume Chatelet *            Manu Evans * Source:    $(DRUNTIMESRC core/stdcpp/string.d) */ module core.stdcpp.string; import core.stdcpp.allocator;import core.stdcpp.xutility : StdNamespace;import core.stdc.stddef : wchar_t; version (OSX)    version = Darwin;else version (iOS)    version = Darwin;else version (TVOS)    version = Darwin;else version (WatchOS)    version = Darwin; version (Darwin){    // Apple decided to rock a different ABI... good for them!    version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT;} version (CppRuntime_GNU){    version (_GLIBCXX_USE_CXX98_ABI)    {        private enum StringNamespace = "std";        version = __GTHREADS;    }    else    {        import core.internal.traits : AliasSeq;        private enum StringNamespace = AliasSeq!("std", "__cxx11");    }}else    alias StringNamespace = StdNamespace; enum DefaultConstruct { value } /// Constructor argument for default constructionenum Default = DefaultConstruct(); @nogc: /** * Character traits classes specify character properties and provide specific * semantics for certain operations on characters and sequences of characters. */extern(C++, (StdNamespace)) struct char_traits(CharT){    alias char_type = CharT;     static size_t length(const(char_type)* s) @trusted pure nothrow @nogc    {        static if (is(char_type == char) || is(char_type == ubyte))        {            import core.stdc.string : strlen;            return strlen(s);        }        else        {            size_t len = 0;            for (; *s != char_type(0); ++s)                ++len;            return len;        }    }     static char_type* move(char_type* s1, const char_type* s2, size_t n) @trusted pure nothrow @nogc    {        import core.stdc.string : memmove;        import core.stdc.wchar_ : wmemmove;        import core.stdc.stddef : wchar_t;         if (n == 0)            return s1;         version (CRuntime_Microsoft)        {            enum crt = __traits(getTargetInfo, "cppRuntimeLibrary");            static if (crt.length >= 6 && crt[0 .. 6] == "msvcrt")                enum use_wmemmove = false; // https://issues.dlang.org/show_bug.cgi?id=20456            else                enum use_wmemmove = true;        }        else            enum use_wmemmove = true;         static if (use_wmemmove                && (is(char_type == wchar_t)                    || is(char_type == ushort) && wchar_t.sizeof == ushort.sizeof // Windows                    || is(char_type == uint) && wchar_t.sizeof == uint.sizeof)) // POSIX            return cast(char_type*) wmemmove(s1, s2, n);        else            return cast(char_type*) memmove(s1, s2, n * char_type.sizeof);    }} // I don't think we can have these here, otherwise symbols are emit to druntime, and we don't want that...//alias std_string = basic_string!char;//alias std_u16string = basic_string!wchar; // TODO: can't mangle these yet either...//alias std_u32string = basic_string!dchar;//alias std_wstring = basic_string!wchar_t; // TODO: we can't mangle wchar_t properly (yet?) /** * D language counterpart to C++ std::basic_string. * * C++ reference: $(LINK2 https://en.cppreference.com/w/cpp/string/basic_string) */extern(C++, class)extern(C++, (StringNamespace))struct basic_string(T, Traits = char_traits!T, Alloc = allocator!T){extern(D):@nogc:     ///    enum size_type npos = size_type.max;     ///    alias size_type = size_t;    ///    alias difference_type = ptrdiff_t;    ///    alias value_type = T;    ///    alias traits_type = Traits;    ///    alias allocator_type = Alloc;    ///    alias pointer = value_type*;    ///    alias const_pointer = const(value_type)*;     ///    alias toString = as_array;     /// MSVC allocates on default initialisation in debug, which can't be modelled by D `struct`    @disable this();     ///    alias length = size;    ///    alias opDollar = length;    ///    bool empty() const nothrow @trusted                                     { return size() == 0; }     ///    size_t[2] opSlice(size_t dim : 0)(size_t start, size_t end) const pure nothrow @safe @nogc { return [start, end]; }     ///    ref inout(T) opIndex(size_t index) inout pure nothrow @safe @nogc       { return as_array[index]; }    ///    inout(T)[] opIndex(size_t[2] slice) inout pure nothrow @safe @nogc      { return as_array[slice[0] .. slice[1]]; }    ///    inout(T)[] opIndex() inout pure nothrow @safe @nogc                     { return as_array(); }     /// Two `basic_string`s are equal if they represent the same sequence of code units.    bool opEquals(scope const ref basic_string s) const pure nothrow @safe  { return as_array == s.as_array; }    /// ditto    bool opEquals(scope const T[] s) const pure nothrow @safe               { return as_array == s; }     /// Performs lexicographical comparison.    int opCmp(scope const ref basic_string rhs) const pure nothrow @safe    { return __cmp(as_array, rhs.as_array); }    /// ditto    int opCmp(scope const T[] rhs) const pure nothrow @safe                 { return __cmp(as_array, rhs); }     /// Hash to allow `basic_string`s to be used as keys for built-in associative arrays.    /// **The result will generally not be the same as C++ `std::hash<std::basic_string<T>>`.**    size_t toHash() const @nogc nothrow pure @safe                          { return .hashOf(as_array); }     ///    void clear()                                                            { eos(0); } // TODO: bounds-check    ///    void resize(size_type n, T c = T(0)) @trusted    {        if (n <= size())            eos(n);        else            append(n - size(), c);    }     ///    ref inout(T) front() inout nothrow @safe                                { return this[0]; }    ///    ref inout(T) back() inout nothrow @safe                                 { return this[$-1]; }     ///    const(T)* c_str() const nothrow @safe                                   { return data(); }     // Modifiers    ///    ref basic_string opAssign()(auto ref basic_string str)                  { return assign(str); }//    ref basic_string assign(size_type n, T c);    ///    ref basic_string opAssign(const(T)[] str)                               { return assign(str); }    ///    ref basic_string opAssign(T c)                                          { return assign((&c)[0 .. 1]); }     ///    ref basic_string opIndexAssign(T c, size_t index)                       { as_array[index] = c; return this; }    ///    ref basic_string opIndexAssign(T c, size_t[2] slice)                    { as_array[slice[0] .. slice[1]] = c; return this; }    ///    ref basic_string opIndexAssign(const(T)[] str, size_t[2] slice)         { as_array[slice[0] .. slice[1]] = str[]; return this; }    ///    ref basic_string opIndexAssign(T c)                                     { as_array[] = c; return this; }    ///    ref basic_string opIndexAssign(const(T)[] str)                          { as_array[] = str[]; return this; }     ///    ref basic_string opIndexOpAssign(string op)(T c, size_t index)          { mixin("as_array[index] " ~ op ~ "= c;"); return this; }    ///    ref basic_string opIndexOpAssign(string op)(T c, size_t[2] slice)       { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= c;"); return this; }    ///    ref basic_string opIndexOpAssign(string op)(const(T)[] str, size_t[2] slice)    { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= str[];"); return this; }    ///    ref basic_string opIndexOpAssign(string op)(T c)                        { mixin("as_array[] " ~ op ~ "= c;"); return this; }    ///    ref basic_string opIndexOpAssign(string op)(const(T)[] str)             { mixin("as_array[] " ~ op ~ "= str[];"); return this; }    ///    ref basic_string append(T c)                                            { return append((&c)[0 .. 1]); }    ///    ref basic_string opOpAssign(string op : "~")(const(T)[] str)            { return append(str); }    ///    ref basic_string opOpAssign(string op : "~")(T c)                       { return append((&c)[0 .. 1]); }     ///    ref basic_string insert(size_type pos, ref const(basic_string) str)     { return insert(pos, str.data(), str.size()); }    ///    ref basic_string insert(size_type pos, ref const(basic_string) str, size_type subpos, size_type sublen) @trusted    {        const _strsz = str.size();        assert(subpos <= _strsz);//        if (subpos > _strsz)//            throw new RangeError("subpos exceeds length of str");        return insert(pos, str.data() + subpos, min(sublen, _strsz - subpos));    }    ///    ref basic_string insert(S : size_type)(S pos, const(T)* s)    {        // This overload is declared as a template to give precedence to the slice overload const(T)[] in case of conflict.        assert(s);        return insert(pos, s, traits_type.length(s));    }    ///    ref basic_string insert(size_type pos, const(T)[] s)                    { insert(pos, &s[0], s.length); return this; }     ///    ref basic_string erase(size_type pos = 0) // TODO: bounds-check    {//        _My_data._Check_offset(pos);        eos(pos);        return this;    }    ///    ref basic_string erase(size_type pos, size_type len) // TODO: bounds-check    {//        _My_data._Check_offset(pos);        T[] str = as_array();        size_type new_len = str.length - len;        this[pos .. new_len] = this[pos + len .. str.length]; // TODO: should be memmove!        eos(new_len);        return this;    }     ///    ref basic_string replace()(size_type pos, size_type len, auto ref basic_string str)     { return replace(pos, len, str.data(), str.size()); }    ///    ref basic_string replace()(size_type pos, size_type len, auto ref basic_string str,                            size_type subpos, size_type sublen=npos)    {        size_type strsz = str.size();        assert(subpos <= strsz);//        if (subpos > strsz)//            throw new RangeError("subpos exceeds size of str");        return replace(pos, len, str.data() + subpos, min(sublen, strsz - subpos));    }    ///    ref basic_string replace(size_type pos, size_type len, const(value_type)[] s)           { return replace(pos, len, s.ptr, s.length); }    ///    ref basic_string replace(S : size_type)(S pos, size_type len, const(value_type)* s)    {        // This overload is declared as a template to give precedence to the slice overload const(T)[] in case of conflict.        assert(s !is null, "string::replace received null");        return replace(pos, len, s, traits_type.length(s));    }     ///    void push_back(T c) @trusted                                            { append((&c)[0 .. 1]); }    ///    void pop_back()                                                         { erase(size() - 1); }     version (CppRuntime_Microsoft)    {        //----------------------------------------------------------------------------------        // Microsoft runtime        //----------------------------------------------------------------------------------         ///        this(DefaultConstruct)                                              { _Alloc_proxy(); _Tidy_init(); }        ///        this(const(T)[] str)                                                { _Alloc_proxy(); _Tidy_init(); assign(str); }        ///        this(const(T)[] str, ref const(allocator_type) al)                  { _Alloc_proxy(); _AssignAllocator(al); _Tidy_init(); assign(str); }        ///        this(this)        {            _Alloc_proxy();            if (_Get_data()._IsAllocated())            {                T[] _Str = _Get_data()._Mystr;                _Tidy_init();                assign(_Str);            }        }         ///        ~this()                                                             { _Tidy_deallocate(); }         ///        ref inout(Alloc) get_allocator() inout                              { return _Getal(); }         ///        size_type max_size() const nothrow @safe                            { return ((size_t.max / T.sizeof) - 1) / 2; } // HACK: clone the windows version precisely?         ///        size_type size() const nothrow @safe                                { return _Get_data()._Mysize; }        ///        size_type capacity() const nothrow @safe                            { return _Get_data()._Myres; }        ///        inout(T)* data() inout @safe                                        { return _Get_data()._Myptr; }        ///        inout(T)[] as_array() return ref scope inout nothrow @trusted       { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }        ///        ref inout(T) at(size_type i) inout nothrow @trusted                 { return _Get_data()._Myptr[0 .. _Get_data()._Mysize][i]; }         ///        ref basic_string assign(const(T)[] str)        {            size_type _Count = str.length;            auto _My_data = &_Get_data();            if (_Count <= _My_data._Myres)            {                T* _Old_ptr = _My_data._Myptr;                _My_data._Mysize = _Count;                _Old_ptr[0 .. _Count] = str[]; // TODO: this needs to be a memmove(), does that work here?                _Old_ptr[_Count] = T(0);                return this;            }            return _Reallocate_for(_Count, (T* _New_ptr, size_type _Count, const(T)* _Ptr) nothrow {                _New_ptr[0 .. _Count] = _Ptr[0 .. _Count];                _New_ptr[_Count] = T(0);            }, str.ptr);        }         ///        ref basic_string assign(const ref basic_string str)        {            if (&this != &str)                assign(str.as_array);            return this;        }         ///        ref basic_string append(const(T)[] str)        {            size_type _Count = str.length;            auto _My_data = &_Get_data();            size_type _Old_size = _My_data._Mysize;            if (_Count <= _My_data._Myres - _Old_size)            {                pointer _Old_ptr = _My_data._Myptr;                _My_data._Mysize = _Old_size + _Count;                _Old_ptr[_Old_size .. _Old_size + _Count] = str[]; // TODO: this needs to be a memmove(), does that work here?                _Old_ptr[_Old_size + _Count] = T(0);                return this;            }            return _Reallocate_grow_by(_Count, (T* _New_ptr, const(T)[] _Old_str, const(T)[] _Str) {                _New_ptr[0 .. _Old_str.length] = _Old_str[];                _New_ptr[_Old_str.length .. _Old_str.length + _Str.length] = _Str[];                _New_ptr[_Old_str.length + _Str.length] = T(0);            }, str);        }         ///        ref basic_string append(size_type n, T c)        {            alias _Count = n;            alias _Ch = c;            auto _My_data = &_Get_data();            const size_type _Old_size = _My_data._Mysize;            if (_Count <= _My_data._Myres - _Old_size)            {                _My_data._Mysize = _Old_size + _Count;                pointer _Old_ptr = _My_data._Myptr();                _Old_ptr[_Old_size .. _Old_size + _Count] = _Ch;                _Old_ptr[_Old_size + _Count] = T(0);                return this;            }             return _Reallocate_grow_by(_Count, (T* _New_ptr, const(T)[] _Old_str, size_type _Count, T _Ch) {                _New_ptr[0 .. _Old_str.length] = _Old_str[];                _New_ptr[_Old_str.length .. _Old_str.length + _Count] = _Ch;                _New_ptr[_Old_str.length + _Count] = T(0);            }, _Count, _Ch);        }         ///        void reserve(size_type _Newcap = 0)        {            // determine new minimum length of allocated storage             auto _My_data = &_Get_data();             if (_My_data._Mysize > _Newcap)            {                // requested capacity is not large enough for current size, ignore                return; // nothing to do            }             if (_My_data._Myres == _Newcap)            {                // we're already at the requested capacity                return; // nothing to do            }             if (_My_data._Myres < _Newcap)            {                // reallocate to grow                const size_type _Old_size = _My_data._Mysize;                _Reallocate_grow_by(                    _Newcap - _Old_size, (T* _New_ptr, const(T)[] _Old_str) {                        _New_ptr[0 .. _Old_str.length] = _Old_str[];                        _New_ptr[_Old_str.length] = _Old_str.ptr[_Old_str.length];                    });                 _My_data._Mysize = _Old_size;                return;            }             if (_My_data._BUF_SIZE > _Newcap && _My_data._Large_string_engaged())            {                // deallocate everything; switch back to "small" mode                _Become_small();                return;            }             // ignore requests to reserve to [_BUF_SIZE, _Myres)        }         ///        void shrink_to_fit()        {            // reduce capacity             auto _My_data = &_Get_data();            if (!_My_data._Large_string_engaged())            {                // can't shrink from small mode                return;            }             if (_My_data._Mysize < _My_data._BUF_SIZE)            {                _Become_small();                return;            }             const size_type _Target_capacity = min(_My_data._Mysize | _My_data._ALLOC_MASK, max_size());            if (_Target_capacity < _My_data._Myres)            {                // worth shrinking, do it                auto _Al = &_Getal();                pointer _New_ptr = _Al.allocate(_Target_capacity + 1); // throws                _Base._Orphan_all();                _New_ptr[0 .. _My_data._Mysize + 1] = _My_data._Bx._Ptr[0 .. _My_data._Mysize + 1];                _Al.deallocate(_My_data._Bx._Ptr, _My_data._Myres + 1);                _My_data._Bx._Ptr = _New_ptr;                _My_data._Myres = _Target_capacity;            }        }         ///        ref basic_string insert(size_type pos, const(T)* s, size_type n)        {            // insert [_Ptr, _Ptr + _Count) at _Off            alias _Off = pos;

Lines 1–500 of 2593.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t