From 8b4700cac930d738cf06e7f49ba88a503edc331a Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Sun, 5 Jul 2015 13:38:22 -0700 Subject: [PATCH 1/5] First implementation of std::string/std::vector --- mak/COPY | 3 + mak/DOCS | 3 + mak/SRCS | 4 + src/core/stdcpp/allocator.d | 20 +++ src/core/stdcpp/string.d | 337 ++++++++++++++++++++++++++++++++++++ src/core/stdcpp/vector.d | 159 +++++++++++++++++ 6 files changed, 526 insertions(+) create mode 100644 src/core/stdcpp/allocator.d create mode 100644 src/core/stdcpp/string.d create mode 100644 src/core/stdcpp/vector.d diff --git a/mak/COPY b/mak/COPY index cdd87a145a..d3042edf50 100644 --- a/mak/COPY +++ b/mak/COPY @@ -50,6 +50,9 @@ COPY=\ \ $(IMPDIR)\core\stdcpp\typeinfo.d \ $(IMPDIR)\core\stdcpp\exception.d \ + $(IMPDIR)\core\stdcpp\allocator.d \ + $(IMPDIR)\core\stdcpp\string.d \ + $(IMPDIR)\core\stdcpp\vector.d \ \ $(IMPDIR)\core\sys\darwin\execinfo.d \ $(IMPDIR)\core\sys\darwin\pthread.d \ diff --git a/mak/DOCS b/mak/DOCS index c825362b20..dd12a6838c 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -40,6 +40,9 @@ DOCS=\ \ $(DOCDIR)\core_stdcpp_exception.html \ $(DOCDIR)\core_stdcpp_typeinfo.html \ + $(DOCDIR)\core_stdcpp_allocator.html \ + $(DOCDIR)\core_stdcpp_string.html \ + $(DOCDIR)\core_stdcpp_vector.html \ \ $(DOCDIR)\core_sync_barrier.html \ $(DOCDIR)\core_sync_condition.html \ diff --git a/mak/SRCS b/mak/SRCS index f998eb29f9..3f8b860291 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -46,6 +46,10 @@ SRCS=\ src\core\stdc\time.d \ src\core\stdc\wchar_.d \ \ + src\core\stdcpp\allocator.d \ + src\core\stdcpp\string.d \ + src\core\stdcpp\vector.d \ + \ src\core\sync\barrier.d \ src\core\sync\condition.d \ src\core\sync\config.d \ diff --git a/src/core/stdcpp/allocator.d b/src/core/stdcpp/allocator.d new file mode 100644 index 0000000000..991f70848d --- /dev/null +++ b/src/core/stdcpp/allocator.d @@ -0,0 +1,20 @@ +/** + * D header file for interaction with C++ std::allocator. + * + * Copyright: Copyright Guillaume Chatelet 2014 - 2015. + * 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 + * Source: $(DRUNTIMESRC core/stdcpp/allocator.d) + */ + +module core.stdcpp.allocator; + +extern(C++, std): + +/** + * Allocators are classes that define memory models to be used by some parts of + * the C++ Standard Library, and most specifically, by STL containers. + */ +struct allocator(T) { } diff --git a/src/core/stdcpp/string.d b/src/core/stdcpp/string.d new file mode 100644 index 0000000000..b8879404a7 --- /dev/null +++ b/src/core/stdcpp/string.d @@ -0,0 +1,337 @@ +/** + * D header file for interaction with C++ std::string. + * + * Copyright: Copyright Guillaume Chatelet 2014 - 2015. + * 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 + * Source: $(DRUNTIMESRC core/stdcpp/string.d) + */ + +module core.stdcpp.string; + +/** + * Because of broken name mangling of extern C++, this file is only available + * for Linux platform right now. Name mangling is hardcoded with pragmas. + */ +version(linux): +pragma(lib, "stdc++"); + +/////////////////////////////////////////////////////////////////////////////// +// std::string declaration. +// +// Current caveats : +// - manual name mangling (=> only string is functionnal, wstring won't work) +// https://issues.dlang.org/show_bug.cgi?id=14086 +// https://issues.dlang.org/show_bug.cgi?id=14178 +// - won't work with custom allocators. +// - iterators are implemented as pointers +// - no reverse_iterator nor rbegin/rend +// - missing functions : replace, swap +/////////////////////////////////////////////////////////////////////////////// + +import core.stdcpp.allocator; + +extern(C++, std): + +/** + * Character traits classes specify character properties and provide specific + * semantics for certain operations on characters and sequences of characters. + */ +struct char_traits(CharT) {} + +/** + * The basic_string is the generalization of class string for any character + * type. + */ +struct basic_string(T, TRAITS = char_traits!T, ALLOC = allocator!T) +{ + enum size_t npos = size_t.max; + + alias value_type = T; + alias traits_type = TRAITS; + alias allocator_type = ALLOC; + alias reference = ref T; + alias const_reference = ref const(T); + alias pointer = T*; + alias const_pointer = const(T*); + alias iterator = pointer; + alias const_iterator = const_pointer; + // alias reverse_iterator + // alias const_reverse_iterator + alias difference_type = ptrdiff_t; + alias size_type = size_t; + + // Ctor/dtor + pragma(mangle, "_ZNSsC1Ev") + @disable this(); + + pragma(mangle, "_ZNSsC1ERKSs") + this(ref const this); + + pragma(mangle, "_ZNSsC1EPKcRKSaIcE") + this(const(T*) _, ref const allocator_type _ = defaultAlloc); + + pragma(mangle, "_ZNSsD1Ev") + ~this(); + + pragma(mangle, "_ZNSsaSERKSs") + ref basic_string opAssign(ref const basic_string s); + + // Iterators + pragma(mangle, "_ZNSs5beginEv") + iterator begin() nothrow; + + pragma(mangle, "_ZNKSs5beginEv") + const_iterator begin() nothrow const; + + pragma(mangle, "_ZNKSs6cbeginEv") + const_iterator cbegin() nothrow const; + + pragma(mangle, "_ZNSs3endEv") + iterator end() nothrow; + + pragma(mangle, "_ZNKSs3endEv") + const_iterator end() nothrow const; + + pragma(mangle, "_ZNKSs4cendEv") + const_iterator cend() nothrow const; + + // no reverse iterator for now. + + // Capacity + pragma(mangle, "_ZNKSs4sizeEv") + size_t size() nothrow const; + + pragma(mangle, "_ZNKSs6lengthEv") + size_t length() nothrow const; + + pragma(mangle, "_ZNKSs8max_sizeEv") + size_t max_size() nothrow const; + + pragma(mangle, "_ZNKSs8capacityEv") + size_t capacity() nothrow const; + + pragma(mangle, "_ZNKSs5emptyEv") + bool empty() nothrow const; + + pragma(mangle, "_ZNSs5clearEv") + void clear() nothrow; + + pragma(mangle, "_ZNSs6resizeEm") + void resize(size_t n); + + pragma(mangle, "_ZNSs6resizeEmc") + void resize(size_t n, T c); + + pragma(mangle, "_ZNSs7reserveEm") + void reserve(size_t n = 0); + + pragma(mangle, "_ZNSs13shrink_to_fitEv") + void shrink_to_fit(); + + // Element access + pragma(mangle, "_ZNSsixEm") + ref T opIndex(size_t i); + + pragma(mangle, "_ZNKSsixEm") + ref const(T) opIndex(size_t i) const; + + pragma(mangle, "_ZNSs2atEm") + ref T at(size_t i); + + pragma(mangle, "_ZNKSs2atEm") + ref const(T) at(size_t i) const; + + pragma(mangle, "_ZNSs4backEv") + ref T back(); + + pragma(mangle, "_ZNKSs4backEv") + ref const(T) back() const; + + pragma(mangle, "_ZNSs5frontEv") + ref T front(); + + pragma(mangle, "_ZNKSs5frontEv") + ref const(T) front() const; + + // Modifiers + pragma(mangle, "_ZNSspLERKSs") + ref basic_string opOpAssign(string op)(ref const basic_string _) if (op == "+"); + + pragma(mangle, "_ZNSspLEPKc") + ref basic_string opOpAssign(string op)(const(T*) _) if (op == "+"); + + pragma(mangle, "_ZNSspLEc") + ref basic_string opOpAssign(string op)(T _) if (op == "+"); + + pragma(mangle, "_ZNSs6appendEmc") + ref basic_string append(size_t n, char c); + + pragma(mangle, "_ZNSs6appendEPKc") + ref basic_string append(const char* s); + + pragma(mangle, "_ZNSs6appendEPKcm") + ref basic_string append(const char* s, size_t n); + + pragma(mangle, "_ZNSs6appendERKSs") + ref basic_string append(ref const basic_string str); + + pragma(mangle, "_ZNSs6appendERKSsmm") + ref basic_string append(ref const basic_string str, size_t subpos, size_t sublen); + + pragma(mangle, "_ZNSs9push_backEc") + void push_back(T c); + + pragma(mangle, "_ZNSs6assignEmc") + ref basic_string assign(size_t n, char c); + + pragma(mangle, "_ZNSs6assignEPKc") + ref basic_string assign(const char* s); + + pragma(mangle, "_ZNSs6assignEPKcm") + ref basic_string assign(const char* s, size_t n); + + pragma(mangle, "_ZNSs6assignERKSs") + ref basic_string assign(ref const basic_string str); + + pragma(mangle, "_ZNSs6assignERKSsmm") + ref basic_string assign(ref const basic_string str, size_t subpos, size_t sublen); + + pragma(mangle, "_ZNSs6insertEmRKSs") + ref basic_string insert (size_t pos, ref const basic_string str); + + pragma(mangle, "_ZNSs6insertEmRKSsmm") + ref basic_string insert (size_t pos, ref const basic_string str, size_t subpos, size_t sublen); + + pragma(mangle, "_ZNSs6insertEmPKc") + ref basic_string insert (size_t pos, const char* s); + + pragma(mangle, "_ZNSs6insertEmPKcm") + ref basic_string insert (size_t pos, const char* s, size_t n); + + pragma(mangle, "_ZNSs6insertEmmc") + ref basic_string insert (size_t pos, size_t n, char c); + + pragma(mangle, "_ZNSs5eraseEmm") + ref basic_string erase(size_t pos = 0, size_t len = npos); + + // replace + // swap + pragma(mangle, "_ZNSs8pop_backEv") + void pop_back(); + + // String operations + pragma(mangle, "_ZNKSs5c_strEv") + const(T*) c_str() nothrow const; + + pragma(mangle, "_ZNKSs4dataEv") + const(T*) data() nothrow const; + + pragma(mangle, "_ZNKSs4copyEPcmm") + size_t copy(T* s, size_t len, size_t pos = 0) const; + + pragma(mangle, "_ZNKSs4findERKSsm") + size_t find(ref const basic_string str, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs4findEPKcm") + size_t find(const(T*) s, size_t pos = 0) const; + + pragma(mangle, "_ZNKSs4findEPKcmm") + size_t find(const(T*) s, size_t pos, size_type n) const; + + pragma(mangle, "_ZNKSs4findEcm") + size_t find(T c, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs5rfindERKSsm") + size_t rfind(ref const basic_string str, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs5rfindEPKcm") + size_t rfind(const(T*) s, size_t pos = npos) const; + + pragma(mangle, "_ZNKSs5rfindEPKcmm") + size_t rfind(const(T*) s, size_t pos, size_t n) const; + + pragma(mangle, "_ZNKSs5rfindEcm") + size_t rfind(T c, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs13find_first_ofERKSsm") + size_t find_first_of(ref const basic_string str, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs13find_first_ofEPKcm") + size_t find_first_of(const(T*) s, size_t pos = 0) const; + + pragma(mangle, "_ZNKSs13find_first_ofEPKcmm") + size_t find_first_of(const(T*) s, size_t pos, size_t n) const; + + pragma(mangle, "_ZNKSs13find_first_ofEcm") + size_t find_first_of(T c, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs12find_last_ofERKSsm") + size_t find_last_of(ref const basic_string str, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs12find_last_ofEPKcm") + size_t find_last_of(const(T*) s, size_t pos = npos) const; + + pragma(mangle, "_ZNKSs12find_last_ofEPKcmm") + size_t find_last_of(const(T*) s, size_t pos, size_t n) const; + + pragma(mangle, "_ZNKSs12find_last_ofEcm") + size_t find_last_of(T c, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs17find_first_not_ofERKSsm") + size_t find_first_not_of(ref const basic_string str, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs17find_first_not_ofEPKcm") + size_t find_first_not_of(const(T*) s, size_t pos = 0) const; + + pragma(mangle, "_ZNKSs17find_first_not_ofEPKcmm") + size_t find_first_not_of(const(T*) s, size_t pos, size_t n) const; + + pragma(mangle, "_ZNKSs17find_first_not_ofEcm") + size_t find_first_not_of(T c, size_t pos = 0) nothrow const; + + pragma(mangle, "_ZNKSs16find_last_not_ofERKSsm") + size_t find_last_not_of(ref const basic_string str, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs16find_last_not_ofEPKcm") + size_t find_last_not_of(const(T*) s, size_t pos = npos) const; + + pragma(mangle, "_ZNKSs16find_last_not_ofEPKcmm") + size_t find_last_not_of(const(T*) s, size_t pos, size_t n) const; + + pragma(mangle, "_ZNKSs16find_last_not_ofEcm") + size_t find_last_not_of(T c, size_t pos = npos) nothrow const; + + pragma(mangle, "_ZNKSs6substrEmm") + basic_string substr(size_t pos = 0, size_t len = npos) const; + + pragma(mangle, "_ZNKSs7compareERKSs") + int compare(ref const basic_string str) nothrow const; + + pragma(mangle, "_ZNKSs7compareEmmRKSs") + int compare(size_t pos, size_t len, ref const basic_string str) const; + + pragma(mangle, "_ZNKSs7compareEmmRKSsmm") + int compare(size_t pos, size_t len, ref const basic_string str, size_t subpos, size_t sublen) const; + + pragma(mangle, "_ZNKSs7compareEPKc") + int compare(const(T*) s) const; + + pragma(mangle, "_ZNKSs7compareEmmPKc") + int compare(size_t pos, size_t len, const(T*) s) const; + + pragma(mangle, "_ZNKSs7compareEmmPKcm") + int compare(size_t pos, size_t len, const(T*) s, size_t n) const; + + // D helpers + const(T[]) asArray() const { return c_str()[0 .. size()]; } + +private: + void[8] _ = void; // to match sizeof(std::string) and pad the object correctly. + __gshared static immutable allocator!T defaultAlloc; +} + +alias basic_string!char std_string; +alias basic_string!wchar std_wstring; diff --git a/src/core/stdcpp/vector.d b/src/core/stdcpp/vector.d new file mode 100644 index 0000000000..d563d96455 --- /dev/null +++ b/src/core/stdcpp/vector.d @@ -0,0 +1,159 @@ +/** + * D header file for interaction with C++ std::vector. + * + * Copyright: Copyright Guillaume Chatelet 2014 - 2015. + * 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 + * Source: $(DRUNTIMESRC core/stdcpp/vector.d) + */ + +module core.stdcpp.vector; + +// Because of broken name mangling of extern C++, this file is considered +// experimental and not yet available. +version(none): +pragma(lib, "stdc++"); + +/////////////////////////////////////////////////////////////////////////////// +// std::vector declaration. +// +// Current caveats : +// - manual name mangling (=> only vector!int is functionnal) +// See https://issues.dlang.org/show_bug.cgi?id=14086. +// - won't work with custom allocators. +// - missing noexcept +// - iterators are implemented as pointers +// - no reverse_iterator nor rbegin/rend +/////////////////////////////////////////////////////////////////////////////// + +import core.stdcpp.allocator; + +extern(C++, std): + +struct vector(T, ALLOC = allocator!T) +{ + alias value_type = T; + alias allocator_type = ALLOC; + alias reference = ref T; + alias const_reference = ref const(T); + alias pointer = T*; + alias const_pointer = const(T*); + alias iterator = pointer; + alias const_iterator = const_pointer; + // alias reverse_iterator + // alias const_reverse_iterator + alias difference_type = ptrdiff_t; + alias size_type = size_t; + + // Ctor/dtor + pragma(mangle, "_ZNSt6vectorIiSaIiEEC1Ev") + this(); + + pragma(mangle, "_ZNSt6vectorIiSaIiEEC2EmRKS0_") + this(size_type n, ref const allocator_type _ = defaultAlloc); + + pragma(mangle, "_ZNSt6vectorIiSaIiEEC2EmRKiRKS0_") + this(size_type n, ref const value_type val, ref const allocator_type _ = defaultAlloc); + + pragma(mangle, "_ZNSt6vectorIiSaIiEEC2ERKS1_") + this(ref const vector x); + + pragma(mangle, "_ZNSt6vectorIiSaIiEED1Ev") + ~this(); + + // pragma(mangle, "_ZNSt6vectorIiSaIiEEaSERKS1_") + // ref vector opAssign(ref const vector s); + + // Iterators + pragma(mangle, "_ZNSt6vectorIiSaIiEE5beginEv") + iterator begin(); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE5beginEv") + const_iterator begin() const; + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE6cbeginEv") + const_iterator cbegin() const; + + pragma(mangle, "_ZNSt6vectorIiSaIiEE3endEv") + iterator end(); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE3endEv") + const_iterator end() const; + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE4cendEv") + const_iterator cend() const; + + // no reverse iterator for now. + + // Capacity + pragma(mangle, "_ZNKSt6vectorIiSaIiEE4sizeEv") + size_t size() const; + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE8max_sizeEv") + size_t max_size() const; + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE8capacityEv") + size_t capacity() const; + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE5emptyEv") + bool empty() const; + + pragma(mangle, "_ZNSt6vectorIiSaIiEE5clearEv") + void clear(); + + pragma(mangle, "_ZNSt6vectorIiSaIiEE6resizeEm") + void resize(size_t n); + + pragma(mangle, "_ZNSt6vectorIiSaIiEE6resizeEmRKi") + void resize(size_t n, T c); + + pragma(mangle, "_ZNSt6vectorIiSaIiEE7reserveEm") + void reserve(size_t n = 0); + + pragma(mangle, "_ZNSt6vectorIiSaIiEE13shrink_to_fitEv") + void shrink_to_fit(); + + // Element access + pragma(mangle, "_ZNSt6vectorIiSaIiEEixEm") + ref T opIndex(size_t i); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEEixEm") + ref const(T) opIndex(size_t i) const; + + pragma(mangle, "_ZNSt6vectorIiSaIiEE2atEm") + ref T at(size_t i); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE2atEm") + ref const(T) at(size_t i) const; + + pragma(mangle, "_ZNSt6vectorIiSaIiEE4backEv") + ref T back(); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE4backEv") + ref const(T) back() const; + + pragma(mangle, "_ZNSt6vectorIiSaIiEE5frontEv") + ref T front(); + + pragma(mangle, "_ZNKSt6vectorIiSaIiEE5frontEv") + ref const(T) front() const; + + // Modifiers + pragma(mangle, "_ZNSt6vectorIiSaIiEE9push_backEOi") + void push_back(ref const T _); + + pragma(inline, true) + void push_back(const T _) { push_back(_);} // forwards to ref version + + pragma(mangle, "_ZNSt6vectorIiSaIiEE8pop_backEv") + void pop_back(); + + // D helpers + const(T[]) asArray() const { return c_str()[0 .. size()]; } + +private: + void[24] _ = void; // to match sizeof(std::vector) and pad the object correctly. + __gshared static immutable allocator!T defaultAlloc; +} From 79f7254e24d6b3e0d2d943a0806d83b5f7fb40a4 Mon Sep 17 00:00:00 2001 From: Manu Evans Date: Fri, 8 Jun 2018 00:07:07 -0700 Subject: [PATCH 2/5] Resurrected @gchatelet's STL branch --- src/core/stdcpp/allocator.d | 3 +- src/core/stdcpp/string.d | 354 +++++++++++------------------------- src/core/stdcpp/vector.d | 120 ++++-------- 3 files changed, 149 insertions(+), 328 deletions(-) diff --git a/src/core/stdcpp/allocator.d b/src/core/stdcpp/allocator.d index 991f70848d..015445ad50 100644 --- a/src/core/stdcpp/allocator.d +++ b/src/core/stdcpp/allocator.d @@ -6,6 +6,7 @@ * $(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/allocator.d) */ @@ -17,4 +18,4 @@ extern(C++, std): * Allocators are classes that define memory models to be used by some parts of * the C++ Standard Library, and most specifically, by STL containers. */ -struct allocator(T) { } +extern(C++, class) struct allocator(T) { } diff --git a/src/core/stdcpp/string.d b/src/core/stdcpp/string.d index b8879404a7..42b5984c46 100644 --- a/src/core/stdcpp/string.d +++ b/src/core/stdcpp/string.d @@ -6,32 +6,25 @@ * $(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; -/** - * Because of broken name mangling of extern C++, this file is only available - * for Linux platform right now. Name mangling is hardcoded with pragmas. - */ -version(linux): -pragma(lib, "stdc++"); - /////////////////////////////////////////////////////////////////////////////// // std::string declaration. // // Current caveats : -// - manual name mangling (=> only string is functionnal, wstring won't work) -// https://issues.dlang.org/show_bug.cgi?id=14086 -// https://issues.dlang.org/show_bug.cgi?id=14178 -// - won't work with custom allocators. +// - mangling issues still exist +// - won't work with custom allocators // - iterators are implemented as pointers // - no reverse_iterator nor rbegin/rend // - missing functions : replace, swap /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; +import core.stdc.stddef; extern(C++, std): @@ -45,17 +38,17 @@ struct char_traits(CharT) {} * The basic_string is the generalization of class string for any character * type. */ -struct basic_string(T, TRAITS = char_traits!T, ALLOC = allocator!T) +extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = allocator!T) { - enum size_t npos = size_t.max; + enum size_type npos = size_type.max; alias value_type = T; - alias traits_type = TRAITS; - alias allocator_type = ALLOC; + alias traits_type = Traits; + alias allocator_type = Alloc; alias reference = ref T; alias const_reference = ref const(T); alias pointer = T*; - alias const_pointer = const(T*); + alias const_pointer = const(T)*; alias iterator = pointer; alias const_iterator = const_pointer; // alias reverse_iterator @@ -63,270 +56,141 @@ struct basic_string(T, TRAITS = char_traits!T, ALLOC = allocator!T) alias difference_type = ptrdiff_t; alias size_type = size_t; - // Ctor/dtor - pragma(mangle, "_ZNSsC1Ev") - @disable this(); - - pragma(mangle, "_ZNSsC1ERKSs") - this(ref const this); - - pragma(mangle, "_ZNSsC1EPKcRKSaIcE") - this(const(T*) _, ref const allocator_type _ = defaultAlloc); - - pragma(mangle, "_ZNSsD1Ev") + // ctor/dtor + this(const(T)* ptr, size_type count); + this(const(T)* ptr, size_type count, ref const(allocator_type) al = defaultAlloc); + this(const(T)* ptr); + this(const(T)* ptr, ref const(allocator_type) al = defaultAlloc); + extern(D) this(const(T)[] dstr) { this(dstr.ptr, dstr.length); } + extern(D) this(const(T)[] dstr, ref const(allocator_type) al = defaultAlloc) { this(dstr.ptr, dstr.length); } ~this(); - pragma(mangle, "_ZNSsaSERKSs") - ref basic_string opAssign(ref const basic_string s); + ref basic_string opAssign(ref const(basic_string) s); // Iterators - pragma(mangle, "_ZNSs5beginEv") iterator begin() nothrow; + const_iterator begin() const nothrow; + const_iterator cbegin() const nothrow; - pragma(mangle, "_ZNKSs5beginEv") - const_iterator begin() nothrow const; - - pragma(mangle, "_ZNKSs6cbeginEv") - const_iterator cbegin() nothrow const; - - pragma(mangle, "_ZNSs3endEv") iterator end() nothrow; - - pragma(mangle, "_ZNKSs3endEv") - const_iterator end() nothrow const; - - pragma(mangle, "_ZNKSs4cendEv") - const_iterator cend() nothrow const; + const_iterator end() const nothrow; + const_iterator cend() const nothrow; // no reverse iterator for now. // Capacity - pragma(mangle, "_ZNKSs4sizeEv") - size_t size() nothrow const; - - pragma(mangle, "_ZNKSs6lengthEv") - size_t length() nothrow const; - - pragma(mangle, "_ZNKSs8max_sizeEv") - size_t max_size() nothrow const; + size_type size() const nothrow; + size_type length() const nothrow; + size_type max_size() const nothrow; + size_type capacity() const nothrow; - pragma(mangle, "_ZNKSs8capacityEv") - size_t capacity() nothrow const; + bool empty() const nothrow; - pragma(mangle, "_ZNKSs5emptyEv") - bool empty() nothrow const; - - pragma(mangle, "_ZNSs5clearEv") void clear() nothrow; - - pragma(mangle, "_ZNSs6resizeEm") - void resize(size_t n); - - pragma(mangle, "_ZNSs6resizeEmc") - void resize(size_t n, T c); - - pragma(mangle, "_ZNSs7reserveEm") - void reserve(size_t n = 0); - - pragma(mangle, "_ZNSs13shrink_to_fitEv") + void resize(size_type n); + void resize(size_type n, T c); + void reserve(size_type n = 0); void shrink_to_fit(); // Element access - pragma(mangle, "_ZNSsixEm") - ref T opIndex(size_t i); - - pragma(mangle, "_ZNKSsixEm") - ref const(T) opIndex(size_t i) const; + ref T opIndex(size_type i); + ref const(T) opIndex(size_type i) const; + ref T at(size_type i); + ref const(T) at(size_type i) const; - pragma(mangle, "_ZNSs2atEm") - ref T at(size_t i); - - pragma(mangle, "_ZNKSs2atEm") - ref const(T) at(size_t i) const; - - pragma(mangle, "_ZNSs4backEv") ref T back(); - - pragma(mangle, "_ZNKSs4backEv") ref const(T) back() const; - - pragma(mangle, "_ZNSs5frontEv") ref T front(); - - pragma(mangle, "_ZNKSs5frontEv") ref const(T) front() const; - // Modifiers - pragma(mangle, "_ZNSspLERKSs") - ref basic_string opOpAssign(string op)(ref const basic_string _) if (op == "+"); - - pragma(mangle, "_ZNSspLEPKc") - ref basic_string opOpAssign(string op)(const(T*) _) if (op == "+"); - - pragma(mangle, "_ZNSspLEc") - ref basic_string opOpAssign(string op)(T _) if (op == "+"); - - pragma(mangle, "_ZNSs6appendEmc") - ref basic_string append(size_t n, char c); + const(T)* c_str() const nothrow; + T* data() nothrow; + const(T)* data() const nothrow; - pragma(mangle, "_ZNSs6appendEPKc") - ref basic_string append(const char* s); - - pragma(mangle, "_ZNSs6appendEPKcm") - ref basic_string append(const char* s, size_t n); - - pragma(mangle, "_ZNSs6appendERKSs") - ref basic_string append(ref const basic_string str); - - pragma(mangle, "_ZNSs6appendERKSsmm") - ref basic_string append(ref const basic_string str, size_t subpos, size_t sublen); + // Modifiers + ref basic_string opOpAssign(string op : "+")(ref const(basic_string) s); + ref basic_string opOpAssign(string op : "+")(const(T)* s); + ref basic_string opOpAssign(string op : "+")(T s); + extern(D) ref basic_string opOpAssign(string op : "~")(ref const(basic_string) s) { this += s; return this; } + extern(D) ref basic_string opOpAssign(string op : "~")(const(T)* s) { this += s; return this; } + extern(D) ref basic_string opOpAssign(string op : "~")(const(T)[] s) { auto t = basic_string(s.ptr, s.length); this += t; return this; } + extern(D) ref basic_string opOpAssign(string op : "~")(T s) { this += s; return this; } + + ref basic_string append(size_type n, T c); + ref basic_string append(const(T)* s); + ref basic_string append(const(T)* s, size_type n); + ref basic_string append(ref const(basic_string) str); + ref basic_string append(ref const(basic_string) str, size_type subpos, size_type sublen); + extern(D) ref basic_string append(const(T)[] s) { append(s.ptr, s.length); return this; } - pragma(mangle, "_ZNSs9push_backEc") void push_back(T c); - pragma(mangle, "_ZNSs6assignEmc") - ref basic_string assign(size_t n, char c); - - pragma(mangle, "_ZNSs6assignEPKc") - ref basic_string assign(const char* s); - - pragma(mangle, "_ZNSs6assignEPKcm") - ref basic_string assign(const char* s, size_t n); - - pragma(mangle, "_ZNSs6assignERKSs") - ref basic_string assign(ref const basic_string str); - - pragma(mangle, "_ZNSs6assignERKSsmm") - ref basic_string assign(ref const basic_string str, size_t subpos, size_t sublen); - - pragma(mangle, "_ZNSs6insertEmRKSs") - ref basic_string insert (size_t pos, ref const basic_string str); + ref basic_string assign(size_type n, T c); + ref basic_string assign(const(T)* s); + ref basic_string assign(const(T)* s, size_type n); + ref basic_string assign(ref const(basic_string) str); + ref basic_string assign(ref const(basic_string) str, size_type subpos, size_type sublen); + extern(D) ref basic_string assign(const(T)[] s) { assign(s.ptr, s.length); return this; } - pragma(mangle, "_ZNSs6insertEmRKSsmm") - ref basic_string insert (size_t pos, ref const basic_string str, size_t subpos, size_t sublen); + ref basic_string insert(size_type pos, ref const(basic_string) str); + ref basic_string insert(size_type pos, ref const(basic_string) str, size_type subpos, size_type sublen); + ref basic_string insert(size_type pos, const(T)* s); + ref basic_string insert(size_type pos, const(T)* s, size_type n); + ref basic_string insert(size_type pos, size_type n, T c); + extern(D) ref basic_string insert(size_type pos, const(T)[] s) { insert(pos, s.ptr, s.length); return this; } - pragma(mangle, "_ZNSs6insertEmPKc") - ref basic_string insert (size_t pos, const char* s); - - pragma(mangle, "_ZNSs6insertEmPKcm") - ref basic_string insert (size_t pos, const char* s, size_t n); - - pragma(mangle, "_ZNSs6insertEmmc") - ref basic_string insert (size_t pos, size_t n, char c); - - pragma(mangle, "_ZNSs5eraseEmm") - ref basic_string erase(size_t pos = 0, size_t len = npos); + ref basic_string erase(size_type pos = 0, size_type len = npos); // replace // swap - pragma(mangle, "_ZNSs8pop_backEv") void pop_back(); // String operations - pragma(mangle, "_ZNKSs5c_strEv") - const(T*) c_str() nothrow const; - - pragma(mangle, "_ZNKSs4dataEv") - const(T*) data() nothrow const; - - pragma(mangle, "_ZNKSs4copyEPcmm") - size_t copy(T* s, size_t len, size_t pos = 0) const; - - pragma(mangle, "_ZNKSs4findERKSsm") - size_t find(ref const basic_string str, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs4findEPKcm") - size_t find(const(T*) s, size_t pos = 0) const; - - pragma(mangle, "_ZNKSs4findEPKcmm") - size_t find(const(T*) s, size_t pos, size_type n) const; - - pragma(mangle, "_ZNKSs4findEcm") - size_t find(T c, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs5rfindERKSsm") - size_t rfind(ref const basic_string str, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs5rfindEPKcm") - size_t rfind(const(T*) s, size_t pos = npos) const; - - pragma(mangle, "_ZNKSs5rfindEPKcmm") - size_t rfind(const(T*) s, size_t pos, size_t n) const; - - pragma(mangle, "_ZNKSs5rfindEcm") - size_t rfind(T c, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs13find_first_ofERKSsm") - size_t find_first_of(ref const basic_string str, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs13find_first_ofEPKcm") - size_t find_first_of(const(T*) s, size_t pos = 0) const; - - pragma(mangle, "_ZNKSs13find_first_ofEPKcmm") - size_t find_first_of(const(T*) s, size_t pos, size_t n) const; - - pragma(mangle, "_ZNKSs13find_first_ofEcm") - size_t find_first_of(T c, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs12find_last_ofERKSsm") - size_t find_last_of(ref const basic_string str, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs12find_last_ofEPKcm") - size_t find_last_of(const(T*) s, size_t pos = npos) const; - - pragma(mangle, "_ZNKSs12find_last_ofEPKcmm") - size_t find_last_of(const(T*) s, size_t pos, size_t n) const; - - pragma(mangle, "_ZNKSs12find_last_ofEcm") - size_t find_last_of(T c, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs17find_first_not_ofERKSsm") - size_t find_first_not_of(ref const basic_string str, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs17find_first_not_ofEPKcm") - size_t find_first_not_of(const(T*) s, size_t pos = 0) const; - - pragma(mangle, "_ZNKSs17find_first_not_ofEPKcmm") - size_t find_first_not_of(const(T*) s, size_t pos, size_t n) const; - - pragma(mangle, "_ZNKSs17find_first_not_ofEcm") - size_t find_first_not_of(T c, size_t pos = 0) nothrow const; - - pragma(mangle, "_ZNKSs16find_last_not_ofERKSsm") - size_t find_last_not_of(ref const basic_string str, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs16find_last_not_ofEPKcm") - size_t find_last_not_of(const(T*) s, size_t pos = npos) const; - - pragma(mangle, "_ZNKSs16find_last_not_ofEPKcmm") - size_t find_last_not_of(const(T*) s, size_t pos, size_t n) const; - - pragma(mangle, "_ZNKSs16find_last_not_ofEcm") - size_t find_last_not_of(T c, size_t pos = npos) nothrow const; - - pragma(mangle, "_ZNKSs6substrEmm") - basic_string substr(size_t pos = 0, size_t len = npos) const; - - pragma(mangle, "_ZNKSs7compareERKSs") - int compare(ref const basic_string str) nothrow const; - - pragma(mangle, "_ZNKSs7compareEmmRKSs") - int compare(size_t pos, size_t len, ref const basic_string str) const; - - pragma(mangle, "_ZNKSs7compareEmmRKSsmm") - int compare(size_t pos, size_t len, ref const basic_string str, size_t subpos, size_t sublen) const; - - pragma(mangle, "_ZNKSs7compareEPKc") - int compare(const(T*) s) const; - - pragma(mangle, "_ZNKSs7compareEmmPKc") - int compare(size_t pos, size_t len, const(T*) s) const; - - pragma(mangle, "_ZNKSs7compareEmmPKcm") - int compare(size_t pos, size_t len, const(T*) s, size_t n) const; + size_type copy(T* s, size_type len, size_type pos = 0) const; + + size_type find(ref const(basic_string) str, size_type pos = 0) const nothrow; + size_type find(const(T)* s, size_type pos = 0) const; + size_type find(const(T)* s, size_type pos, size_type n) const; + size_type find(T c, size_type pos = 0) const nothrow; + + size_type rfind(ref const(basic_string) str, size_type pos = npos) const nothrow; + size_type rfind(const(T)* s, size_type pos = npos) const; + size_type rfind(const(T)* s, size_type pos, size_type n) const; + size_type rfind(T c, size_type pos = npos) const nothrow; + + size_type find_first_of(ref const(basic_string) str, size_type pos = 0) const nothrow; + size_type find_first_of(const(T)* s, size_type pos = 0) const; + size_type find_first_of(const(T)* s, size_type pos, size_type n) const; + size_type find_first_of(T c, size_type pos = 0) const nothrow; + + size_type find_last_of(ref const(basic_string) str, size_type pos = npos) const nothrow; + size_type find_last_of(const(T)* s, size_type pos = npos) const; + size_type find_last_of(const(T)* s, size_type pos, size_type n) const; + size_type find_last_of(T c, size_type pos = npos) const nothrow; + + size_type find_first_not_of(ref const(basic_string) str, size_type pos = 0) const nothrow; + size_type find_first_not_of(const(T)* s, size_type pos = 0) const; + size_type find_first_not_of(const(T)* s, size_type pos, size_type n) const; + size_type find_first_not_of(T c, size_type pos = 0) const nothrow; + + size_type find_last_not_of(ref const(basic_string) str, size_type pos = npos) const nothrow; + size_type find_last_not_of(const(T)* s, size_type pos = npos) const; + size_type find_last_not_of(const(T)* s, size_type pos, size_type n) const; + size_type find_last_not_of(T c, size_type pos = npos) const nothrow; + + basic_string substr(size_type pos = 0, size_type len = npos) const; + + int compare(ref const(basic_string) str) const nothrow; + int compare(size_type pos, size_type len, ref const(basic_string) str) const; + int compare(size_type pos, size_type len, ref const(basic_string) str, size_type subpos, size_type sublen) const; + int compare(const(T)* s) const; + int compare(size_type pos, size_type len, const(T)* s) const; + int compare(size_type pos, size_type len, const(T)* s, size_type n) const; // D helpers - const(T[]) asArray() const { return c_str()[0 .. size()]; } + alias as_array this; + extern(D) T[] as_array() { return data()[0 .. size()]; } + extern(D) const(T)[] as_array() const { return data()[0 .. size()]; } private: void[8] _ = void; // to match sizeof(std::string) and pad the object correctly. @@ -334,4 +198,6 @@ private: } alias basic_string!char std_string; -alias basic_string!wchar std_wstring; +//alias basic_string!wchar std_u16string; // TODO: can't mangle these yet either... +//alias basic_string!dchar std_u32string; +//alias basic_string!wchar_t std_wstring; // TODO: we can't mangle wchar_t properly (yet?) diff --git a/src/core/stdcpp/vector.d b/src/core/stdcpp/vector.d index d563d96455..4b37ccd78a 100644 --- a/src/core/stdcpp/vector.d +++ b/src/core/stdcpp/vector.d @@ -6,23 +6,18 @@ * $(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/vector.d) */ module core.stdcpp.vector; -// Because of broken name mangling of extern C++, this file is considered -// experimental and not yet available. -version(none): -pragma(lib, "stdc++"); - /////////////////////////////////////////////////////////////////////////////// // std::vector declaration. // // Current caveats : -// - manual name mangling (=> only vector!int is functionnal) -// See https://issues.dlang.org/show_bug.cgi?id=14086. -// - won't work with custom allocators. +// - mangling issues still exist +// - won't work with custom allocators // - missing noexcept // - iterators are implemented as pointers // - no reverse_iterator nor rbegin/rend @@ -32,14 +27,14 @@ import core.stdcpp.allocator; extern(C++, std): -struct vector(T, ALLOC = allocator!T) +extern(C++, class) struct vector(T, Alloc = allocator!T) { alias value_type = T; - alias allocator_type = ALLOC; + alias allocator_type = Alloc; alias reference = ref T; alias const_reference = ref const(T); alias pointer = T*; - alias const_pointer = const(T*); + alias const_pointer = const(T)*; alias iterator = pointer; alias const_iterator = const_pointer; // alias reverse_iterator @@ -47,111 +42,70 @@ struct vector(T, ALLOC = allocator!T) alias difference_type = ptrdiff_t; alias size_type = size_t; - // Ctor/dtor - pragma(mangle, "_ZNSt6vectorIiSaIiEEC1Ev") - this(); - - pragma(mangle, "_ZNSt6vectorIiSaIiEEC2EmRKS0_") - this(size_type n, ref const allocator_type _ = defaultAlloc); - - pragma(mangle, "_ZNSt6vectorIiSaIiEEC2EmRKiRKS0_") - this(size_type n, ref const value_type val, ref const allocator_type _ = defaultAlloc); - - pragma(mangle, "_ZNSt6vectorIiSaIiEEC2ERKS1_") - this(ref const vector x); - - pragma(mangle, "_ZNSt6vectorIiSaIiEED1Ev") + // ctor/dtor + this(size_type count); + this(size_type count, ref const(value_type) val); + this(size_type count, ref const(value_type) val, ref const(allocator_type) al = defaultAlloc); + this(ref const(vector) x); + this(iterator first, iterator last); + this(iterator first, iterator last, ref const(allocator_type) al = defaultAlloc); + this(const_iterator first, const_iterator last); + this(const_iterator first, const_iterator last, ref const(allocator_type) al = defaultAlloc); + extern(D) this(T[] arr) { this(arr.ptr, arr.ptr + arr.length); } + extern(D) this(T[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } + extern(D) this(const(T)[] arr) { this(arr.ptr, arr.ptr + arr.length); } + extern(D) this(const(T)[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } ~this(); - // pragma(mangle, "_ZNSt6vectorIiSaIiEEaSERKS1_") - // ref vector opAssign(ref const vector s); + ref vector opAssign(ref const(vector) s); // Iterators - pragma(mangle, "_ZNSt6vectorIiSaIiEE5beginEv") iterator begin(); - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE5beginEv") const_iterator begin() const; - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE6cbeginEv") const_iterator cbegin() const; - - pragma(mangle, "_ZNSt6vectorIiSaIiEE3endEv") iterator end(); - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE3endEv") const_iterator end() const; - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE4cendEv") const_iterator cend() const; // no reverse iterator for now. // Capacity - pragma(mangle, "_ZNKSt6vectorIiSaIiEE4sizeEv") - size_t size() const; - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE8max_sizeEv") - size_t max_size() const; + size_type size() const; + size_type max_size() const; + size_type capacity() const; - pragma(mangle, "_ZNKSt6vectorIiSaIiEE8capacityEv") - size_t capacity() const; - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE5emptyEv") bool empty() const; - pragma(mangle, "_ZNSt6vectorIiSaIiEE5clearEv") void clear(); - - pragma(mangle, "_ZNSt6vectorIiSaIiEE6resizeEm") - void resize(size_t n); - - pragma(mangle, "_ZNSt6vectorIiSaIiEE6resizeEmRKi") - void resize(size_t n, T c); - - pragma(mangle, "_ZNSt6vectorIiSaIiEE7reserveEm") - void reserve(size_t n = 0); - - pragma(mangle, "_ZNSt6vectorIiSaIiEE13shrink_to_fitEv") + void resize(size_type n); + void resize(size_type n, T c); + void reserve(size_type n = 0); void shrink_to_fit(); // Element access - pragma(mangle, "_ZNSt6vectorIiSaIiEEixEm") - ref T opIndex(size_t i); - - pragma(mangle, "_ZNKSt6vectorIiSaIiEEixEm") - ref const(T) opIndex(size_t i) const; + T* data() nothrow; + const(T)* data() const nothrow; - pragma(mangle, "_ZNSt6vectorIiSaIiEE2atEm") - ref T at(size_t i); + ref T opIndex(size_type i); + ref const(T) opIndex(size_type i) const; + ref T at(size_type i); + ref const(T) at(size_type i) const; - pragma(mangle, "_ZNKSt6vectorIiSaIiEE2atEm") - ref const(T) at(size_t i) const; - - pragma(mangle, "_ZNSt6vectorIiSaIiEE4backEv") ref T back(); - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE4backEv") ref const(T) back() const; - - pragma(mangle, "_ZNSt6vectorIiSaIiEE5frontEv") ref T front(); - - pragma(mangle, "_ZNKSt6vectorIiSaIiEE5frontEv") ref const(T) front() const; // Modifiers - pragma(mangle, "_ZNSt6vectorIiSaIiEE9push_backEOi") - void push_back(ref const T _); - - pragma(inline, true) - void push_back(const T _) { push_back(_);} // forwards to ref version + void push_back(ref const(T) _); + extern(D) void push_back(const(T) el) { push_back(el); } // forwards to ref version - pragma(mangle, "_ZNSt6vectorIiSaIiEE8pop_backEv") void pop_back(); // D helpers - const(T[]) asArray() const { return c_str()[0 .. size()]; } + alias as_array this; + extern(D) T[] as_array() { return data()[0 .. size()]; } + extern(D) const(T)[] as_array() const { return data()[0 .. size()]; } private: void[24] _ = void; // to match sizeof(std::vector) and pad the object correctly. From 11a185215d3c4c24f4435c0a0fd6c7781ac8c562 Mon Sep 17 00:00:00 2001 From: Manu Evans Date: Sat, 16 Jun 2018 15:50:04 -0700 Subject: [PATCH 3/5] Tweaked the stuff some more... --- src/core/stdcpp/string.d | 66 ++++++++++++++++++++++++---------------- src/core/stdcpp/vector.d | 64 +++++++++++++++++++++++--------------- 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/core/stdcpp/string.d b/src/core/stdcpp/string.d index 42b5984c46..6aa663a5ae 100644 --- a/src/core/stdcpp/string.d +++ b/src/core/stdcpp/string.d @@ -63,49 +63,49 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca this(const(T)* ptr, ref const(allocator_type) al = defaultAlloc); extern(D) this(const(T)[] dstr) { this(dstr.ptr, dstr.length); } extern(D) this(const(T)[] dstr, ref const(allocator_type) al = defaultAlloc) { this(dstr.ptr, dstr.length); } - ~this(); + ~this() nothrow; ref basic_string opAssign(ref const(basic_string) s); // Iterators - iterator begin() nothrow; - const_iterator begin() const nothrow; - const_iterator cbegin() const nothrow; + iterator begin() nothrow @trusted @nogc; + const_iterator begin() const nothrow @trusted @nogc; + const_iterator cbegin() const nothrow @trusted @nogc; - iterator end() nothrow; - const_iterator end() const nothrow; - const_iterator cend() const nothrow; + iterator end() nothrow @trusted @nogc; + const_iterator end() const nothrow @trusted @nogc; + const_iterator cend() const nothrow @trusted @nogc; // no reverse iterator for now. // Capacity - size_type size() const nothrow; - size_type length() const nothrow; - size_type max_size() const nothrow; - size_type capacity() const nothrow; + size_type size() const nothrow @trusted @nogc; + size_type length() const nothrow @trusted @nogc; + size_type max_size() const nothrow @trusted @nogc; + size_type capacity() const nothrow @trusted @nogc; - bool empty() const nothrow; + bool empty() const nothrow @trusted @nogc; void clear() nothrow; void resize(size_type n); void resize(size_type n, T c); - void reserve(size_type n = 0); + void reserve(size_type n = 0) @trusted @nogc; void shrink_to_fit(); // Element access - ref T opIndex(size_type i); - ref const(T) opIndex(size_type i) const; - ref T at(size_type i); - ref const(T) at(size_type i) const; + ref T opIndex(size_type i) @trusted @nogc; + ref const(T) opIndex(size_type i) const @trusted @nogc; + ref T at(size_type i) @trusted @nogc; + ref const(T) at(size_type i) const @trusted @nogc; - ref T back(); - ref const(T) back() const; - ref T front(); - ref const(T) front() const; + ref T back() @trusted @nogc; + ref const(T) back() const @trusted @nogc; + ref T front() @trusted @nogc; + ref const(T) front() const @trusted @nogc; - const(T)* c_str() const nothrow; - T* data() nothrow; - const(T)* data() const nothrow; + const(T)* c_str() const nothrow @trusted @nogc; + T* data() nothrow @trusted @nogc; + const(T)* data() const nothrow @trusted @nogc; // Modifiers ref basic_string opOpAssign(string op : "+")(ref const(basic_string) s); @@ -189,8 +189,22 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca // D helpers alias as_array this; - extern(D) T[] as_array() { return data()[0 .. size()]; } - extern(D) const(T)[] as_array() const { return data()[0 .. size()]; } + extern(D) T[] as_array() nothrow @safe @nogc { return this[]; } + extern(D) const(T)[] as_array() const nothrow @safe @nogc { return this[]; } + + extern(D) T[] opSlice() nothrow @safe @nogc { return data()[0 .. size()]; } + extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return data()[0 .. size()]; } + extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } + + // support all the assignment variants + extern(D) void opSliceAssign(T value) { opSlice()[] = value; } + extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } + extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } + extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } + extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } + extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } private: void[8] _ = void; // to match sizeof(std::string) and pad the object correctly. diff --git a/src/core/stdcpp/vector.d b/src/core/stdcpp/vector.d index 4b37ccd78a..ac7c2205ef 100644 --- a/src/core/stdcpp/vector.d +++ b/src/core/stdcpp/vector.d @@ -21,6 +21,8 @@ module core.stdcpp.vector; // - missing noexcept // - iterators are implemented as pointers // - no reverse_iterator nor rbegin/rend +// - nothrow @trusted @nogc for most functions depend on knowledge +// of T's construction/destruction/assignment semantics /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; @@ -60,41 +62,41 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) ref vector opAssign(ref const(vector) s); // Iterators - iterator begin(); - const_iterator begin() const; - const_iterator cbegin() const; - iterator end(); - const_iterator end() const; - const_iterator cend() const; + iterator begin() @trusted @nogc; + const_iterator begin() const @trusted @nogc; + const_iterator cbegin() const @trusted @nogc; + iterator end() @trusted @nogc; + const_iterator end() const @trusted @nogc; + const_iterator cend() const @trusted @nogc; // no reverse iterator for now. // Capacity - size_type size() const; - size_type max_size() const; - size_type capacity() const; + size_type size() const nothrow @trusted @nogc; + size_type max_size() const nothrow @trusted @nogc; + size_type capacity() const nothrow @trusted @nogc; - bool empty() const; + bool empty() const nothrow @trusted @nogc; - void clear(); + void clear() nothrow; void resize(size_type n); void resize(size_type n, T c); - void reserve(size_type n = 0); + void reserve(size_type n = 0) @trusted @nogc; void shrink_to_fit(); // Element access - T* data() nothrow; - const(T)* data() const nothrow; + T* data() nothrow @trusted @nogc; + const(T)* data() const nothrow @trusted @nogc; - ref T opIndex(size_type i); - ref const(T) opIndex(size_type i) const; - ref T at(size_type i); - ref const(T) at(size_type i) const; + ref T opIndex(size_type i) @trusted @nogc; + ref const(T) opIndex(size_type i) const @trusted @nogc; + ref T at(size_type i) @trusted @nogc; + ref const(T) at(size_type i) const @trusted @nogc; - ref T back(); - ref const(T) back() const; - ref T front(); - ref const(T) front() const; + ref T back() @trusted @nogc; + ref const(T) back() const @trusted @nogc; + ref T front() @trusted @nogc; + ref const(T) front() const @trusted @nogc; // Modifiers void push_back(ref const(T) _); @@ -104,8 +106,22 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) // D helpers alias as_array this; - extern(D) T[] as_array() { return data()[0 .. size()]; } - extern(D) const(T)[] as_array() const { return data()[0 .. size()]; } + extern(D) T[] as_array() nothrow @safe @nogc { return this[]; } + extern(D) const(T)[] as_array() const nothrow @safe @nogc { return this[]; } + + extern(D) T[] opSlice() nothrow @safe @nogc { return data()[0 .. size()]; } + extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return data()[0 .. size()]; } + extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } + + // support all the assignment variants + extern(D) void opSliceAssign(T value) { opSlice()[] = value; } + extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } + extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } + extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } + extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } + extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } private: void[24] _ = void; // to match sizeof(std::vector) and pad the object correctly. From 585e8c4f70594fd9dde1314d7de3641d570f1096 Mon Sep 17 00:00:00 2001 From: Manu Evans Date: Sat, 4 Aug 2018 15:31:59 -0700 Subject: [PATCH 4/5] string, vector, array working on MSVC. --- mak/COPY | 7 +- mak/DOCS | 7 +- mak/SRCS | 5 ++ src/core/stdcpp/allocator.d | 2 + src/core/stdcpp/array.d | 133 +++++++++++++++++++++++++++++++ src/core/stdcpp/exception.d | 151 ++++++++++++++++++------------------ src/core/stdcpp/string.d | 118 ++++++++++++++++++---------- src/core/stdcpp/tuple.d | 56 +++++++++++++ src/core/stdcpp/typeinfo.d | 20 ++--- src/core/stdcpp/utility.d | 69 ++++++++++++++++ src/core/stdcpp/vector.d | 74 ++++++++++++------ 11 files changed, 491 insertions(+), 151 deletions(-) create mode 100644 src/core/stdcpp/array.d create mode 100644 src/core/stdcpp/tuple.d create mode 100644 src/core/stdcpp/utility.d diff --git a/mak/COPY b/mak/COPY index d3042edf50..e187c4aabd 100644 --- a/mak/COPY +++ b/mak/COPY @@ -48,10 +48,13 @@ COPY=\ $(IMPDIR)\core\stdc\wchar_.d \ $(IMPDIR)\core\stdc\wctype.d \ \ - $(IMPDIR)\core\stdcpp\typeinfo.d \ - $(IMPDIR)\core\stdcpp\exception.d \ $(IMPDIR)\core\stdcpp\allocator.d \ + $(IMPDIR)\core\stdcpp\array.d \ + $(IMPDIR)\core\stdcpp\exception.d \ $(IMPDIR)\core\stdcpp\string.d \ + $(IMPDIR)\core\stdcpp\tuple.d \ + $(IMPDIR)\core\stdcpp\typeinfo.d \ + $(IMPDIR)\core\stdcpp\utility.d \ $(IMPDIR)\core\stdcpp\vector.d \ \ $(IMPDIR)\core\sys\darwin\execinfo.d \ diff --git a/mak/DOCS b/mak/DOCS index dd12a6838c..5b4affca82 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -38,10 +38,13 @@ DOCS=\ $(DOCDIR)\core_stdc_wchar_.html \ $(DOCDIR)\core_stdc_wctype.html \ \ - $(DOCDIR)\core_stdcpp_exception.html \ - $(DOCDIR)\core_stdcpp_typeinfo.html \ $(DOCDIR)\core_stdcpp_allocator.html \ + $(DOCDIR)\core_stdcpp_array.html \ + $(DOCDIR)\core_stdcpp_exception.html \ $(DOCDIR)\core_stdcpp_string.html \ + $(DOCDIR)\core_stdcpp_tuple.html \ + $(DOCDIR)\core_stdcpp_typeinfo.html \ + $(DOCDIR)\core_stdcpp_utility.html \ $(DOCDIR)\core_stdcpp_vector.html \ \ $(DOCDIR)\core_sync_barrier.html \ diff --git a/mak/SRCS b/mak/SRCS index 3f8b860291..0cea3391b6 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -47,7 +47,12 @@ SRCS=\ src\core\stdc\wchar_.d \ \ src\core\stdcpp\allocator.d \ + src\core\stdcpp\array.d \ + src\core\stdcpp\exception.d \ src\core\stdcpp\string.d \ + src\core\stdcpp\tuple.d \ + src\core\stdcpp\typeinfo.d \ + src\core\stdcpp\utility.d \ src\core\stdcpp\vector.d \ \ src\core\sync\barrier.d \ diff --git a/src/core/stdcpp/allocator.d b/src/core/stdcpp/allocator.d index 015445ad50..b92175978f 100644 --- a/src/core/stdcpp/allocator.d +++ b/src/core/stdcpp/allocator.d @@ -12,6 +12,8 @@ module core.stdcpp.allocator; +alias allocator = std.allocator; + extern(C++, std): /** diff --git a/src/core/stdcpp/array.d b/src/core/stdcpp/array.d new file mode 100644 index 0000000000..c692b15d5f --- /dev/null +++ b/src/core/stdcpp/array.d @@ -0,0 +1,133 @@ +/** + * D header file for interaction with C++ std::array. + * + * Copyright: Manu Evans 2014 - 2018. + * License: Distributed under the + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + * (See accompanying file LICENSE) + * Authors: Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/array.d) + */ + +module core.stdcpp.array; + +/////////////////////////////////////////////////////////////////////////////// +// std::array declaration. +// +// - no iterators +/////////////////////////////////////////////////////////////////////////////// + +import stdcpp.allocator; + +alias array = std.array; + +extern(C++, std): + +extern(C++, class) struct array(T, size_t N) +{ + alias size_type = size_t; + alias difference_type = ptrdiff_t; + alias value_type = T; + alias reference = ref T; + alias const_reference = ref const(T); + alias pointer = T*; + alias const_pointer = const(T)*; +// alias iterator = pointer; +// alias const_iterator = const_pointer; +// alias reverse_iterator +// alias const_reverse_iterator + + // Iterators +// iterator begin() @trusted @nogc; +// const_iterator begin() const @trusted @nogc; +// const_iterator cbegin() const @trusted @nogc; +// iterator end() @trusted @nogc; +// const_iterator end() const @trusted @nogc; +// const_iterator cend() const @trusted @nogc; + + // no reverse iterator for now. + + alias as_array this; + + extern(D) size_type size() const nothrow @safe @nogc { return N; } + extern(D) size_type max_size() const nothrow @safe @nogc { return N; } + extern(D) bool empty() const nothrow @safe @nogc { return N > 0; } + + // Element access + extern(D) reference front() @safe @nogc { return as_array()[0]; } + extern(D) const_reference front() const @safe @nogc { return as_array()[0]; } + extern(D) reference back() @safe @nogc { return as_array()[N == 0 ? 0 : N-1]; } + extern(D) const_reference back() const @safe @nogc { return as_array()[N == 0 ? 0 : N-1]; } + + extern(D) void fill(ref const(T) value) @safe @nogc { foreach (ref T v; as_array()) v = value; } + + // D helpers + extern(D) T[] opSlice() nothrow @safe @nogc { return as_array(); } + extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return as_array(); } + extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= N, "Index out of bounds"); return as_array()[start .. end]; } + extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= N, "Index out of bounds"); return as_array()[start .. end]; } + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return N; } + + // support all the assignment variants + extern(D) void opSliceAssign(T value) { opSlice()[] = value; } + extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } + extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } + extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } + extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } + extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } + +private: + version(CRuntime_Microsoft) + { + import core.stdcpp.utility : _Xout_of_range; + + T[N ? N : 1] _Elems; + + void _Xran() const @trusted @nogc { _Xout_of_range("invalid array subscript"); } + + public: + // perf will be greatly improved by inlining the primitive access functions + extern(D) T* data() nothrow @safe @nogc { return &_Elems[0]; } + extern(D) const(T)* data() const nothrow @safe @nogc { return &_Elems[0]; } + + extern(D) ref T opIndex(size_type i) nothrow @safe @nogc { return _Elems[0 .. N][i]; } + extern(D) ref const(T) opIndex(size_type i) const nothrow @safe @nogc { return _Elems[0 .. N][i]; } + extern(D) ref T at(size_type i) nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); } } + extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); } } + + extern(D) T[] as_array() nothrow @safe @nogc { return _Elems[0 .. N]; } + extern(D) const(T)[] as_array() const nothrow @safe @nogc { return _Elems[0 .. N]; } + } + else version(CRuntime_Glibc) + { + static if (N > 0) + { + T[N] _M_elems; + } + else + { + struct _Placeholder {} + _Placeholder _M_placeholder; + } + + public: + import core.exception : RangeError; + + // perf will be greatly improved by inlining the primitive access functions + extern(D) T* data() nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } + extern(D) const(T)* data() const nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } + + extern(D) ref T opIndex(size_type i) nothrow @nogc { static if (N > 0) { return _M_elems[i]; } else { return (cast(T[])null)[i]; } } + extern(D) ref const(T) opIndex(size_type i) const nothrow @nogc { static if (N > 0) { return _M_elems[i]; } else { return (cast(T[])null)[i]; } } + extern(D) ref T at(size_type i) @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } + extern(D) ref const(T) at(size_type i) const @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } + + alias as_array this; + extern(D) T[] as_array() nothrow @safe @nogc { static if (N > 0) { return _M_elems[]; } else { return null; } } + extern(D) const(T)[] as_array() const nothrow @safe @nogc { static if (N > 0) { return _M_elems[]; } else { return null; } } + } + else + { + static assert(false, "C++ runtime not supported"); + } +} diff --git a/src/core/stdcpp/exception.d b/src/core/stdcpp/exception.d index 1a54ccc4de..af5a986772 100644 --- a/src/core/stdcpp/exception.d +++ b/src/core/stdcpp/exception.d @@ -11,95 +11,96 @@ module core.stdcpp.exception; +alias exception = std.exception; +alias bad_exception = std.bad_exception; +alias bad_alloc = std.bad_alloc; + +extern (C++, std): + version (CRuntime_DigitalMars) { import core.stdcpp.typeinfo; - extern (C++, std) + alias void function() unexpected_handler; + unexpected_handler set_unexpected(unexpected_handler f) nothrow; + void unexpected(); + + alias void function() terminate_handler; + terminate_handler set_terminate(terminate_handler f) nothrow; + void terminate(); + + bool uncaught_exception(); + + class exception { - alias void function() unexpected_handler; - unexpected_handler set_unexpected(unexpected_handler f) nothrow; - void unexpected(); - - alias void function() terminate_handler; - terminate_handler set_terminate(terminate_handler f) nothrow; - void terminate(); - - bool uncaught_exception(); - - class exception - { - this() nothrow { } - this(const exception) nothrow { } - //exception operator=(const exception) nothrow { return this; } - //virtual ~this() nothrow; - void dtor() { } - const(char)* what() const nothrow; - } - - class bad_exception : exception - { - this() nothrow { } - this(const bad_exception) nothrow { } - //bad_exception operator=(const bad_exception) nothrow { return this; } - //virtual ~this() nothrow; - override const(char)* what() const nothrow; - } + this() nothrow { } + this(const exception) nothrow { } + //exception operator=(const exception) nothrow { return this; } + //virtual ~this() nothrow; + void dtor() { } + const(char)* what() const nothrow; + } + + class bad_exception : exception + { + this() nothrow { } + this(const bad_exception) nothrow { } + //bad_exception operator=(const bad_exception) nothrow { return this; } + //virtual ~this() nothrow; + override const(char)* what() const nothrow; } } else version (CRuntime_Glibc) { - extern (C++, std) + alias void function() unexpected_handler; + unexpected_handler set_unexpected(unexpected_handler f) nothrow; + void unexpected(); + + alias void function() terminate_handler; + terminate_handler set_terminate(terminate_handler f) nothrow; + void terminate(); + + pure bool uncaught_exception(); + + class exception { - alias void function() unexpected_handler; - unexpected_handler set_unexpected(unexpected_handler f) nothrow; - void unexpected(); - - alias void function() terminate_handler; - terminate_handler set_terminate(terminate_handler f) nothrow; - void terminate(); - - pure bool uncaught_exception(); - - class exception - { - this(); - //virtual ~this(); - void dtor1(); - void dtor2(); - const(char)* what() const; - } - - class bad_exception : exception - { - this(); - //virtual ~this(); - override const(char)* what() const; - } + this(); + //virtual ~this(); + void dtor1(); + void dtor2(); + const(char)* what() const; + } + + class bad_exception : exception + { + this(); + //virtual ~this(); + override const(char)* what() const; } } else version (CRuntime_Microsoft) { - extern (C++, std) + class exception + { + this(const(char)* _Message = "unknown", int x = 1) { _Ptr = _Message; } + this(ref const(exception) _Right) { _Ptr = _Right._Ptr; } + ~this() {} + + const(char)* what() const { return _Ptr ? _Ptr : "unknown exception"; } + + private: + const(char)* _Ptr; + } + + class bad_exception : exception + { + this(const(char)* _Message = "bad exception") { super(_Message); } + ~this() {} + } + + class bad_alloc : exception { - class exception - { - this(); - this(const exception); - //exception operator=(const exception) { return this; } - //virtual ~this(); - void dtor() { } - const(char)* what() const; - - private: - const(char)* mywhat; - bool dofree; - } - - class bad_exception : exception - { - this(const(char)* msg = "bad exception"); - //virtual ~this(); - } + this() { super("bad allocation", 1); } + ~this() {} } } diff --git a/src/core/stdcpp/string.d b/src/core/stdcpp/string.d index 6aa663a5ae..a797743202 100644 --- a/src/core/stdcpp/string.d +++ b/src/core/stdcpp/string.d @@ -24,7 +24,12 @@ module core.stdcpp.string; /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; -import core.stdc.stddef; +import core.stdc.stddef : wchar_t; + +alias std_string = std.string; +//alias std_u16string = std.u16string; +//alias std_u32string = std.u32string; +//alias std_wstring = std.wstring; extern(C++, std): @@ -32,7 +37,7 @@ extern(C++, std): * Character traits classes specify character properties and provide specific * semantics for certain operations on characters and sequences of characters. */ -struct char_traits(CharT) {} +extern(C++, struct) struct char_traits(CharT) {} /** * The basic_string is the generalization of class string for any character @@ -42,27 +47,29 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca { 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 reference = ref T; - alias const_reference = ref const(T); - alias pointer = T*; - alias const_pointer = const(T)*; + alias reference = ref value_type; + alias const_reference = ref const(value_type); + alias pointer = value_type*; + alias const_pointer = const(value_type)*; alias iterator = pointer; alias const_iterator = const_pointer; // alias reverse_iterator // alias const_reverse_iterator - alias difference_type = ptrdiff_t; - alias size_type = size_t; + + alias as_array this; // ctor/dtor this(const(T)* ptr, size_type count); - this(const(T)* ptr, size_type count, ref const(allocator_type) al = defaultAlloc); + this(const(T)* ptr, size_type count, ref const(allocator_type) al); this(const(T)* ptr); - this(const(T)* ptr, ref const(allocator_type) al = defaultAlloc); - extern(D) this(const(T)[] dstr) { this(dstr.ptr, dstr.length); } - extern(D) this(const(T)[] dstr, ref const(allocator_type) al = defaultAlloc) { this(dstr.ptr, dstr.length); } + this(const(T)* ptr, ref const(allocator_type) al); +// extern(D) this(const(T)[] dstr) { this(dstr.ptr, dstr.length); } +// extern(D) this(const(T)[] dstr, ref const(allocator_type) al) { this(dstr.ptr, dstr.length, al); } ~this() nothrow; ref basic_string opAssign(ref const(basic_string) s); @@ -79,12 +86,10 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca // no reverse iterator for now. // Capacity - size_type size() const nothrow @trusted @nogc; - size_type length() const nothrow @trusted @nogc; + size_type length() const nothrow @trusted @nogc { return size(); } size_type max_size() const nothrow @trusted @nogc; - size_type capacity() const nothrow @trusted @nogc; - bool empty() const nothrow @trusted @nogc; + bool empty() const nothrow @trusted @nogc { return size() == 0; } void clear() nothrow; void resize(size_type n); @@ -93,19 +98,12 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca void shrink_to_fit(); // Element access - ref T opIndex(size_type i) @trusted @nogc; - ref const(T) opIndex(size_type i) const @trusted @nogc; - ref T at(size_type i) @trusted @nogc; - ref const(T) at(size_type i) const @trusted @nogc; - ref T back() @trusted @nogc; ref const(T) back() const @trusted @nogc; ref T front() @trusted @nogc; ref const(T) front() const @trusted @nogc; - const(T)* c_str() const nothrow @trusted @nogc; - T* data() nothrow @trusted @nogc; - const(T)* data() const nothrow @trusted @nogc; + extern(D) const(T)* c_str() const nothrow @trusted @nogc { return data(); } // Modifiers ref basic_string opOpAssign(string op : "+")(ref const(basic_string) s); @@ -137,7 +135,7 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca ref basic_string insert(size_type pos, const(T)* s); ref basic_string insert(size_type pos, const(T)* s, size_type n); ref basic_string insert(size_type pos, size_type n, T c); - extern(D) ref basic_string insert(size_type pos, const(T)[] s) { insert(pos, s.ptr, s.length); return this; } +// extern(D) ref basic_string insert(size_type pos, const(T)[] s) { insert(pos, s.ptr, s.length); return this; } ref basic_string erase(size_type pos = 0, size_type len = npos); @@ -188,14 +186,10 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca int compare(size_type pos, size_type len, const(T)* s, size_type n) const; // D helpers - alias as_array this; - extern(D) T[] as_array() nothrow @safe @nogc { return this[]; } - extern(D) const(T)[] as_array() const nothrow @safe @nogc { return this[]; } - - extern(D) T[] opSlice() nothrow @safe @nogc { return data()[0 .. size()]; } - extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return data()[0 .. size()]; } - extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } - extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) T[] opSlice() nothrow @trusted @nogc { return as_array(); } + extern(D) const(T)[] opSlice() const nothrow @trusted @nogc { return as_array(); } + extern(D) T[] opSlice(size_type start, size_type end) @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return as_array()[start .. end]; } + extern(D) const(T)[] opSlice(size_type start, size_type end) const @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return as_array()[start .. end]; } extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } // support all the assignment variants @@ -207,11 +201,57 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } private: - void[8] _ = void; // to match sizeof(std::string) and pad the object correctly. - __gshared static immutable allocator!T defaultAlloc; + version(CRuntime_Microsoft) + { + import core.stdcpp.utility : _Container_base, _Compressed_pair, _Xout_of_range; + + void _Xran() const @trusted @nogc { _Xout_of_range("invalid string position"); } + + extern(C++, class) struct _String_val + { + enum _BUF_SIZE = 16 / value_type.sizeof < 1 ? 1 : 16 / value_type.sizeof; + + union _Bxty + { + value_type[_BUF_SIZE] _Buf; + pointer _Ptr; + } + + _Container_base base; + alias base this; + + _Bxty _Bx = void; + size_type _Mysize; // current length of string + size_type _Myres; // current storage reserved for string + + extern(D) @property inout(value_type)* _Myptr() inout nothrow @trusted @nogc { return _BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf.ptr; } + } + + _Compressed_pair!(void, _String_val) _Mypair; + + public: + // perf will be greatly improved by inlining the primitive access functions + extern(D) size_type size() const nothrow @safe @nogc { return _Mypair._Myval2._Mysize; } + extern(D) size_type capacity() const nothrow @safe @nogc { return _Mypair._Myval2._Myres; } + + extern(D) T* data() nothrow @safe @nogc { return _Mypair._Myval2._Myptr; } + extern(D) const(T)* data() const nothrow @safe @nogc { return _Mypair._Myval2._Myptr; } + + extern(D) ref T opIndex(size_type i) nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize][i]; } + extern(D) ref const(T) opIndex(size_type i) const nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize][i]; } + extern(D) ref T at(size_type i) nothrow @trusted @nogc { if (_Mypair._Myval2._Mysize <= i) _Xran(); return _Mypair._Myval2._Myptr[i]; } + extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { if (_Mypair._Myval2._Mysize <= i) _Xran(); return _Mypair._Myval2._Myptr[i]; } + + extern(D) T[] as_array() nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize]; } + extern(D) const(T)[] as_array() const nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize]; } + } + else + { + static assert(false, "C++ runtime not supported"); + } } -alias basic_string!char std_string; -//alias basic_string!wchar std_u16string; // TODO: can't mangle these yet either... -//alias basic_string!dchar std_u32string; -//alias basic_string!wchar_t std_wstring; // TODO: we can't mangle wchar_t properly (yet?) +alias basic_string!char string; +//alias basic_string!wchar u16string; // TODO: can't mangle these yet either... +//alias basic_string!dchar u32string; +//alias basic_string!wchar_t wstring; // TODO: we can't mangle wchar_t properly (yet?) diff --git a/src/core/stdcpp/tuple.d b/src/core/stdcpp/tuple.d new file mode 100644 index 0000000000..deef82bf85 --- /dev/null +++ b/src/core/stdcpp/tuple.d @@ -0,0 +1,56 @@ +/** + * D header file for interaction with C++ std::tuple. + * + * Copyright: Copyright Manu Evans 2018. + * License: Distributed under the + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + * (See accompanying file LICENSE) + * Authors: Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/tuple.d) + */ + +module core.stdcpp.tuple; + +alias std_tuple = std.tuple; + +extern(C++, std): + +private template allTypes(T...) +{ + static if (T.length == 0) + enum allTypes = true; + else + enum allTypes = is(T[0]) && allTypes!(T[1 .. $]); +} + +extern(C++, class) struct tuple(Types...) if (allTypes!Types) +{ + enum length = Types.length; + + ref auto get(size_t i)() nothrow @safe @nogc { return tupleof[i]; } + + auto opSlice() { return this.tupleof; } + alias opSlice this; + +private: + template ToNum(size_t i) + { + static if (i < 10) + enum ToNum = [ '0' + i ]; + else + enum ToNum = ToNum!(i / 10) ~ [ '0' + (i % 10) ]; + } + static foreach (i, T; Types) + mixin("T v" ~ ToNum!i ~ ";"); +} + +struct tuple_element(size_t i, T : tuple!Types, Types...) +{ + alias type = Types[i]; +} +alias tuple_element_t(size_t i, T : tuple!Types, Types...) = tuple_element!(i, tuple!Types).type; + +auto ref tuple_element_t!(i, T) get(size_t i, T : tuple!Types, Types...)(auto ref T tup) +{ + return tup.tupleof[i]; +} diff --git a/src/core/stdcpp/typeinfo.d b/src/core/stdcpp/typeinfo.d index 085b10b74e..a7b7b0b6d3 100644 --- a/src/core/stdcpp/typeinfo.d +++ b/src/core/stdcpp/typeinfo.d @@ -36,7 +36,7 @@ version (CRuntime_DigitalMars) //type_info operator=(const type_info rhs); } - class bad_cast : core.stdcpp.exception.std.exception + class bad_cast : exception { this() nothrow { } this(const bad_cast) nothrow { } @@ -45,7 +45,7 @@ version (CRuntime_DigitalMars) override const(char)* what() const nothrow; } - class bad_typeid : core.stdcpp.exception.std.exception + class bad_typeid : exception { this() nothrow { } this(const bad_typeid) nothrow { } @@ -84,16 +84,16 @@ else version (CRuntime_Microsoft) //type_info operator=(const type_info rhs); } - class bad_cast : core.stdcpp.exception.std.exception + class bad_cast : exception { - this(const(char)* msg = "bad cast"); - //virtual ~this(); + this(const(char)* _Message = "bad cast") { super(_Message); } + ~this() {} } - class bad_typeid : core.stdcpp.exception.std.exception + class bad_typeid :exception { - this(const(char)* msg = "bad typeid"); - //virtual ~this(); + this(const(char)* _Message = "bad typeid") { super(_Message); } + ~this() {} } } } @@ -131,14 +131,14 @@ else version (CRuntime_Glibc) this(const(char)*); } - class bad_cast : core.stdcpp.exception.std.exception + class bad_cast : exception { this(); //~this(); override const(char)* what() const; } - class bad_typeid : core.stdcpp.exception.std.exception + class bad_typeid : exception { this(); //~this(); diff --git a/src/core/stdcpp/utility.d b/src/core/stdcpp/utility.d new file mode 100644 index 0000000000..f841590f62 --- /dev/null +++ b/src/core/stdcpp/utility.d @@ -0,0 +1,69 @@ +/** + * D header file for interaction with C++ std::utility. + * + * Copyright: Copyright Manu Evans 2018. + * License: Distributed under the + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + * (See accompanying file LICENSE) + * Authors: Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/utility.d) + */ + +module core.stdcpp.utility; + +extern(C++, std): + +/** + * std.pair is a struct template that provides a way to store two heterogeneous objects as a single unit. + * A pair is a specific case of a std.tuple with two elements. + */ +struct pair(T1, T2) +{ + alias first_type = T1; + alias second_type = T2; + + first_type first; + second_type second; +} + +version(CRuntime_Microsoft) +{ + version (_ITERATOR_DEBUG_LEVEL_0) + enum _ITERATOR_DEBUG_LEVEL = 0; + else version (_ITERATOR_DEBUG_LEVEL_1) + enum _ITERATOR_DEBUG_LEVEL = 1; + else version (_ITERATOR_DEBUG_LEVEL_2) + enum _ITERATOR_DEBUG_LEVEL = 2; + else + enum _ITERATOR_DEBUG_LEVEL = 0; // default? dunno... + + static if (_ITERATOR_DEBUG_LEVEL == 0) + { + struct _Container_base0 {} + alias _Container_base = _Container_base0; + } + else + { + struct _Container_proxy + { + const(_Container_base12)* _Mycont; + _Iterator_base12* _Myfirstiter; + } + struct _Container_base12 { _Container_proxy* _Myproxy; } + alias _Container_base = _Container_base12; + } + + extern (C++, class) struct _Compressed_pair(_Ty1, _Ty2, bool Ty1Empty = is(_Ty1 == void)) + { + static if (!Ty1Empty) + _Ty1 _Myval1; + _Ty2 _Myval2; + } + + void _Xbad_alloc() nothrow @trusted @nogc; + void _Xinvalid_argument(const(char)* message) nothrow @trusted @nogc; + void _Xlength_error(const(char)* message) nothrow @trusted @nogc; + void _Xout_of_range(const(char)* message) nothrow @trusted @nogc; + void _Xoverflow_error(const(char)* message) nothrow @trusted @nogc; + void _Xruntime_error(const(char)* message) nothrow @trusted @nogc; +} diff --git a/src/core/stdcpp/vector.d b/src/core/stdcpp/vector.d index ac7c2205ef..08a0116147 100644 --- a/src/core/stdcpp/vector.d +++ b/src/core/stdcpp/vector.d @@ -27,6 +27,8 @@ module core.stdcpp.vector; import core.stdcpp.allocator; +alias vector = std.vector; + extern(C++, std): extern(C++, class) struct vector(T, Alloc = allocator!T) @@ -44,6 +46,8 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) alias difference_type = ptrdiff_t; alias size_type = size_t; + alias as_array this; + // ctor/dtor this(size_type count); this(size_type count, ref const(value_type) val); @@ -53,10 +57,10 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) this(iterator first, iterator last, ref const(allocator_type) al = defaultAlloc); this(const_iterator first, const_iterator last); this(const_iterator first, const_iterator last, ref const(allocator_type) al = defaultAlloc); - extern(D) this(T[] arr) { this(arr.ptr, arr.ptr + arr.length); } - extern(D) this(T[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } - extern(D) this(const(T)[] arr) { this(arr.ptr, arr.ptr + arr.length); } - extern(D) this(const(T)[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } +// extern(D) this(T[] arr) { this(arr.ptr, arr.ptr + arr.length); } +// extern(D) this(T[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } +// extern(D) this(const(T)[] arr) { this(arr.ptr, arr.ptr + arr.length); } +// extern(D) this(const(T)[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } ~this(); ref vector opAssign(ref const(vector) s); @@ -72,11 +76,7 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) // no reverse iterator for now. // Capacity - size_type size() const nothrow @trusted @nogc; size_type max_size() const nothrow @trusted @nogc; - size_type capacity() const nothrow @trusted @nogc; - - bool empty() const nothrow @trusted @nogc; void clear() nothrow; void resize(size_type n); @@ -85,14 +85,6 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) void shrink_to_fit(); // Element access - T* data() nothrow @trusted @nogc; - const(T)* data() const nothrow @trusted @nogc; - - ref T opIndex(size_type i) @trusted @nogc; - ref const(T) opIndex(size_type i) const @trusted @nogc; - ref T at(size_type i) @trusted @nogc; - ref const(T) at(size_type i) const @trusted @nogc; - ref T back() @trusted @nogc; ref const(T) back() const @trusted @nogc; ref T front() @trusted @nogc; @@ -105,14 +97,13 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) void pop_back(); // D helpers - alias as_array this; extern(D) T[] as_array() nothrow @safe @nogc { return this[]; } extern(D) const(T)[] as_array() const nothrow @safe @nogc { return this[]; } - extern(D) T[] opSlice() nothrow @safe @nogc { return data()[0 .. size()]; } - extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return data()[0 .. size()]; } - extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } - extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) T[] opSlice() nothrow @trusted @nogc { return data()[0 .. size()]; } + extern(D) const(T)[] opSlice() const nothrow @trusted @nogc { return data()[0 .. size()]; } + extern(D) T[] opSlice(size_type start, size_type end) @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } + extern(D) const(T)[] opSlice(size_type start, size_type end) const @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } // support all the assignment variants @@ -124,6 +115,43 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } private: - void[24] _ = void; // to match sizeof(std::vector) and pad the object correctly. - __gshared static immutable allocator!T defaultAlloc; + extern (D) __gshared static immutable allocator!T defaultAlloc; + + version(CRuntime_Microsoft) + { + import core.stdcpp.utility : _Container_base, _Compressed_pair, _Xlength_error, _Xout_of_range; + + void _Xlen() const @trusted @nogc { _Xlength_error("vector!T too long"); } + void _Xran() const @trusted @nogc { _Xout_of_range("invalid vector!T subscript"); } + + extern (C++, class) struct _Vector_val + { + _Container_base base; + alias base this; + + pointer _Myfirst; // pointer to beginning of array + pointer _Mylast; // pointer to current end of sequence + pointer _Myend; // pointer to end of array + } + + _Compressed_pair!(void, _Vector_val) _Mypair; + + public: + // perf will be greatly improved by inlining the primitive access functions + extern(D) size_type size() const nothrow @safe @nogc { return _Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst; } + extern(D) size_type capacity() const nothrow @safe @nogc { return _Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst; } + extern(D) bool empty() const nothrow @safe @nogc { return _Mypair._Myval2._Myfirst == _Mypair._Myval2._Mylast; } + + extern(D) T* data() nothrow @safe @nogc { return _Mypair._Myval2._Myfirst; } + extern(D) const(T)* data() const nothrow @safe @nogc { return _Mypair._Myval2._Myfirst; } + + extern(D) ref T opIndex(size_type i) @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } + extern(D) ref const(T) opIndex(size_type i) const @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } + extern(D) ref T at(size_type i) @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } + extern(D) ref const(T) at(size_type i) const @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } + } + else + { + static assert(false, "C++ runtime not supported"); + } } From fca0fb528407b1ca870207d9bff79ee7264500c2 Mon Sep 17 00:00:00 2001 From: Manu Evans Date: Sun, 26 Aug 2018 20:01:51 -0700 Subject: [PATCH 5/5] Further work --- src/core/stdcpp/allocator.d | 54 +++++++- src/core/stdcpp/array.d | 108 +++++---------- src/core/stdcpp/string.d | 242 +++++++++++++++++++++++----------- src/core/stdcpp/type_traits.d | 28 ++++ src/core/stdcpp/typeinfo.d | 2 +- src/core/stdcpp/utility.d | 47 +++++-- src/core/stdcpp/vector.d | 176 +++++++++++++++++-------- 7 files changed, 430 insertions(+), 227 deletions(-) create mode 100644 src/core/stdcpp/type_traits.d diff --git a/src/core/stdcpp/allocator.d b/src/core/stdcpp/allocator.d index b92175978f..6dede14681 100644 --- a/src/core/stdcpp/allocator.d +++ b/src/core/stdcpp/allocator.d @@ -20,4 +20,56 @@ extern(C++, std): * Allocators are classes that define memory models to be used by some parts of * the C++ Standard Library, and most specifically, by STL containers. */ -extern(C++, class) struct allocator(T) { } +extern(C++, class) struct allocator(T) +{ + static assert(!is(T == const), "The C++ Standard forbids containers of const elements because allocator!(const T) is ill-formed."); + + alias value_type = T; + + alias pointer = value_type*; + alias const_pointer = const value_type*; + + alias reference = ref value_type; + alias const_reference = ref const(value_type); + + alias size_type = size_t; + alias difference_type = ptrdiff_t; + + extern(D) size_t max_size() const nothrow @safe @nogc { return size_t.max / T.sizeof; } + + // these need to be defined locally to work on local types... + extern(D) void construct(Ty, Args...)(Ty* ptr, auto ref Args args) + { + // placement new... + assert(false, "TODO: can't use emplace, cus it's in phobos..."); + } + + extern(D) void destroy(Ty)(Ty* ptr) + { + import object : destroy; + ptr.destroy(); // TODO: use `destruct` instead of destroy, which should exist in the future... + } + + + // platform specific detail + version(CRuntime_Microsoft) + { + extern(D) void deallocate(pointer ptr, size_type count) nothrow @safe @nogc { _Deallocate(ptr, count, T.sizeof); } + extern(D) pointer allocate(size_type count) nothrow @trusted @nogc { return cast(pointer)_Allocate(count, T.sizeof); } + extern(D) pointer allocate(size_type count, const(void)*) nothrow @safe @nogc { return allocate(count); } + } + else + { + void deallocate(pointer ptr, size_type count) nothrow @trusted @nogc; + pointer allocate(size_type count) nothrow @trusted @nogc; + pointer allocate(size_type count, const(void)*) nothrow @trusted @nogc; + } +} + + +// platform detail +version(CRuntime_Microsoft) +{ + void* _Allocate(size_t _Count, size_t _Sz, bool _Try_aligned_allocation = true) nothrow @trusted @nogc; + void _Deallocate(void* _Ptr, size_t _Count, size_t _Sz) nothrow @trusted @nogc; +} diff --git a/src/core/stdcpp/array.d b/src/core/stdcpp/array.d index c692b15d5f..680cd1c2a4 100644 --- a/src/core/stdcpp/array.d +++ b/src/core/stdcpp/array.d @@ -11,14 +11,6 @@ module core.stdcpp.array; -/////////////////////////////////////////////////////////////////////////////// -// std::array declaration. -// -// - no iterators -/////////////////////////////////////////////////////////////////////////////// - -import stdcpp.allocator; - alias array = std.array; extern(C++, std): @@ -32,74 +24,56 @@ extern(C++, class) struct array(T, size_t N) alias const_reference = ref const(T); alias pointer = T*; alias const_pointer = const(T)*; -// alias iterator = pointer; -// alias const_iterator = const_pointer; -// alias reverse_iterator -// alias const_reverse_iterator - - // Iterators -// iterator begin() @trusted @nogc; -// const_iterator begin() const @trusted @nogc; -// const_iterator cbegin() const @trusted @nogc; -// iterator end() @trusted @nogc; -// const_iterator end() const @trusted @nogc; -// const_iterator cend() const @trusted @nogc; - - // no reverse iterator for now. - alias as_array this; + alias as_array this; - extern(D) size_type size() const nothrow @safe @nogc { return N; } - extern(D) size_type max_size() const nothrow @safe @nogc { return N; } - extern(D) bool empty() const nothrow @safe @nogc { return N > 0; } + extern(D) size_type size() const nothrow @safe @nogc { return N; } + extern(D) size_type max_size() const nothrow @safe @nogc { return N; } + extern(D) bool empty() const nothrow @safe @nogc { return N == 0; } // Element access - extern(D) reference front() @safe @nogc { return as_array()[0]; } - extern(D) const_reference front() const @safe @nogc { return as_array()[0]; } - extern(D) reference back() @safe @nogc { return as_array()[N == 0 ? 0 : N-1]; } - extern(D) const_reference back() const @safe @nogc { return as_array()[N == 0 ? 0 : N-1]; } + extern(D) reference front() @safe @nogc { static if (N > 0) { return as_array()[0]; } else { return as_array()[][0]; } } + extern(D) const_reference front() const @safe @nogc { static if (N > 0) { return as_array()[0]; } else { return as_array()[][0]; } } + extern(D) reference back() @safe @nogc { static if (N > 0) { return as_array()[N-1]; } else { return as_array()[][0]; } } + extern(D) const_reference back() const @safe @nogc { static if (N > 0) { return as_array()[N-1]; } else { return as_array()[][0]; } } - extern(D) void fill(ref const(T) value) @safe @nogc { foreach (ref T v; as_array()) v = value; } + extern(D) void fill(ref const(T) value) @safe @nogc { foreach (ref T v; as_array()) v = value; } // D helpers - extern(D) T[] opSlice() nothrow @safe @nogc { return as_array(); } - extern(D) const(T)[] opSlice() const nothrow @safe @nogc { return as_array(); } - extern(D) T[] opSlice(size_type start, size_type end) @safe { assert(start <= end && end <= N, "Index out of bounds"); return as_array()[start .. end]; } - extern(D) const(T)[] opSlice(size_type start, size_type end) const @safe { assert(start <= end && end <= N, "Index out of bounds"); return as_array()[start .. end]; } - extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return N; } - - // support all the assignment variants - extern(D) void opSliceAssign(T value) { opSlice()[] = value; } - extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } - extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } - extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } - extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } - extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } - -private: + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return N; } + version(CRuntime_Microsoft) { - import core.stdcpp.utility : _Xout_of_range; + // perf will be greatly improved by inlining the primitive access functions + extern(D) T* data() nothrow @safe @nogc { return &_Elems[0]; } + extern(D) const(T)* data() const nothrow @safe @nogc { return &_Elems[0]; } - T[N ? N : 1] _Elems; + extern(D) ref T at(size_type i) nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); return _Elems[0]; } } + extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); return _Elems[0]; } } - void _Xran() const @trusted @nogc { _Xout_of_range("invalid array subscript"); } + extern(D) ref inout(T)[N] as_array() const inout @safe @nogc { return _Elems[0 .. N]; } - public: - // perf will be greatly improved by inlining the primitive access functions - extern(D) T* data() nothrow @safe @nogc { return &_Elems[0]; } - extern(D) const(T)* data() const nothrow @safe @nogc { return &_Elems[0]; } + private: + import core.stdcpp.utility : _Xout_of_range; - extern(D) ref T opIndex(size_type i) nothrow @safe @nogc { return _Elems[0 .. N][i]; } - extern(D) ref const(T) opIndex(size_type i) const nothrow @safe @nogc { return _Elems[0 .. N][i]; } - extern(D) ref T at(size_type i) nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); } } - extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { static if (N > 0) { if (N <= i) _Xran(); return _Elems.ptr[i]; } else { _Xran(); } } + T[N ? N : 1] _Elems; - extern(D) T[] as_array() nothrow @safe @nogc { return _Elems[0 .. N]; } - extern(D) const(T)[] as_array() const nothrow @safe @nogc { return _Elems[0 .. N]; } + void _Xran() const @safe @nogc { _Xout_of_range("invalid array subscript"); } } else version(CRuntime_Glibc) { + import core.exception : RangeError; + + // perf will be greatly improved by inlining the primitive access functions + extern(D) T* data() nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } + extern(D) const(T)* data() const nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } + + extern(D) ref T at(size_type i) @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } + extern(D) ref const(T) at(size_type i) const @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } + + extern(D) ref inout(T)[N] as_array() inout nothrow @safe @nogc { return _M_elems[0 .. N]; } + + private: static if (N > 0) { T[N] _M_elems; @@ -109,22 +83,6 @@ private: struct _Placeholder {} _Placeholder _M_placeholder; } - - public: - import core.exception : RangeError; - - // perf will be greatly improved by inlining the primitive access functions - extern(D) T* data() nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } - extern(D) const(T)* data() const nothrow @safe @nogc { static if (N > 0) { return &_M_elems[0]; } else { return null; } } - - extern(D) ref T opIndex(size_type i) nothrow @nogc { static if (N > 0) { return _M_elems[i]; } else { return (cast(T[])null)[i]; } } - extern(D) ref const(T) opIndex(size_type i) const nothrow @nogc { static if (N > 0) { return _M_elems[i]; } else { return (cast(T[])null)[i]; } } - extern(D) ref T at(size_type i) @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } - extern(D) ref const(T) at(size_type i) const @trusted { if (i >= N) throw new RangeError("Index out of range"); return _M_elems.ptr[i]; } - - alias as_array this; - extern(D) T[] as_array() nothrow @safe @nogc { static if (N > 0) { return _M_elems[]; } else { return null; } } - extern(D) const(T)[] as_array() const nothrow @safe @nogc { static if (N > 0) { return _M_elems[]; } else { return null; } } } else { diff --git a/src/core/stdcpp/string.d b/src/core/stdcpp/string.d index a797743202..481b6eb878 100644 --- a/src/core/stdcpp/string.d +++ b/src/core/stdcpp/string.d @@ -24,7 +24,9 @@ module core.stdcpp.string; /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; +import core.stdcpp.utility : _ITERATOR_DEBUG_LEVEL; import core.stdc.stddef : wchar_t; +import core.stdc.string : strlen; alias std_string = std.string; //alias std_u16string = std.u16string; @@ -33,12 +35,19 @@ alias std_string = std.string; extern(C++, std): +alias basic_string!char string; +//alias basic_string!wchar u16string; // TODO: can't mangle these yet either... +//alias basic_string!dchar u32string; +//alias basic_string!wchar_t wstring; // TODO: we can't mangle wchar_t properly (yet?) + + /** * Character traits classes specify character properties and provide specific * semantics for certain operations on characters and sequences of characters. */ extern(C++, struct) struct char_traits(CharT) {} + /** * The basic_string is the generalization of class string for any character * type. @@ -56,40 +65,39 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca alias const_reference = ref const(value_type); alias pointer = value_type*; alias const_pointer = const(value_type)*; - alias iterator = pointer; - alias const_iterator = const_pointer; - // alias reverse_iterator - // alias const_reverse_iterator + +// alias iterator = pointer; +// alias const_iterator = const_pointer; +// alias reverse_iterator +// alias const_reverse_iterator alias as_array this; + // MSVC allocates on default initialisation in debug, which can't be modelled by D `struct` + @disable this(); + // ctor/dtor - this(const(T)* ptr, size_type count); - this(const(T)* ptr, size_type count, ref const(allocator_type) al); - this(const(T)* ptr); - this(const(T)* ptr, ref const(allocator_type) al); -// extern(D) this(const(T)[] dstr) { this(dstr.ptr, dstr.length); } -// extern(D) this(const(T)[] dstr, ref const(allocator_type) al) { this(dstr.ptr, dstr.length, al); } + extern(D) this(const(T)[] dstr) nothrow @safe @nogc { this(&dstr[0], dstr.length); } + extern(D) this(const(T)[] dstr, ref const(allocator_type) al) nothrow @safe @nogc { this(&dstr[0], dstr.length, al); } ~this() nothrow; ref basic_string opAssign(ref const(basic_string) s); // Iterators - iterator begin() nothrow @trusted @nogc; - const_iterator begin() const nothrow @trusted @nogc; - const_iterator cbegin() const nothrow @trusted @nogc; - - iterator end() nothrow @trusted @nogc; - const_iterator end() const nothrow @trusted @nogc; - const_iterator cend() const nothrow @trusted @nogc; +// iterator begin() nothrow @trusted @nogc; +// const_iterator begin() const nothrow @trusted @nogc; +// const_iterator cbegin() const nothrow @trusted @nogc; +// iterator end() nothrow @trusted @nogc; +// const_iterator end() const nothrow @trusted @nogc; +// const_iterator cend() const nothrow @trusted @nogc; // no reverse iterator for now. // Capacity - size_type length() const nothrow @trusted @nogc { return size(); } + size_type length() const nothrow @safe @nogc { return size(); } size_type max_size() const nothrow @trusted @nogc; - bool empty() const nothrow @trusted @nogc { return size() == 0; } + bool empty() const nothrow @safe @nogc { return size() == 0; } void clear() nothrow; void resize(size_type n); @@ -98,12 +106,12 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca void shrink_to_fit(); // Element access - ref T back() @trusted @nogc; - ref const(T) back() const @trusted @nogc; - ref T front() @trusted @nogc; - ref const(T) front() const @trusted @nogc; + extern(D) reference front() @safe @nogc { return as_array()[0]; } + extern(D) const_reference front() const @safe @nogc { return as_array()[0]; } + extern(D) reference back() @safe @nogc { return as_array()[size()-1]; } + extern(D) const_reference back() const @safe @nogc { return as_array()[size()-1]; } - extern(D) const(T)* c_str() const nothrow @trusted @nogc { return data(); } + extern(D) const(T)* c_str() const nothrow @safe @nogc { return data(); } // Modifiers ref basic_string opOpAssign(string op : "+")(ref const(basic_string) s); @@ -115,27 +123,27 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca extern(D) ref basic_string opOpAssign(string op : "~")(T s) { this += s; return this; } ref basic_string append(size_type n, T c); - ref basic_string append(const(T)* s); - ref basic_string append(const(T)* s, size_type n); + extern(D) ref basic_string append(const(T)* s) nothrow @nogc { assert(s); return append(s, strlen(s)); } + ref basic_string append(const(T)* s, size_type n) nothrow @trusted @nogc; ref basic_string append(ref const(basic_string) str); ref basic_string append(ref const(basic_string) str, size_type subpos, size_type sublen); - extern(D) ref basic_string append(const(T)[] s) { append(s.ptr, s.length); return this; } + extern(D) ref basic_string append(const(T)[] s) nothrow @safe @nogc { append(&s[0], s.length); return this; } void push_back(T c); ref basic_string assign(size_type n, T c); - ref basic_string assign(const(T)* s); - ref basic_string assign(const(T)* s, size_type n); + extern(D) ref basic_string assign(const(T)* s) nothrow @nogc { assert(s); return assign(s, strlen(s)); } + ref basic_string assign(const(T)* s, size_type n) nothrow @trusted @nogc; ref basic_string assign(ref const(basic_string) str); ref basic_string assign(ref const(basic_string) str, size_type subpos, size_type sublen); - extern(D) ref basic_string assign(const(T)[] s) { assign(s.ptr, s.length); return this; } + extern(D) ref basic_string assign(const(T)[] s) nothrow @safe @nogc { assign(&s[0], s.length); return this; } ref basic_string insert(size_type pos, ref const(basic_string) str); ref basic_string insert(size_type pos, ref const(basic_string) str, size_type subpos, size_type sublen); - ref basic_string insert(size_type pos, const(T)* s); - ref basic_string insert(size_type pos, const(T)* s, size_type n); +// ref basic_string insert(size_type pos, const(T)* s) nothrow @nogc { assert(s); return insert(pos, s, strlen(s)); } + ref basic_string insert(size_type pos, const(T)* s, size_type n) nothrow @trusted @nogc; ref basic_string insert(size_type pos, size_type n, T c); -// extern(D) ref basic_string insert(size_type pos, const(T)[] s) { insert(pos, s.ptr, s.length); return this; } +// extern(D) ref basic_string insert(size_type pos, const(T)[] s) nothrow @safe @nogc { insert(pos, &s[0], s.length); return this; } ref basic_string erase(size_type pos = 0, size_type len = npos); @@ -144,7 +152,7 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca void pop_back(); // String operations - size_type copy(T* s, size_type len, size_type pos = 0) const; + deprecated size_type copy(T* s, size_type len, size_type pos = 0) const; size_type find(ref const(basic_string) str, size_type pos = 0) const nothrow; size_type find(const(T)* s, size_type pos = 0) const; @@ -186,72 +194,148 @@ extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = alloca int compare(size_type pos, size_type len, const(T)* s, size_type n) const; // D helpers - extern(D) T[] opSlice() nothrow @trusted @nogc { return as_array(); } - extern(D) const(T)[] opSlice() const nothrow @trusted @nogc { return as_array(); } - extern(D) T[] opSlice(size_type start, size_type end) @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return as_array()[start .. end]; } - extern(D) const(T)[] opSlice(size_type start, size_type end) const @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return as_array()[start .. end]; } - extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } - - // support all the assignment variants - extern(D) void opSliceAssign(T value) { opSlice()[] = value; } - extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } - extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } - extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } - extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } - extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } -private: version(CRuntime_Microsoft) { - import core.stdcpp.utility : _Container_base, _Compressed_pair, _Xout_of_range; + this(const(T)* ptr, size_type count) nothrow @safe @nogc { _Tidy(); assign(ptr, count); } + this(const(T)* ptr, size_type count, ref const(allocator_type) al) nothrow @safe @nogc { _AssignAllocator(al); _Tidy(); assign(ptr, count); } + this(const(T)* ptr) nothrow @nogc { _Tidy(); assign(ptr); } + this(const(T)* ptr, ref const(allocator_type) al) nothrow @nogc { _AssignAllocator(al); _Tidy(); assign(ptr); } - void _Xran() const @trusted @nogc { _Xout_of_range("invalid string position"); } + // perf will be greatly improved by inlining the primitive access functions + extern(D) size_type size() const nothrow @safe @nogc { return _Get_data()._Mysize; } + extern(D) size_type capacity() const nothrow @safe @nogc { return _Get_data()._Myres; } - extern(C++, class) struct _String_val - { - enum _BUF_SIZE = 16 / value_type.sizeof < 1 ? 1 : 16 / value_type.sizeof; + extern(D) T* data() nothrow @safe @nogc { return _Get_data()._Myptr; } + extern(D) const(T)* data() const nothrow @safe @nogc { return _Get_data()._Myptr; } + + extern(D) ref T at(size_type i) nothrow @trusted @nogc { if (_Get_data()._Mysize <= i) _Xran(); return _Get_data()._Myptr[i]; } + extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { if (_Get_data()._Mysize <= i) _Xran(); return _Get_data()._Myptr[i]; } - union _Bxty + extern(D) T[] as_array() nothrow @trusted @nogc { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; } + extern(D) const(T)[] as_array() const nothrow @trusted @nogc { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; } + + extern(D) this(this) + { + // we meed a compatible postblit + static if (_ITERATOR_DEBUG_LEVEL > 0) { - value_type[_BUF_SIZE] _Buf; - pointer _Ptr; + _Base._Alloc_proxy(); } - _Container_base base; - alias base this; + if (_Get_data()._IsAllocated()) + { + pointer _Ptr = _Get_data()._Myptr; + size_type _Count = _Get_data()._Mysize; - _Bxty _Bx = void; - size_type _Mysize; // current length of string - size_type _Myres; // current storage reserved for string + // re-init to zero + _Get_data()._Mysize = 0; + _Get_data()._Myres = 0; - extern(D) @property inout(value_type)* _Myptr() inout nothrow @trusted @nogc { return _BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf.ptr; } + _Tidy(); + assign(_Ptr, _Count); + } } - _Compressed_pair!(void, _String_val) _Mypair; + private: + import core.stdcpp.utility : _Xout_of_range; - public: - // perf will be greatly improved by inlining the primitive access functions - extern(D) size_type size() const nothrow @safe @nogc { return _Mypair._Myval2._Mysize; } - extern(D) size_type capacity() const nothrow @safe @nogc { return _Mypair._Myval2._Myres; } + pragma(inline, true) + { + extern (D) ref _Base.Alloc _Getal() nothrow @safe @nogc { return _Base._Mypair._Myval1; } + extern (D) ref inout(_Base.ValTy) _Get_data() inout nothrow @safe @nogc { return _Base._Mypair._Myval2; } + + extern (D) void _Eos(size_type _Newsize) nothrow @nogc { _Get_data()._Myptr()[_Get_data()._Mysize = _Newsize] = T(0); } + } + + extern (D) void _AssignAllocator(ref const(allocator_type) al) nothrow @nogc + { + static if (_Base._Mypair._HasFirst) + _Getal() = al; + } - extern(D) T* data() nothrow @safe @nogc { return _Mypair._Myval2._Myptr; } - extern(D) const(T)* data() const nothrow @safe @nogc { return _Mypair._Myval2._Myptr; } + extern (D) void _Tidy(bool _Built = false, size_type _Newsize = 0) nothrow @trusted @nogc + { + if (_Built && _Base.ValTy._BUF_SIZE <= _Get_data()._Myres) + { + assert(false); // TODO: free buffer... + } + _Get_data()._Myres = _Base.ValTy._BUF_SIZE - 1; + _Eos(_Newsize); + } - extern(D) ref T opIndex(size_type i) nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize][i]; } - extern(D) ref const(T) opIndex(size_type i) const nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize][i]; } - extern(D) ref T at(size_type i) nothrow @trusted @nogc { if (_Mypair._Myval2._Mysize <= i) _Xran(); return _Mypair._Myval2._Myptr[i]; } - extern(D) ref const(T) at(size_type i) const nothrow @trusted @nogc { if (_Mypair._Myval2._Mysize <= i) _Xran(); return _Mypair._Myval2._Myptr[i]; } + void _Xran() const @trusted @nogc { _Xout_of_range("invalid string position"); } - extern(D) T[] as_array() nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize]; } - extern(D) const(T)[] as_array() const nothrow @trusted @nogc { return _Mypair._Myval2._Myptr[0 .. _Mypair._Myval2._Mysize]; } + _String_alloc!(_String_base_types!(T, Alloc)) _Base; } else { static assert(false, "C++ runtime not supported"); } + +private: + // HACK: because no rvalue->ref + extern (D) __gshared static immutable allocator_type defaultAlloc; } -alias basic_string!char string; -//alias basic_string!wchar u16string; // TODO: can't mangle these yet either... -//alias basic_string!dchar u32string; -//alias basic_string!wchar_t wstring; // TODO: we can't mangle wchar_t properly (yet?) + +// platform detail +version(CRuntime_Microsoft) +{ + extern (C++, struct) struct _String_base_types(_Elem, _Alloc) + { + alias Ty = _Elem; + alias Alloc = _Alloc; + } + + extern (C++, class) struct _String_alloc(_Alloc_types) + { + import core.stdcpp.utility : _Compressed_pair; + + alias Ty = _Alloc_types.Ty; + alias Alloc = _Alloc_types.Alloc; + alias ValTy = _String_val!Ty; + + void _Orphan_all() nothrow @trusted @nogc; + + static if (_ITERATOR_DEBUG_LEVEL > 0) + { + void _Alloc_proxy() nothrow @trusted @nogc; + void _Free_proxy() nothrow @trusted @nogc; + } + + _Compressed_pair!(Alloc, ValTy) _Mypair; + } + + extern (C++, class) struct _String_val(T) + { + import core.stdcpp.utility : _Container_base; + import core.stdcpp.type_traits : is_empty; + + enum _BUF_SIZE = 16 / T.sizeof < 1 ? 1 : 16 / T.sizeof; + enum _ALLOC_MASK = T.sizeof <= 1 ? 15 : T.sizeof <= 2 ? 7 : T.sizeof <= 4 ? 3 : T.sizeof <= 8 ? 1 : 0; + + static if (!is_empty!_Container_base.value) + { + _Container_base _Base; + } + + union _Bxty + { + T[_BUF_SIZE] _Buf; + T* _Ptr; + } + + _Bxty _Bx = void; + size_t _Mysize; // current length of string + size_t _Myres; // current storage reserved for string + + pragma(inline, true) + { + extern(D) bool _IsAllocated() const @safe @nogc { return _BUF_SIZE <= _Myres; } + extern(D) @property T* _Myptr() nothrow @trusted @nogc { return _BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf.ptr; } + extern(D) @property const(T)* _Myptr() const nothrow @trusted @nogc { return _BUF_SIZE <= _Myres ? _Bx._Ptr : _Bx._Buf.ptr; } + } + } +} diff --git a/src/core/stdcpp/type_traits.d b/src/core/stdcpp/type_traits.d new file mode 100644 index 0000000000..70b21ae421 --- /dev/null +++ b/src/core/stdcpp/type_traits.d @@ -0,0 +1,28 @@ +/** +* D header file for interaction with C++ std::type_traits. +* +* Copyright: Copyright Manu Evans 2018. +* License: Distributed under the +* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). +* (See accompanying file LICENSE) +* Authors: Manu Evans +* Source: $(DRUNTIMESRC core/stdcpp/type_traits.d) +*/ + +module core.stdcpp.type_traits; + +extern(C++, std): + +struct integral_constant(T, T Val) +{ + enum T value = Val; + alias value_type = T; + alias type = integral_constant!(value_type, value); +} + +struct is_empty(T) +{ + enum value = T.tupleof.length == 0; + alias value_type = typeof(value); + alias type = integral_constant!(typeof(value), value); +} diff --git a/src/core/stdcpp/typeinfo.d b/src/core/stdcpp/typeinfo.d index a7b7b0b6d3..972e15d078 100644 --- a/src/core/stdcpp/typeinfo.d +++ b/src/core/stdcpp/typeinfo.d @@ -90,7 +90,7 @@ else version (CRuntime_Microsoft) ~this() {} } - class bad_typeid :exception + class bad_typeid : exception { this(const(char)* _Message = "bad typeid") { super(_Message); } ~this() {} diff --git a/src/core/stdcpp/utility.d b/src/core/stdcpp/utility.d index f841590f62..6e5b5c7ae6 100644 --- a/src/core/stdcpp/utility.d +++ b/src/core/stdcpp/utility.d @@ -28,6 +28,8 @@ struct pair(T1, T2) version(CRuntime_Microsoft) { + import core.stdcpp.type_traits : is_empty; + version (_ITERATOR_DEBUG_LEVEL_0) enum _ITERATOR_DEBUG_LEVEL = 0; else version (_ITERATOR_DEBUG_LEVEL_1) @@ -35,28 +37,47 @@ version(CRuntime_Microsoft) else version (_ITERATOR_DEBUG_LEVEL_2) enum _ITERATOR_DEBUG_LEVEL = 2; else - enum _ITERATOR_DEBUG_LEVEL = 0; // default? dunno... + { + // as a best-guess, -release will produce code that matches the MSVC release CRT + debug + enum _ITERATOR_DEBUG_LEVEL = 2; + else + enum _ITERATOR_DEBUG_LEVEL = 0; + } - static if (_ITERATOR_DEBUG_LEVEL == 0) + struct _Container_base0 {} + + struct _Iterator_base12 { - struct _Container_base0 {} - alias _Container_base = _Container_base0; + _Container_proxy *_Myproxy; + _Iterator_base12 *_Mynextiter; } - else + struct _Container_proxy { - struct _Container_proxy - { - const(_Container_base12)* _Mycont; - _Iterator_base12* _Myfirstiter; - } - struct _Container_base12 { _Container_proxy* _Myproxy; } - alias _Container_base = _Container_base12; + const(_Container_base12)* _Mycont; + _Iterator_base12* _Myfirstiter; } + struct _Container_base12 { _Container_proxy* _Myproxy; } - extern (C++, class) struct _Compressed_pair(_Ty1, _Ty2, bool Ty1Empty = is(_Ty1 == void)) + static if (_ITERATOR_DEBUG_LEVEL == 0) + alias _Container_base = _Container_base0; + else + alias _Container_base = _Container_base12; + + extern (C++, class) struct _Compressed_pair(_Ty1, _Ty2, bool Ty1Empty = is_empty!_Ty1.value) { + enum _HasFirst = !Ty1Empty; + + ref inout(_Ty1) _Get_first() inout nothrow @safe @nogc { return _Myval1; } + ref inout(_Ty2) _Get_second() inout nothrow @safe @nogc { return _Myval2; } + static if (!Ty1Empty) _Ty1 _Myval1; + else + { + @property ref inout(_Ty1) _Myval1() inout nothrow @trusted @nogc { return *_GetBase(); } + private inout(_Ty1)* _GetBase() inout { return cast(_Ty1*)&this; } + } _Ty2 _Myval2; } diff --git a/src/core/stdcpp/vector.d b/src/core/stdcpp/vector.d index 08a0116147..3dc8d42b73 100644 --- a/src/core/stdcpp/vector.d +++ b/src/core/stdcpp/vector.d @@ -26,6 +26,7 @@ module core.stdcpp.vector; /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; +import core.stdcpp.utility : _ITERATOR_DEBUG_LEVEL; alias vector = std.vector; @@ -33,30 +34,33 @@ extern(C++, std): extern(C++, class) struct vector(T, Alloc = allocator!T) { + static assert(!is(T == bool), "vector!bool not supported!"); + alias value_type = T; alias allocator_type = Alloc; alias reference = ref T; alias const_reference = ref const(T); alias pointer = T*; alias const_pointer = const(T)*; - alias iterator = pointer; - alias const_iterator = const_pointer; - // alias reverse_iterator - // alias const_reverse_iterator alias difference_type = ptrdiff_t; alias size_type = size_t; +// alias iterator = pointer; +// alias const_iterator = const_pointer; +// alias reverse_iterator +// alias const_reverse_iterator + alias as_array this; // ctor/dtor this(size_type count); this(size_type count, ref const(value_type) val); - this(size_type count, ref const(value_type) val, ref const(allocator_type) al = defaultAlloc); + this(size_type count, ref const(value_type) val, ref const(allocator_type) al); this(ref const(vector) x); - this(iterator first, iterator last); - this(iterator first, iterator last, ref const(allocator_type) al = defaultAlloc); - this(const_iterator first, const_iterator last); - this(const_iterator first, const_iterator last, ref const(allocator_type) al = defaultAlloc); +// this(iterator first, iterator last); +// this(iterator first, iterator last, ref const(allocator_type) al = defaultAlloc); +// this(const_iterator first, const_iterator last); +// this(const_iterator first, const_iterator last, ref const(allocator_type) al = defaultAlloc); // extern(D) this(T[] arr) { this(arr.ptr, arr.ptr + arr.length); } // extern(D) this(T[] arr, ref const(allocator_type) al = defaultAlloc) { this(arr.ptr, arr.ptr + arr.length); } // extern(D) this(const(T)[] arr) { this(arr.ptr, arr.ptr + arr.length); } @@ -66,15 +70,18 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) ref vector opAssign(ref const(vector) s); // Iterators - iterator begin() @trusted @nogc; - const_iterator begin() const @trusted @nogc; - const_iterator cbegin() const @trusted @nogc; - iterator end() @trusted @nogc; - const_iterator end() const @trusted @nogc; - const_iterator cend() const @trusted @nogc; +// iterator begin() @trusted @nogc; +// const_iterator begin() const @trusted @nogc; +// const_iterator cbegin() const @trusted @nogc; +// iterator end() @trusted @nogc; +// const_iterator end() const @trusted @nogc; +// const_iterator cend() const @trusted @nogc; // no reverse iterator for now. + // MSVC allocates on default initialisation in debug, which can't be modelled by D `struct` + @disable this(); + // Capacity size_type max_size() const nothrow @trusted @nogc; @@ -85,10 +92,10 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) void shrink_to_fit(); // Element access - ref T back() @trusted @nogc; - ref const(T) back() const @trusted @nogc; - ref T front() @trusted @nogc; - ref const(T) front() const @trusted @nogc; + extern(D) reference front() @safe @nogc { return as_array()[0]; } + extern(D) const_reference front() const @safe @nogc { return as_array()[0]; } + extern(D) reference back() @safe @nogc { return as_array()[size()-1]; } + extern(D) const_reference back() const @safe @nogc { return as_array()[size()-1]; } // Modifiers void push_back(ref const(T) _); @@ -97,61 +104,114 @@ extern(C++, class) struct vector(T, Alloc = allocator!T) void pop_back(); // D helpers - extern(D) T[] as_array() nothrow @safe @nogc { return this[]; } - extern(D) const(T)[] as_array() const nothrow @safe @nogc { return this[]; } - - extern(D) T[] opSlice() nothrow @trusted @nogc { return data()[0 .. size()]; } - extern(D) const(T)[] opSlice() const nothrow @trusted @nogc { return data()[0 .. size()]; } - extern(D) T[] opSlice(size_type start, size_type end) @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } - extern(D) const(T)[] opSlice(size_type start, size_type end) const @trusted { assert(start <= end && end <= size(), "Index out of bounds"); return data()[start .. end]; } extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } - // support all the assignment variants - extern(D) void opSliceAssign(T value) { opSlice()[] = value; } - extern(D) void opSliceAssign(T value, size_type i, size_type j) { opSlice(i, j)[] = value; } - extern(D) void opSliceUnary(string op)() if (op == "++" || op == "--") { mixin(op ~ "opSlice()[];"); } - extern(D) void opSliceUnary(string op)(size_type i, size_type j) if (op == "++" || op == "--") { mixin(op ~ "opSlice(i, j)[];"); } - extern(D) void opSliceOpAssign(string op)(T value) { mixin("opSlice()[] " ~ op ~ "= value;"); } - extern(D) void opSliceOpAssign(string op)(T value, size_type i, size_type j) { mixin("opSlice(i, j)[] " ~ op ~ "= value;"); } - -private: - extern (D) __gshared static immutable allocator!T defaultAlloc; - version(CRuntime_Microsoft) { - import core.stdcpp.utility : _Container_base, _Compressed_pair, _Xlength_error, _Xout_of_range; + // perf will be greatly improved by inlining the primitive access functions + extern(D) size_type size() const nothrow @safe @nogc { return _Get_data()._Mylast - _Get_data()._Myfirst; } + extern(D) size_type capacity() const nothrow @safe @nogc { return _Get_data()._Myend - _Get_data()._Myfirst; } + extern(D) bool empty() const nothrow @safe @nogc { return _Get_data()._Myfirst == _Get_data()._Mylast; } + + extern(D) T* data() nothrow @safe @nogc { return _Get_data()._Myfirst; } + extern(D) const(T)* data() const nothrow @safe @nogc { return _Get_data()._Myfirst; } + + extern(D) ref T at(size_type i) @trusted @nogc { if (size() <= i) _Xran(); return _Get_data()._Myfirst[i]; } + extern(D) ref const(T) at(size_type i) const @trusted @nogc { if (size() <= i) _Xran(); return _Get_data()._Myfirst[i]; } - void _Xlen() const @trusted @nogc { _Xlength_error("vector!T too long"); } - void _Xran() const @trusted @nogc { _Xout_of_range("invalid vector!T subscript"); } + extern(D) T[] as_array() nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()]; } + extern(D) const(T)[] as_array() const nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()]; } - extern (C++, class) struct _Vector_val + extern(D) this(this) { - _Container_base base; - alias base this; + // we meed a compatible postblit + static if (_ITERATOR_DEBUG_LEVEL > 0) + { + _Base._Alloc_proxy(); + } - pointer _Myfirst; // pointer to beginning of array - pointer _Mylast; // pointer to current end of sequence - pointer _Myend; // pointer to end of array + size_t len = size(); // the alloc len should probably keep a few in excess? (check the MS implementation) + pointer newAlloc = _Getal().allocate(len); + + newAlloc[0 .. len] = _Get_data()._Myfirst[0 .. len]; + + _Get_data()._Myfirst = newAlloc; + _Get_data()._Mylast = newAlloc + len; + _Get_data()._Myend = newAlloc + len; } - _Compressed_pair!(void, _Vector_val) _Mypair; + private: + import core.stdcpp.utility : _Xlength_error, _Xout_of_range; - public: - // perf will be greatly improved by inlining the primitive access functions - extern(D) size_type size() const nothrow @safe @nogc { return _Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst; } - extern(D) size_type capacity() const nothrow @safe @nogc { return _Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst; } - extern(D) bool empty() const nothrow @safe @nogc { return _Mypair._Myval2._Myfirst == _Mypair._Myval2._Mylast; } + pragma(inline, true) + { + extern (D) ref _Base.Alloc _Getal() nothrow @safe @nogc { return _Base._Mypair._Myval1; } + extern (D) ref inout(_Base.ValTy) _Get_data() inout nothrow @safe @nogc { return _Base._Mypair._Myval2; } + } - extern(D) T* data() nothrow @safe @nogc { return _Mypair._Myval2._Myfirst; } - extern(D) const(T)* data() const nothrow @safe @nogc { return _Mypair._Myval2._Myfirst; } + extern(D) void _Xlen() const @trusted @nogc { _Xlength_error("vector!T too long"); } + extern(D) void _Xran() const @trusted @nogc { _Xout_of_range("invalid vector!T subscript"); } - extern(D) ref T opIndex(size_type i) @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } - extern(D) ref const(T) opIndex(size_type i) const @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } - extern(D) ref T at(size_type i) @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } - extern(D) ref const(T) at(size_type i) const @trusted @nogc { if (size() <= i) _Xran(); return _Mypair._Myval2._Myfirst[i]; } + _Vector_alloc!(_Vec_base_types!(T, Alloc)) _Base; + + // extern to functions that we are sure will be instantiated +// void _Destroy(pointer _First, pointer _Last) nothrow @trusted @nogc; +// size_type _Grow_to(size_type _Count) const nothrow @trusted @nogc; +// void _Reallocate(size_type _Count) nothrow @trusted @nogc; +// void _Reserve(size_type _Count) nothrow @trusted @nogc; +// void _Tidy() nothrow @trusted @nogc; } else { static assert(false, "C++ runtime not supported"); } + +private: + // HACK: because no rvalue->ref + extern (D) __gshared static immutable allocator_type defaultAlloc; +} + + +// platform detail +version(CRuntime_Microsoft) +{ + extern (C++, struct) struct _Vec_base_types(_Ty, _Alloc0) + { + alias Ty = _Ty; + alias Alloc = _Alloc0; + } + + extern (C++, class) struct _Vector_alloc(_Alloc_types) + { + import core.stdcpp.utility : _Compressed_pair; + + alias Ty = _Alloc_types.Ty; + alias Alloc = _Alloc_types.Alloc; + alias ValTy = _Vector_val!Ty; + + void _Orphan_all() nothrow @trusted @nogc; + + static if (_ITERATOR_DEBUG_LEVEL > 0) + { + void _Alloc_proxy() nothrow @trusted @nogc; + void _Free_proxy() nothrow @trusted @nogc; + } + + _Compressed_pair!(Alloc, ValTy) _Mypair; + } + + extern (C++, class) struct _Vector_val(T) + { + import core.stdcpp.utility : _Container_base; + import core.stdcpp.type_traits : is_empty; + + static if (!is_empty!_Container_base.value) + { + _Container_base _Base; + } + + T* _Myfirst; // pointer to beginning of array + T* _Mylast; // pointer to current end of sequence + T* _Myend; // pointer to end of array + } }