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 }