Skip to content

Commit 12fd979

Browse files
committed
Implement native scalar age
1 parent 76377ca commit 12fd979

File tree

9 files changed

+2334
-28
lines changed

9 files changed

+2334
-28
lines changed

stdlib/public/SwiftShims/UnicodeData.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ SWIFT_RUNTIME_STDLIB_INTERNAL
8787
__swift_intptr_t _swift_stdlib_getScalarName(__swift_uint32_t scalar,
8888
__swift_uint8_t *buffer);
8989

90+
SWIFT_RUNTIME_STDLIB_INTERNAL
91+
__swift_uint16_t _swift_stdlib_getAge(__swift_uint32_t scalar);
92+
9093
#ifdef __cplusplus
9194
} // extern "C"
9295
#endif

stdlib/public/SwiftShims/UnicodeShims.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,6 @@ typedef __swift_uint16_t __swift_stdlib_UChar;
271271
typedef __swift_uint8_t
272272
__swift_stdlib_UVersionInfo[__SWIFT_STDLIB_U_MAX_VERSION_LENGTH];
273273

274-
SWIFT_RUNTIME_STDLIB_API
275-
void __swift_stdlib_u_charAge(
276-
__swift_stdlib_UChar32, __swift_stdlib_UVersionInfo _Nonnull);
277-
278274
SWIFT_RUNTIME_STDLIB_API
279275
__swift_int32_t
280276
__swift_stdlib_u_getIntPropertyValue(__swift_stdlib_UChar32,

stdlib/public/core/UnicodeScalarProperties.swift

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -872,15 +872,16 @@ extension Unicode.Scalar.Properties {
872872
/// This property corresponds to the "Age" property in the
873873
/// [Unicode Standard](http://www.unicode.org/versions/latest/).
874874
public var age: Unicode.Version? {
875-
var versionInfo: __swift_stdlib_UVersionInfo = (0, 0, 0, 0)
876-
withUnsafeMutablePointer(to: &versionInfo) { tuplePtr in
877-
tuplePtr.withMemoryRebound(to: UInt8.self, capacity: 4) {
878-
versionInfoPtr in
879-
__swift_stdlib_u_charAge(icuValue, versionInfoPtr)
880-
}
875+
let age = _swift_stdlib_getAge(_scalar.value)
876+
877+
if age == .max {
878+
return nil
881879
}
882-
guard versionInfo.0 != 0 else { return nil }
883-
return (major: Int(versionInfo.0), minor: Int(versionInfo.1))
880+
881+
let major = age & 0xFF
882+
let minor = (age & 0xFF00) >> 8
883+
884+
return (major: Int(major), minor: Int(minor))
884885
}
885886
}
886887

stdlib/public/stubs/UnicodeScalarProps.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,41 @@ __swift_intptr_t _swift_stdlib_getScalarName(__swift_uint32_t scalar,
257257
// The return value is the number of initialized bytes.
258258
return c;
259259
}
260+
261+
SWIFT_RUNTIME_STDLIB_INTERNAL
262+
__swift_uint16_t _swift_stdlib_getAge(__swift_uint32_t scalar) {
263+
auto lowerBoundIndex = 0;
264+
auto endIndex = 1659;
265+
auto upperBoundIndex = endIndex - 1;
266+
267+
while (upperBoundIndex >= lowerBoundIndex) {
268+
auto idx = lowerBoundIndex + (upperBoundIndex - lowerBoundIndex) / 2;
269+
270+
auto entry = _swift_stdlib_ages[idx];
271+
272+
auto lowerBoundScalar = (entry << 43) >> 43;
273+
auto rangeCount = entry >> 32;
274+
auto upperBoundScalar = lowerBoundScalar + rangeCount;
275+
276+
auto ageIdx = (__swift_uint8_t)((entry << 32) >> 32 >> 21);
277+
278+
if (scalar >= lowerBoundScalar && scalar <= upperBoundScalar) {
279+
return _swift_stdlib_ages_data[ageIdx];
280+
}
281+
282+
if (scalar > upperBoundScalar) {
283+
lowerBoundIndex = idx + 1;
284+
continue;
285+
}
286+
287+
if (scalar < lowerBoundScalar) {
288+
upperBoundIndex = idx - 1;
289+
continue;
290+
}
291+
}
292+
293+
// If we made it out here, then our scalar was not found in the composition
294+
// array.
295+
// Return the max here to indicate that we couldn't find one.
296+
return std::numeric_limits<__swift_uint16_t>::max();
297+
}

stdlib/public/stubs/UnicodeScalarProps.h

Lines changed: 234 additions & 0 deletions
Large diffs are not rendered by default.

stdlib/public/stubs/UnicodeShims.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ typedef __swift_stdlib_UProperty UProperty;
3636
typedef uint8_t UVersionInfo[U_MAX_VERSION_LENGTH];
3737

3838
// Comparison and character property APIs
39-
void u_charAge(UChar32, UVersionInfo);
4039
int32_t u_getIntPropertyValue(UChar32, UProperty);
4140
}
4241

@@ -58,21 +57,6 @@ int32_t u_getIntPropertyValue(UChar32, UProperty);
5857

5958
#endif
6059

61-
namespace {
62-
template <typename T, typename U> T *ptr_cast(U *p) {
63-
return static_cast<T *>(static_cast<void *>(p));
64-
}
65-
template <typename T, typename U> const T *ptr_cast(const U *p) {
66-
return static_cast<const T *>(static_cast<const void *>(p));
67-
}
68-
}
69-
70-
void
71-
__swift_stdlib_u_charAge(__swift_stdlib_UChar32 c,
72-
__swift_stdlib_UVersionInfo versionInfo) {
73-
return u_charAge(c, versionInfo);
74-
}
75-
7660
__swift_int32_t
7761
__swift_stdlib_u_getIntPropertyValue(__swift_stdlib_UChar32 c,
7862
__swift_stdlib_UProperty p) {

utils/gen-unicode-data/Data/DerivedAge.txt

Lines changed: 1952 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import GenUtils
14+
15+
func getAge(
16+
from data: String,
17+
into result: inout [(ClosedRange<UInt32>, [UInt8])]
18+
) {
19+
for line in data.split(separator: "\n") {
20+
// Skip comments
21+
guard !line.hasPrefix("#") else {
22+
continue
23+
}
24+
25+
let info = line.split(separator: "#")
26+
let components = info[0].split(separator: ";")
27+
28+
let scalars: ClosedRange<UInt32>
29+
30+
let filteredScalars = components[0].filter { !$0.isWhitespace }
31+
32+
// If we have . appear, it means we have a legitimate range. Otherwise,
33+
// it's a singular scalar.
34+
if filteredScalars.contains(".") {
35+
let range = filteredScalars.split(separator: ".")
36+
37+
scalars = UInt32(range[0], radix: 16)! ... UInt32(range[1], radix: 16)!
38+
} else {
39+
let scalar = UInt32(filteredScalars, radix: 16)!
40+
41+
scalars = scalar ... scalar
42+
}
43+
44+
let version = components[1].filter { !$0.isWhitespace }
45+
let parts = version.split(separator: ".")
46+
47+
let major = UInt8(parts[0])!
48+
let minor = UInt8(parts[1])!
49+
50+
result.append((scalars, [major, minor]))
51+
}
52+
}
53+
54+
func emitAge(
55+
data: [(ClosedRange<UInt32>, [UInt8])],
56+
into result: inout String
57+
) {
58+
var uniqueAges: Set<[UInt8]> = []
59+
60+
for (_, age) in data {
61+
uniqueAges.insert(age)
62+
}
63+
64+
let ages = uniqueAges.map {
65+
UInt16($0[0]) | (UInt16($0[1]) << 8)
66+
}
67+
68+
emitCollection(ages, name: "_swift_stdlib_ages_data", into: &result)
69+
70+
emitCollection(
71+
data,
72+
name: "_swift_stdlib_ages",
73+
type: "__swift_uint64_t",
74+
into: &result
75+
) {
76+
var value: UInt64 = UInt64($0.0.lowerBound)
77+
78+
let age = UInt16($0.1[0]) | (UInt16($0.1[1]) << 8)
79+
let ageIndex = ages.firstIndex(of: age)!
80+
81+
value |= UInt64(ageIndex) << 21
82+
83+
value |= UInt64($0.0.count - 1) << 32
84+
85+
return "0x\(String(value, radix: 16, uppercase: true))"
86+
}
87+
}
88+
89+
func generateAgeProp(into result: inout String) {
90+
let derivedAge = readFile("Data/DerivedAge.txt")
91+
92+
var ageData: [(ClosedRange<UInt32>, [UInt8])] = []
93+
94+
getAge(from: derivedAge, into: &ageData)
95+
96+
emitAge(data: flatten(ageData), into: &result)
97+
}

utils/gen-unicode-data/Sources/GenScalarProps/main.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func generateScalarProps() {
2020
generateNameAliasProp(into: &result)
2121
generateMappingProps(into: &result)
2222
generateNameProp(into: &result)
23+
generateAgeProp(into: &result)
2324

2425
write(result, to: "../../stdlib/public/stubs/UnicodeScalarProps.cpp")
2526
}

0 commit comments

Comments
 (0)