1 /**
2  * D header file for interaction with Microsoft C++ <xutility>
3  *
4  * Copyright: Copyright (c) 2018 D Language Foundation
5  * License: Distributed under the
6  *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7  *    (See accompanying file LICENSE)
8  * Authors:   Manu Evans
9  * Source:    $(DRUNTIMESRC core/stdcpp/xutility.d)
10  */
11 
12 module core.stdcpp.xutility;
13 
14 @nogc:
15 
16 version (CppRuntime_Clang)
17 {
18     import core.internal.traits : AliasSeq;
19     enum StdNamespace = AliasSeq!("std", "__1");
20 }
21 else
22 {
23     enum StdNamespace = "std";
24 }
25 
26 /**
27  * Possible values of the `__cplusplus` macro provided by C++ compilers
28  *
29  * For foolproofness, use ordering comparison, e.g. `__cplusplus >= CppStdRevision.cpp17`.
30  */
31 enum CppStdRevision : uint
32 {
33     cpp98 = 199711,
34     cpp11 = 201103,
35     cpp14 = 201402,
36     cpp17 = 201703,
37     cpp20 = 202002,
38 }
39 
40 /**
41  * Returns the target C++ version, encoded as C++ compilers do
42  *
43  * C++ compilers provide a `__cplusplus` macro which returns an integer
44  * representing the targetted standard. This manifest provides the same
45  * interface, retrieved from the compiler via a `__traits`.
46  */
47 enum __cplusplus = __traits(getTargetInfo, "cppStd");
48 
49 // wrangle C++ features
50 enum __cpp_sized_deallocation = __cplusplus >= CppStdRevision.cpp14 || is(typeof(_MSC_VER)) ? 201309 : 0;
51 enum __cpp_aligned_new = __cplusplus >= CppStdRevision.cpp17 ? 201606 : 0;
52 
53 
54 version (CppRuntime_Microsoft)
55 {
56     import core.stdcpp.type_traits : is_empty;
57 
58     version (_MSC_VER_1200)
59         enum _MSC_VER = 1200;
60     else version (_MSC_VER_1300)
61         enum _MSC_VER = 1300;
62     else version (_MSC_VER_1310)
63         enum _MSC_VER = 1310;
64     else version (_MSC_VER_1400)
65         enum _MSC_VER = 1400;
66     else version (_MSC_VER_1500)
67         enum _MSC_VER = 1500;
68     else version (_MSC_VER_1600)
69         enum _MSC_VER = 1600;
70     else version (_MSC_VER_1700)
71         enum _MSC_VER = 1700;
72     else version (_MSC_VER_1800)
73         enum _MSC_VER = 1800;
74     else version (_MSC_VER_1900)
75         enum _MSC_VER = 1900;
76     else version (_MSC_VER_1910)
77         enum _MSC_VER = 1910;
78     else version (_MSC_VER_1911)
79         enum _MSC_VER = 1911;
80     else version (_MSC_VER_1912)
81         enum _MSC_VER = 1912;
82     else version (_MSC_VER_1913)
83         enum _MSC_VER = 1913;
84     else version (_MSC_VER_1914)
85         enum _MSC_VER = 1914;
86     else version (_MSC_VER_1915)
87         enum _MSC_VER = 1915;
88     else version (_MSC_VER_1916)
89         enum _MSC_VER = 1916;
90     else version (_MSC_VER_1920)
91         enum _MSC_VER = 1920;
92     else version (_MSC_VER_1921)
93         enum _MSC_VER = 1921;
94     else version (_MSC_VER_1922)
95         enum _MSC_VER = 1922;
96     else version (_MSC_VER_1923)
97         enum _MSC_VER = 1923;
98     else
99         enum _MSC_VER = 1923; // assume most recent compiler version
100 
101     // Client code can mixin the set of MSVC linker directives
102     mixin template MSVCLinkDirectives(bool failMismatch = false)
103     {
104         import core.stdcpp.xutility : __CXXLIB__, _ITERATOR_DEBUG_LEVEL;
105 
106         static if (__CXXLIB__ == "libcmtd")
107         {
108             pragma(lib, "libcpmtd");
109             static if (failMismatch)
110                 pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MTd_StaticDebug");
111         }
112         else static if (__CXXLIB__ == "msvcrtd")
113         {
114             pragma(lib, "msvcprtd");
115             static if (failMismatch)
116                 pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MDd_DynamicDebug");
117         }
118         else static if (__CXXLIB__ == "libcmt")
119         {
120             pragma(lib, "libcpmt");
121             static if (failMismatch)
122                 pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MT_StaticRelease");
123         }
124         else static if (__CXXLIB__ == "msvcrt")
125         {
126             pragma(lib, "msvcprt");
127             static if (failMismatch)
128                 pragma(linkerDirective, "/FAILIFMISMATCH:RuntimeLibrary=MD_DynamicRelease");
129         }
130         static if (failMismatch)
131             pragma(linkerDirective, "/FAILIFMISMATCH:_ITERATOR_DEBUG_LEVEL=" ~ ('0' + _ITERATOR_DEBUG_LEVEL));
132     }
133 
134     // HACK: should we guess _DEBUG for `debug` builds?
135     version (NDEBUG) {}
136     else debug version = _DEBUG;
137 
138     // By specific user request
139     version (_ITERATOR_DEBUG_LEVEL_0)
140         enum _ITERATOR_DEBUG_LEVEL = 0;
141     else version (_ITERATOR_DEBUG_LEVEL_1)
142         enum _ITERATOR_DEBUG_LEVEL = 1;
143     else version (_ITERATOR_DEBUG_LEVEL_2)
144         enum _ITERATOR_DEBUG_LEVEL = 2;
145     else
146     {
147         // Match the C Runtime
148         static if (__CXXLIB__ == "libcmtd" || __CXXLIB__ == "msvcrtd")
149             enum _ITERATOR_DEBUG_LEVEL = 2;
150         else static if (__CXXLIB__ == "libcmt" || __CXXLIB__ == "msvcrt" ||
151                         __CXXLIB__ == "msvcrt100" || __CXXLIB__ == "msvcrt110" || __CXXLIB__ == "msvcrt120")
152             enum _ITERATOR_DEBUG_LEVEL = 0;
153         else
154         {
155             static if (__CXXLIB__.length > 0)
156                 pragma(msg, "Unrecognised C++ runtime library '" ~ __CXXLIB__ ~ "'");
157 
158             // No runtime specified; as a best-guess, -release will produce code that matches the MSVC release CRT
159             version (_DEBUG)
160                 enum _ITERATOR_DEBUG_LEVEL = 2;
161             else
162                 enum _ITERATOR_DEBUG_LEVEL = 0;
163         }
164     }
165 
166     // convenient alias for the C++ std library name
167     enum __CXXLIB__ = __traits(getTargetInfo, "cppRuntimeLibrary");
168 
169 extern(C++, "std"):
170 package:
171     enum _LOCK_DEBUG = 3;
172 
173     extern(C++, class) struct _Lockit
174     {
175         this(int) nothrow @nogc @safe;
176         ~this() nothrow @nogc @safe;
177 
178     private:
179         int _Locktype;
180     }
181     void dummyDtor() { assert(false); }
182     pragma(linkerDirective, "/ALTERNATENAME:" ~ _Lockit.__dtor.mangleof ~ "=" ~ dummyDtor.mangleof);
183 
184     struct _Container_base0
185     {
186     extern(D):
187         void _Orphan_all()() nothrow @nogc @safe {}
188         void _Swap_all()(ref _Container_base0) nothrow @nogc @safe {}
189         void _Swap_proxy_and_iterators()(ref _Container_base0) nothrow {}
190     }
191     struct _Iterator_base0
192     {
193     extern(D):
194         void _Adopt()(const(void)*) nothrow @nogc @safe {}
195         const(_Container_base0)* _Getcont()() const nothrow @nogc @safe { return null; }
196 
197         enum bool _Unwrap_when_unverified = true;
198     }
199 
200     struct _Container_proxy
201     {
202         const(_Container_base12)* _Mycont;
203         _Iterator_base12* _Myfirstiter;
204     }
205 
206     struct _Container_base12
207     {
208     extern(D):
209         inout(_Iterator_base12*)*_Getpfirst()() inout nothrow @nogc @safe
210         {
211             return _Myproxy == null ? null : &_Myproxy._Myfirstiter;
212         }
213         void _Orphan_all()() nothrow @nogc @safe
214         {
215             static if (_ITERATOR_DEBUG_LEVEL == 2)
216             {
217                 if (_Myproxy != null)
218                 {
219                     auto _Lock = _Lockit(_LOCK_DEBUG);
220                     for (_Iterator_base12 **_Pnext = &_Myproxy._Myfirstiter; *_Pnext != null; *_Pnext = (*_Pnext)._Mynextiter)
221                         (*_Pnext)._Myproxy = null;
222                     _Myproxy._Myfirstiter = null;
223                 }
224             }
225         }
226 //        void _Swap_all()(ref _Container_base12) nothrow @nogc;
227 
228         void _Swap_proxy_and_iterators()(ref _Container_base12 _Right) nothrow
229         {
230             static if (_ITERATOR_DEBUG_LEVEL == 2)
231                 auto _Lock = _Lockit(_LOCK_DEBUG);
232 
233             _Container_proxy* _Temp = _Myproxy;
234             _Myproxy = _Right._Myproxy;
235             _Right._Myproxy = _Temp;
236 
237             if (_Myproxy)
238                 _Myproxy._Mycont = &this;
239 
240             if (_Right._Myproxy)
241                 _Right._Myproxy._Mycont = &_Right;
242         }
243 
244         _Container_proxy* _Myproxy;
245     }
246 
247     struct _Iterator_base12
248     {
249     extern(D):
250         void _Adopt()(_Container_base12 *_Parent) nothrow @nogc @safe
251         {
252             if (_Parent == null)
253             {
254                 static if (_ITERATOR_DEBUG_LEVEL == 2)
255                 {
256                     auto _Lock = _Lockit(_LOCK_DEBUG);
257                     _Orphan_me();
258                 }
259             }
260             else
261             {
262                 _Container_proxy *_Parent_proxy = _Parent._Myproxy;
263 
264                 static if (_ITERATOR_DEBUG_LEVEL == 2)
265                 {
266                     if (_Myproxy != _Parent_proxy)
267                     {
268                         auto _Lock = _Lockit(_LOCK_DEBUG);
269                         _Orphan_me();
270                         _Mynextiter = _Parent_proxy._Myfirstiter;
271                         _Parent_proxy._Myfirstiter = &this;
272                         _Myproxy = _Parent_proxy;
273                     }
274                 }
275                 else
276                     _Myproxy = _Parent_proxy;
277             }
278         }
279         void _Clrcont()() nothrow @nogc @safe
280         {
281             _Myproxy = null;
282         }
283         const(_Container_base12)* _Getcont()() const nothrow @nogc @safe
284         {
285             return _Myproxy == null ? null : _Myproxy._Mycont;
286         }
287         inout(_Iterator_base12*)*_Getpnext()() inout nothrow @nogc @safe
288         {
289             return &_Mynextiter;
290         }
291         void _Orphan_me()() nothrow @nogc @safe
292         {
293             static if (_ITERATOR_DEBUG_LEVEL == 2)
294             {
295                 if (_Myproxy != null)
296                 {
297                     _Iterator_base12 **_Pnext = &_Myproxy._Myfirstiter;
298                     while (*_Pnext != null && *_Pnext != &this)
299                         _Pnext = &(*_Pnext)._Mynextiter;
300                     assert(*_Pnext, "ITERATOR LIST CORRUPTED!");
301                     *_Pnext = _Mynextiter;
302                     _Myproxy = null;
303                 }
304             }
305         }
306 
307         enum bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0;
308 
309         _Container_proxy *_Myproxy;
310         _Iterator_base12 *_Mynextiter;
311     }
312 
313     static if (_ITERATOR_DEBUG_LEVEL == 0)
314     {
315         alias _Container_base = _Container_base0;
316         alias _Iterator_base = _Iterator_base0;
317     }
318     else
319     {
320         alias _Container_base = _Container_base12;
321         alias _Iterator_base = _Iterator_base12;
322     }
323 
324     extern (C++, class) struct _Compressed_pair(_Ty1, _Ty2, bool Ty1Empty = is_empty!_Ty1.value)
325     {
326     pragma (inline, true):
327     extern(D):
328     pure nothrow @nogc:
329         enum _HasFirst = !Ty1Empty;
330 
331         ref inout(_Ty1) first() inout @safe { return _Myval1; }
332         ref inout(_Ty2) second() inout @safe { return _Myval2; }
333 
334         static if (!Ty1Empty)
335             _Ty1 _Myval1;
336         else
337         {
338             @property ref inout(_Ty1) _Myval1() inout @trusted { return *_GetBase(); }
339             private inout(_Ty1)* _GetBase() inout @trusted { return cast(inout(_Ty1)*)&this; }
340         }
341         _Ty2 _Myval2;
342     }
343 
344     // these are all [[noreturn]]
345     void _Xbad_alloc() nothrow;
346     void _Xinvalid_argument(const(char)* message) nothrow;
347     void _Xlength_error(const(char)* message) nothrow;
348     void _Xout_of_range(const(char)* message) nothrow;
349     void _Xoverflow_error(const(char)* message) nothrow;
350     void _Xruntime_error(const(char)* message) nothrow;
351 }
352 else version (CppRuntime_Clang)
353 {
354     import core.stdcpp.type_traits : is_empty;
355 
356 extern(C++, "std"):
357 
358     extern (C++, class) struct __compressed_pair(_T1, _T2)
359     {
360     pragma (inline, true):
361     extern(D):
362         enum Ty1Empty = is_empty!_T1.value;
363         enum Ty2Empty = is_empty!_T2.value;
364 
365         ref inout(_T1) first() inout nothrow @safe @nogc { return __value1_; }
366         ref inout(_T2) second() inout nothrow @safe @nogc { return __value2_; }
367 
368     private:
369         private inout(_T1)* __get_base1() inout { return cast(inout(_T1)*)&this; }
370         private inout(_T2)* __get_base2() inout { return cast(inout(_T2)*)&__get_base1()[Ty1Empty ? 0 : 1]; }
371 
372         static if (!Ty1Empty)
373             _T1 __value1_;
374         else
375             @property ref inout(_T1) __value1_() inout nothrow @trusted @nogc { return *__get_base1(); }
376         static if (!Ty2Empty)
377             _T2 __value2_;
378         else
379             @property ref inout(_T2) __value2_() inout nothrow @trusted @nogc { return *__get_base2(); }
380     }
381 }
382 version (CppRuntime_Gcc)
383 {
384     import core.atomic;
385 
386     alias _Atomic_word = int;
387 
388     void __atomic_add_dispatch()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
389     {
390         version (__GTHREADS)
391         {
392             // TODO: check __gthread_active_p()
393 //            if (__gthread_active_p())
394                 __atomic_add(__mem, __val);
395 //            }
396 //            else
397 //            __atomic_add_single(__mem, __val);
398         }
399         else
400             __atomic_add_single(__mem, __val);
401     }
402 
403     void __atomic_add()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
404     {
405         atomicFetchAdd!(MemoryOrder.acq_rel)(*__mem, __val);
406     }
407 
408     void __atomic_add_single()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
409     {
410         *__mem += __val;
411     }
412 
413     _Atomic_word __exchange_and_add_dispatch()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
414     {
415         version (__GTHREADS)
416         {
417             // TODO: check __gthread_active_p()
418             return __exchange_and_add(__mem, __val);
419 
420 //            if (__gthread_active_p())
421 //                return __exchange_and_add(__mem, __val);
422 //            else
423 //                return __exchange_and_add_single(__mem, __val);
424         }
425         else
426             return __exchange_and_add_single(__mem, __val);
427     }
428 
429     _Atomic_word __exchange_and_add()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
430     {
431         return atomicFetchAdd!(MemoryOrder.acq_rel)(*__mem, __val);
432     }
433 
434     _Atomic_word __exchange_and_add_single()(_Atomic_word* __mem, int __val) nothrow @nogc @safe
435     {
436         _Atomic_word __result = *__mem;
437         *__mem += __val;
438         return __result;
439     }
440 }