Skip to content

Commit 354f2ad

Browse files
committed
[stdlib] Add "numeric{Type,Value}" to Unicode.Scalar.Properties
1 parent e7078a4 commit 354f2ad

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

stdlib/public/SwiftShims/UnicodeShims.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,16 @@ typedef enum __swift_stdlib_UCharNameChoice {
436436
#endif
437437
} __swift_stdlib_UCharNameChoice;
438438

439+
typedef enum __swift_stdlib_UNumericType {
440+
__swift_stdlib_U_NT_NONE,
441+
__swift_stdlib_U_NT_DECIMAL,
442+
__swift_stdlib_U_NT_DIGIT,
443+
__swift_stdlib_U_NT_NUMERIC,
444+
#ifndef U_HIDE_DEPRECATED_API
445+
__swift_stdlib_U_NT_COUNT
446+
#endif
447+
} __swift_stdlib_UNumericType;
448+
439449
typedef struct __swift_stdlib_UBreakIterator __swift_stdlib_UBreakIterator;
440450
typedef struct __swift_stdlib_UNormalizer2 __swift_stdlib_UNormalizer2;
441451
typedef __swift_int8_t __swift_stdlib_UBool;
@@ -541,6 +551,9 @@ __swift_int32_t __swift_stdlib_u_strToUpper(
541551
const __swift_stdlib_UChar *src, __swift_int32_t srcLength,
542552
const char *locale, __swift_stdlib_UErrorCode *pErrorCode);
543553

554+
SWIFT_RUNTIME_STDLIB_INTERFACE
555+
double __swift_stdlib_u_getNumericValue(__swift_stdlib_UChar32 c);
556+
544557

545558
#ifdef __cplusplus
546559
}} // extern "C", namespace swift

