mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* SwiftDtoa v2: Better, Smaller, Faster floating-point formatting SwiftDtoa is the C/C++ code used in the Swift runtime to produce the textual representations used by the `description` and `debugDescription` properties of the standard Swift floating-point types. This update includes a number of algorithmic improvements to SwiftDtoa to improve portability, reduce code size, and improve performance but does not change the actual output. About SwiftDtoa =============== In early versions of Swift, the `description` properties used the C library `sprintf` functionality with a fixed number of digits. In 2018, that logic was replaced with the first version of SwiftDtoa which used used a fast, adaptive algorithm to automatically choose the correct number of digits for a particular value. The resulting decimal output is always: * Accurate. Parsing the decimal form will yield exactly the same binary floating-point value again. This guarantee holds for any parser that accurately implements IEEE 754. In particular, the Swift standard library can guarantee that for any Double `d` that is not a NaN, `Double(d.description) == d`. * Short. Among all accurate forms, this form has the fewest significant digits. (Caution: Surprisingly, this is not the same as minimizing the number of characters. In some cases, minimizing the number of characters requires producing additional significant digits.) * Close. If there are multiple accurate, short forms, this code chooses the decimal form that is closest to the exact binary value. If there are two exactly the same distance, the one with an even final digit will be used. Algorithms that can produce this "optimal" output have been known since at least 1990, when Steele and White published their Dragon4 algorithm. However, Dragon4 and other algorithms from that period relied on high-precision integer arithmetic, which made them slow. More recently, a surge of interest in this problem has produced dramatically better algorithms that can produce the same results using only fast fixed-precision arithmetic. This format is ideal for JSON and other textual interchange: accuracy ensures that the value will be correctly decoded, shortness minimizes network traffic, and the existence of high-performance algorithms allows this form to be generated more quickly than many `printf`-based implementations. This format is also ideal for logging, debugging, and other general display. In particular, the shortness guarantee avoids the confusion of unnecessary additional digits, so that the result of `1.0 / 10.0` consistently displays as `0.1` instead of `0.100000000000000000001`. About SwiftDtoa v2 ================== Compared to the original SwiftDtoa code, this update is: **Better**: The core logic is implemented using only C99 features with 64-bit and smaller integer arithmetic. If available, 128-bit integers are used for better performance. The core routines do not require any floating-point support from the C/C++ standard library and with only minor modifications should be usable on systems with no hardware or software floating-point support at all. This version also has experimental support for IEEE 754 binary128 format, though this support is obviously not included when compiling for the Swift standard library. **Smaller**: Code size reduction compared to the earlier versions was a primary goal for this effort. In particular, the new binary128 support shares essentially all of its code with the float80 implementation. **Faster**: Even with the code size reductions, all formats are noticeably faster. The primary performance gains come from three major changes: Text digits are now emitted directly in the core routines in a form that requires only minimal adjustment to produce the final text. Digit generation produces 2, 4, or even 8 digits at a time, depending on the format. The double logic optimistically produces 7 digits in the initial scaling with a Ryu-inspired backtracking when fewer digits suffice. SwiftDtoa's algorithms ====================== SwiftDtoa started out as a variation of Florian Loitsch' Grisu2 that addressed the shortness failures of that algorithm. Subsequent work has incorporated ideas from Errol3, Ryu, and other sources to yield a production-quality implementation that is performance- and size-competitive with current research code. Those who wish to understand the details can read the extensive comments included in the code. Note that float16 actually uses a different algorithm than the other formats, as the extremely limited range can be handled with much simpler techniques. The float80/binary128 logic sacrifices some performance optimizations in order to minimize the code size for these less-used formats; the goal for SwiftDtoa v2 has been to match the float80 performance of earlier implementations while reducing code size and widening the arithmetic routines sufficiently to support binary128. SwiftDtoa Testing ================= A newly-developed test harness generates several large files of test data that include known-correct results computed with high-precision arithmetic routines. The test files include: * Critical values generated by the algorithm presented in the Errol paper (about 48 million cases for binary128) * Values for which the optimal decimal form is exactly midway between two binary floating-point values. * All exact powers of two representable in this format. * Floating-point values that are close to exact powers of ten. In addition, several billion random values for each format were compared to the results from other implementations. For binary16 and binary32 this provided exhaustive validation of every possible input value. Code Size and Performance ========================= The tables below summarize the code size and performance for the SwiftDtoa C library module by itself on several different processor architectures. When used from Swift, the `.description` and `.debugDescription` implementations incur additional overhead for creating and returning Swift strings that are not captured here. The code size tables show the total size in bytes of the compiled `.o` object files for a particular version of that code. The headings indicate the floating-point formats supported by that particular build (e.g., "16,32" for a version that supports binary16 and binary32 but no other formats). The performance numbers below were obtained from a custom test harness that generates random bit patterns, interprets them as the corresponding floating-point value, and averages the overall time. For float80, the random bit patterns were generated in a way that avoids generating invalid values. All code was compiled with the system C/C++ compiler using `-O2` optimization. A few notes about particular implementations: * **SwiftDtoa v1** is the original SwiftDtoa implementation as committed to the Swift runtime in April 2018. * **SwiftDtoa v1a** is the same as SwiftDtoa v1 with added binary16 support. * **SwiftDtoa v2** can be configured with preprocessor macros to support any subset of the supported formats. I've provided sizes here for several different build configurations. * **Ryu** (Ulf Anders) implements binary32 and binary64 as completely independent source files. The size here is the total size of the two .o object files. * **Ryu(size)** is Ryu compiled with the `RYU_OPTIMIZE_SIZE` option. * **Dragonbox** (Junekey Jeon). The size here is the compiled size of a simple `.cpp` file that instantiates the template for the specified formats, plus the size of the associated text output logic. * **Dragonbox(size)** is Dragonbox compiled to minimize size by using a compressed power-of-10 table. * **gdtoa** has a very large feature set. For this reason, I excluded it from the code size comparison since I didn't consider the numbers to be comparable to the others. x86_64 ---------------- These were built using Apple clang 12.0.5 on a 2019 16" MacBook Pro (2.4GHz 8-core Intel Core i9) running macOS 11.1. **Code Size** Bold numbers here indicate the configurations that have shipped as part of the Swift runtime. | | 16,32,64,80 | 32,64,80 | 32,64 | |---------------|------------:|------------:|------------:| |SwiftDtoa v1 | | **15128** | | |SwiftDtoa v1a | **16888** | | | |SwiftDtoa v2 | **20220** | 18628 | 8248 | |Ryu | | | 40408 | |Ryu(size) | | | 23836 | |Dragonbox | | | 23176 | |Dragonbox(size)| | | 15132 | **Performance** | | binary16 | binary32 | binary64 | float80 | binary128 | |--------------|---------:|---------:|---------:|--------:|----------:| |SwiftDtoa v1 | | 25ns | 46ns | 82ns | | |SwiftDtoa v1a | 37ns | 26ns | 47ns | 83ns | | |SwiftDtoa v2 | 22ns | 19ns | 31ns | 72ns | 90ns | |Ryu | | 19ns | 26ns | | | |Ryu(size) | | 17ns | 24ns | | | |Dragonbox | | 19ns | 24ns | | | |Dragonbox(size) | | 19ns | 29ns | | | |gdtoa | 220ns | 381ns | 1184ns | 16044ns | 22800ns | ARM64 ---------------- These were built using Apple clang 12.0.0 on a 2020 M1 Mac Mini running macOS 11.1. **Code Size** | | 16,32,64 | 32,64 | |---------------|---------:|------:| |SwiftDtoa v1 | | 7436 | |SwiftDtoa v1a | 9124 | | |SwiftDtoa v2 | 9964 | 8228 | |Ryu | | 35764 | |Ryu(size) | | 16708 | |Dragonbox | | 27108 | |Dragonbox(size)| | 19172 | **Performance** | | binary16 | binary32 | binary64 | float80 | binary128 | |--------------|---------:|---------:|---------:|--------:|----------:| |SwiftDtoa v1 | | 21ns | 39ns | | | |SwiftDtoa v1a | 17ns | 21ns | 39ns | | | |SwiftDtoa v2 | 15ns | 17ns | 29ns | 54ns | 71ns | |Ryu | | 15ns | 19ns | | | |Ryu(size) | | 29ns | 24ns | | | |Dragonbox | | 16ns | 24ns | | | |Dragonbox(size) | | 15ns | 34ns | | | |gdtoa | 143ns | 242ns | 858ns | 25129ns | 36195ns | ARM32 ---------------- These were built using clang 8.0.1 on a BeagleBone Black (500MHz ARMv7) running FreeBSD 12.1-RELEASE. **Code Size** | | 16,32,64 | 32,64 | |---------------|---------:|------:| |SwiftDtoa v1 | | 8668 | |SwiftDtoa v1a | 10356 | | |SwiftDtoa v2 | 9796 | 8340 | |Ryu | | 32292 | |Ryu(size) | | 14592 | |Dragonbox | | 29000 | |Dragonbox(size)| | 21980 | **Performance** | | binary16 | binary32 | binary64 | float80 | binary128 | |--------------|---------:|---------:|---------:|--------:|----------:| |SwiftDtoa v1 | | 459ns | 1152ns | | | |SwiftDtoa v1a | 383ns | 451ns | 1148ns | | | |SwiftDtoa v2 | 202ns | 357ns | 715ns | 2720ns | 3379ns | |Ryu | | 345ns | 5450ns | | | |Ryu(size) | | 786ns | 5577ns | | | |Dragonbox | | 300ns | 904ns | | | |Dragonbox(size) | | 294ns | 1021ns | | | |gdtoa | 2180ns | 4749ns | 18742ns |293000ns | 440000ns | * This is fast enough now even for non-optimized test runs * Fix float80 Nan/Inf parsing, comment more thoroughly
451 lines
13 KiB
C++
451 lines
13 KiB
C++
//===--- Stubs.cpp - Swift Language ABI Runtime Stubs ---------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Misc stubs for functions which should be defined in the core standard
|
|
// library, but are difficult or impossible to write in Swift at the
|
|
// moment.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#if defined(__FreeBSD__)
|
|
#define _WITH_GETLINE
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
// Avoid defining macro max(), min() which conflict with std::max(), std::min()
|
|
#define NOMINMAX
|
|
#include <windows.h>
|
|
#else
|
|
#if !defined(__HAIKU__) && !defined(__wasi__)
|
|
#include <sys/errno.h>
|
|
#else
|
|
#include <errno.h>
|
|
#endif
|
|
#include <sys/resource.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <climits>
|
|
#include <clocale>
|
|
#include <cmath>
|
|
#include <cstdarg>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#if defined(__OpenBSD__) || defined(__ANDROID__) || defined(__linux__) || defined(__wasi__) || defined(_WIN32)
|
|
#include <locale.h>
|
|
#if defined(_WIN32)
|
|
#define locale_t _locale_t
|
|
#endif
|
|
#else
|
|
#include <xlocale.h>
|
|
#endif
|
|
#include <limits>
|
|
#include <thread>
|
|
|
|
#if defined(__ANDROID__)
|
|
#include <android/api-level.h>
|
|
#endif
|
|
|
|
#include "swift/Runtime/Debug.h"
|
|
#include "swift/Runtime/SwiftDtoa.h"
|
|
#include "swift/Basic/Lazy.h"
|
|
|
|
#include "../SwiftShims/LibcShims.h"
|
|
#include "../SwiftShims/RuntimeShims.h"
|
|
#include "../SwiftShims/RuntimeStubs.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
static uint64_t uint64ToStringImpl(char *Buffer, uint64_t Value,
|
|
int64_t Radix, bool Uppercase,
|
|
bool Negative) {
|
|
char *P = Buffer;
|
|
uint64_t Y = Value;
|
|
|
|
if (Y == 0) {
|
|
*P++ = '0';
|
|
} else if (Radix == 10) {
|
|
while (Y) {
|
|
*P++ = '0' + char(Y % 10);
|
|
Y /= 10;
|
|
}
|
|
} else {
|
|
unsigned Radix32 = Radix;
|
|
while (Y) {
|
|
*P++ = llvm::hexdigit(Y % Radix32, !Uppercase);
|
|
Y /= Radix32;
|
|
}
|
|
}
|
|
|
|
if (Negative)
|
|
*P++ = '-';
|
|
std::reverse(Buffer, P);
|
|
return size_t(P - Buffer);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
uint64_t swift_int64ToString(char *Buffer, size_t BufferLength,
|
|
int64_t Value, int64_t Radix,
|
|
bool Uppercase) {
|
|
if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 65))
|
|
swift::crash("swift_int64ToString: insufficient buffer size");
|
|
|
|
if (Radix == 0 || Radix > 36)
|
|
swift::crash("swift_int64ToString: invalid radix for string conversion");
|
|
|
|
bool Negative = Value < 0;
|
|
|
|
// Compute an absolute value safely, without using unary negation on INT_MIN,
|
|
// which is undefined behavior.
|
|
uint64_t UnsignedValue = Value;
|
|
if (Negative) {
|
|
// Assumes two's complement representation.
|
|
UnsignedValue = ~UnsignedValue + 1;
|
|
}
|
|
|
|
return uint64ToStringImpl(Buffer, UnsignedValue, Radix, Uppercase,
|
|
Negative);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
uint64_t swift_uint64ToString(char *Buffer, intptr_t BufferLength,
|
|
uint64_t Value, int64_t Radix,
|
|
bool Uppercase) {
|
|
if ((Radix >= 10 && BufferLength < 32) || (Radix < 10 && BufferLength < 64))
|
|
swift::crash("swift_int64ToString: insufficient buffer size");
|
|
|
|
if (Radix == 0 || Radix > 36)
|
|
swift::crash("swift_int64ToString: invalid radix for string conversion");
|
|
|
|
return uint64ToStringImpl(Buffer, Value, Radix, Uppercase,
|
|
/*Negative=*/false);
|
|
}
|
|
|
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__)
|
|
static inline locale_t getCLocale() {
|
|
// On these platforms convenience functions from xlocale.h interpret nullptr
|
|
// as C locale.
|
|
return nullptr;
|
|
}
|
|
#elif defined(__CYGWIN__) || defined(__HAIKU__)
|
|
// In Cygwin, getCLocale() is not used.
|
|
#elif defined(_WIN32)
|
|
static _locale_t makeCLocale() {
|
|
_locale_t CLocale = _create_locale(LC_ALL, "C");
|
|
if (!CLocale) {
|
|
swift::crash("makeCLocale: _create_locale() returned a null pointer");
|
|
}
|
|
return CLocale;
|
|
}
|
|
|
|
static _locale_t getCLocale() {
|
|
return SWIFT_LAZY_CONSTANT(makeCLocale());
|
|
}
|
|
#else
|
|
static locale_t makeCLocale() {
|
|
locale_t CLocale = newlocale(LC_ALL_MASK, "C", nullptr);
|
|
if (!CLocale) {
|
|
swift::crash("makeCLocale: newlocale() returned a null pointer");
|
|
}
|
|
return CLocale;
|
|
}
|
|
|
|
static locale_t getCLocale() {
|
|
return SWIFT_LAZY_CONSTANT(makeCLocale());
|
|
}
|
|
#endif
|
|
|
|
// TODO: replace this with a float16 implementation instead of calling _float.
|
|
// Argument type will have to stay float, though; only the formatting changes.
|
|
// Note, return type is __swift_ssize_t, not uint64_t as with the other
|
|
// formatters. We'd use this type there if we could, but it's ABI so we can't
|
|
// go back and change it.
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
__swift_ssize_t swift_float16ToString(char *Buffer, size_t BufferLength,
|
|
float Value, bool Debug) {
|
|
__fp16 v = Value;
|
|
return swift_dtoa_optimal_binary16_p(&v, Buffer, BufferLength);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
uint64_t swift_float32ToString(char *Buffer, size_t BufferLength,
|
|
float Value, bool Debug) {
|
|
return swift_dtoa_optimal_float(Value, Buffer, BufferLength);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
uint64_t swift_float64ToString(char *Buffer, size_t BufferLength,
|
|
double Value, bool Debug) {
|
|
return swift_dtoa_optimal_double(Value, Buffer, BufferLength);
|
|
}
|
|
|
|
// We only support float80 on platforms that use that exact format for 'long double'
|
|
// This should match the conditionals in Runtime.swift
|
|
#if !defined(_WIN32) && !defined(__ANDROID__) && (defined(__i386__) || defined(__i686__) || defined(__x86_64__))
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
|
|
uint64_t swift_float80ToString(char *Buffer, size_t BufferLength,
|
|
long double Value, bool Debug) {
|
|
// SwiftDtoa.cpp automatically enables float80 on platforms that use it for 'long double'
|
|
return swift_dtoa_optimal_float80_p(&Value, Buffer, BufferLength);
|
|
}
|
|
#endif
|
|
|
|
/// \param[out] LinePtr Replaced with the pointer to the malloc()-allocated
|
|
/// line. Can be NULL if no characters were read. This buffer should be
|
|
/// freed by the caller.
|
|
///
|
|
/// \returns Size of character data returned in \c LinePtr, or -1
|
|
/// if an error occurred, or EOF was reached.
|
|
__swift_ssize_t
|
|
swift_stdlib_readLine_stdin(unsigned char **LinePtr) {
|
|
#if defined(_WIN32)
|
|
if (LinePtr == nullptr)
|
|
return -1;
|
|
|
|
__swift_ssize_t Capacity = 0;
|
|
__swift_ssize_t Pos = 0;
|
|
unsigned char *ReadBuf = nullptr;
|
|
|
|
_lock_file(stdin);
|
|
|
|
for (;;) {
|
|
int ch = _fgetc_nolock(stdin);
|
|
|
|
if (ferror(stdin) || (ch == EOF && Pos == 0)) {
|
|
if (ReadBuf)
|
|
free(ReadBuf);
|
|
_unlock_file(stdin);
|
|
return -1;
|
|
}
|
|
|
|
if (Capacity - Pos <= 1) {
|
|
// Capacity changes to 128, 128*2, 128*4, 128*8, ...
|
|
Capacity = Capacity ? Capacity * 2 : 128;
|
|
unsigned char *NextReadBuf =
|
|
static_cast<unsigned char *>(realloc(ReadBuf, Capacity));
|
|
if (NextReadBuf == nullptr) {
|
|
if (ReadBuf)
|
|
free(ReadBuf);
|
|
_unlock_file(stdin);
|
|
return -1;
|
|
}
|
|
ReadBuf = NextReadBuf;
|
|
}
|
|
|
|
if (ch == EOF)
|
|
break;
|
|
ReadBuf[Pos++] = ch;
|
|
if (ch == '\n')
|
|
break;
|
|
}
|
|
|
|
ReadBuf[Pos] = '\0';
|
|
*LinePtr = ReadBuf;
|
|
_unlock_file(stdin);
|
|
return Pos;
|
|
#else
|
|
size_t Capacity = 0;
|
|
int result;
|
|
do {
|
|
result = getline((char **)LinePtr, &Capacity, stdin);
|
|
} while (result < 0 && errno == EINTR);
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
#if defined(__CYGWIN__) || defined(_WIN32)
|
|
#define strcasecmp _stricmp
|
|
#endif
|
|
|
|
static bool swift_stringIsSignalingNaN(const char *nptr) {
|
|
if (nptr[0] == '+' || nptr[0] == '-') {
|
|
++nptr;
|
|
}
|
|
|
|
return strcasecmp(nptr, "snan") == 0;
|
|
}
|
|
|
|
// This implementation should only be used on platforms without the
|
|
// relevant strto* functions, such as Cygwin or Haiku.
|
|
// Note that using this currently causes test failures.
|
|
template <typename T>
|
|
T _swift_strto(const char *nptr, char **endptr) {
|
|
std::istringstream ValueStream(nptr);
|
|
ValueStream.imbue(std::locale::classic());
|
|
T ParsedValue;
|
|
ValueStream >> ParsedValue;
|
|
|
|
std::streamoff pos = ValueStream.tellg();
|
|
if (ValueStream.eof())
|
|
pos = static_cast<std::streamoff>(strlen(nptr));
|
|
if (pos <= 0) {
|
|
errno = ERANGE;
|
|
return 0.0;
|
|
}
|
|
|
|
return ParsedValue;
|
|
}
|
|
|
|
#if defined(__OpenBSD__) || defined(_WIN32) || defined(__CYGWIN__) || defined(__HAIKU__)
|
|
#define NEED_SWIFT_STRTOD_L
|
|
#define strtod_l swift_strtod_l
|
|
#define NEED_SWIFT_STRTOF_L
|
|
#define strtof_l swift_strtof_l
|
|
#define NEED_SWIFT_STRTOLD_L
|
|
#define strtold_l swift_strtold_l
|
|
#elif defined(__ANDROID__)
|
|
#if __ANDROID_API__ < 21 // Introduced in Android API 21 - L
|
|
#define NEED_SWIFT_STRTOLD_L
|
|
#define strtold_l swift_strtold_l
|
|
#endif
|
|
|
|
#if __ANDROID_API__ < 26 // Introduced in Android API 26 - O
|
|
#define NEED_SWIFT_STRTOD_L
|
|
#define strtod_l swift_strtod_l
|
|
#define NEED_SWIFT_STRTOF_L
|
|
#define strtof_l swift_strtof_l
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(NEED_SWIFT_STRTOD_L)
|
|
static double swift_strtod_l(const char *nptr, char **endptr, locale_t loc) {
|
|
#if defined(_WIN32)
|
|
return _strtod_l(nptr, endptr, getCLocale());
|
|
#elif defined(__CYGWIN__) || defined(__HAIKU__)
|
|
return _swift_strto<double>(nptr, endptr);
|
|
#else
|
|
return strtod(nptr, endptr);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(NEED_SWIFT_STRTOF_L)
|
|
static float swift_strtof_l(const char *nptr, char **endptr, locale_t loc) {
|
|
#if defined(_WIN32)
|
|
return _strtof_l(nptr, endptr, getCLocale());
|
|
#elif defined(__CYGWIN__) || defined(__HAIKU__)
|
|
return _swift_strto<float>(nptr, endptr);
|
|
#else
|
|
return strtof(nptr, endptr);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if defined(NEED_SWIFT_STRTOLD_L)
|
|
static long double swift_strtold_l(const char *nptr, char **endptr,
|
|
locale_t loc) {
|
|
#if defined(_WIN32)
|
|
return _strtod_l(nptr, endptr, getCLocale());
|
|
#elif defined(__ANDROID__)
|
|
return strtod(nptr, endptr);
|
|
#elif defined(__CYGWIN__) || defined(__HAIKU__)
|
|
return _swift_strto<long double>(nptr, endptr);
|
|
#else
|
|
return strtold(nptr, endptr);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#undef NEED_SWIFT_STRTOD_L
|
|
#undef NEED_SWIFT_STRTOF_L
|
|
#undef NEED_SWIFT_STRTOLD_L
|
|
|
|
static inline void _swift_set_errno(int to) {
|
|
#if defined(_WIN32)
|
|
_set_errno(0);
|
|
#else
|
|
errno = 0;
|
|
#endif
|
|
}
|
|
|
|
// We can't return Float80, but we can receive a pointer to one, so
|
|
// switch the return type and the out parameter on strtold.
|
|
template <typename T>
|
|
static const char *_swift_stdlib_strtoX_clocale_impl(
|
|
const char * nptr, T* outResult, T huge,
|
|
T (*posixImpl)(const char *, char **, locale_t)
|
|
) {
|
|
if (swift_stringIsSignalingNaN(nptr)) {
|
|
// TODO: ensure that the returned sNaN bit pattern matches that of sNaNs
|
|
// produced by Swift.
|
|
*outResult = std::numeric_limits<T>::signaling_NaN();
|
|
return nptr + std::strlen(nptr);
|
|
}
|
|
|
|
char *EndPtr;
|
|
_swift_set_errno(0);
|
|
const auto result = posixImpl(nptr, &EndPtr, getCLocale());
|
|
*outResult = result;
|
|
return EndPtr;
|
|
}
|
|
|
|
const char *_swift_stdlib_strtold_clocale(
|
|
const char * nptr, void *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, static_cast<long double*>(outResult), HUGE_VALL, strtold_l);
|
|
}
|
|
|
|
const char *_swift_stdlib_strtod_clocale(
|
|
const char * nptr, double *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, outResult, HUGE_VAL, strtod_l);
|
|
}
|
|
|
|
const char *_swift_stdlib_strtof_clocale(
|
|
const char * nptr, float *outResult) {
|
|
return _swift_stdlib_strtoX_clocale_impl(
|
|
nptr, outResult, HUGE_VALF, strtof_l);
|
|
}
|
|
|
|
const char *_swift_stdlib_strtof16_clocale(
|
|
const char * nptr, __fp16 *outResult) {
|
|
float tmp;
|
|
const char *result = _swift_stdlib_strtof_clocale(nptr, &tmp);
|
|
*outResult = tmp;
|
|
return result;
|
|
}
|
|
|
|
void _swift_stdlib_flockfile_stdout() {
|
|
#if defined(_WIN32)
|
|
_lock_file(stdout);
|
|
#elif defined(__wasi__)
|
|
// WebAssembly/WASI doesn't support file locking yet https://bugs.swift.org/browse/SR-12097
|
|
#else
|
|
flockfile(stdout);
|
|
#endif
|
|
}
|
|
|
|
void _swift_stdlib_funlockfile_stdout() {
|
|
#if defined(_WIN32)
|
|
_unlock_file(stdout);
|
|
#elif defined(__wasi__)
|
|
// WebAssembly/WASI doesn't support file locking yet https://bugs.swift.org/browse/SR-12097
|
|
#else
|
|
funlockfile(stdout);
|
|
#endif
|
|
}
|
|
|
|
int _swift_stdlib_putc_stderr(int C) {
|
|
return putc(C, stderr);
|
|
}
|
|
|
|
size_t _swift_stdlib_getHardwareConcurrency() {
|
|
#ifdef SWIFT_STDLIB_SINGLE_THREADED_RUNTIME
|
|
return 1;
|
|
#else
|
|
return std::thread::hardware_concurrency();
|
|
#endif
|
|
}
|