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