/** * D header file for interaction with Microsoft C++ * * 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; } }