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 }