diff options
Diffstat (limited to 'libphobos/libdruntime/core/stdcpp/xutility.d')
-rw-r--r-- | libphobos/libdruntime/core/stdcpp/xutility.d | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/libphobos/libdruntime/core/stdcpp/xutility.d b/libphobos/libdruntime/core/stdcpp/xutility.d new file mode 100644 index 00000000000..fa61701e1cf --- /dev/null +++ b/libphobos/libdruntime/core/stdcpp/xutility.d @@ -0,0 +1,427 @@ +/** + * D header file for interaction with Microsoft C++ <xutility> + * + * Copyright: Copyright (c) 2018 D Language Foundation + * License: Distributed under the + * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + * (See accompanying file LICENSE) + * Authors: Manu Evans + * Source: $(DRUNTIMESRC core/stdcpp/xutility.d) + */ + +module core.stdcpp.xutility; + +@nogc: + +version (CppRuntime_Clang) +{ + import core.internal.traits : AliasSeq; + enum StdNamespace = AliasSeq!("std", "__1"); +} +else +{ + enum StdNamespace = "std"; +} + +enum CppStdRevision : uint +{ + cpp98 = 199711, + cpp11 = 201103, + cpp14 = 201402, + cpp17 = 201703 +} + +enum __cplusplus = __traits(getTargetInfo, "cppStd"); + +// wrangle C++ features +enum __cpp_sized_deallocation = __cplusplus >= CppStdRevision.cpp14 || is(typeof(_MSC_VER)) ? 201309 : 0; +enum __cpp_aligned_new = __cplusplus >= CppStdRevision.cpp17 ? 201606 : 0; + + +version (CppRuntime_Microsoft) +{ + import core.stdcpp.type_traits : is_empty; + + version (_MSC_VER_1200) + enum _MSC_VER = 1200; + else version (_MSC_VER_1300) + enum _MSC_VER = 1300; + else version (_MSC_VER_1310) + enum _MSC_VER = 1310; + else version (_MSC_VER_1400) + enum _MSC_VER = 1400; + else version (_MSC_VER_1500) + enum _MSC_VER = 1500; + else version (_MSC_VER_1600) + enum _MSC_VER = 1600; + else version (_MSC_VER_1700) + enum _MSC_VER = 1700; + else version (_MSC_VER_1800) + enum _MSC_VER = 1800; + else version (_MSC_VER_1900) + enum _MSC_VER = 1900; + else version (_MSC_VER_1910) + enum _MSC_VER = 1910; + else version (_MSC_VER_1911) + enum _MSC_VER = 1911; + else version (_MSC_VER_1912) + enum _MSC_VER = 1912; + else version (_MSC_VER_1913) + enum _MSC_VER = 1913; + else version (_MSC_VER_1914) + enum _MSC_VER = 1914; + else version (_MSC_VER_1915) + enum _MSC_VER = 1915; + else version (_MSC_VER_1916) + enum _MSC_VER = 1916; + else version (_MSC_VER_1920) + enum _MSC_VER = 1920; + else version (_MSC_VER_1921) + enum _MSC_VER = 1921; + else version (_MSC_VER_1922) + enum _MSC_VER = 1922; + else version (_MSC_VER_1923) + enum _MSC_VER = 1923; + else + enum _MSC_VER = 1923; // assume most recent compiler version + + // Client code can mixin the set of MSVC linker directives + mixin template MSVCLinkDirectives(bool failMismatch = false) + { + import core.stdcpp.xutility : __CXXLIB__, _ITERATOR_DEBUG_LEVEL; + + static if (__CXXLIB__ == "libcmtd") + { + pragma(lib, "libcpmtd"); + static if (failMismatch) + pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MTd_StaticDebug"); + } + else static if (__CXXLIB__ == "msvcrtd") + { + pragma(lib, "msvcprtd"); + static if (failMismatch) + pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MDd_DynamicDebug"); + } + else static if (__CXXLIB__ == "libcmt") + { + pragma(lib, "libcpmt"); + static if (failMismatch) + pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MT_StaticRelease"); + } + else static if (__CXXLIB__ == "msvcrt") + { + pragma(lib, "msvcprt"); + static if (failMismatch) + pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MD_DynamicRelease"); + } + static if (failMismatch) + pragma(linkerDirective, "/FAILIFMISMATCH:_ITERATOR_DEBUG_LEVEL=" ~ ('0' + _ITERATOR_DEBUG_LEVEL)); + } + + // HACK: should we guess _DEBUG for `debug` builds? + version (NDEBUG) {} + else debug version = _DEBUG; + + // By specific user request + 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 + { + // Match the C Runtime + static if (__CXXLIB__ == "libcmtd" || __CXXLIB__ == "msvcrtd") + enum _ITERATOR_DEBUG_LEVEL = 2; + else static if (__CXXLIB__ == "libcmt" || __CXXLIB__ == "msvcrt" || + __CXXLIB__ == "msvcrt100" || __CXXLIB__ == "msvcrt110" || __CXXLIB__ == "msvcrt120") + enum _ITERATOR_DEBUG_LEVEL = 0; + else + { + static if (__CXXLIB__.length > 0) + pragma(msg, "Unrecognised C++ runtime library '" ~ __CXXLIB__ ~ "'"); + + // No runtime specified; as a best-guess, -release will produce code that matches the MSVC release CRT + version (_DEBUG) + enum _ITERATOR_DEBUG_LEVEL = 2; + else + enum _ITERATOR_DEBUG_LEVEL = 0; + } + } + + // convenient alias for the C++ std library name + enum __CXXLIB__ = __traits(getTargetInfo, "cppRuntimeLibrary"); + +extern(C++, "std"): +package: + enum _LOCK_DEBUG = 3; + + extern(C++, class) struct _Lockit + { + this(int) nothrow @nogc @safe; + ~this() nothrow @nogc @safe; + + private: + int _Locktype; + } + void dummyDtor() { assert(false); } + pragma(linkerDirective, "/ALTERNATENAME:" ~ _Lockit.__dtor.mangleof ~ "=" ~ dummyDtor.mangleof); + + struct _Container_base0 + { + extern(D): + void _Orphan_all()() nothrow @nogc @safe {} + void _Swap_all()(ref _Container_base0) nothrow @nogc @safe {} + void _Swap_proxy_and_iterators()(ref _Container_base0) nothrow {} + } + struct _Iterator_base0 + { + extern(D): + void _Adopt()(const(void)*) nothrow @nogc @safe {} + const(_Container_base0)* _Getcont()() const nothrow @nogc @safe { return null; } + + enum bool _Unwrap_when_unverified = true; + } + + struct _Container_proxy + { + const(_Container_base12)* _Mycont; + _Iterator_base12* _Myfirstiter; + } + + struct _Container_base12 + { + extern(D): + inout(_Iterator_base12*)*_Getpfirst()() inout nothrow @nogc @safe + { + return _Myproxy == null ? null : &_Myproxy._Myfirstiter; + } + void _Orphan_all()() nothrow @nogc @safe + { + static if (_ITERATOR_DEBUG_LEVEL == 2) + { + if (_Myproxy != null) + { + auto _Lock = _Lockit(_LOCK_DEBUG); + for (_Iterator_base12 **_Pnext = &_Myproxy._Myfirstiter; *_Pnext != null; *_Pnext = (*_Pnext)._Mynextiter) + (*_Pnext)._Myproxy = null; + _Myproxy._Myfirstiter = null; + } + } + } +// void _Swap_all()(ref _Container_base12) nothrow @nogc; + + void _Swap_proxy_and_iterators()(ref _Container_base12 _Right) nothrow + { + static if (_ITERATOR_DEBUG_LEVEL == 2) + auto _Lock = _Lockit(_LOCK_DEBUG); + + _Container_proxy* _Temp = _Myproxy; + _Myproxy = _Right._Myproxy; + _Right._Myproxy = _Temp; + + if (_Myproxy) + _Myproxy._Mycont = &this; + + if (_Right._Myproxy) + _Right._Myproxy._Mycont = &_Right; + } + + _Container_proxy* _Myproxy; + } + + struct _Iterator_base12 + { + extern(D): + void _Adopt()(_Container_base12 *_Parent) nothrow @nogc @safe + { + if (_Parent == null) + { + static if (_ITERATOR_DEBUG_LEVEL == 2) + { + auto _Lock = _Lockit(_LOCK_DEBUG); + _Orphan_me(); + } + } + else + { + _Container_proxy *_Parent_proxy = _Parent._Myproxy; + + static if (_ITERATOR_DEBUG_LEVEL == 2) + { + if (_Myproxy != _Parent_proxy) + { + auto _Lock = _Lockit(_LOCK_DEBUG); + _Orphan_me(); + _Mynextiter = _Parent_proxy._Myfirstiter; + _Parent_proxy._Myfirstiter = &this; + _Myproxy = _Parent_proxy; + } + } + else + _Myproxy = _Parent_proxy; + } + } + void _Clrcont()() nothrow @nogc @safe + { + _Myproxy = null; + } + const(_Container_base12)* _Getcont()() const nothrow @nogc @safe + { + return _Myproxy == null ? null : _Myproxy._Mycont; + } + inout(_Iterator_base12*)*_Getpnext()() inout nothrow @nogc @safe + { + return &_Mynextiter; + } + void _Orphan_me()() nothrow @nogc @safe + { + static if (_ITERATOR_DEBUG_LEVEL == 2) + { + if (_Myproxy != null) + { + _Iterator_base12 **_Pnext = &_Myproxy._Myfirstiter; + while (*_Pnext != null && *_Pnext != &this) + _Pnext = &(*_Pnext)._Mynextiter; + assert(*_Pnext, "ITERATOR LIST CORRUPTED!"); + *_Pnext = _Mynextiter; + _Myproxy = null; + } + } + } + + enum bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0; + + _Container_proxy *_Myproxy; + _Iterator_base12 *_Mynextiter; + } + + static if (_ITERATOR_DEBUG_LEVEL == 0) + { + alias _Container_base = _Container_base0; + alias _Iterator_base = _Iterator_base0; + } + else + { + alias _Container_base = _Container_base12; + alias _Iterator_base = _Iterator_base12; + } + + extern (C++, class) struct _Compressed_pair(_Ty1, _Ty2, bool Ty1Empty = is_empty!_Ty1.value) + { + pragma (inline, true): + extern(D): + pure nothrow @nogc: + enum _HasFirst = !Ty1Empty; + + ref inout(_Ty1) first() inout @safe { return _Myval1; } + ref inout(_Ty2) second() inout @safe { return _Myval2; } + + static if (!Ty1Empty) + _Ty1 _Myval1; + else + { + @property ref inout(_Ty1) _Myval1() inout @trusted { return *_GetBase(); } + private inout(_Ty1)* _GetBase() inout @trusted { return cast(inout(_Ty1)*)&this; } + } + _Ty2 _Myval2; + } + + // these are all [[noreturn]] + void _Xbad_alloc() nothrow; + void _Xinvalid_argument(const(char)* message) nothrow; + void _Xlength_error(const(char)* message) nothrow; + void _Xout_of_range(const(char)* message) nothrow; + void _Xoverflow_error(const(char)* message) nothrow; + void _Xruntime_error(const(char)* message) nothrow; +} +else version (CppRuntime_Clang) +{ + import core.stdcpp.type_traits : is_empty; + +extern(C++, "std"): + + extern (C++, class) struct __compressed_pair(_T1, _T2) + { + pragma (inline, true): + extern(D): + enum Ty1Empty = is_empty!_T1.value; + enum Ty2Empty = is_empty!_T2.value; + + ref inout(_T1) first() inout nothrow @safe @nogc { return __value1_; } + ref inout(_T2) second() inout nothrow @safe @nogc { return __value2_; } + + private: + private inout(_T1)* __get_base1() inout { return cast(inout(_T1)*)&this; } + private inout(_T2)* __get_base2() inout { return cast(inout(_T2)*)&__get_base1()[Ty1Empty ? 0 : 1]; } + + static if (!Ty1Empty) + _T1 __value1_; + else + @property ref inout(_T1) __value1_() inout nothrow @trusted @nogc { return *__get_base1(); } + static if (!Ty2Empty) + _T2 __value2_; + else + @property ref inout(_T2) __value2_() inout nothrow @trusted @nogc { return *__get_base2(); } + } +} +version (CppRuntime_Gcc) +{ + import core.atomic; + + alias _Atomic_word = int; + + void __atomic_add_dispatch()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + version (__GTHREADS) + { + // TODO: check __gthread_active_p() +// if (__gthread_active_p()) + __atomic_add(__mem, __val); +// } +// else +// __atomic_add_single(__mem, __val); + } + else + __atomic_add_single(__mem, __val); + } + + void __atomic_add()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + atomicFetchAdd!(MemoryOrder.acq_rel)(*__mem, __val); + } + + void __atomic_add_single()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + *__mem += __val; + } + + _Atomic_word __exchange_and_add_dispatch()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + version (__GTHREADS) + { + // TODO: check __gthread_active_p() + return __exchange_and_add(__mem, __val); + +// if (__gthread_active_p()) +// return __exchange_and_add(__mem, __val); +// else +// return __exchange_and_add_single(__mem, __val); + } + else + return __exchange_and_add_single(__mem, __val); + } + + _Atomic_word __exchange_and_add()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + return atomicFetchAdd!(MemoryOrder.acq_rel)(*__mem, __val); + } + + _Atomic_word __exchange_and_add_single()(_Atomic_word* __mem, int __val) nothrow @nogc @safe + { + _Atomic_word __result = *__mem; + *__mem += __val; + return __result; + } +} |