@@ -454,33 +454,42 @@ extension _CocoaDictionary: _DictionaryBuffer {
454
454
internal var startIndex : Index {
455
455
@_effects ( releasenone)
456
456
get {
457
- return Index ( self , startIndex: ( ) )
457
+ let allKeys = _stdlib_NSDictionary_allKeys ( self . object)
458
+ return Index ( Index . Storage ( self , allKeys, 0 ) )
458
459
}
459
460
}
460
461
461
462
@usableFromInline // FIXME(cocoa-index): Should be inlinable
462
463
internal var endIndex : Index {
463
464
@_effects ( releasenone)
464
465
get {
465
- return Index ( self , endIndex: ( ) )
466
+ let allKeys = _stdlib_NSDictionary_allKeys ( self . object)
467
+ return Index ( Index . Storage ( self , allKeys, allKeys. value) )
466
468
}
467
469
}
468
470
469
471
@usableFromInline // FIXME(cocoa-index): Should be inlinable
470
472
@_effects ( releasenone)
471
- internal func index( after i: Index ) -> Index {
472
- var i = i
473
- formIndex ( after: & i)
474
- return i
473
+ internal func index( after index: Index ) -> Index {
474
+ var result = index
475
+ formIndex ( after: & result)
476
+ return result
477
+ }
478
+
479
+ internal func validate( _ index: Index ) {
480
+ _precondition ( index. storage. base. object === self . object, " Invalid index " )
481
+ _precondition ( index. storage. currentKeyIndex < index. storage. allKeys. value,
482
+ " Attempt to access endIndex " )
475
483
}
476
484
477
485
@usableFromInline // FIXME(cocoa-index): Should be inlinable
478
486
@_effects ( releasenone)
479
- internal func formIndex( after i: inout Index ) {
480
- _precondition ( i. base. object === self . object, " Invalid index " )
481
- _precondition ( i. currentKeyIndex < i. allKeys. value,
482
- " Cannot increment endIndex " )
483
- i. currentKeyIndex += 1
487
+ internal func formIndex( after index: inout Index ) {
488
+ validate ( index)
489
+ let isUnique = index. isUniquelyReferenced ( )
490
+ if !isUnique { index. storage = index. copy ( ) }
491
+ let storage = index. storage // FIXME: rdar://problem/44863751
492
+ storage. currentKeyIndex += 1
484
493
}
485
494
486
495
@usableFromInline // FIXME(cocoa-index): Should be inlinable
@@ -495,16 +504,13 @@ extension _CocoaDictionary: _DictionaryBuffer {
495
504
}
496
505
497
506
let allKeys = _stdlib_NSDictionary_allKeys ( object)
498
- var keyIndex = - 1
499
507
for i in 0 ..< allKeys. value {
500
508
if _stdlib_NSObject_isEqual ( key, allKeys [ i] ) {
501
- keyIndex = i
502
- break
509
+ return Index ( Index . Storage ( self , allKeys, i) )
503
510
}
504
511
}
505
- _sanityCheck ( keyIndex >= 0 ,
506
- " Key was found in fast path, but not found later? " )
507
- return Index ( self , allKeys, keyIndex)
512
+ _sanityCheckFailure (
513
+ " An NSDictionary key wassn't listed amongst its enumerated contents " )
508
514
}
509
515
510
516
@inlinable
@@ -527,25 +533,25 @@ extension _CocoaDictionary: _DictionaryBuffer {
527
533
@usableFromInline // FIXME(cocoa-index): Should be inlinable
528
534
@_effects ( releasenone)
529
535
internal func lookup( _ index: Index ) -> ( key: Key , value: Value ) {
530
- _precondition ( index. base. object === self . object, " Invalid index " )
531
- let key : Key = index. allKeys [ index. currentKeyIndex]
532
- let value : Value = index. base. object. object ( forKey: key) !
536
+ _precondition ( index. storage . base. object === self . object, " Invalid index " )
537
+ let key : Key = index. storage . allKeys [ index. storage . currentKeyIndex]
538
+ let value : Value = index. storage . base. object. object ( forKey: key) !
533
539
return ( key, value)
534
540
}
535
541
536
542
@usableFromInline // FIXME(cocoa-index): Make inlinable
537
543
@_effects ( releasenone)
538
544
func key( at index: Index ) -> Key {
539
- _precondition ( index. base. object === self . object, " Invalid index " )
545
+ _precondition ( index. storage . base. object === self . object, " Invalid index " )
540
546
return index. key
541
547
}
542
548
543
549
@usableFromInline // FIXME(cocoa-index): Make inlinable
544
550
@_effects ( releasenone)
545
551
func value( at index: Index ) -> Value {
546
- _precondition ( index. base. object === self . object, " Invalid index " )
547
- let key = index. allKeys [ index. currentKeyIndex]
548
- return index. base. object. object ( forKey: key) !
552
+ _precondition ( index. storage . base. object === self . object, " Invalid index " )
553
+ let key = index. storage . allKeys [ index. storage . currentKeyIndex]
554
+ return index. storage . base. object. object ( forKey: key) !
549
555
}
550
556
}
551
557
@@ -565,10 +571,23 @@ extension _CocoaDictionary {
565
571
}
566
572
567
573
extension _CocoaDictionary {
568
- // FIXME(cocoa-index): Overhaul and make @_fixed_layout
574
+ @_fixed_layout
569
575
@usableFromInline
570
576
internal struct Index {
571
- // Assumption: we rely on NSDictionary.getObjects when being
577
+ @usableFromInline
578
+ internal var storage : Storage
579
+
580
+ internal init ( _ storage: Storage ) {
581
+ self . storage = storage
582
+ }
583
+ }
584
+ }
585
+
586
+ extension _CocoaDictionary . Index {
587
+ // FIXME(cocoa-index): Try using an NSEnumerator to speed this up.
588
+ @usableFromInline
589
+ internal class Storage {
590
+ // Assumption: we rely on NSDictionary.getObjects when being
572
591
// repeatedly called on the same NSDictionary, returning items in the same
573
592
// order every time.
574
593
// Similarly, the same assumption holds for NSSet.allObjects.
@@ -586,18 +605,6 @@ extension _CocoaDictionary {
586
605
/// Index into `allKeys`
587
606
internal var currentKeyIndex : Int
588
607
589
- internal init ( _ base: __owned _CocoaDictionary, startIndex: ( ) ) {
590
- self . base = base
591
- self . allKeys = _stdlib_NSDictionary_allKeys ( base. object)
592
- self . currentKeyIndex = 0
593
- }
594
-
595
- internal init ( _ base: __owned _CocoaDictionary, endIndex: ( ) ) {
596
- self . base = base
597
- self . allKeys = _stdlib_NSDictionary_allKeys ( base. object)
598
- self . currentKeyIndex = allKeys. value
599
- }
600
-
601
608
internal init (
602
609
_ base: __owned _CocoaDictionary,
603
610
_ allKeys: __owned _HeapBuffer< Int , AnyObject > ,
@@ -610,15 +617,28 @@ extension _CocoaDictionary {
610
617
}
611
618
}
612
619
620
+ extension _CocoaDictionary . Index {
621
+ @inlinable
622
+ internal mutating func isUniquelyReferenced( ) -> Bool {
623
+ return _isUnique_native ( & storage)
624
+ }
625
+
626
+ @usableFromInline
627
+ internal mutating func copy( ) -> Storage {
628
+ let storage = self . storage
629
+ return Storage ( storage. base, storage. allKeys, storage. currentKeyIndex)
630
+ }
631
+ }
632
+
613
633
extension _CocoaDictionary . Index {
614
634
@usableFromInline // FIXME(cocoa-index): Make inlinable
615
635
@nonobjc
616
636
internal var key : AnyObject {
617
637
@_effects ( readonly)
618
638
get {
619
- _precondition ( currentKeyIndex < allKeys. value,
639
+ _precondition ( storage . currentKeyIndex < storage . allKeys. value,
620
640
" Attempting to access Dictionary elements using an invalid index " )
621
- return allKeys [ currentKeyIndex]
641
+ return storage . allKeys [ storage . currentKeyIndex]
622
642
}
623
643
}
624
644
@@ -627,7 +647,7 @@ extension _CocoaDictionary.Index {
627
647
internal var age : Int32 {
628
648
@_effects ( readonly)
629
649
get {
630
- return _HashTable. age ( for: base. object)
650
+ return _HashTable. age ( for: storage . base. object)
631
651
}
632
652
}
633
653
}
@@ -639,9 +659,9 @@ extension _CocoaDictionary.Index: Equatable {
639
659
lhs: _CocoaDictionary . Index ,
640
660
rhs: _CocoaDictionary . Index
641
661
) -> Bool {
642
- _precondition ( lhs. base. object === rhs. base. object,
662
+ _precondition ( lhs. storage . base. object === rhs. storage . base. object,
643
663
" Comparing indexes from different dictionaries " )
644
- return lhs. currentKeyIndex == rhs. currentKeyIndex
664
+ return lhs. storage . currentKeyIndex == rhs. storage . currentKeyIndex
645
665
}
646
666
}
647
667
@@ -652,9 +672,9 @@ extension _CocoaDictionary.Index: Comparable {
652
672
lhs: _CocoaDictionary . Index ,
653
673
rhs: _CocoaDictionary . Index
654
674
) -> Bool {
655
- _precondition ( lhs. base. object === rhs. base. object,
675
+ _precondition ( lhs. storage . base. object === rhs. storage . base. object,
656
676
" Comparing indexes from different dictionaries " )
657
- return lhs. currentKeyIndex < rhs. currentKeyIndex
677
+ return lhs. storage . currentKeyIndex < rhs. storage . currentKeyIndex
658
678
}
659
679
}
660
680
0 commit comments