1 /*** 2 * D compatible types that correspond to various basic types in associated 3 * C and C++ compilers. 4 * 5 * Copyright: Copyright Sean Kelly 2005 - 2009. 6 * License: Distributed under the 7 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 8 * (See accompanying file LICENSE) 9 * Authors: Sean Kelly 10 * Source: $(DRUNTIMESRC core/stdc/_config.d) 11 * Standards: ISO/IEC 9899:1999 (E) 12 */ 13 14 module core.stdc.config; 15 16 version (StdDdoc) 17 { 18 private 19 { 20 version (Posix) 21 enum isPosix = true; 22 else 23 enum isPosix = false; 24 static if (isPosix && (void*).sizeof > int.sizeof) 25 { 26 alias ddoc_long = long; 27 alias ddoc_ulong = ulong; 28 } 29 else 30 { 31 alias ddoc_long = int; 32 alias ddoc_ulong = uint; 33 } 34 struct ddoc_complex(T) { T re; T im; } 35 } 36 37 /*** 38 * Used for a signed integer type that corresponds in size to the associated 39 * C compiler's `long` type. 40 */ 41 alias c_long = ddoc_long; 42 43 /*** 44 * Used for an unsigned integer type that corresponds in size to the associated 45 * C compiler's `unsigned long` type. 46 */ 47 alias c_ulong = ddoc_ulong; 48 49 /*** 50 * Used for a signed integer type that corresponds in size and mangling to the associated 51 * C++ compiler's `long` type. 52 */ 53 alias cpp_long = c_long; 54 55 /*** 56 * Used for an unsigned integer type that corresponds in size and mangling to the associated 57 * C++ compiler's `unsigned long` type. 58 */ 59 alias cpp_ulong = c_ulong; 60 61 /*** 62 * Used for a signed integer type that corresponds in size and mangling to the associated 63 * C++ compiler's `long long` type. 64 */ 65 alias cpp_longlong = long; 66 67 /*** 68 * Used for an unsigned integer type that corresponds in size and mangling to the associated 69 * C++ compiler's `unsigned long long` type. 70 */ 71 alias cpp_ulonglong = ulong; 72 73 /*** 74 * Used for a floating point type that corresponds in size and mangling to the associated 75 * C++ compiler's `long double` type. 76 */ 77 alias c_long_double = real; 78 79 /*** 80 * Used for an unsigned integer type that corresponds in size and mangling to the associated 81 * C++ compiler's `size_t` type. 82 */ 83 alias cpp_size_t = size_t; 84 85 /*** 86 * Used for a signed integer type that corresponds in size and mangling to the associated 87 * C++ compiler's `ptrdiff_t` type. 88 */ 89 alias cpp_ptrdiff_t = ptrdiff_t; 90 91 /*** 92 * Used for a complex floating point type that corresponds in size and ABI to the associated 93 * C compiler's `_Complex float` type. 94 */ 95 alias c_complex_float = ddoc_complex!float; 96 97 /*** 98 * Used for a complex floating point type that corresponds in size and ABI to the associated 99 * C compiler's `_Complex double` type. 100 */ 101 alias c_complex_double = ddoc_complex!double; 102 103 /*** 104 * Used for a complex floating point type that corresponds in size and ABI to the associated 105 * C compiler's `_Complex long double` type. 106 */ 107 alias c_complex_real = ddoc_complex!real; 108 } 109 else 110 { 111 112 version (OSX) 113 version = Darwin; 114 else version (iOS) 115 version = Darwin; 116 else version (TVOS) 117 version = Darwin; 118 else version (WatchOS) 119 version = Darwin; 120 121 version (Windows) 122 { 123 enum __c_long : int; 124 enum __c_ulong : uint; 125 126 alias int c_long; 127 alias uint c_ulong; 128 129 alias __c_long cpp_long; 130 alias __c_ulong cpp_ulong; 131 132 alias long cpp_longlong; 133 alias ulong cpp_ulonglong; 134 } 135 else version (Posix) 136 { 137 static if ( (void*).sizeof > int.sizeof ) 138 { 139 enum __c_longlong : long; 140 enum __c_ulonglong : ulong; 141 142 alias long c_long; 143 alias ulong c_ulong; 144 145 alias long cpp_long; 146 alias ulong cpp_ulong; 147 148 alias __c_longlong cpp_longlong; 149 alias __c_ulonglong cpp_ulonglong; 150 } 151 else 152 { 153 enum __c_long : int; 154 enum __c_ulong : uint; 155 156 alias int c_long; 157 alias uint c_ulong; 158 159 alias __c_long cpp_long; 160 alias __c_ulong cpp_ulong; 161 162 alias long cpp_longlong; 163 alias ulong cpp_ulonglong; 164 } 165 } 166 else version (WASI) 167 { 168 static if ( (void*).sizeof > int.sizeof ) 169 { 170 enum __c_longlong : long; 171 enum __c_ulonglong : ulong; 172 173 alias long c_long; 174 alias ulong c_ulong; 175 176 alias long cpp_long; 177 alias ulong cpp_ulong; 178 179 alias __c_longlong cpp_longlong; 180 alias __c_ulonglong cpp_ulonglong; 181 } 182 else 183 { 184 enum __c_long : int; 185 enum __c_ulong : uint; 186 187 alias int c_long; 188 alias uint c_ulong; 189 190 alias __c_long cpp_long; 191 alias __c_ulong cpp_ulong; 192 193 alias long cpp_longlong; 194 alias ulong cpp_ulonglong; 195 } 196 } 197 else version (FreeStanding) 198 { 199 static if ( (void*).sizeof > int.sizeof ) 200 { 201 enum __c_longlong : long; 202 enum __c_ulonglong : ulong; 203 204 alias long c_long; 205 alias ulong c_ulong; 206 207 alias long cpp_long; 208 alias ulong cpp_ulong; 209 210 alias __c_longlong cpp_longlong; 211 alias __c_ulonglong cpp_ulonglong; 212 } 213 else 214 { 215 enum __c_long : int; 216 enum __c_ulong : uint; 217 218 alias int c_long; 219 alias uint c_ulong; 220 221 alias __c_long cpp_long; 222 alias __c_ulong cpp_ulong; 223 224 alias long cpp_longlong; 225 alias ulong cpp_ulonglong; 226 } 227 228 } 229 230 version (GNU) 231 alias c_long_double = real; 232 else version (LDC) 233 alias c_long_double = real; // 64-bit real for MSVC targets 234 else version (SDC) 235 { 236 version (X86) 237 alias c_long_double = real; 238 else version (X86_64) 239 alias c_long_double = real; 240 } 241 else version (CRuntime_Microsoft) 242 { 243 /* long double is 64 bits, not 80 bits, but is mangled differently 244 * than double. To distinguish double from long double, create a wrapper to represent 245 * long double, then recognize that wrapper specially in the compiler 246 * to generate the correct name mangling and correct function call/return 247 * ABI conformance. 248 */ 249 enum __c_long_double : double; 250 251 alias __c_long_double c_long_double; 252 } 253 else version (DigitalMars) 254 { 255 version (X86) 256 { 257 alias real c_long_double; 258 } 259 else version (X86_64) 260 { 261 version (linux) 262 alias real c_long_double; 263 else version (FreeBSD) 264 alias real c_long_double; 265 else version (OpenBSD) 266 alias real c_long_double; 267 else version (NetBSD) 268 alias real c_long_double; 269 else version (DragonFlyBSD) 270 alias real c_long_double; 271 else version (Solaris) 272 alias real c_long_double; 273 else version (Darwin) 274 alias real c_long_double; 275 } 276 } 277 278 static assert(is(c_long_double), "c_long_double needs to be declared for this platform/architecture."); 279 280 version (Darwin) 281 { 282 alias cpp_size_t = cpp_ulong; 283 version (D_LP64) 284 alias cpp_ptrdiff_t = cpp_long; 285 else 286 alias cpp_ptrdiff_t = ptrdiff_t; 287 } 288 else 289 { 290 alias cpp_size_t = size_t; 291 alias cpp_ptrdiff_t = ptrdiff_t; 292 } 293 294 /** ABI layout of native complex types. 295 */ 296 struct _Complex(T) 297 if (is(T == float) || is(T == double) || is(T == c_long_double)) 298 { 299 T re = 0; 300 T im = 0; 301 302 // Construction 303 /+ https://issues.dlang.org/show_bug.cgi?id=23788 dmd codegen problem with constructors and _Complex!float 304 this(_Complex!float c) { re = c.re; im = c.im; } 305 this(_Complex!double c) { re = c.re; im = c.im; } 306 this(_Complex!c_long_double c) { re = c.re; im = c.im; } 307 308 this(T re, T im) { this.re = re; this.im = im; } 309 310 this(T re) { this.re = re; this.im = 0; } 311 +/ 312 // Cast 313 R opCast(R)() 314 if (is(R == _Complex!float) || is(R == _Complex!double) || is(R == _Complex!c_long_double)) 315 { 316 return R(this.re, this.im); 317 } 318 319 // Assignment 320 321 ref _Complex opAssign(_Complex!float c) { re = c.re; im = c.im; return this; } 322 ref _Complex opAssign(_Complex!double c) { re = c.re; im = c.im; return this; } 323 ref _Complex opAssign(_Complex!c_long_double c) { re = c.re; im = c.im; return this; } 324 325 ref _Complex opAssign(T t) { re = t; im = 0; return this; } 326 327 // Equals 328 329 bool opEquals(_Complex!float c) { return re == c.re && im == c.im; } 330 bool opEquals(_Complex!double c) { return re == c.re && im == c.im; } 331 bool opEquals(_Complex!c_long_double c) { return re == c.re && im == c.im; } 332 333 bool opEquals(T t) { return re == t && im == 0; } 334 335 // Unary operators 336 337 // +complex 338 _Complex opUnary(string op)() 339 if (op == "+") 340 { 341 return this; 342 } 343 344 // -complex 345 _Complex opUnary(string op)() 346 if (op == "-") 347 { 348 return _Complex(-re, -im); 349 } 350 351 // BINARY OPERATORS 352 353 // complex op complex 354 _Complex!(CommonType!(T,R)) opBinary(string op, R)(_Complex!R z) 355 { 356 alias C = typeof(return); 357 auto w = C(this.re, this.im); 358 return w.opOpAssign!(op)(z); 359 } 360 361 // complex op numeric 362 _Complex!(CommonType!(T,R)) opBinary(string op, R)(R r) 363 if (is(R : c_long_double)) 364 { 365 alias C = typeof(return); 366 auto w = C(this.re, this.im); 367 return w.opOpAssign!(op)(r); 368 } 369 370 // numeric + complex, numeric * complex 371 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 372 if ((op == "+" || op == "*") && is(R : c_long_double)) 373 { 374 return opBinary!(op)(r); 375 } 376 377 // numeric - complex 378 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 379 if (op == "-" && is(R : c_long_double)) 380 { 381 return _Complex(r - re, -im); 382 } 383 384 // numeric / complex 385 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 386 if (op == "/" && is(R : c_long_double)) 387 { 388 import core.math : fabs; 389 typeof(return) w = void; 390 if (fabs(re) < fabs(im)) 391 { 392 immutable ratio = re/im; 393 immutable rdivd = r/(re*ratio + im); 394 395 w.re = rdivd*ratio; 396 w.im = -rdivd; 397 } 398 else 399 { 400 immutable ratio = im/re; 401 immutable rdivd = r/(re + im*ratio); 402 403 w.re = rdivd; 404 w.im = -rdivd*ratio; 405 } 406 407 return w; 408 } 409 410 // OP-ASSIGN OPERATORS 411 412 // complex += complex, complex -= complex 413 ref _Complex opOpAssign(string op, C)(C z) 414 if ((op == "+" || op == "-") && is(C R == _Complex!R)) 415 { 416 mixin ("re "~op~"= z.re;"); 417 mixin ("im "~op~"= z.im;"); 418 return this; 419 } 420 421 // complex *= complex 422 ref _Complex opOpAssign(string op, C)(C z) 423 if (op == "*" && is(C R == _Complex!R)) 424 { 425 auto temp = re*z.re - im*z.im; 426 im = im*z.re + re*z.im; 427 re = temp; 428 return this; 429 } 430 431 // complex /= complex 432 ref _Complex opOpAssign(string op, C)(C z) 433 if (op == "/" && is(C R == _Complex!R)) 434 { 435 import core.math : fabs; 436 if (fabs(z.re) < fabs(z.im)) 437 { 438 immutable ratio = z.re/z.im; 439 immutable denom = z.re*ratio + z.im; 440 441 immutable temp = (re*ratio + im)/denom; 442 im = (im*ratio - re)/denom; 443 re = temp; 444 } 445 else 446 { 447 immutable ratio = z.im/z.re; 448 immutable denom = z.re + z.im*ratio; 449 450 immutable temp = (re + im*ratio)/denom; 451 im = (im - re*ratio)/denom; 452 re = temp; 453 } 454 return this; 455 } 456 457 // complex += numeric, complex -= numeric 458 ref _Complex opOpAssign(string op, U : T)(U a) 459 if (op == "+" || op == "-") 460 { 461 mixin ("re "~op~"= a;"); 462 return this; 463 } 464 465 // complex *= numeric, complex /= numeric 466 ref _Complex opOpAssign(string op, U : T)(U a) 467 if (op == "*" || op == "/") 468 { 469 mixin ("re "~op~"= a;"); 470 mixin ("im "~op~"= a;"); 471 return this; 472 } 473 474 // Helper properties. 475 pragma(inline, true) 476 { 477 static @property epsilon()() { return _Complex(T.epsilon, T.epsilon); } 478 static @property infinity()() { return _Complex(T.infinity, T.infinity); } 479 static @property max()() { return _Complex(T.max, T.max); } 480 static @property min_normal()() { return _Complex(T.min_normal, T.min_normal); } 481 static @property nan()() { return _Complex(T.nan, T.nan); } 482 static @property dig()() { return T.dig; } 483 static @property mant_dig()() { return T.mant_dig; } 484 static @property max_10_exp()() { return T.max_10_exp; } 485 static @property max_exp()() { return T.max_exp; } 486 static @property min_10_exp()() { return T.min_10_exp; } 487 static @property min_exp()() { return T.min_exp; } 488 } 489 } 490 491 enum __c_complex_float : _Complex!float; 492 enum __c_complex_double : _Complex!double; 493 enum __c_complex_real : _Complex!c_long_double; 494 495 alias c_complex_float = __c_complex_float; 496 alias c_complex_double = __c_complex_double; 497 alias c_complex_real = __c_complex_real; 498 499 private template CommonType(T, R) 500 { 501 // Special kludge for Microsoft c_long_double 502 static if (is(T == c_long_double)) 503 alias CommonType = T; 504 else static if (is(R == c_long_double)) 505 alias CommonType = R; 506 else 507 alias CommonType = typeof(true ? T.init : R.init); 508 } 509 510 /************ unittests ****************/ 511 512 version (unittest) 513 { 514 private: 515 516 alias _cfloat = _Complex!float; 517 alias _cdouble = _Complex!double; 518 alias _creal = _Complex!c_long_double; 519 520 T abs(T)(T t) => t < 0 ? -t : t; 521 } 522 523 @safe pure nothrow unittest 524 { 525 auto c1 = _cdouble(1.0, 1.0); 526 527 // Check unary operations. 528 auto c2 = _cdouble(0.5, 2.0); 529 530 assert(c2 == +c2); 531 532 assert((-c2).re == -(c2.re)); 533 assert((-c2).im == -(c2.im)); 534 assert(c2 == -(-c2)); 535 536 // Check complex-complex operations. 537 auto cpc = c1 + c2; 538 assert(cpc.re == c1.re + c2.re); 539 assert(cpc.im == c1.im + c2.im); 540 541 auto cmc = c1 - c2; 542 assert(cmc.re == c1.re - c2.re); 543 assert(cmc.im == c1.im - c2.im); 544 545 auto ctc = c1 * c2; 546 assert(ctc == _cdouble(-1.5, 2.5)); 547 548 auto cdc = c1 / c2; 549 assert(abs(cdc.re - 0.5882352941177) < 1e-12); 550 assert(abs(cdc.im - -0.3529411764706) < 1e-12); 551 552 // Check complex-real operations. 553 double a = 123.456; 554 555 auto cpr = c1 + a; 556 assert(cpr.re == c1.re + a); 557 assert(cpr.im == c1.im); 558 559 auto cmr = c1 - a; 560 assert(cmr.re == c1.re - a); 561 assert(cmr.im == c1.im); 562 563 auto ctr = c1 * a; 564 assert(ctr.re == c1.re*a); 565 assert(ctr.im == c1.im*a); 566 567 auto cdr = c1 / a; 568 assert(abs(cdr.re - 0.00810005184033) < 1e-12); 569 assert(abs(cdr.im - 0.00810005184033) < 1e-12); 570 571 auto rpc = a + c1; 572 assert(rpc == cpr); 573 574 auto rmc = a - c1; 575 assert(rmc.re == a-c1.re); 576 assert(rmc.im == -c1.im); 577 578 auto rtc = a * c1; 579 assert(rtc == ctr); 580 581 auto rdc = a / c1; 582 assert(abs(rdc.re - 61.728) < 1e-12); 583 assert(abs(rdc.im - -61.728) < 1e-12); 584 585 rdc = a / c2; 586 assert(abs(rdc.re - 14.5242352941) < 1e-10); 587 assert(abs(rdc.im - -58.0969411765) < 1e-10); 588 589 // Check operations between different complex types. 590 auto cf = _cfloat(1.0, 1.0); 591 auto cr = _creal(1.0, 1.0); 592 auto c1pcf = c1 + cf; 593 auto c1pcr = c1 + cr; 594 static assert(is(typeof(c1pcf) == _cdouble)); 595 static assert(is(typeof(c1pcr) == _creal)); 596 assert(c1pcf.re == c1pcr.re); 597 assert(c1pcf.im == c1pcr.im); 598 599 auto c1c = c1; 600 auto c2c = c2; 601 602 c1c /= c1; 603 assert(abs(c1c.re - 1.0) < 1e-10); 604 assert(abs(c1c.im - 0.0) < 1e-10); 605 606 c1c = c1; 607 c1c /= c2; 608 assert(abs(c1c.re - 0.5882352941177) < 1e-12); 609 assert(abs(c1c.im - -0.3529411764706) < 1e-12); 610 611 c2c /= c1; 612 assert(abs(c2c.re - 1.25) < 1e-11); 613 assert(abs(c2c.im - 0.75) < 1e-12); 614 615 c2c = c2; 616 c2c /= c2; 617 assert(abs(c2c.re - 1.0) < 1e-11); 618 assert(abs(c2c.im - 0.0) < 1e-12); 619 } 620 621 @safe pure nothrow unittest 622 { 623 // Initialization 624 _cdouble a = _cdouble(1, 0); 625 assert(a.re == 1 && a.im == 0); 626 _cdouble b = _cdouble(1.0, 0); 627 assert(b.re == 1.0 && b.im == 0); 628 // _cdouble c = _creal(1.0, 2); 629 // assert(c.re == 1.0 && c.im == 2); 630 } 631 632 @safe pure nothrow unittest 633 { 634 // Assignments and comparisons 635 _cdouble z; 636 637 z = 1; 638 assert(z == 1); 639 assert(z.re == 1.0 && z.im == 0.0); 640 641 z = 2.0; 642 assert(z == 2.0); 643 assert(z.re == 2.0 && z.im == 0.0); 644 645 z = 1.0L; 646 assert(z == 1.0L); 647 assert(z.re == 1.0 && z.im == 0.0); 648 649 auto w = _creal(1.0, 1.0); 650 z = w; 651 assert(z == w); 652 assert(z.re == 1.0 && z.im == 1.0); 653 654 auto c = _cfloat(2.0, 2.0); 655 z = c; 656 assert(z == c); 657 assert(z.re == 2.0 && z.im == 2.0); 658 } 659 660 } 661 662 663 // Returns the mangled name for the 64-bit time_t versions of 664 // functions affected by musl's transition to 64-bit time_t. 665 // https://musl.libc.org/time64.html 666 version (CRuntime_Musl) 667 { 668 version (WebAssembly) 669 enum muslRedirTime64 = false; 670 else 671 version (CRuntime_Musl_Pre_Time64) 672 enum muslRedirTime64 = false; 673 else 674 { 675 // time_t was defined as a C long in older Musl versions. 676 enum muslRedirTime64 = (c_long.sizeof == 4); 677 } 678 } 679 else 680 enum muslRedirTime64 = false; 681 682 package(core) template muslRedirTime64Mangle(string name, string redirectedName) 683 { 684 static if (muslRedirTime64) 685 enum muslRedirTime64Mangle = redirectedName; 686 else 687 enum muslRedirTime64Mangle = name; 688 }