@@ -352,12 +352,15 @@ public class KeyPath<Root, Value>: PartialKeyPath<Root> {
352352 var isBreak = false
353353 let ( rawComponent, _) = buffer. next ( )
354354
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+ }
361364 }
362365
363366 let maxSize = buffer. maxSize
@@ -385,37 +388,28 @@ public class KeyPath<Root, Value>: PartialKeyPath<Root> {
385388
386389 func projectCurrent< Current> ( _: Current . Type ) {
387390 func projectNew< New> ( _: New . Type ) {
388- let newBase = currentValueBuffer. withMemoryRebound (
391+ let base = currentValueBuffer. withMemoryRebound (
389392 to: Current . self
390393 ) {
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,
393400 to: New . self,
394401 endingWith: Value . self,
395- & isBreak
402+ & isBreak,
403+ pointer: $0. baseAddress. _unsafelyUnwrappedUnchecked
396404 )
397405 }
398406
399407 // If we've broken from the projection, it means we found nil
400408 // while optional chaining.
401409 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-
412410 return
413411 }
414412
415- currentValueBuffer. withMemoryRebound ( to: New . self) {
416- $0. initializeElement ( at: 0 , to: newBase)
417- }
418-
419413 currentType = newType
420414
421415 if isLast {
@@ -564,25 +558,26 @@ public class ReferenceWritableKeyPath<
564558 func projectCurrent< Current> ( _: Current . Type ) {
565559 var isBreak = false
566560
567- let newBase = currentValueBuffer. withMemoryRebound (
561+ let base = currentValueBuffer. withMemoryRebound (
568562 to: Current . self
569563 ) {
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,
572570 to: New . self,
573571 endingWith: Value . self,
574- & isBreak
572+ & isBreak,
573+ pointer: $0. baseAddress. _unsafelyUnwrappedUnchecked
575574 )
576575 }
577576
578577 guard _fastPath ( !isBreak) else {
579578 _preconditionFailure ( " should not have stopped key path projection " )
580579 }
581580
582- currentValueBuffer. withMemoryRebound ( to: New . self) {
583- $0. initializeElement ( at: 0 , to: newBase)
584- }
585-
586581 currentType = nextType
587582 }
588583
@@ -1781,41 +1776,23 @@ internal struct RawKeyPathComponent {
17811776 count: buffer. count - componentSize)
17821777 }
17831778
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-
18011779 internal func _projectReadOnly< CurValue, NewValue, LeafValue> (
18021780 _ base: CurValue ,
18031781 to: NewValue . Type ,
18041782 endingWith: LeafValue . Type ,
1805- _ isBreak: inout Bool
1806- ) -> NewValue {
1783+ _ isBreak: inout Bool ,
1784+ pointer: UnsafeMutablePointer < NewValue >
1785+ ) {
18071786 switch value {
18081787 case . struct( let offset) :
1809- let newValue = _withUnprotectedUnsafeBytes ( of: base) {
1788+ _withUnprotectedUnsafeBytes ( of: base) {
18101789 let p = $0. baseAddress. _unsafelyUnwrappedUnchecked + offset
18111790
18121791 // The contents of the struct should be well-typed, so we can assume
18131792 // typed memory here.
1814- return p. assumingMemoryBound ( to: NewValue . self) . pointee
1793+ pointer . initialize ( to : p. assumingMemoryBound ( to: NewValue . self) . pointee)
18151794 }
18161795
1817- return newValue
1818-
18191796 case . class( let offset) :
18201797 _internalInvariant ( CurValue . self is AnyObject . Type ,
18211798 " base is not a class " )
@@ -1830,21 +1807,24 @@ internal struct RawKeyPathComponent {
18301807 // 'modify' access.
18311808 Builtin . performInstantaneousReadAccess ( offsetAddress. _rawValue,
18321809 NewValue . self)
1833- return offsetAddress. assumingMemoryBound ( to: NewValue . self) . pointee
1810+
1811+ pointer. initialize (
1812+ to: offsetAddress. assumingMemoryBound ( to: NewValue . self) . pointee
1813+ )
18341814
18351815 case . get( id: _, accessors: let accessors, argument: let argument) ,
18361816 . mutatingGetSet( id: _, accessors: let accessors, argument: let argument) ,
18371817 . nonmutatingGetSet( id: _, accessors: let accessors, argument: let argument) :
18381818 let getter : ComputedAccessorsPtr . Getter < CurValue , NewValue > = accessors. getter ( )
18391819
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+ )
18441826 )
18451827
1846- return newValue
1847-
18481828 case . optionalChain:
18491829 _internalInvariant ( CurValue . self == Optional< NewValue> . self ,
18501830 " should be unwrapping optional value " )
@@ -1857,17 +1837,21 @@ internal struct RawKeyPathComponent {
18571837 if _fastPath ( tag == 0 ) {
18581838 // Optional "shares" a layout with its Wrapped type meaning we can
18591839 // 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
18611842 }
18621843
18631844 // We found nil.
18641845 isBreak = true
18651846
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+ }
18711855
18721856 case . optionalForce:
18731857 _internalInvariant ( CurValue . self == Optional< NewValue> . self ,
@@ -1879,7 +1863,8 @@ internal struct RawKeyPathComponent {
18791863 if _fastPath ( tag == 0 ) {
18801864 // Optional "shares" a layout with its Wrapped type meaning we can
18811865 // 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
18831868 }
18841869
18851870 _preconditionFailure ( " unwrapped nil optional " )
@@ -1893,7 +1878,7 @@ internal struct RawKeyPathComponent {
18931878 let tag : UInt32 = 0
18941879 Builtin . injectEnumTag ( & new, tag. _value)
18951880
1896- return new
1881+ pointer . initialize ( to : new)
18971882 }
18981883 }
18991884
@@ -2657,12 +2642,19 @@ internal func _appendingKeyPaths<
26572642 // header, plus space for the middle type.
26582643 // Align up the root so that we can put the component type after it.
26592644 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
26622650 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.
26642655 resultSize = MemoryLayout< Int> . _roundingUpToAlignment( resultSize)
26652656 resultSize += MemoryLayout< Int> . size
2657+
26662658 // Immediately following is the tail-allocated space for the KVC string.
26672659 let totalResultSize = MemoryLayout< Int32>
26682660 . _roundingUpToAlignment( resultSize + appendedKVCLength)
@@ -2686,12 +2678,14 @@ internal func _appendingKeyPaths<
26862678 // Save space for the header.
26872679 let leafIsReferenceWritable = type ( of: leaf) . kind == . reference
26882680 destBuilder. pushHeader ( KeyPathBuffer . Header (
2689- size: componentSize - MemoryLayout < Int > . size ,
2681+ size: componentSize,
26902682 trivial: rootBuffer. trivial && leafBuffer. trivial,
26912683 hasReferencePrefix: rootBuffer. hasReferencePrefix
26922684 || 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
26952689 ) )
26962690
26972691 let leafHasReferencePrefix = leafBuffer. hasReferencePrefix
0 commit comments