Skip to content

Commit 9fe5a89

Browse files
authored
Merge pull request #21 from natecook1000/all_scalars
Add an `AllScalars` collection
2 parents 5b1ec04 + 9218005 commit 9fe5a89

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

Sources/Util/AllScalars.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
extension Unicode.Scalar {
2+
public struct AllScalars: RandomAccessCollection {
3+
// Unicode scalar values are in two discontiguous blocks:
4+
// 0...0xD7FF and 0xE000...0x10FFFF
5+
internal static var lowerSectionFirstValue: Int { 0 }
6+
internal static var lowerSectionLastValue: Int { 0xD7FF }
7+
internal static var upperSectionFirstValue: Int { 0xE000 }
8+
internal static var upperSectionLastValue: Int { 0x10FFFF }
9+
10+
internal static var surrogateRangeCount: Int {
11+
(upperSectionFirstValue - lowerSectionLastValue) - 1
12+
}
13+
14+
internal func toContiguous(_ i: Int) -> Int {
15+
i >= Self.upperSectionFirstValue
16+
? i - Self.surrogateRangeCount
17+
: i
18+
}
19+
20+
internal func fromContiguous(_ i: Int) -> Int {
21+
i > Self.lowerSectionLastValue
22+
? i + Self.surrogateRangeCount
23+
: i
24+
}
25+
26+
public var startIndex: Int { 0 }
27+
public var endIndex: Int { toContiguous(Self.upperSectionLastValue + 1) }
28+
29+
public subscript(position: Int) -> Unicode.Scalar {
30+
Unicode.Scalar(UInt32(fromContiguous(position)))!
31+
}
32+
33+
public func _customIndexOfEquatableElement(_ scalar: Unicode.Scalar) -> Int?? {
34+
toContiguous(Int(scalar.value))
35+
}
36+
37+
public func _customContainsEquatableElement(_: Unicode.Scalar) -> Bool? {
38+
true
39+
}
40+
}
41+
42+
public static var allScalars: AllScalars {
43+
AllScalars()
44+
}
45+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import XCTest
2+
@testable import Util
3+
4+
let allScalars = Unicode.Scalar.allScalars
5+
6+
class AllScalarsTests: XCTestCase {
7+
func testCollectionConformance() {
8+
let calculatedCount = (0...0xD7FF).count + (0xE000...0x10FFFF).count
9+
XCTAssertEqual(calculatedCount, allScalars.count)
10+
XCTAssertEqual(calculatedCount, allScalars.reduce(0, { sum, _ in sum + 1 }))
11+
}
12+
13+
func testIndexOf() throws {
14+
for scalar in "béड🥰 \u{0} \u{D7FF} \u{E000} \u{10FFFF}".unicodeScalars {
15+
let i = try XCTUnwrap(allScalars.firstIndex(of: scalar))
16+
XCTAssertEqual(scalar, allScalars[i])
17+
}
18+
}
19+
20+
func testProperties() throws {
21+
let whitespaces = allScalars.filter { $0.properties.isWhitespace }
22+
XCTAssertEqual(25, whitespaces.count)
23+
24+
let numericIndices = allScalars
25+
.indices
26+
.filter { allScalars[$0].properties.numericType == .decimal }
27+
XCTAssertEqual(650, numericIndices.count)
28+
29+
let digitSum = try numericIndices
30+
.map { try XCTUnwrap(allScalars[$0].properties.numericValue) }
31+
.reduce(0, +)
32+
XCTAssertEqual(2925, digitSum)
33+
XCTAssertEqual(4.5, digitSum / Double(numericIndices.count))
34+
}
35+
}

0 commit comments

Comments
 (0)