stdlib/public/core/UnicodeScalarProperties.swift

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,3 +1298,112 @@ extension Unicode.Scalar.Properties {
12981298
return Unicode.CanonicalCombiningClass(rawValue: rawValue)
12991299
}
13001300
}
1301+
1302+
extension Unicode {
1303+
1304+
/// The numeric type of a scalar.
1305+
///
1306+
/// Scalars with a non-nil numeric type include numbers, fractions, numeric
1307+
/// superscripts and subscripts, and circled or otherwise decorated number
1308+
/// glyphs.
1309+
///
1310+
/// Some letterlike scalars used in numeric systems, such as Greek or Latin
1311+
/// letters, do not have a non-nil numeric type, in order to prevent programs
1312+
/// from incorrectly interpreting them as numbers in non-numeric contexts.
1313+
public enum NumericType {
1314+
1315+
/// Digits that are commonly understood to form base-10 numbers.
1316+
///
1317+
/// Specifically, scalars have this numeric type if they occupy a contiguous
1318+
/// range of code points representing numeric values `0...9`.
1319+
case decimal
1320+
1321+
/// Decimal digits that otherwise do not meet the requirements of numeric
1322+
/// type `decimal`.
1323+
///
1324+
/// Scalars with this numeric type are often those that represent a decimal
1325+
/// digit but would not typically be used to write a base-10 number, such as
1326+
/// "④" (U+2463 CIRCLED DIGIT FOUR).
1327+
///
1328+
/// In practice, the distinction between `digit` and `numeric` has not
1329+
/// proven to be valuable. As of Unicode 6.3, any new scalars that represent
1330+
/// numbers but do not meet the requirements of `decimal` will have numeric
1331+
/// type `numeric`, and programs can treat `digit` and `numeric`
1332+
/// equivalently.
1333+
case digit
1334+
1335+
/// Numbers that are not decimal digits.
1336+
///
1337+
/// This numeric type includes fractions such as "⅕" (U+2155 VULGAR FRACITON
1338+
/// ONE FIFTH), numerical CJK ideographs like "兆" (U+5146 CJK UNIFIED
1339+
/// IDEOGRAPH-5146), and other scalars that are not decimal digits used
1340+
/// positionally in the writing of base-10 numbers.
1341+
case numeric
1342+
1343+
internal init?(rawValue: __swift_stdlib_UNumericType) {
1344+
switch rawValue {
1345+
case __swift_stdlib_U_NT_NONE: return nil
1346+
case __swift_stdlib_U_NT_DECIMAL: self = .decimal
1347+
case __swift_stdlib_U_NT_DIGIT: self = .digit
1348+
case __swift_stdlib_U_NT_NUMERIC: self = .numeric
1349+
default: fatalError("Unknown numeric type \(rawValue)")
1350+
}
1351+
}
1352+
}
1353+
}
1354+
1355+
/// Numeric properties of scalars.
1356+
extension Unicode.Scalar.Properties {
1357+
1358+
/// The numeric type of the scalar.
1359+
///
1360+
/// The value of this property is nil for scalars that do not represent a
1361+
/// number.
1362+
///
1363+
/// ```
1364+
/// print("X", ("X" as Unicode.Scalar).properties.numericType)
1365+
/// // Prints "X nil"
1366+
/// print("4", ("4" as Unicode.Scalar).properties.numericType)
1367+
/// // Prints "4 Optional(Swift.Unicode.NumericType.decimal)"
1368+
/// print("\u{2463}", ("\u{2463}" as Unicode.Scalar).properties.numericType)
1369+
/// // Prints "④ Optional(Swift.Unicode.NumericType.digit)"
1370+
/// print("\u{2155}", ("\u{2155}" as Unicode.Scalar).properties.numericType)
1371+
/// // Prints "⅕ Optional(Swift.Unicode.NumericType.numeric)"
1372+
/// ```
1373+
///
1374+
/// This property corresponds to the `Numeric_Type` property in the
1375+
/// [Unicode Standard](http://www.unicode.org/versions/latest/).
1376+
public var numericType: Unicode.NumericType? {
1377+
let rawValue = __swift_stdlib_UNumericType(
1378+
UInt32(__swift_stdlib_u_getIntPropertyValue(
1379+
_value, __swift_stdlib_UCHAR_NUMERIC_TYPE)))
1380+
return Unicode.NumericType(rawValue: rawValue)
1381+
}
1382+
1383+
/// The numeric value of the scalar.
1384+
///
1385+
/// The value of this property is `Double.nan` for scalars that do not
1386+
/// represent a number.
1387+
///
1388+
/// The numeric value of a scalar is represented as a `Double` because some
1389+
/// scalars represent fractions.
1390+
///
1391+
/// ```
1392+
/// print("X", ("X" as Unicode.Scalar).properties.numericValue)
1393+
/// // Prints "X nan"
1394+
/// print("4", ("4" as Unicode.Scalar).properties.numericValue)
1395+
/// // Prints "4 4.0"
1396+
/// print("\u{2463}", ("\u{2463}" as Unicode.Scalar).properties.numericValue)
1397+
/// // Prints "④ 4.0"
1398+
/// print("\u{2155}", ("\u{2155}" as Unicode.Scalar).properties.numericValue)
1399+
/// // Prints "⅕ 0.2"
1400+
/// ```
1401+
///
1402+
/// This property corresponds to the `Numeric_Value` property in the
1403+
/// [Unicode Standard](http://www.unicode.org/versions/latest/).
1404+
public var numericValue: Double {
1405+
let icuNoNumericValue: Double = -123456789
1406+
let result = __swift_stdlib_u_getNumericValue(_value)
1407+
return result != icuNoNumericValue ? result : .nan
1408+
}
1409+
}

stdlib/public/stubs/UnicodeNormalization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ int32_t u_strToTitle(UChar *, int32_t, const UChar *, int32_t,
6363
UBreakIterator *, const char *, UErrorCode *);
6464
int32_t u_strToUpper(UChar *, int32_t, const UChar *, int32_t, const char *,
6565
UErrorCode *);
66+
double u_getNumericValue(UChar32);
6667
}
6768

6869
#else
@@ -388,6 +389,10 @@ __swift_int32_t swift::__swift_stdlib_u_strToUpper(
388389
locale, ptr_cast<UErrorCode>(pErrorCode));
389390
}
390391

392+
double swift::__swift_stdlib_u_getNumericValue(__swift_stdlib_UChar32 c) {
393+
return u_getNumericValue(c);
394+
}
395+
391396

392397
// Force an autolink with ICU
393398
#if defined(__MACH__)

0 commit comments

Comments
 (0)