diff --git a/mak/COPY b/mak/COPY index cdd87a145a..e187c4aabd 100644 --- a/mak/COPY +++ b/mak/COPY @@ -48,8 +48,14 @@ COPY=\ $(IMPDIR)\core\stdc\wchar_.d \ $(IMPDIR)\core\stdc\wctype.d \ \ - $(IMPDIR)\core\stdcpp\typeinfo.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 \ $(IMPDIR)\core\sys\darwin\pthread.d \ diff --git a/mak/DOCS b/mak/DOCS index c825362b20..5b4affca82 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -38,8 +38,14 @@ DOCS=\ $(DOCDIR)\core_stdc_wchar_.html \ $(DOCDIR)\core_stdc_wctype.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 \ $(DOCDIR)\core_sync_condition.html \ diff --git a/mak/SRCS b/mak/SRCS index f998eb29f9..0cea3391b6 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -46,6 +46,15 @@ SRCS=\ src\core\stdc\time.d \ 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 \ 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..6dede14681 --- /dev/null +++ b/src/core/stdcpp/allocator.d @@ -0,0 +1,75 @@ +/** + * 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 + * Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/allocator.d) + */ + +module core.stdcpp.allocator; + +alias allocator = std.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. + */ +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 new file mode 100644 index 0000000000..680cd1c2a4 --- /dev/null +++ b/src/core/stdcpp/array.d @@ -0,0 +1,91 @@ +/** + * 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; + +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 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 { 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; } + + // D helpers + 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) + { + // 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 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]; } } + + extern(D) ref inout(T)[N] as_array() const inout @safe @nogc { return _Elems[0 .. N]; } + + private: + import core.stdcpp.utility : _Xout_of_range; + + T[N ? N : 1] _Elems; + + 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; + } + else + { + struct _Placeholder {} + _Placeholder _M_placeholder; + } + } + 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 new file mode 100644 index 0000000000..481b6eb878 --- /dev/null +++ b/src/core/stdcpp/string.d @@ -0,0 +1,341 @@ +/** + * 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 + * Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/string.d) + */ + +module core.stdcpp.string; + +/////////////////////////////////////////////////////////////////////////////// +// std::string declaration. +// +// Current caveats : +// - 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.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; +//alias std_u32string = std.u32string; +//alias std_wstring = std.wstring; + +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. + */ +extern(C++, class) struct basic_string(T, Traits = char_traits!T, Alloc = allocator!T) +{ + 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 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 as_array this; + + // MSVC allocates on default initialisation in debug, which can't be modelled by D `struct` + @disable this(); + + // ctor/dtor + 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; + + // no reverse iterator for now. + + // Capacity + size_type length() const nothrow @safe @nogc { return size(); } + size_type max_size() const nothrow @trusted @nogc; + + bool empty() const nothrow @safe @nogc { return size() == 0; } + + void clear() nothrow; + void resize(size_type n); + void resize(size_type n, T c); + void reserve(size_type n = 0) @trusted @nogc; + void shrink_to_fit(); + + // 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()[size()-1]; } + extern(D) const_reference back() const @safe @nogc { return as_array()[size()-1]; } + + extern(D) const(T)* c_str() const nothrow @safe @nogc { return data(); } + + // 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); + 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) nothrow @safe @nogc { append(&s[0], s.length); return this; } + + void push_back(T c); + + ref basic_string assign(size_type n, T c); + 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) 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) 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) nothrow @safe @nogc { insert(pos, &s[0], s.length); return this; } + + ref basic_string erase(size_type pos = 0, size_type len = npos); + + // replace + // swap + void pop_back(); + + // String operations + 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; + 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 + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } + + version(CRuntime_Microsoft) + { + 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); } + + // 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(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]; } + + 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) + { + _Base._Alloc_proxy(); + } + + if (_Get_data()._IsAllocated()) + { + pointer _Ptr = _Get_data()._Myptr; + size_type _Count = _Get_data()._Mysize; + + // re-init to zero + _Get_data()._Mysize = 0; + _Get_data()._Myres = 0; + + _Tidy(); + assign(_Ptr, _Count); + } + } + + private: + import core.stdcpp.utility : _Xout_of_range; + + 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) 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); + } + + void _Xran() const @trusted @nogc { _Xout_of_range("invalid string position"); } + + _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; +} + + +// 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/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/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 085b10b74e..972e15d078 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..6e5b5c7ae6 --- /dev/null +++ b/src/core/stdcpp/utility.d @@ -0,0 +1,90 @@ +/** + * 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) +{ + import core.stdcpp.type_traits : is_empty; + + 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 + { + // 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; + } + + struct _Container_base0 {} + + struct _Iterator_base12 + { + _Container_proxy *_Myproxy; + _Iterator_base12 *_Mynextiter; + } + struct _Container_proxy + { + const(_Container_base12)* _Mycont; + _Iterator_base12* _Myfirstiter; + } + struct _Container_base12 { _Container_proxy* _Myproxy; } + + 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; + } + + 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 new file mode 100644 index 0000000000..3dc8d42b73 --- /dev/null +++ b/src/core/stdcpp/vector.d @@ -0,0 +1,217 @@ +/** + * 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 + * Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/vector.d) + */ + +module core.stdcpp.vector; + +/////////////////////////////////////////////////////////////////////////////// +// std::vector declaration. +// +// Current caveats : +// - mangling issues still exist +// - won't work with custom allocators +// - 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; +import core.stdcpp.utility : _ITERATOR_DEBUG_LEVEL; + +alias vector = std.vector; + +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 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); + 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(); + + 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; + + // 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; + + void clear() nothrow; + void resize(size_type n); + void resize(size_type n, T c); + void reserve(size_type n = 0) @trusted @nogc; + void shrink_to_fit(); + + // 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()[size()-1]; } + extern(D) const_reference back() const @safe @nogc { return as_array()[size()-1]; } + + // Modifiers + void push_back(ref const(T) _); + extern(D) void push_back(const(T) el) { push_back(el); } // forwards to ref version + + void pop_back(); + + // D helpers + extern(D) size_type opDollar(size_t pos)() const nothrow @safe @nogc { static assert(pos == 0, "std::vector is one-dimensional"); return size(); } + + version(CRuntime_Microsoft) + { + // 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]; } + + 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(D) this(this) + { + // we meed a compatible postblit + static if (_ITERATOR_DEBUG_LEVEL > 0) + { + _Base._Alloc_proxy(); + } + + 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; + } + + private: + import core.stdcpp.utility : _Xlength_error, _Xout_of_range; + + 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 _Xlen() const @trusted @nogc { _Xlength_error("vector!T too long"); } + extern(D) void _Xran() const @trusted @nogc { _Xout_of_range("invalid vector!T subscript"); } + + _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 + } +}