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 198 version (GNU) 199 alias c_long_double = real; 200 else version (LDC) 201 alias c_long_double = real; // 64-bit real for MSVC targets 202 else version (SDC) 203 { 204 version (X86) 205 alias c_long_double = real; 206 else version (X86_64) 207 alias c_long_double = real; 208 } 209 else version (CRuntime_Microsoft) 210 { 211 /* long double is 64 bits, not 80 bits, but is mangled differently 212 * than double. To distinguish double from long double, create a wrapper to represent 213 * long double, then recognize that wrapper specially in the compiler 214 * to generate the correct name mangling and correct function call/return 215 * ABI conformance. 216 */ 217 enum __c_long_double : double; 218 219 alias __c_long_double c_long_double; 220 } 221 else version (DigitalMars) 222 { 223 version (X86) 224 { 225 alias real c_long_double; 226 } 227 else version (X86_64) 228 { 229 version (linux) 230 alias real c_long_double; 231 else version (FreeBSD) 232 alias real c_long_double; 233 else version (OpenBSD) 234 alias real c_long_double; 235 else version (NetBSD) 236 alias real c_long_double; 237 else version (DragonFlyBSD) 238 alias real c_long_double; 239 else version (Solaris) 240 alias real c_long_double; 241 else version (Darwin) 242 alias real c_long_double; 243 } 244 } 245 246 static assert(is(c_long_double), "c_long_double needs to be declared for this platform/architecture."); 247 248 version (Darwin) 249 { 250 alias cpp_size_t = cpp_ulong; 251 version (D_LP64) 252 alias cpp_ptrdiff_t = cpp_long; 253 else 254 alias cpp_ptrdiff_t = ptrdiff_t; 255 } 256 else 257 { 258 alias cpp_size_t = size_t; 259 alias cpp_ptrdiff_t = ptrdiff_t; 260 } 261 262 /** ABI layout of native complex types. 263 */ 264 struct _Complex(T) 265 if (is(T == float) || is(T == double) || is(T == c_long_double)) 266 { 267 T re = 0; 268 T im = 0; 269 270 // Construction 271 /+ https://issues.dlang.org/show_bug.cgi?id=23788 dmd codegen problem with constructors and _Complex!float 272 this(_Complex!float c) { re = c.re; im = c.im; } 273 this(_Complex!double c) { re = c.re; im = c.im; } 274 this(_Complex!c_long_double c) { re = c.re; im = c.im; } 275 276 this(T re, T im) { this.re = re; this.im = im; } 277 278 this(T re) { this.re = re; this.im = 0; } 279 +/ 280 // Cast 281 R opCast(R)() 282 if (is(R == _Complex!float) || is(R == _Complex!double) || is(R == _Complex!c_long_double)) 283 { 284 return R(this.re, this.im); 285 } 286 287 // Assignment 288 289 ref _Complex opAssign(_Complex!float c) { re = c.re; im = c.im; return this; } 290 ref _Complex opAssign(_Complex!double c) { re = c.re; im = c.im; return this; } 291 ref _Complex opAssign(_Complex!c_long_double c) { re = c.re; im = c.im; return this; } 292 293 ref _Complex opAssign(T t) { re = t; im = 0; return this; } 294 295 // Equals 296 297 bool opEquals(_Complex!float c) { return re == c.re && im == c.im; } 298 bool opEquals(_Complex!double c) { return re == c.re && im == c.im; } 299 bool opEquals(_Complex!c_long_double c) { return re == c.re && im == c.im; } 300 301 bool opEquals(T t) { return re == t && im == 0; } 302 303 // Unary operators 304 305 // +complex 306 _Complex opUnary(string op)() 307 if (op == "+") 308 { 309 return this; 310 } 311 312 // -complex 313 _Complex opUnary(string op)() 314 if (op == "-") 315 { 316 return _Complex(-re, -im); 317 } 318 319 // BINARY OPERATORS 320 321 // complex op complex 322 _Complex!(CommonType!(T,R)) opBinary(string op, R)(_Complex!R z) 323 { 324 alias C = typeof(return); 325 auto w = C(this.re, this.im); 326 return w.opOpAssign!(op)(z); 327 } 328 329 // complex op numeric 330 _Complex!(CommonType!(T,R)) opBinary(string op, R)(R r) 331 if (is(R : c_long_double)) 332 { 333 alias C = typeof(return); 334 auto w = C(this.re, this.im); 335 return w.opOpAssign!(op)(r); 336 } 337 338 // numeric + complex, numeric * complex 339 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 340 if ((op == "+" || op == "*") && is(R : c_long_double)) 341 { 342 return opBinary!(op)(r); 343 } 344 345 // numeric - complex 346 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 347 if (op == "-" && is(R : c_long_double)) 348 { 349 return _Complex(r - re, -im); 350 } 351 352 // numeric / complex 353 _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r) 354 if (op == "/" && is(R : c_long_double)) 355 { 356 import core.math : fabs; 357 typeof(return) w = void; 358 if (fabs(re) < fabs(im)) 359 { 360 immutable ratio = re/im; 361 immutable rdivd = r/(re*ratio + im); 362 363 w.re = rdivd*ratio; 364 w.im = -rdivd; 365 } 366 else 367 { 368 immutable ratio = im/re; 369 immutable rdivd = r/(re + im*ratio); 370 371 w.re = rdivd; 372 w.im = -rdivd*ratio; 373 } 374 375 return w; 376 } 377 378 // OP-ASSIGN OPERATORS 379 380 // complex += complex, complex -= complex 381 ref _Complex opOpAssign(string op, C)(C z) 382 if ((op == "+" || op == "-") && is(C R == _Complex!R)) 383 { 384 mixin ("re "~op~"= z.re;"); 385 mixin ("im "~op~"= z.im;"); 386 return this; 387 } 388 389 // complex *= complex 390 ref _Complex opOpAssign(string op, C)(C z) 391 if (op == "*" && is(C R == _Complex!R)) 392 { 393 auto temp = re*z.re - im*z.im; 394 im = im*z.re + re*z.im; 395 re = temp; 396 return this; 397 } 398 399 // complex /= complex 400 ref _Complex opOpAssign(string op, C)(C z) 401 if (op == "/" && is(C R == _Complex!R)) 402 { 403 import core.math : fabs; 404 if (fabs(z.re) < fabs(z.im)) 405 { 406 immutable ratio = z.re/z.im; 407 immutable denom = z.re*ratio + z.im; 408 409 immutable temp = (re*ratio + im)/denom; 410 im = (im*ratio - re)/denom; 411 re = temp; 412 } 413 else 414 { 415 immutable ratio = z.im/z.re; 416 immutable denom = z.re + z.im*ratio; 417 418 immutable temp = (re + im*ratio)/denom; 419 im = (im - re*ratio)/denom; 420 re = temp; 421 } 422 return this; 423 } 424 425 // complex += numeric, complex -= numeric 426 ref _Complex opOpAssign(string op, U : T)(U a) 427 if (op == "+" || op == "-") 428 { 429 mixin ("re "~op~"= a;"); 430 return this; 431 } 432 433 // complex *= numeric, complex /= numeric 434 ref _Complex opOpAssign(string op, U : T)(U a) 435 if (op == "*" || op == "/") 436 { 437 mixin ("re "~op~"= a;"); 438 mixin ("im "~op~"= a;"); 439 return this; 440 } 441 442 // Helper properties. 443 pragma(inline, true) 444 { 445 static @property epsilon()() { return _Complex(T.epsilon, T.epsilon); } 446 static @property infinity()() { return _Complex(T.infinity, T.infinity); } 447 static @property max()() { return _Complex(T.max, T.max); } 448 static @property min_normal()() { return _Complex(T.min_normal, T.min_normal); } 449 static @property nan()() { return _Complex(T.nan, T.nan); } 450 static @property dig()() { return T.dig; } 451 static @property mant_dig()() { return T.mant_dig; } 452 static @property max_10_exp()() { return T.max_10_exp; } 453 static @property max_exp()() { return T.max_exp; } 454 static @property min_10_exp()() { return T.min_10_exp; } 455 static @property min_exp()() { return T.min_exp; } 456 } 457 } 458 459 enum __c_complex_float : _Complex!float; 460 enum __c_complex_double : _Complex!double; 461 enum __c_complex_real : _Complex!c_long_double; 462 463 alias c_complex_float = __c_complex_float; 464 alias c_complex_double = __c_complex_double; 465 alias c_complex_real = __c_complex_real; 466 467 private template CommonType(T, R) 468 { 469 // Special kludge for Microsoft c_long_double 470 static if (is(T == c_long_double)) 471 alias CommonType = T; 472 else static if (is(R == c_long_double)) 473 alias CommonType = R; 474 else 475 alias CommonType = typeof(true ? T.init : R.init); 476 } 477 478 /************ unittests ****************/ 479 480 version (unittest) 481 { 482 private: 483 484 alias _cfloat = _Complex!float; 485 alias _cdouble = _Complex!double; 486 alias _creal = _Complex!c_long_double; 487 488 T abs(T)(T t) => t < 0 ? -t : t; 489 } 490 491 @safe pure nothrow unittest 492 { 493 auto c1 = _cdouble(1.0, 1.0); 494 495 // Check unary operations. 496 auto c2 = _cdouble(0.5, 2.0); 497 498 assert(c2 == +c2); 499 500 assert((-c2).re == -(c2.re)); 501 assert((-c2).im == -(c2.im)); 502 assert(c2 == -(-c2)); 503 504 // Check complex-complex operations. 505 auto cpc = c1 + c2; 506 assert(cpc.re == c1.re + c2.re); 507 assert(cpc.im == c1.im + c2.im); 508 509 auto cmc = c1 - c2; 510 assert(cmc.re == c1.re - c2.re); 511 assert(cmc.im == c1.im - c2.im); 512 513 auto ctc = c1 * c2; 514 assert(ctc == _cdouble(-1.5, 2.5)); 515 516 auto cdc = c1 / c2; 517 assert(abs(cdc.re - 0.5882352941177) < 1e-12); 518 assert(abs(cdc.im - -0.3529411764706) < 1e-12); 519 520 // Check complex-real operations. 521 double a = 123.456; 522 523 auto cpr = c1 + a; 524 assert(cpr.re == c1.re + a); 525 assert(cpr.im == c1.im); 526 527 auto cmr = c1 - a; 528 assert(cmr.re == c1.re - a); 529 assert(cmr.im == c1.im); 530 531 auto ctr = c1 * a; 532 assert(ctr.re == c1.re*a); 533 assert(ctr.im == c1.im*a); 534 535 auto cdr = c1 / a; 536 assert(abs(cdr.re - 0.00810005184033) < 1e-12); 537 assert(abs(cdr.im - 0.00810005184033) < 1e-12); 538 539 auto rpc = a + c1; 540 assert(rpc == cpr); 541 542 auto rmc = a - c1; 543 assert(rmc.re == a-c1.re); 544 assert(rmc.im == -c1.im); 545 546 auto rtc = a * c1; 547 assert(rtc == ctr); 548 549 auto rdc = a / c1; 550 assert(abs(rdc.re - 61.728) < 1e-12); 551 assert(abs(rdc.im - -61.728) < 1e-12); 552 553 rdc = a / c2; 554 assert(abs(rdc.re - 14.5242352941) < 1e-10); 555 assert(abs(rdc.im - -58.0969411765) < 1e-10); 556 557 // Check operations between different complex types. 558 auto cf = _cfloat(1.0, 1.0); 559 auto cr = _creal(1.0, 1.0); 560 auto c1pcf = c1 + cf; 561 auto c1pcr = c1 + cr; 562 static assert(is(typeof(c1pcf) == _cdouble)); 563 static assert(is(typeof(c1pcr) == _creal)); 564 assert(c1pcf.re == c1pcr.re); 565 assert(c1pcf.im == c1pcr.im); 566 567 auto c1c = c1; 568 auto c2c = c2; 569 570 c1c /= c1; 571 assert(abs(c1c.re - 1.0) < 1e-10); 572 assert(abs(c1c.im - 0.0) < 1e-10); 573 574 c1c = c1; 575 c1c /= c2; 576 assert(abs(c1c.re - 0.5882352941177) < 1e-12); 577 assert(abs(c1c.im - -0.3529411764706) < 1e-12); 578 579 c2c /= c1; 580 assert(abs(c2c.re - 1.25) < 1e-11); 581 assert(abs(c2c.im - 0.75) < 1e-12); 582 583 c2c = c2; 584 c2c /= c2; 585 assert(abs(c2c.re - 1.0) < 1e-11); 586 assert(abs(c2c.im - 0.0) < 1e-12); 587 } 588 589 @safe pure nothrow unittest 590 { 591 // Initialization 592 _cdouble a = _cdouble(1, 0); 593 assert(a.re == 1 && a.im == 0); 594 _cdouble b = _cdouble(1.0, 0); 595 assert(b.re == 1.0 && b.im == 0); 596 // _cdouble c = _creal(1.0, 2); 597 // assert(c.re == 1.0 && c.im == 2); 598 } 599 600 @safe pure nothrow unittest 601 { 602 // Assignments and comparisons 603 _cdouble z; 604 605 z = 1; 606 assert(z == 1); 607 assert(z.re == 1.0 && z.im == 0.0); 608 609 z = 2.0; 610 assert(z == 2.0); 611 assert(z.re == 2.0 && z.im == 0.0); 612 613 z = 1.0L; 614 assert(z == 1.0L); 615 assert(z.re == 1.0 && z.im == 0.0); 616 617 auto w = _creal(1.0, 1.0); 618 z = w; 619 assert(z == w); 620 assert(z.re == 1.0 && z.im == 1.0); 621 622 auto c = _cfloat(2.0, 2.0); 623 z = c; 624 assert(z == c); 625 assert(z.re == 2.0 && z.im == 2.0); 626 } 627 628 } 629 630 631 // Returns the mangled name for the 64-bit time_t versions of 632 // functions affected by musl's transition to 64-bit time_t. 633 // https://musl.libc.org/time64.html 634 version (CRuntime_Musl) 635 { 636 version (CRuntime_Musl_Pre_Time64) 637 enum muslRedirTime64 = false; 638 else 639 { 640 // time_t was defined as a C long in older Musl versions. 641 enum muslRedirTime64 = (c_long.sizeof == 4); 642 } 643 } 644 else 645 enum muslRedirTime64 = false; 646 647 package(core) template muslRedirTime64Mangle(string name, string redirectedName) 648 { 649 static if (muslRedirTime64) 650 enum muslRedirTime64Mangle = redirectedName; 651 else 652 enum muslRedirTime64Mangle = name; 653 }