| /** | 
 |  * 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; | 
 |     } | 
 | } |