Skip to content

Commit 3f46c15

Browse files
committed
Fixed and improved: virtualization of currency labels. Removed: NumericTextStyles/(Label.swift, Search.swift). Cleanup.
1 parent 2099f4f commit 3f46c15

File tree

7 files changed

+113
-197
lines changed

7 files changed

+113
-197
lines changed

Sources/DiffableTextKit/Helpers/Direction.swift renamed to Sources/DiffableTextKit/Models/Direction.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//*============================================================================*
1313

1414
/// A forwards/backwards model.
15-
@frozen @usableFromInline enum Direction {
15+
@frozen public enum Direction {
1616

1717
//=------------------------------------------------------------------------=
1818
// MARK: Instances
@@ -25,19 +25,17 @@
2525
// MARK: Initializers
2626
//=------------------------------------------------------------------------=
2727

28-
@inlinable init?<T>(_ start: T, to end: T) where T: Comparable {
29-
switch true {
30-
case start < end: self = .forwards
31-
case start > end: self = .backwards
32-
default: return nil
33-
}
28+
@inlinable public init?<T>(_ start: T, to end: T) where T: Comparable {
29+
if start < end { self = .forwards }
30+
else if start > end { self = .backwards }
31+
else { return nil }
3432
}
3533

3634
//=------------------------------------------------------------------------=
3735
// MARK: Transformations
3836
//=------------------------------------------------------------------------=
3937

40-
@inlinable func reversed() -> Self {
38+
@inlinable public func reversed() -> Self {
4139
switch self {
4240
case .forwards: return .backwards
4341
case .backwards: return .forwards

Sources/DiffableTextStylesXNumeric/Helpers/Label.swift

Lines changed: 0 additions & 73 deletions
This file was deleted.

Sources/DiffableTextStylesXNumeric/Helpers/Links.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ import Foundation
6868
// MARK: Accessors
6969
//=------------------------------------------------------------------------=
7070

71-
@inlinable subscript(character: Character) -> Component? {
72-
_read { yield components[character] }
71+
/// All components are mapped, so force unwrapping characters is OK.
72+
@inlinable subscript(component: Component) -> Character {
73+
characters[component]!
7374
}
7475

75-
/// Bidirectional mapping is required for all components, so force unwrapping characters is OK.
76-
@inlinable subscript(component: Component) -> Character! {
77-
_read { yield characters[component] }
76+
@inlinable subscript(character: Character) -> Component? {
77+
components[character]
7878
}
7979

8080
//=------------------------------------------------------------------------=

Sources/DiffableTextStylesXNumeric/Helpers/Search.swift

Lines changed: 0 additions & 75 deletions
This file was deleted.

Sources/DiffableTextStylesXNumeric/Models/Scheme+Currency.swift

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import Foundation
2222
//=------------------------------------------------------------------------=
2323

2424
@usableFromInline let id: ID
25-
@usableFromInline let label: Label
2625
@usableFromInline let lexicon: Lexicon
2726
@usableFromInline let preferences: Preferences
28-
27+
@usableFromInline let instruction: Instruction?
28+
2929
//=------------------------------------------------------------------------=
3030
// MARK: Initializers
3131
//=------------------------------------------------------------------------=
@@ -36,19 +36,16 @@ import Foundation
3636
formatter.currencyCode = id.code
3737
assert(formatter.numberStyle == .none)
3838
//=--------------------------------------=
39-
// MARK: Instantiate
40-
//=--------------------------------------=
41-
self.id = id
42-
//=--------------------------------------=
4339
// MARK: Instantiate - None
4440
//=--------------------------------------=
41+
self.id = id
4542
self.lexicon = .currency(formatter)
46-
self.label = .currency(id, lexicon)
4743
//=--------------------------------------=
4844
// MARK: Instantiate - Currency
4945
//=--------------------------------------=
5046
formatter.numberStyle = .currency
5147
self.preferences = Preferences(formatter)
48+
self.instruction = Instruction(id, lexicon)
5249
}
5350

5451
//=------------------------------------------------------------------------=
@@ -102,29 +99,101 @@ import Foundation
10299
formatter.maximumFractionDigits
103100
}
104101
}
102+
103+
//*========================================================================*
104+
// MARK: * Instruction
105+
//*========================================================================*
106+
107+
/// A model for marking currency labels as virtual.
108+
///
109+
/// The characters used to express currencies are usually disjoint
110+
/// from the characters used to express their amounts, but sometimes they include fraction separators.
111+
/// This instruction is used to efficiently mark faux fraction separators, when they exist.
112+
///
113+
@usableFromInline struct Instruction {
114+
115+
//=--------------------------------------------------------------------=
116+
// MARK: State
117+
//=--------------------------------------------------------------------=
118+
119+
@usableFromInline let occurances: Int
120+
@usableFromInline let character: Character
121+
@usableFromInline let direction: Direction
122+
123+
//=--------------------------------------------------------------------=
124+
// MARK: Initializers
125+
//=--------------------------------------------------------------------=
126+
127+
@inlinable init?<S>(_ label: S, _ character: Character,
128+
_ direction: Direction) where S: Sequence, S.Element == Character {
129+
self.occurances = label.count(where: { $0 == character })
130+
//=--------------------------------------=
131+
// MARK: Validate
132+
//=--------------------------------------=
133+
guard occurances > 0 else { return nil }
134+
//=--------------------------------------=
135+
// MARK: Instantiate
136+
//=--------------------------------------=
137+
self.character = character
138+
self.direction = direction
139+
}
140+
141+
@inlinable init?(_ id: ID, _ lexicon: Lexicon) {
142+
let separator = lexicon.separators[.fraction]
143+
let labels = IntegerFormatStyle<Int>
144+
.Currency(code: id.code, locale: id.locale)
145+
.precision(.fractionLength(0)).format(0).split(
146+
separator: lexicon.digits[.zero],
147+
omittingEmptySubsequences: false)
148+
//=----------------------------------=
149+
// MARK: Instantiate
150+
//=----------------------------------=
151+
if let instance = Self(labels[0], separator, .forwards) { self = instance }
152+
else if let instance = Self(labels[1], separator, .backwards) { self = instance }
153+
else { return nil }
154+
}
155+
156+
//=------------------------------------------------------------------------=
157+
// MARK: Utilities
158+
//=------------------------------------------------------------------------=
159+
160+
@inlinable func autocorrect(_ snapshot: inout Snapshot) {
161+
switch direction {
162+
case .forwards: autocorrect(&snapshot, indices: snapshot.indices)
163+
case .backwards: autocorrect(&snapshot, indices: snapshot.indices.reversed())
164+
}
165+
}
166+
167+
@inlinable func autocorrect<S>(_ snapshot: inout Snapshot,
168+
indices: S) where S: Sequence, S.Element == Snapshot.Index {
169+
var count = 0; for index in indices where
170+
snapshot[index].character == character {
171+
snapshot.update(attributes: index) { $0 = .phantom }
172+
count += 1; guard count < occurances else { return }
173+
}
174+
}
175+
}
105176
}
106177

107178
//=----------------------------------------------------------------------------=
108-
// MARK: + Specialization
179+
// MARK: + Scheme
109180
//=----------------------------------------------------------------------------=
110181

111182
extension NumericTextSchemeXCurrency {
112183

113184
//=------------------------------------------------------------------------=
114-
// MARK: Preferences
185+
// MARK: Autocorrect
115186
//=------------------------------------------------------------------------=
116187

117-
@inlinable func precision<T>(_ value: T.Type) -> Precision<T> where T: Value {
118-
Precision(fraction: preferences.fraction)
188+
@inlinable func autocorrect(_ snapshot: inout Snapshot) {
189+
instruction?.autocorrect(&snapshot)
119190
}
120191

121192
//=------------------------------------------------------------------------=
122-
// MARK: Autocorrect
193+
// MARK: Preferences
123194
//=------------------------------------------------------------------------=
124195

125-
@inlinable func autocorrect(_ snapshot: inout Snapshot) {
126-
guard !label.characters.isEmpty else { return }
127-
guard let indices = label.indices(in: snapshot) else { return }
128-
snapshot.update(attributes: indices) { attribute in attribute = .phantom }
196+
@inlinable func precision<T>(_ value: T.Type) -> Precision<T> where T: Value {
197+
Precision(fraction: preferences.fraction)
129198
}
130199
}

Sources/DiffableTextStylesXNumeric/Models/Scheme+Standard.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,9 @@ import Foundation
3333
formatter.locale = id.locale
3434
assert(formatter.numberStyle == .none)
3535
//=--------------------------------------=
36-
// MARK: Instantiate
37-
//=--------------------------------------=
38-
self.id = id
39-
//=--------------------------------------=
4036
// MARK: Instantiate - None
4137
//=--------------------------------------=
38+
self.id = id
4239
self.lexicon = .standard(formatter)
4340
}
4441

0 commit comments

Comments
 (0)