@@ -706,7 +706,11 @@ extension Layout {
706
706
layoutContext ctx: SizeAndSpacingContext ,
707
707
children: LayoutProxyCollection
708
708
) where R: StatefulRule , R. Value == LayoutComputer {
709
- preconditionFailure ( " TODO " )
709
+ rule. update { ( engine: inout ViewLayoutEngine < Self > ) in
710
+ engine. update ( layout: self , context: ctx, children: children)
711
+ } create: {
712
+ ViewLayoutEngine ( layout: self , context: ctx, children: children)
713
+ }
710
714
}
711
715
712
716
public static var layoutProperties : LayoutProperties {
@@ -1118,6 +1122,165 @@ extension ViewSpacing: CustomStringConvertible {
1118
1122
}
1119
1123
}
1120
1124
1125
+ // MARK: - DefaultAlignmentFunction [6.4.41]
1126
+
1127
+ private protocol DefaultAlignmentFunction {
1128
+ static func defaultAlignment(
1129
+ _ key: AlignmentKey ,
1130
+ size: ViewSize ,
1131
+ data: UnsafeMutableRawPointer
1132
+ ) -> CGFloat ?
1133
+ }
1134
+
1135
+ // MARK: - ViewLayoutEngine [6.4.41] [WIP]
1136
+
1137
+ struct ViewLayoutEngine < L> : DefaultAlignmentFunction , LayoutEngine where L: Layout {
1138
+ var layout : L
1139
+
1140
+ var cache : L . Cache
1141
+
1142
+ var proxies : LayoutProxyCollection
1143
+
1144
+ var layoutDirection : LayoutDirection
1145
+
1146
+ var sizeCache : ViewSizeCache = . init( )
1147
+
1148
+ var cachedAlignmentSize : ViewSize = . zero
1149
+
1150
+ var cachedAlignmentGeometry : [ ViewGeometry ] = [ ]
1151
+
1152
+ var cachedAlignment : Cache3 < ObjectIdentifier , CGFloat ? > = . init( )
1153
+
1154
+ var preferredSpacing : ViewSpacing ?
1155
+
1156
+ init (
1157
+ layout: L ,
1158
+ context ctx: SizeAndSpacingContext ,
1159
+ children: LayoutProxyCollection
1160
+ ) {
1161
+ self . proxies = children
1162
+ self . layoutDirection = ctx. layoutDirection
1163
+ self . layout = layout
1164
+ self . cache = layout. makeCache (
1165
+ subviews: LayoutSubviews (
1166
+ context: children. context,
1167
+ storage: . direct( children. attributes) ,
1168
+ layoutDirection: layoutDirection
1169
+ )
1170
+ )
1171
+ }
1172
+
1173
+ mutating func update(
1174
+ layout: L ,
1175
+ context ctx: SizeAndSpacingContext ,
1176
+ children: LayoutProxyCollection
1177
+ ) {
1178
+ self . proxies = children
1179
+ self . layoutDirection = ctx. layoutDirection
1180
+ self . layout = layout
1181
+ self . sizeCache = . init( )
1182
+ self . cachedAlignmentGeometry = [ ]
1183
+ self . cachedAlignment = . init( )
1184
+ self . preferredSpacing = nil
1185
+ layout. updateCache (
1186
+ & cache,
1187
+ subviews: LayoutSubviews (
1188
+ context: proxies. context,
1189
+ storage: . direct( proxies. attributes) ,
1190
+ layoutDirection: layoutDirection
1191
+ )
1192
+ )
1193
+ }
1194
+
1195
+ func layoutPriority( ) -> Double {
1196
+ proxies. attributes. isEmpty ? - Double. infinity : Double . zero
1197
+ }
1198
+
1199
+ mutating func spacing( ) -> Spacing {
1200
+ guard let preferredSpacing else {
1201
+ let subviews = LayoutSubviews (
1202
+ context: proxies. context,
1203
+ storage: . direct( proxies. attributes) ,
1204
+ layoutDirection: layoutDirection
1205
+ )
1206
+ let spacing = layout. spacing ( subviews: subviews, cache: & cache)
1207
+ preferredSpacing = spacing
1208
+ return spacing. spacing
1209
+ }
1210
+ return preferredSpacing. spacing
1211
+ }
1212
+
1213
+ mutating func sizeThatFits( _ proposedSize: _ProposedSize ) -> CGSize {
1214
+ sizeCache. get ( proposedSize) {
1215
+ layout. sizeThatFits (
1216
+ proposal: ProposedViewSize ( proposedSize) ,
1217
+ subviews: LayoutSubviews (
1218
+ context: proxies. context,
1219
+ storage: . direct( proxies. attributes) ,
1220
+ layoutDirection: layoutDirection
1221
+ ) ,
1222
+ cache: & cache
1223
+ )
1224
+ }
1225
+ }
1226
+
1227
+ mutating func childGeometries( at parentSize: ViewSize , origin: CGPoint ) -> [ ViewGeometry ] {
1228
+ preconditionFailure ( " TODO " )
1229
+ }
1230
+
1231
+ mutating func explicitAlignment( _ k: AlignmentKey , at viewSize: ViewSize ) -> CGFloat ? {
1232
+ if cachedAlignmentSize != viewSize {
1233
+ cachedAlignmentSize = viewSize
1234
+ cachedAlignmentGeometry = [ ]
1235
+ cachedAlignment = . init( )
1236
+ }
1237
+ let key = ObjectIdentifier ( k. id)
1238
+ guard let value = cachedAlignment. find ( key) else {
1239
+ let value = withUnsafePointer ( to: self ) { ptr in
1240
+ Self . defaultAlignment ( k, size: viewSize, data: UnsafeMutableRawPointer ( mutating: ptr) )
1241
+ }
1242
+ cachedAlignment. put ( key, value: value)
1243
+ return value
1244
+ }
1245
+ return value
1246
+ }
1247
+
1248
+ static func defaultAlignment( _ key: AlignmentKey , size: ViewSize , data: UnsafeMutableRawPointer ) -> CGFloat ? {
1249
+ guard size. value. isFinite else {
1250
+ return nil
1251
+ }
1252
+ let enginePtr = data. assumingMemoryBound ( to: Self . self)
1253
+
1254
+ let proxies = enginePtr. pointee. proxies
1255
+ let oldAlignmentGeometry = enginePtr. pointee. cachedAlignmentGeometry
1256
+ let alignmentGeometry : [ ViewGeometry ]
1257
+ if oldAlignmentGeometry. count == proxies. count {
1258
+ alignmentGeometry = oldAlignmentGeometry
1259
+ } else {
1260
+ alignmentGeometry = enginePtr. pointee. childGeometries ( at: size, origin: . zero)
1261
+ enginePtr. pointee. cachedAlignmentGeometry = alignmentGeometry
1262
+ }
1263
+ var result : CGFloat ? = nil
1264
+ guard !alignmentGeometry. isEmpty else {
1265
+ return nil
1266
+ }
1267
+ var n = 0
1268
+ for (index, proxy) in proxies. enumerated ( ) {
1269
+ let geometry = alignmentGeometry [ index]
1270
+ guard let value = proxy. layoutComputer. explicitAlignment (
1271
+ key,
1272
+ at: geometry. dimensions. size
1273
+ ) else {
1274
+ continue
1275
+ }
1276
+ let origin = key. axis == . horizontal ? geometry. origin. x : geometry. origin. y
1277
+ key. id. _combineExplicit ( childValue: origin + value, n, into: & result)
1278
+ n += 1
1279
+ }
1280
+ return result
1281
+ }
1282
+ }
1283
+
1121
1284
// MARK: - LayoutSubviews
1122
1285
1123
1286
/// A collection of proxy values that represent the subviews of a layout view.
@@ -1152,7 +1315,7 @@ public struct LayoutSubviews: Equatable, RandomAccessCollection, Sendable {
1152
1315
1153
1316
var context : AnyRuleContext
1154
1317
1155
- private enum Storage : Equatable {
1318
+ fileprivate enum Storage : Equatable {
1156
1319
case direct( [ LayoutProxyAttributes ] )
1157
1320
case indirect( [ IndexedAttributes ] )
1158
1321
@@ -1170,7 +1333,7 @@ public struct LayoutSubviews: Equatable, RandomAccessCollection, Sendable {
1170
1333
}
1171
1334
}
1172
1335
1173
- private var storage : Storage
1336
+ fileprivate var storage : Storage
1174
1337
1175
1338
/// The layout direction inherited by the container view.
1176
1339
///
@@ -1450,9 +1613,27 @@ public struct LayoutSubview: Equatable {
1450
1613
@available ( * , unavailable)
1451
1614
extension LayoutSubview : Sendable { }
1452
1615
1453
- // MARK: - PlacementData [WIP]
1616
+ // MARK: - PlacementData [6.4.41] [WIP]
1617
+
1618
+ private struct PlacementData {
1619
+ var geometrys : [ ViewGeometry ]
1620
+
1621
+ var invalidCount : Int
1454
1622
1455
- private struct PlacementData { }
1623
+ var frame : CGRect
1624
+
1625
+ var layoutDirection : LayoutDirection
1626
+
1627
+ mutating func setGeometry( _ geometry: ViewGeometry , at index: Int , layoutDirection: LayoutDirection ) {
1628
+ if geometrys [ index] . isInvalid {
1629
+ invalidCount += 1
1630
+ }
1631
+ geometrys [ index] = geometry
1632
+ if layoutDirection != self . layoutDirection {
1633
+ geometrys [ index] . origin. x = frame. maxX - ( geometry. frame. maxX - frame. x)
1634
+ }
1635
+ }
1636
+ }
1456
1637
1457
1638
// MARK: - LayoutValueKey
1458
1639
@@ -1692,7 +1873,7 @@ package struct AnyLayoutProperties: Rule, AsyncAttribute {
1692
1873
}
1693
1874
}
1694
1875
1695
- // MARK: - ViewSizeCache
1876
+ // MARK: - ViewSizeCache [6.4.41]
1696
1877
1697
1878
/// A cache for storing and retrieving view sizes based on proposed size values.
1698
1879
///
@@ -1719,7 +1900,16 @@ package struct ViewSizeCache {
1719
1900
/// - Returns: The cached or newly computed size.
1720
1901
@inline ( __always)
1721
1902
package mutating func get( _ k: _ProposedSize , makeValue: ( ) -> CGSize ) -> CGSize {
1722
- cache. get ( ProposedViewSize ( k) , makeValue: makeValue)
1903
+ let key = ProposedViewSize ( k)
1904
+ if let value = cache. find ( key) {
1905
+ LayoutTrace . traceCacheLookup ( k, true )
1906
+ return value
1907
+ } else {
1908
+ LayoutTrace . traceCacheLookup ( k, false )
1909
+ let value = makeValue ( )
1910
+ cache. put ( key, value: value)
1911
+ return value
1912
+ }
1723
1913
}
1724
1914
}
1725
1915
0 commit comments