The OpenD Programming Language

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 }