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 }