mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-10 04:45:56 +03:00
391 lines
10 KiB
D
391 lines
10 KiB
D
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2015 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// http://www.boost.org/LICENSE_1_0.txt
|
|
|
|
module ddmd.root.port;
|
|
|
|
import core.stdc.ctype;
|
|
import core.stdc.string;
|
|
import core.stdc.stdio;
|
|
import core.stdc.errno;
|
|
import core.math;
|
|
|
|
version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint;
|
|
version(CRuntime_Microsoft) extern(C++) struct longdouble { real r; }
|
|
version(CRuntime_Microsoft) extern(C++) size_t ld_sprint(char* str, int fmt, longdouble x);
|
|
|
|
extern (C) float strtof(const(char)* p, char** endp);
|
|
extern (C) double strtod(const(char)* p, char** endp);
|
|
|
|
version(IN_LLVM_MSVC)
|
|
extern (C) double strtold(const(char)* p, char** endp);
|
|
else
|
|
version(CRuntime_Microsoft)
|
|
extern (C++) longdouble strtold_dm(const(char)* p, char** endp);
|
|
else
|
|
extern (C) real strtold(const(char)* p, char** endp);
|
|
|
|
version(CRuntime_Microsoft)
|
|
{
|
|
enum _OVERFLOW = 3; /* overflow range error */
|
|
enum _UNDERFLOW = 4; /* underflow range error */
|
|
|
|
extern (C) int _atoflt(float* value, const char * str);
|
|
extern (C) int _atodbl(double* value, const char * str);
|
|
}
|
|
|
|
extern (C++) struct Port
|
|
{
|
|
enum nan = double.nan;
|
|
enum infinity = double.infinity;
|
|
version(IN_LLVM_MSVC)
|
|
private alias ldbl = double;
|
|
else
|
|
private alias ldbl = real;
|
|
|
|
version(IN_LLVM)
|
|
{
|
|
enum ldbl_min_normal = ldbl.min_normal;
|
|
enum ldbl_max = ldbl.max;
|
|
enum ldbl_nan = ldbl.nan;
|
|
enum ldbl_infinity = ldbl.infinity;
|
|
enum ldbl_dig = ldbl.dig;
|
|
enum ldbl_epsilon = ldbl.epsilon;
|
|
enum ldbl_mant_dig = ldbl.mant_dig;
|
|
enum ldbl_max_10_exp = ldbl.max_10_exp;
|
|
enum ldbl_max_exp = ldbl.max_exp;
|
|
enum ldbl_min_10_exp = ldbl.min_10_exp;
|
|
enum ldbl_min_exp = ldbl.min_exp;
|
|
}
|
|
else
|
|
{
|
|
enum ldbl_max = real.max;
|
|
enum ldbl_nan = real.nan;
|
|
enum ldbl_infinity = real.infinity;
|
|
}
|
|
version(IN_LLVM)
|
|
{
|
|
static __gshared bool yl2x_supported = false;
|
|
static __gshared bool yl2xp1_supported = false;
|
|
}
|
|
else
|
|
version(DigitalMars)
|
|
{
|
|
static __gshared bool yl2x_supported = true;
|
|
static __gshared bool yl2xp1_supported = true;
|
|
}
|
|
else
|
|
{
|
|
static __gshared bool yl2x_supported = false;
|
|
static __gshared bool yl2xp1_supported = false;
|
|
}
|
|
static __gshared real snan;
|
|
|
|
static bool isNan(double r)
|
|
{
|
|
return !(r == r);
|
|
}
|
|
|
|
static real sqrt(real x)
|
|
{
|
|
return .sqrt(x);
|
|
}
|
|
|
|
static real fmodl(real a, real b)
|
|
{
|
|
return a % b;
|
|
}
|
|
|
|
static bool fequal(real a, real b)
|
|
{
|
|
// don't compare pad bytes in extended precision
|
|
enum sz = (real.mant_dig == 64) ? 10 : real.sizeof;
|
|
return memcmp(&a, &b, sz) == 0;
|
|
}
|
|
|
|
static int memicmp(const char* s1, const char* s2, size_t n)
|
|
{
|
|
int result = 0;
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
char c1 = s1[i];
|
|
char c2 = s2[i];
|
|
|
|
result = c1 - c2;
|
|
if (result)
|
|
{
|
|
result = toupper(c1) - toupper(c2);
|
|
if (result)
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static char* strupr(char* s)
|
|
{
|
|
char* t = s;
|
|
|
|
while (*s)
|
|
{
|
|
*s = cast(char)toupper(*s);
|
|
s++;
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
static int isSignallingNan(double r)
|
|
{
|
|
return isNan(r) && !(((cast(ubyte*)&r)[6]) & 8);
|
|
}
|
|
|
|
static int isSignallingNan(real r)
|
|
{
|
|
return isNan(r) && !(((cast(ubyte*)&r)[7]) & 0x40);
|
|
}
|
|
|
|
version(CRuntime_Microsoft)
|
|
{
|
|
static int isSignallingNan(longdouble ld)
|
|
{
|
|
return isSignallingNan(*cast(real*)&ld);
|
|
}
|
|
}
|
|
|
|
static int isInfinity(double r)
|
|
{
|
|
return r is double.infinity || r is -double.infinity;
|
|
}
|
|
|
|
static float strtof(const(char)* p, char** endp)
|
|
{
|
|
version (CRuntime_DigitalMars)
|
|
{
|
|
auto save = __locale_decpoint;
|
|
__locale_decpoint = ".";
|
|
}
|
|
version (CRuntime_Microsoft)
|
|
{
|
|
float r;
|
|
if(endp)
|
|
{
|
|
r = .strtod(p, endp); // does not set errno for underflows, but unused
|
|
}
|
|
else
|
|
{
|
|
int res = _atoflt(&r, p);
|
|
if (res == _UNDERFLOW || res == _OVERFLOW)
|
|
errno = ERANGE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto r = .strtof(p, endp);
|
|
}
|
|
version (CRuntime_DigitalMars) __locale_decpoint = save;
|
|
return r;
|
|
}
|
|
|
|
static double strtod(const(char)* p, char** endp)
|
|
{
|
|
version (CRuntime_DigitalMars)
|
|
{
|
|
auto save = __locale_decpoint;
|
|
__locale_decpoint = ".";
|
|
}
|
|
version (CRuntime_Microsoft)
|
|
{
|
|
double r;
|
|
if(endp)
|
|
{
|
|
r = .strtod(p, endp); // does not set errno for underflows, but unused
|
|
}
|
|
else
|
|
{
|
|
int res = _atodbl(&r, p);
|
|
if (res == _UNDERFLOW || res == _OVERFLOW)
|
|
errno = ERANGE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto r = .strtod(p, endp);
|
|
}
|
|
version (CRuntime_DigitalMars) __locale_decpoint = save;
|
|
return r;
|
|
}
|
|
|
|
static real strtold(const(char)* p, char** endp)
|
|
{
|
|
version (CRuntime_DigitalMars)
|
|
{
|
|
auto save = __locale_decpoint;
|
|
__locale_decpoint = ".";
|
|
}
|
|
|
|
version(IN_LLVM_MSVC)
|
|
auto r = .strtold(p, endp); // C99 conformant since VS 2015
|
|
else
|
|
version (CRuntime_Microsoft)
|
|
auto r = .strtold_dm(p, endp).r;
|
|
else
|
|
auto r = .strtold(p, endp);
|
|
version (CRuntime_DigitalMars) __locale_decpoint = save;
|
|
return r;
|
|
}
|
|
|
|
static size_t ld_sprint(char* str, int fmt, real x)
|
|
{
|
|
version(IN_LLVM_MSVC)
|
|
{
|
|
if ((cast(real)cast(ulong)x) == x)
|
|
{
|
|
// ((1.5 -> 1 -> 1.0) == 1.5) is false
|
|
// ((1.0 -> 1 -> 1.0) == 1.0) is true
|
|
// see http://en.cppreference.com/w/cpp/io/c/fprintf
|
|
char[4] sfmt = "%#g\0";
|
|
sfmt[2] = cast(char)fmt;
|
|
return sprintf(str, sfmt.ptr, double(x));
|
|
}
|
|
else
|
|
{
|
|
char[3] sfmt = "%g\0";
|
|
sfmt[1] = cast(char)fmt;
|
|
return sprintf(str, sfmt.ptr, double(x));
|
|
}
|
|
}
|
|
else
|
|
version(CRuntime_Microsoft)
|
|
{
|
|
return .ld_sprint(str, fmt, longdouble(x));
|
|
}
|
|
else
|
|
{
|
|
if ((cast(real)cast(ulong)x) == x)
|
|
{
|
|
// ((1.5 -> 1 -> 1.0) == 1.5) is false
|
|
// ((1.0 -> 1 -> 1.0) == 1.0) is true
|
|
// see http://en.cppreference.com/w/cpp/io/c/fprintf
|
|
char[5] sfmt = "%#Lg\0";
|
|
sfmt[3] = cast(char)fmt;
|
|
return sprintf(str, sfmt.ptr, x);
|
|
}
|
|
else
|
|
{
|
|
char[4] sfmt = "%Lg\0";
|
|
sfmt[2] = cast(char)fmt;
|
|
return sprintf(str, sfmt.ptr, x);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void yl2x_impl(real* x, real* y, real* res)
|
|
{
|
|
version(DigitalMars)
|
|
*res = yl2x(*x, *y);
|
|
version(IN_LLVM)
|
|
assert(0);
|
|
}
|
|
|
|
static void yl2xp1_impl(real* x, real* y, real* res)
|
|
{
|
|
version(DigitalMars)
|
|
*res = yl2xp1(*x, *y);
|
|
version(IN_LLVM)
|
|
assert(0);
|
|
}
|
|
|
|
// Little endian
|
|
static void writelongLE(uint value, void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
p[3] = cast(ubyte)(value >> 24);
|
|
p[2] = cast(ubyte)(value >> 16);
|
|
p[1] = cast(ubyte)(value >> 8);
|
|
p[0] = cast(ubyte)(value);
|
|
}
|
|
|
|
// Little endian
|
|
static uint readlongLE(void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
|
|
}
|
|
|
|
// Big endian
|
|
static void writelongBE(uint value, void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
p[0] = cast(ubyte)(value >> 24);
|
|
p[1] = cast(ubyte)(value >> 16);
|
|
p[2] = cast(ubyte)(value >> 8);
|
|
p[3] = cast(ubyte)(value);
|
|
}
|
|
|
|
// Big endian
|
|
static uint readlongBE(void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3];
|
|
}
|
|
|
|
// Little endian
|
|
static uint readwordLE(void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
return (p[1] << 8) | p[0];
|
|
}
|
|
|
|
// Big endian
|
|
static uint readwordBE(void* buffer)
|
|
{
|
|
auto p = cast(ubyte*)buffer;
|
|
return (p[0] << 8) | p[1];
|
|
}
|
|
|
|
version(IN_LLVM)
|
|
{
|
|
// LDC_FIXME: Move this into our C++ code, since only driver/gen is
|
|
// still using this.
|
|
static int stricmp(const(char)* s1, const(char)* s2)
|
|
{
|
|
int result = 0;
|
|
for (;;)
|
|
{
|
|
char c1 = *s1;
|
|
char c2 = *s2;
|
|
|
|
result = c1 - c2;
|
|
if (result)
|
|
{
|
|
result = toupper(c1) - toupper(c2);
|
|
if (result)
|
|
break;
|
|
}
|
|
if (!c1)
|
|
break;
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
static void valcpy(void *dst, ulong val, size_t size)
|
|
{
|
|
switch (size)
|
|
{
|
|
case 1: *cast(ubyte *)dst = cast(ubyte)val; break;
|
|
case 2: *cast(ushort *)dst = cast(ushort)val; break;
|
|
case 4: *cast(uint *)dst = cast(uint)val; break;
|
|
case 8: *cast(ulong *)dst = cast(ulong)val; break;
|
|
default: assert(0);
|
|
}
|
|
}
|
|
}
|