@@ -352,12 +352,15 @@ public class KeyPath<Root, Value>: PartialKeyPath<Root> {
352
352
var isBreak = false
353
353
let ( rawComponent, _) = buffer. next ( )
354
354
355
- return rawComponent. _projectReadOnly (
356
- root,
357
- to: Value . self,
358
- endingWith: Value . self,
359
- & isBreak
360
- )
355
+ return Builtin . emplace {
356
+ rawComponent. _projectReadOnly (
357
+ root,
358
+ to: Value . self,
359
+ endingWith: Value . self,
360
+ & isBreak,
361
+ pointer: UnsafeMutablePointer < Value > ( $0)
362
+ )
363
+ }
361
364
}
362
365
363
366
let maxSize = buffer. maxSize
@@ -385,37 +388,28 @@ public class KeyPath<Root, Value>: PartialKeyPath<Root> {
385
388
386
389
func projectCurrent< Current> ( _: Current . Type ) {
387
390
func projectNew< New> ( _: New . Type ) {
388
- let newBase = currentValueBuffer. withMemoryRebound (
391
+ let base = currentValueBuffer. withMemoryRebound (
389
392
to: Current . self
390
393
) {
391
- return rawComponent. _projectReadOnly (
392
- $0. moveElement ( from: 0 ) ,
394
+ $0. moveElement ( from: 0 )
395
+ }
396
+
397
+ currentValueBuffer. withMemoryRebound ( to: New . self) {
398
+ rawComponent. _projectReadOnly (
399
+ base,
393
400
to: New . self,
394
401
endingWith: Value . self,
395
- & isBreak
402
+ & isBreak,
403
+ pointer: $0. baseAddress. _unsafelyUnwrappedUnchecked
396
404
)
397
405
}
398
406
399
407
// If we've broken from the projection, it means we found nil
400
408
// while optional chaining.
401
409
guard _fastPath ( !isBreak) else {
402
- var value : Value = Builtin . zeroInitializer ( )
403
-
404
- // Optional.none has a tag of 1
405
- let tag : UInt32 = 1
406
- Builtin . injectEnumTag ( & value, tag. _value)
407
-
408
- currentValueBuffer. withMemoryRebound ( to: Value . self) {
409
- $0. initializeElement ( at: 0 , to: value)
410
- }
411
-
412
410
return
413
411
}
414
412
415
- currentValueBuffer. withMemoryRebound ( to: New . self) {
416
- $0. initializeElement ( at: 0 , to: newBase)
417
- }
418
-
419
413
currentType = newType
420
414
421
415
if isLast {
@@ -564,25 +558,26 @@ public class ReferenceWritableKeyPath<
564
558
func projectCurrent< Current> ( _: Current . Type ) {
565
559
var isBreak = false
566
560
567
- let newBase = currentValueBuffer. withMemoryRebound (
561
+ let base = currentValueBuffer. withMemoryRebound (
568
562
to: Current . self
569
563
) {
570
- return rawComponent. _projectReadOnly (
571
- $0. moveElement ( from: 0 ) ,
564
+ $0. moveElement ( from: 0 )
565
+ }
566
+
567
+ currentValueBuffer. withMemoryRebound ( to: New . self) {
568
+ rawComponent. _projectReadOnly (
569
+ base,
572
570
to: New . self,
573
571
endingWith: Value . self,
574
- & isBreak
572
+ & isBreak,
573
+ pointer: $0. baseAddress. _unsafelyUnwrappedUnchecked
575
574
)
576
575
}
577
576
578
577
guard _fastPath ( !isBreak) else {
579
578
_preconditionFailure ( " should not have stopped key path projection " )
580
579
}
581
580
582
- currentValueBuffer. withMemoryRebound ( to: New . self) {
583
- $0. initializeElement ( at: 0 , to: newBase)
584
- }
585
-
586
581
currentType = nextType
587
582
}
588
583
@@ -1781,41 +1776,23 @@ internal struct RawKeyPathComponent {
1781
1776
count: buffer. count - componentSize)
1782
1777
}
1783
1778
1784
- internal enum ProjectionResult < NewValue, LeafValue> {
1785
- /// Continue projecting the key path with the given new value.
1786
- case `continue`( NewValue )
1787
- /// Stop projecting the key path and use the given value as the final
1788
- /// result of the projection.
1789
- case `break`( LeafValue )
1790
-
1791
- internal var assumingContinue : NewValue {
1792
- switch self {
1793
- case . continue( let x) :
1794
- return x
1795
- case . break:
1796
- _internalInvariantFailure ( " should not have stopped key path projection " )
1797
- }
1798
- }
1799
- }
1800
-
1801
1779
internal func _projectReadOnly< CurValue, NewValue, LeafValue> (
1802
1780
_ base: CurValue ,
1803
1781
to: NewValue . Type ,
1804
1782
endingWith: LeafValue . Type ,
1805
- _ isBreak: inout Bool
1806
- ) -> NewValue {
1783
+ _ isBreak: inout Bool ,
1784
+ pointer: UnsafeMutablePointer < NewValue >
1785
+ ) {
1807
1786
switch value {
1808
1787
case . struct( let offset) :
1809
- let newValue = _withUnprotectedUnsafeBytes ( of: base) {
1788
+ _withUnprotectedUnsafeBytes ( of: base) {
1810
1789
let p = $0. baseAddress. _unsafelyUnwrappedUnchecked + offset
1811
1790
1812
1791
// The contents of the struct should be well-typed, so we can assume
1813
1792
// typed memory here.
1814
- return p. assumingMemoryBound ( to: NewValue . self) . pointee
1793
+ pointer . initialize ( to : p. assumingMemoryBound ( to: NewValue . self) . pointee)
1815
1794
}
1816
1795
1817
- return newValue
1818
-
1819
1796
case . class( let offset) :
1820
1797
_internalInvariant ( CurValue . self is AnyObject . Type ,
1821
1798
" base is not a class " )
@@ -1830,21 +1807,24 @@ internal struct RawKeyPathComponent {
1830
1807
// 'modify' access.
1831
1808
Builtin . performInstantaneousReadAccess ( offsetAddress. _rawValue,
1832
1809
NewValue . self)
1833
- return offsetAddress. assumingMemoryBound ( to: NewValue . self) . pointee
1810
+
1811
+ pointer. initialize (
1812
+ to: offsetAddress. assumingMemoryBound ( to: NewValue . self) . pointee
1813
+ )
1834
1814
1835
1815
case . get( id: _, accessors: let accessors, argument: let argument) ,
1836
1816
. mutatingGetSet( id: _, accessors: let accessors, argument: let argument) ,
1837
1817
. nonmutatingGetSet( id: _, accessors: let accessors, argument: let argument) :
1838
1818
let getter : ComputedAccessorsPtr . Getter < CurValue , NewValue > = accessors. getter ( )
1839
1819
1840
- let newValue = getter (
1841
- base,
1842
- argument? . data. baseAddress ?? accessors. _value,
1843
- argument? . data. count ?? 0
1820
+ pointer. initialize (
1821
+ to: getter (
1822
+ base,
1823
+ argument? . data. baseAddress ?? accessors. _value,
1824
+ argument? . data. count ?? 0
1825
+ )
1844
1826
)
1845
1827
1846
- return newValue
1847
-
1848
1828
case . optionalChain:
1849
1829
_internalInvariant ( CurValue . self == Optional< NewValue> . self ,
1850
1830
" should be unwrapping optional value " )
@@ -1857,17 +1837,21 @@ internal struct RawKeyPathComponent {
1857
1837
if _fastPath ( tag == 0 ) {
1858
1838
// Optional "shares" a layout with its Wrapped type meaning we can
1859
1839
// reinterpret the base address as an address to its Wrapped value.
1860
- return Builtin . reinterpretCast ( base)
1840
+ pointer. initialize ( to: Builtin . reinterpretCast ( base) )
1841
+ return
1861
1842
}
1862
1843
1863
1844
// We found nil.
1864
1845
isBreak = true
1865
1846
1866
- // Return some zeroed out value for NewValue if we break. The caller will
1867
- // handle returning nil. We do this to prevent allocating metadata in this
1868
- // function because returning something like 'NewValue?' would need to
1869
- // allocate the optional metadata for 'NewValue'.
1870
- return Builtin . zeroInitializer ( )
1847
+ // Initialize the leaf optional value by simply injecting the tag (which
1848
+ // we've found to be 1) directly.
1849
+ pointer. withMemoryRebound ( to: LeafValue . self, capacity: 1 ) {
1850
+ Builtin . injectEnumTag (
1851
+ & $0. pointee,
1852
+ tag. _value
1853
+ )
1854
+ }
1871
1855
1872
1856
case . optionalForce:
1873
1857
_internalInvariant ( CurValue . self == Optional< NewValue> . self ,
@@ -1879,7 +1863,8 @@ internal struct RawKeyPathComponent {
1879
1863
if _fastPath ( tag == 0 ) {
1880
1864
// Optional "shares" a layout with its Wrapped type meaning we can
1881
1865
// reinterpret the base address as an address to its Wrapped value.
1882
- return Builtin . reinterpretCast ( base)
1866
+ pointer. initialize ( to: Builtin . reinterpretCast ( base) )
1867
+ return
1883
1868
}
1884
1869
1885
1870
_preconditionFailure ( " unwrapped nil optional " )
@@ -1893,7 +1878,7 @@ internal struct RawKeyPathComponent {
1893
1878
let tag : UInt32 = 0
1894
1879
Builtin . injectEnumTag ( & new, tag. _value)
1895
1880
1896
- return new
1881
+ pointer . initialize ( to : new)
1897
1882
}
1898
1883
}
1899
1884
@@ -2657,12 +2642,19 @@ internal func _appendingKeyPaths<
2657
2642
// header, plus space for the middle type.
2658
2643
// Align up the root so that we can put the component type after it.
2659
2644
let rootSize = MemoryLayout< Int> . _roundingUpToAlignment( rootBuffer. data. count)
2660
- var resultSize = rootSize + leafBuffer. data. count
2661
- + 2 * MemoryLayout< Int> . size
2645
+ var resultSize = rootSize + // Root component size
2646
+ leafBuffer. data. count + // Leaf component size
2647
+ MemoryLayout< Int> . size // Middle type
2648
+
2649
+ // Size of just our components is equal to root + leaf + middle
2662
2650
let componentSize = resultSize
2663
- // The first tail allocated member is the maxSize of the keypath.
2651
+
2652
+ resultSize += MemoryLayout< Int> . size // Header size (padding if needed)
2653
+
2654
+ // The first member after the components is the maxSize of the keypath.
2664
2655
resultSize = MemoryLayout< Int> . _roundingUpToAlignment( resultSize)
2665
2656
resultSize += MemoryLayout< Int> . size
2657
+
2666
2658
// Immediately following is the tail-allocated space for the KVC string.
2667
2659
let totalResultSize = MemoryLayout< Int32>
2668
2660
. _roundingUpToAlignment( resultSize + appendedKVCLength)
@@ -2686,12 +2678,14 @@ internal func _appendingKeyPaths<
2686
2678
// Save space for the header.
2687
2679
let leafIsReferenceWritable = type ( of: leaf) . kind == . reference
2688
2680
destBuilder. pushHeader ( KeyPathBuffer . Header (
2689
- size: componentSize - MemoryLayout < Int > . size ,
2681
+ size: componentSize,
2690
2682
trivial: rootBuffer. trivial && leafBuffer. trivial,
2691
2683
hasReferencePrefix: rootBuffer. hasReferencePrefix
2692
2684
|| leafIsReferenceWritable,
2693
- isSingleComponent: rootBuffer. isSingleComponent !=
2694
- leafBuffer. isSingleComponent
2685
+
2686
+ // We've already checked if either is an identity, so both have at
2687
+ // least 1 component.
2688
+ isSingleComponent: false
2695
2689
) )
2696
2690
2697
2691
let leafHasReferencePrefix = leafBuffer. hasReferencePrefix
0 commit comments