Skip to content

Commit 2b1e735

Browse files
committed
Update AlignmentKey
1 parent 7aeac27 commit 2b1e735

File tree

2 files changed

+96
-22
lines changed

2 files changed

+96
-22
lines changed

Sources/OpenSwiftUICore/Layout/Alignment/AlignmentGuide.swift

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -177,40 +177,72 @@ extension FrameAlignment {
177177
static func _combineExplicit(childValue _: CGFloat, _: Int, into _: inout CGFloat?) {}
178178
}
179179

180-
181180
// MARK: - AlignmentKey [6.4.41]
182181

183-
@usableFromInline
182+
/// A single sort key type for alignment guides in both axes.
183+
///
184+
/// You don't use this type directly.
185+
@_documentation(visibility: private)
184186
@frozen
185-
package struct AlignmentKey: Hashable, Comparable {
186-
private let bits: UInt
187-
188-
@usableFromInline
189-
package static func < (lhs: AlignmentKey, rhs: AlignmentKey) -> Bool {
190-
lhs.bits < rhs.bits
191-
}
192-
187+
public struct AlignmentKey: Hashable, Comparable {
193188
@AtomicBox
194189
private static var typeCache = TypeCache(typeIDs: [:], types: [])
195190

196191
struct TypeCache {
197192
var typeIDs: [ObjectIdentifier: UInt]
198-
var types: [AlignmentID.Type]
193+
var types: [any AlignmentID.Type]
194+
}
195+
196+
private let bits: UInt
197+
198+
package var id: any AlignmentID.Type {
199+
Self.typeCache.types[index]
199200
}
200201

201-
init(id: AlignmentID.Type, axis _: Axis) {
202-
let index: UInt
203-
if let value = AlignmentKey.typeCache.typeIDs[ObjectIdentifier(id)] {
204-
index = value
205-
} else {
206-
index = UInt(AlignmentKey.typeCache.types.count)
207-
AlignmentKey.typeCache.types.append(id)
208-
AlignmentKey.typeCache.typeIDs[ObjectIdentifier(id)] = index
202+
package var axis: Axis { bits & 1 == 0 ? .horizontal : .vertical }
203+
204+
@inline(__always)
205+
var index: Int { Int(bits / 2 - 1) }
206+
207+
package init(id: AlignmentID.Type, axis: Axis) {
208+
let index = Self.$typeCache.access { cache in
209+
let identifier = ObjectIdentifier(id)
210+
if let value = cache.typeIDs[identifier] {
211+
return value
212+
} else {
213+
let index = UInt(cache.types.count)
214+
cache.types.append(id)
215+
cache.typeIDs[identifier] = index
216+
return index
217+
}
209218
}
210-
bits = index * 2 + 3
219+
bits = (axis == .horizontal ? 0 : 1) + (index + 1) * 2
220+
}
221+
222+
package init() { bits = .zero }
223+
224+
public static func < (lhs: AlignmentKey, rhs: AlignmentKey) -> Bool {
225+
lhs.bits < rhs.bits
211226
}
212227

213-
var id: AlignmentID.Type {
214-
AlignmentKey.typeCache.types[Int(bits / 2 - 1)]
228+
package var fraction: CGFloat {
229+
let computer = LayoutComputer.defaultValue
230+
let dimensions = ViewDimensions(
231+
guideComputer: computer,
232+
size: .fixed(CGSize(width: 1.0, height: 1.0))
233+
)
234+
return id.defaultValue(in: dimensions)
235+
}
236+
}
237+
238+
// MARK: - AlignmentGuide [6.4.41]
239+
240+
package protocol AlignmentGuide: Equatable {
241+
var key: AlignmentKey { get }
242+
}
243+
244+
extension AlignmentGuide {
245+
package var fraction: CGFloat {
246+
key.fraction
215247
}
216248
}

Tests/OpenSwiftUICoreTests/Layout/Alignment/AlignmentGuideTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,45 @@ struct AlignmentIDTests {
5555
#expect(result2.isApproximatelyEqual(to: 3.0))
5656
}
5757
}
58+
59+
// MARK: - AlignmentKeyTests
60+
61+
struct AlignmentKeyTests {
62+
private struct ZeroAlignment: AlignmentID {
63+
static func defaultValue(in context: ViewDimensions) -> CGFloat {
64+
.zero
65+
}
66+
}
67+
68+
private struct SumAlignment: AlignmentID {
69+
static func defaultValue(in context: ViewDimensions) -> CGFloat {
70+
context.size.width + context.size.height
71+
}
72+
}
73+
74+
@Test
75+
func typeAndAxis() {
76+
let horizontalKey1 = AlignmentKey(id: ZeroAlignment.self, axis: .horizontal)
77+
let horizontalKey2 = AlignmentKey(id: SumAlignment.self, axis: .horizontal)
78+
let verticalKey1 = AlignmentKey(id: ZeroAlignment.self, axis: .vertical)
79+
let verticalKey2 = AlignmentKey(id: SumAlignment.self, axis: .vertical)
80+
81+
#expect(horizontalKey1.axis == .horizontal)
82+
#expect(horizontalKey2.axis == .horizontal)
83+
#expect(verticalKey1.axis == .vertical)
84+
#expect(verticalKey2.axis == .vertical)
85+
86+
#expect(horizontalKey1.id == ZeroAlignment.self)
87+
#expect(verticalKey1.id == ZeroAlignment.self)
88+
#expect(horizontalKey2.id == SumAlignment.self)
89+
#expect(verticalKey2.id == SumAlignment.self)
90+
}
91+
92+
@Test
93+
func fraction() {
94+
let key1 = AlignmentKey(id: ZeroAlignment.self, axis: .horizontal)
95+
let key2 = AlignmentKey(id: SumAlignment.self, axis: .horizontal)
96+
#expect(key1.fraction.isApproximatelyEqual(to: .zero))
97+
#expect(key2.fraction.isApproximatelyEqual(to: 2.0))
98+
}
99+
}

0 commit comments

Comments
 (0)