@@ -199,12 +199,15 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
199
199
return false
200
200
}
201
201
202
+ // TODO: Merge the functionality of _computeOffsetForPureStructKeypath,
203
+ // _recalculateOffsetForPureStructKeyPath() and _storedInlineOffset.
204
+
202
205
// If this keypath traverses structs only, it'll have a predictable memory layout.
203
206
// We can then jump to the value directly in _projectReadOnly().
204
- internal func _computeOffsets ( ) -> ( offset : Int , isPureStruct : Bool , isTuple : Bool ) {
207
+ internal func _computeOffsetForPureStructKeypath ( ) {
205
208
_pureStructValueOffset = 0
206
209
var isPureStruct = true
207
- var _isTuple = false
210
+ var exitEarly = false
208
211
defer {
209
212
_isPureStructKeyPath = isPureStruct
210
213
}
@@ -215,43 +218,69 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
215
218
isPureStruct = false
216
219
}
217
220
} else {
218
- while true {
221
+ while !exitEarly {
219
222
let ( rawComponent, optNextType) = buffer. next ( )
220
223
if isTuple ( optNextType as Any ) {
221
224
isPureStruct = false
222
- _isTuple = true
225
+ break
223
226
}
224
227
switch rawComponent. header. kind {
225
228
case . struct:
226
229
_pureStructValueOffset += rawComponent. _structOrClassOffset
227
230
case . class, . computed, . optionalChain, . optionalForce, . optionalWrap, . external:
228
231
isPureStruct = false
232
+ exitEarly = true
229
233
}
230
234
if optNextType == nil {
231
235
break
232
236
}
233
237
}
234
238
}
235
239
}
236
- return ( _pureStructValueOffset, isPureStruct, _isTuple)
237
240
}
238
241
239
- internal func _computeOffsetForPureStructKeypath( ) {
240
- _ = _computeOffsets ( )
242
+ // Recalculates the offset in the case where one pure struct keypath is appended to another.
243
+ internal func _recalculateOffsetForPureStructKeyPath( ) {
244
+ _pureStructValueOffset = 0
245
+ withBuffer {
246
+ var buffer = $0
247
+ while true {
248
+ let ( rawComponent, optNextType) = buffer. next ( )
249
+ switch rawComponent. header. kind {
250
+ case . struct:
251
+ _pureStructValueOffset += rawComponent. _structOrClassOffset
252
+ case . class, . computed, . optionalChain, . optionalForce, . optionalWrap, . external:
253
+ return
254
+ }
255
+ if optNextType == nil {
256
+ break
257
+ }
258
+ }
259
+ }
241
260
}
242
261
243
- // This function was refactored since _computeOffsets() was performing
244
- // essentially the same computation.
245
262
@usableFromInline // Exposed as public API by MemoryLayout<Root>.offset(of:)
246
263
internal var _storedInlineOffset : Int ? {
247
- // TODO: Cache this value in a similar manner to _pureStructValueOffset.
248
- // The current design assumes keypath read and write operations will be called
249
- // much more often than MemoryLayout<Root>.offset(of:).
250
- let offsetInformation = _computeOffsets ( )
251
- if offsetInformation. isPureStruct || offsetInformation. isTuple {
252
- return . some( offsetInformation. offset)
253
- } else {
254
- return . none
264
+ return withBuffer {
265
+ var buffer = $0
266
+
267
+ // The identity key path is effectively a stored keypath of type Self
268
+ // at offset zero
269
+ if buffer. data. isEmpty { return 0 }
270
+
271
+ var offset = 0
272
+ while true {
273
+ let ( rawComponent, optNextType) = buffer. next ( )
274
+ switch rawComponent. header. kind {
275
+ case . struct:
276
+ offset += rawComponent. _structOrClassOffset
277
+
278
+ case . class, . computed, . optionalChain, . optionalForce, . optionalWrap, . external:
279
+ return . none
280
+ }
281
+
282
+ if optNextType == nil { return . some( offset) }
283
+ }
255
284
}
256
285
}
257
286
}
0 commit comments