@@ -158,7 +158,7 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
158
158
let base = UnsafeMutableRawPointer ( Builtin . projectTailElems ( keypath,
159
159
Int32 . self) )
160
160
body ( UnsafeMutableRawBufferPointer ( start: base, count: bytes) )
161
- keypath. _computeOffsetForPureStructKeypath ( )
161
+ keypath. _pureStructValueOffset = 0
162
162
return keypath
163
163
}
164
164
final internal func withBuffer< T> ( _ f: ( KeyPathBuffer ) throws -> T ) rethrows -> T {
@@ -173,7 +173,8 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
173
173
}
174
174
175
175
internal func isClass( _ item: Any . Type ) -> Bool {
176
- // Displays "warning: 'is' test is always true" at compile time, but that's not actually the case.
176
+ // Displays "warning: 'is' test is always true" at compile time,
177
+ // but that's not actually the case.
177
178
return ( item is AnyObject )
178
179
}
179
180
@@ -192,73 +193,14 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
192
193
let mirror = Mirror ( reflecting: unwrapType ( item) )
193
194
let description = mirror. description
194
195
let offsetOfFirstBracketForMirrorDescriptionOfTuple = 11
195
- let idx = description. index ( description. startIndex, offsetBy: offsetOfFirstBracketForMirrorDescriptionOfTuple)
196
+ let idx = description. index ( description. startIndex,
197
+ offsetBy: offsetOfFirstBracketForMirrorDescriptionOfTuple)
196
198
if description [ idx] == " ( " {
197
199
return true
198
200
}
199
201
return false
200
202
}
201
203
202
- // TODO: Merge the functionality of _computeOffsetForPureStructKeypath,
203
- // _recalculateOffsetForPureStructKeyPath() and _storedInlineOffset.
204
-
205
- // If this keypath traverses structs only, it'll have a predictable memory layout.
206
- // We can then jump to the value directly in _projectReadOnly().
207
- internal func _computeOffsetForPureStructKeypath( ) {
208
- _pureStructValueOffset = 0
209
- var isPureStruct = true
210
- var exitEarly = false
211
- defer {
212
- _isPureStructKeyPath = isPureStruct
213
- }
214
- withBuffer {
215
- var buffer = $0
216
- if buffer. data. isEmpty {
217
- if isClass ( Self . _rootAndValueType. root) {
218
- isPureStruct = false
219
- }
220
- } else {
221
- while !exitEarly {
222
- let ( rawComponent, optNextType) = buffer. next ( )
223
- if isTuple ( optNextType as Any ) {
224
- isPureStruct = false
225
- break
226
- }
227
- switch rawComponent. header. kind {
228
- case . struct:
229
- _pureStructValueOffset += rawComponent. _structOrClassOffset
230
- case . class, . computed, . optionalChain, . optionalForce, . optionalWrap, . external:
231
- isPureStruct = false
232
- exitEarly = true
233
- }
234
- if optNextType == nil {
235
- break
236
- }
237
- }
238
- }
239
- }
240
- }
241
-
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
- }
260
- }
261
-
262
204
@usableFromInline // Exposed as public API by MemoryLayout<Root>.offset(of:)
263
205
internal var _storedInlineOffset : Int ? {
264
206
return withBuffer {
@@ -2370,10 +2312,15 @@ extension _AppendKeyPath /* where Self == ReferenceWritableKeyPath<T,U> */ {
2370
2312
/// Note: Currently we only distinguish between keypaths that traverse only structs to get to the final value,
2371
2313
/// and all other types. This is done for performance reasons.
2372
2314
/// Other type information may be handled in the future to improve performance.
2373
- internal func _processAppendingKeyPathType( root: inout AnyKeyPath , leaf: AnyKeyPath ) {
2374
- root. _isPureStructKeyPath = root. isPureStructKeyPath && leaf. isPureStructKeyPath
2375
- if let isPureStruct = root. _isPureStructKeyPath, isPureStruct {
2376
- root. _computeOffsetForPureStructKeypath ( )
2315
+ internal func _processOffsetForAppendedKeyPath(
2316
+ appendedKeyPath: inout AnyKeyPath ,
2317
+ root: AnyKeyPath ,
2318
+ leaf: AnyKeyPath
2319
+ ) {
2320
+ appendedKeyPath. _isPureStructKeyPath = root. isPureStructKeyPath && leaf. isPureStructKeyPath
2321
+ if let isPureStruct = appendedKeyPath. _isPureStructKeyPath, isPureStruct {
2322
+ appendedKeyPath. _pureStructValueOffset = root. _pureStructValueOffset + leaf
2323
+ . _pureStructValueOffset
2377
2324
}
2378
2325
}
2379
2326
@@ -2403,11 +2350,10 @@ internal func _tryToAppendKeyPaths<Result: AnyKeyPath>(
2403
2350
}
2404
2351
return _openExistential ( rootValue, do: open2)
2405
2352
}
2406
- var returnValue : AnyKeyPath = _openExistential ( rootRoot, do: open)
2407
- _processAppendingKeyPathType ( root: & returnValue, leaf: leaf)
2408
- if let returnValue = returnValue as? Result
2409
- {
2410
- return returnValue
2353
+ var returnValue : AnyKeyPath = _openExistential ( rootRoot, do: open)
2354
+ _processOffsetForAppendedKeyPath ( appendedKeyPath: & returnValue, root: root, leaf: leaf)
2355
+ if let returnValue = returnValue as? Result {
2356
+ return returnValue
2411
2357
}
2412
2358
return nil
2413
2359
}
@@ -2555,7 +2501,7 @@ internal func _appendingKeyPaths<
2555
2501
return unsafeDowncast ( result, to: Result . self)
2556
2502
}
2557
2503
}
2558
- _processAppendingKeyPathType ( root : & returnValue, leaf: leaf)
2504
+ _processOffsetForAppendedKeyPath ( appendedKeyPath : & returnValue, root : root , leaf: leaf)
2559
2505
return returnValue as! Result
2560
2506
}
2561
2507
@@ -2639,12 +2585,33 @@ public func _swift_getKeyPath(pattern: UnsafeMutableRawPointer,
2639
2585
let ( keyPathClass, rootType, size, _)
2640
2586
= _getKeyPathClassAndInstanceSizeFromPattern ( patternPtr, arguments)
2641
2587
2588
+ var offset = UInt32 ( 0 )
2589
+ var isPureStruct = true
2590
+ var keyPathBase : Any . Type ?
2642
2591
// Allocate the instance.
2643
2592
let instance = keyPathClass. _create ( capacityInBytes: size) { instanceData in
2644
2593
// Instantiate the pattern into the instance.
2645
- _instantiateKeyPathBuffer ( patternPtr, instanceData, rootType, arguments)
2594
+ let returnValue = _instantiateKeyPathBuffer ( patternPtr, instanceData, rootType, arguments)
2595
+ offset += returnValue. structOffset
2596
+
2597
+ let booleans = returnValue. componentStructList
2598
+ if ( booleans. count == 0 ) {
2599
+ isPureStruct = false
2600
+ }
2601
+ for value in booleans {
2602
+ isPureStruct = isPureStruct && value
2603
+ }
2604
+ keyPathBase = rootType
2646
2605
}
2647
2606
2607
+ // TODO: See if there's a better way to eliminate
2608
+ // tuples from the current `isPureStruct` optimization.
2609
+ if let keyPathBase = keyPathBase, instance. isTuple ( keyPathBase) {
2610
+ isPureStruct = false
2611
+ }
2612
+ instance. _pureStructValueOffset = Int ( offset)
2613
+ instance. _isPureStructKeyPath = isPureStruct
2614
+
2648
2615
// Adopt the KVC string from the pattern.
2649
2616
let kvcStringBase = patternPtr. advanced ( by: 12 )
2650
2617
let kvcStringOffset = kvcStringBase. load ( as: Int32 . self)
@@ -2848,6 +2815,10 @@ internal protocol KeyPathPatternVisitor {
2848
2815
mutating func visitIntermediateComponentType( metadataRef: MetadataReference )
2849
2816
2850
2817
mutating func finish( )
2818
+
2819
+ // Offset for pure-struct keypaths.
2820
+ var structOffset : UInt32 { get set }
2821
+ var isPureStruct : [ Bool ] { get set }
2851
2822
}
2852
2823
2853
2824
internal func _resolveRelativeAddress( _ base: UnsafeRawPointer ,
@@ -3175,6 +3146,8 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
3175
3146
var leaf : Any . Type !
3176
3147
var genericEnvironment : UnsafeRawPointer ?
3177
3148
let patternArgs : UnsafeRawPointer ?
3149
+ var structOffset : UInt32 = 0
3150
+ var isPureStruct : [ Bool ] = [ ]
3178
3151
3179
3152
init ( patternArgs: UnsafeRawPointer ? ) {
3180
3153
self . patternArgs = patternArgs
@@ -3382,6 +3355,8 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
3382
3355
var genericEnvironment : UnsafeRawPointer ?
3383
3356
let patternArgs : UnsafeRawPointer ?
3384
3357
var base : Any . Type
3358
+ var structOffset : UInt32 = 0
3359
+ var isPureStruct : [ Bool ] = [ ]
3385
3360
3386
3361
init ( destData: UnsafeMutableRawBufferPointer ,
3387
3362
patternArgs: UnsafeRawPointer ? ,
@@ -3454,6 +3429,12 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
3454
3429
mutable: Bool ,
3455
3430
offset: KeyPathPatternStoredOffset ) {
3456
3431
let previous = updatePreviousComponentAddr ( )
3432
+ switch kind {
3433
+ case . struct:
3434
+ isPureStruct. append ( true )
3435
+ default :
3436
+ isPureStruct. append ( false )
3437
+ }
3457
3438
switch kind {
3458
3439
case . class:
3459
3440
// A mutable class property can end the reference prefix.
@@ -3470,6 +3451,12 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
3470
3451
mutable: mutable,
3471
3452
inlineOffset: value)
3472
3453
pushDest ( header)
3454
+ switch kind {
3455
+ case . struct:
3456
+ structOffset += value
3457
+ default :
3458
+ break
3459
+ }
3473
3460
case . outOfLine( let offset) :
3474
3461
let header = RawKeyPathComponent . Header ( storedWithOutOfLineOffset: kind,
3475
3462
mutable: mutable)
@@ -3515,6 +3502,7 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
3515
3502
setter: UnsafeRawPointer ? ,
3516
3503
arguments: KeyPathPatternComputedArguments ? ,
3517
3504
externalArgs: UnsafeBufferPointer < Int32 > ? ) {
3505
+ isPureStruct. append ( false )
3518
3506
let previous = updatePreviousComponentAddr ( )
3519
3507
let settable = setter != nil
3520
3508
// A nonmutating settable property can end the reference prefix.
@@ -3654,22 +3642,26 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
3654
3642
}
3655
3643
3656
3644
mutating func visitOptionalChainComponent( ) {
3645
+ isPureStruct. append ( false )
3657
3646
let _ = updatePreviousComponentAddr ( )
3658
3647
let header = RawKeyPathComponent . Header ( optionalChain: ( ) )
3659
3648
pushDest ( header)
3660
3649
}
3661
3650
mutating func visitOptionalWrapComponent( ) {
3651
+ isPureStruct. append ( false )
3662
3652
let _ = updatePreviousComponentAddr ( )
3663
3653
let header = RawKeyPathComponent . Header ( optionalWrap: ( ) )
3664
3654
pushDest ( header)
3665
3655
}
3666
3656
mutating func visitOptionalForceComponent( ) {
3657
+ isPureStruct. append ( false )
3667
3658
let _ = updatePreviousComponentAddr ( )
3668
3659
let header = RawKeyPathComponent . Header ( optionalForce: ( ) )
3669
3660
pushDest ( header)
3670
3661
}
3671
3662
3672
3663
mutating func visitIntermediateComponentType( metadataRef: MetadataReference ) {
3664
+ isPureStruct. append ( false )
3673
3665
// Get the metadata for the intermediate type.
3674
3666
let metadata = _resolveKeyPathMetadataReference (
3675
3667
metadataRef,
@@ -3694,6 +3686,8 @@ internal struct ValidatingInstantiateKeyPathBuffer: KeyPathPatternVisitor {
3694
3686
var sizeVisitor : GetKeyPathClassAndInstanceSizeFromPattern
3695
3687
var instantiateVisitor : InstantiateKeyPathBuffer
3696
3688
let origDest : UnsafeMutableRawPointer
3689
+ var structOffset : UInt32 = 0
3690
+ var isPureStruct : [ Bool ] = [ ]
3697
3691
3698
3692
init ( sizeVisitor: GetKeyPathClassAndInstanceSizeFromPattern ,
3699
3693
instantiateVisitor: InstantiateKeyPathBuffer ) {
@@ -3795,7 +3789,7 @@ internal func _instantiateKeyPathBuffer(
3795
3789
_ origDestData: UnsafeMutableRawBufferPointer ,
3796
3790
_ rootType: Any . Type ,
3797
3791
_ arguments: UnsafeRawPointer
3798
- ) {
3792
+ ) -> ( structOffset : UInt32 , componentStructList : [ Bool ] ) {
3799
3793
let destHeaderPtr = origDestData. baseAddress. unsafelyUnwrapped
3800
3794
var destData = UnsafeMutableRawBufferPointer (
3801
3795
start: destHeaderPtr. advanced ( by: MemoryLayout< Int> . size) ,
@@ -3847,6 +3841,7 @@ internal func _instantiateKeyPathBuffer(
3847
3841
endOfReferencePrefixComponent. storeBytes ( of: componentHeader,
3848
3842
as: RawKeyPathComponent . Header. self)
3849
3843
}
3844
+ return ( walker. structOffset, walker. isPureStruct)
3850
3845
}
3851
3846
3852
3847
#if SWIFT_ENABLE_REFLECTION
0 commit comments