mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[stdlib] Floating-point parsing
Swift SVN r25627
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
import SwiftShims
|
||||
|
||||
%{
|
||||
#
|
||||
@@ -59,6 +60,8 @@ def cFuncSuffix(bits):
|
||||
if bits == 80:
|
||||
return 'l'
|
||||
|
||||
cFuncSuffix2 = {32: 'f', 64: 'd', 80: 'ld'}
|
||||
|
||||
def llvmIntrinsicSuffix(bits):
|
||||
if bits == 32:
|
||||
return 'f32'
|
||||
@@ -200,6 +203,44 @@ extension ${Self} : Printable {
|
||||
}
|
||||
}
|
||||
|
||||
//===--- Parsing ----------------------------------------------------------===//
|
||||
extension ${Self} {
|
||||
/// Construct from an ASCII representation.
|
||||
///
|
||||
/// The result is `nil` if `text` contains non-ASCII text or
|
||||
/// whitespace, or if it is not completely consumed by the POSIX
|
||||
/// function `strto${cFuncSuffix2[bits]}`. Otherwise, the result is
|
||||
/// the value returned by `strto${cFuncSuffix2[bits]}`. See the
|
||||
/// `strto${cFuncSuffix2[bits]} (3)` man page for details of the
|
||||
/// exact format accepted.
|
||||
public init?(_ text: String) {
|
||||
let u16 = text.utf16
|
||||
// Any non-ASCII or whitespace? return nil.
|
||||
if contains(u16, { $0 > 127 || isspace(Int32($0)) != 0 }) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseNTBS(chars: UnsafePointer<CChar>) -> (${Self}, Int) {
|
||||
% if bits == 80:
|
||||
var result: Float80 = 0
|
||||
let endPtr = withUnsafeMutablePointer(&result) {
|
||||
_swift_strtold(chars, UnsafeMutablePointer($0))
|
||||
}
|
||||
% else:
|
||||
var endPtr: UnsafeMutablePointer<CChar> = nil
|
||||
let result = withUnsafeMutablePointer(&endPtr) {
|
||||
strto${cFuncSuffix2[bits]}(chars, $0)
|
||||
}
|
||||
% end
|
||||
return (result, endPtr == nil ? 0 : UnsafePointer(endPtr) - chars)
|
||||
}
|
||||
|
||||
let (result, n) = text.withCString(parseNTBS)
|
||||
if n == 0 || n != count(u16) { return nil }
|
||||
self = result
|
||||
}
|
||||
}
|
||||
|
||||
% if bits in allIntBits:
|
||||
// Not transparent because the compiler crashes in that case.
|
||||
//@transparent
|
||||
|
||||
@@ -311,3 +311,10 @@ extern "C" uint64_t swift_stdlib_atomicFetchAddUInt64(
|
||||
return __c11_atomic_fetch_add(object, operand, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
// We can't return Float80, but we can receive a pointer to one, so
|
||||
// switch the return type and the out parameter on strtold.
|
||||
extern "C" const char *_swift_strtold(const char * nptr, void *outResult) {
|
||||
char *endPtr;
|
||||
*static_cast<long double*>(outResult) = std::strtold(nptr, &endPtr);
|
||||
return endPtr;
|
||||
}
|
||||
|
||||
@@ -29,5 +29,10 @@ int strcmp(const char *s1, const char *s2);
|
||||
int memcmp(const void *s1, const void *s2, __swift_size_t n);
|
||||
int putchar(int c);
|
||||
|
||||
double strtod(const char *restrict nptr, char **restrict endptr);
|
||||
float strtof(const char *restrict nptr, char **restrict endptr);
|
||||
|
||||
int isspace(int c);
|
||||
|
||||
#endif // SWIFT_STDLIB_SHIMS_DARWINSHIMS_H
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@ bool _swift_usesNativeSwiftReferenceCounting_class(const void *);
|
||||
__swift_size_t _swift_class_getInstancePositiveExtentSize(const void *);
|
||||
|
||||
/// Return an NSString to be used as the Mirror summary of the object
|
||||
void* _swift_objCMirrorSummary(const void * nsObject);
|
||||
void *_swift_objCMirrorSummary(const void * nsObject);
|
||||
|
||||
/// Call strtold, changing arguments so we can operate on Float80
|
||||
const char *_swift_strtold(const char *nptr, void *outResult);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}} // extern "C", namespace swift
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// -*- swift -*-
|
||||
// RUN: rm -rf %t ; mkdir -p %t
|
||||
// RUN: %S/../../utils/gyb -Dtarget_ptrsize=%target-ptrsize %s -o %t/NumericParsing.swift
|
||||
// RUN: %S/../../utils/gyb -DCMAKE_SIZEOF_VOID_P=%target-ptrsize %s -o %t/NumericParsing.swift
|
||||
// RUN: %S/../../utils/line-directive %t/NumericParsing.swift -- %target-build-swift %t/NumericParsing.swift -o %t/a.out
|
||||
// RUN: %S/../../utils/line-directive %t/NumericParsing.swift -- %target-run %t/a.out
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
%{
|
||||
from SwiftIntTypes import *
|
||||
|
||||
word_bits = int(target_ptrsize)
|
||||
word_bits = int(CMAKE_SIZEOF_VOID_P)
|
||||
|
||||
def maskOfWidth(n):
|
||||
return (1 << n) - 1
|
||||
@@ -47,6 +47,7 @@ number_of_values = 23
|
||||
}%
|
||||
|
||||
import StdlibUnittest
|
||||
import Darwin
|
||||
|
||||
var tests = TestSuite("NumericParsing")
|
||||
|
||||
@@ -115,4 +116,48 @@ tests.test("${Self}/radixTooHigh") {
|
||||
|
||||
% end
|
||||
|
||||
% for Self in 'Float', 'Double', 'Float80':
|
||||
|
||||
% if Self == 'Float80':
|
||||
#if arch(i386) || arch(x86_64)
|
||||
% end
|
||||
|
||||
tests.test("${Self}/Basics") {
|
||||
setlocale(LC_ALL, "")
|
||||
|
||||
% if Self != 'Float80': # Inf/NaN are not defined for Float80
|
||||
expectEqual(.infinity, ${Self}("Inf"))
|
||||
expectEqual(-(.infinity), ${Self}("-Inf"))
|
||||
expectEqual(toString(${Self}.NaN), toString(${Self}("NaN")!))
|
||||
% end
|
||||
|
||||
expectEqual(-0.0, ${Self}("-0"))
|
||||
expectEqual(-0.0, ${Self}("-0.0"))
|
||||
expectEqual(0.0, ${Self}("0"))
|
||||
expectEqual(0.0, ${Self}("0.0"))
|
||||
expectEqual(64206, ${Self}("0xFACE")) // Yes, strtoXXX supports hex.
|
||||
|
||||
// Check that we can round-trip the string representation of 2^100,
|
||||
// which requires an exponent to express...
|
||||
let large = reduce(Repeat(count: 10, repeatedValue: 1024 as ${Self}), 1, *)
|
||||
let largeText = toString(large)
|
||||
expectEqual(largeText, toString(${Self}(largeText)!))
|
||||
|
||||
// ...ditto for its inverse.
|
||||
let smallText = toString(1 / large)
|
||||
expectEqual(smallText, toString(${Self}(smallText)!))
|
||||
|
||||
// Cases that should fail to parse
|
||||
expectEmpty(${Self}("")) // EMPTY
|
||||
expectEmpty(${Self}("0FACE")) // Hex characters without 0x
|
||||
expectEmpty(${Self}("99x"))
|
||||
expectEmpty(${Self}(" 0")) // Leading whitespace
|
||||
expectEmpty(${Self}("0 ")) // Trailing whitespace
|
||||
}
|
||||
|
||||
% if Self == 'Float80':
|
||||
#endif
|
||||
% end
|
||||
|
||||
% end
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user