@@ -450,33 +450,50 @@ extension _CocoaDictionary: _DictionaryBuffer {
450
450
@usableFromInline
451
451
internal typealias Value = AnyObject
452
452
453
- @inlinable
453
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
454
454
internal var startIndex : Index {
455
- return Index ( self , startIndex: ( ) )
455
+ @_effects ( releasenone)
456
+ get {
457
+ let allKeys = _stdlib_NSDictionary_allKeys ( self . object)
458
+ return Index ( Index . Storage ( self , allKeys, 0 ) )
459
+ }
456
460
}
457
461
458
- @inlinable
462
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
459
463
internal var endIndex : Index {
460
- return Index ( self , endIndex: ( ) )
464
+ @_effects ( releasenone)
465
+ get {
466
+ let allKeys = _stdlib_NSDictionary_allKeys ( self . object)
467
+ return Index ( Index . Storage ( self , allKeys, allKeys. value) )
468
+ }
461
469
}
462
470
463
- @inlinable
464
- internal func index( after i: Index ) -> Index {
465
- var i = i
466
- formIndex ( after: & i)
467
- return i
471
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
472
+ @_effects ( releasenone)
473
+ internal func index( after index: Index ) -> Index {
474
+ var result = index
475
+ formIndex ( after: & result)
476
+ return result
468
477
}
469
478
470
- @usableFromInline
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 " )
483
+ }
484
+
485
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
471
486
@_effects ( releasenone)
472
- internal func formIndex( after i: inout Index ) {
473
- _precondition ( i. base. object === self . object, " Invalid index " )
474
- _precondition ( i. currentKeyIndex < i. allKeys. value,
475
- " Cannot increment endIndex " )
476
- 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
477
493
}
478
494
479
- @usableFromInline
495
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
496
+ @_effects ( releasenone)
480
497
internal func index( forKey key: Key ) -> Index ? {
481
498
// Fast path that does not involve creating an array of all keys. In case
482
499
// the key is present, this lookup is a penalty for the slow path, but the
@@ -487,16 +504,13 @@ extension _CocoaDictionary: _DictionaryBuffer {
487
504
}
488
505
489
506
let allKeys = _stdlib_NSDictionary_allKeys ( object)
490
- var keyIndex = - 1
491
507
for i in 0 ..< allKeys. value {
492
508
if _stdlib_NSObject_isEqual ( key, allKeys [ i] ) {
493
- keyIndex = i
494
- break
509
+ return Index ( Index . Storage ( self , allKeys, i) )
495
510
}
496
511
}
497
- _sanityCheck ( keyIndex >= 0 ,
498
- " Key was found in fast path, but not found later? " )
499
- return Index ( self , allKeys, keyIndex)
512
+ _sanityCheckFailure (
513
+ " An NSDictionary key wassn't listed amongst its enumerated contents " )
500
514
}
501
515
502
516
@inlinable
@@ -516,28 +530,28 @@ extension _CocoaDictionary: _DictionaryBuffer {
516
530
return object. object ( forKey: key)
517
531
}
518
532
519
- @inlinable
520
- @inline ( __always )
533
+ @usableFromInline // FIXME(cocoa-index): Should be inlinable
534
+ @_effects ( releasenone )
521
535
internal func lookup( _ index: Index ) -> ( key: Key , value: Value ) {
522
- _precondition ( index. base. object === self . object, " Invalid index " )
523
- let key : Key = index. allKeys [ index. currentKeyIndex]
524
- 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) !
525
539
return ( key, value)
526
540
}
527
541
528
- @inlinable
529
- @inline ( __always )
542
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
543
+ @_effects ( releasenone )
530
544
func key( at index: Index ) -> Key {
531
- _precondition ( index. base. object === self . object, " Invalid index " )
545
+ _precondition ( index. storage . base. object === self . object, " Invalid index " )
532
546
return index. key
533
547
}
534
548
535
- @inlinable
536
- @inline ( __always )
549
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
550
+ @_effects ( releasenone )
537
551
func value( at index: Index ) -> Value {
538
- _precondition ( index. base. object === self . object, " Invalid index " )
539
- let key = index. allKeys [ index. currentKeyIndex]
540
- 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) !
541
555
}
542
556
}
543
557
@@ -557,45 +571,40 @@ extension _CocoaDictionary {
557
571
}
558
572
559
573
extension _CocoaDictionary {
560
- @_fixed_layout // FIXME(sil-serialize-all)
574
+ @_fixed_layout
561
575
@usableFromInline
562
576
internal struct Index {
563
- // 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
564
591
// repeatedly called on the same NSDictionary, returning items in the same
565
592
// order every time.
566
593
// Similarly, the same assumption holds for NSSet.allObjects.
567
594
568
595
/// A reference to the NSDictionary, which owns members in `allObjects`,
569
596
/// or `allKeys`, for NSSet and NSDictionary respectively.
570
- @usableFromInline // FIXME(sil-serialize-all)
571
597
internal let base : _CocoaDictionary
572
598
// FIXME: swift-3-indexing-model: try to remove the cocoa reference, but
573
599
// make sure that we have a safety check for accessing `allKeys`. Maybe
574
600
// move both into the dictionary/set itself.
575
601
576
602
/// An unowned array of keys.
577
- @usableFromInline // FIXME(sil-serialize-all)
578
603
internal var allKeys : _HeapBuffer < Int , AnyObject >
579
604
580
605
/// Index into `allKeys`
581
- @usableFromInline // FIXME(sil-serialize-all)
582
606
internal var currentKeyIndex : Int
583
607
584
- @inlinable // FIXME(sil-serialize-all)
585
- internal init ( _ base: __owned _CocoaDictionary, startIndex: ( ) ) {
586
- self . base = base
587
- self . allKeys = _stdlib_NSDictionary_allKeys ( base. object)
588
- self . currentKeyIndex = 0
589
- }
590
-
591
- @inlinable // FIXME(sil-serialize-all)
592
- internal init ( _ base: __owned _CocoaDictionary, endIndex: ( ) ) {
593
- self . base = base
594
- self . allKeys = _stdlib_NSDictionary_allKeys ( base. object)
595
- self . currentKeyIndex = allKeys. value
596
- }
597
-
598
- @inlinable // FIXME(sil-serialize-all)
599
608
internal init (
600
609
_ base: __owned _CocoaDictionary,
601
610
_ allKeys: __owned _HeapBuffer< Int , AnyObject > ,
@@ -610,44 +619,62 @@ extension _CocoaDictionary {
610
619
611
620
extension _CocoaDictionary . Index {
612
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
+
633
+ extension _CocoaDictionary . Index {
634
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
613
635
@nonobjc
614
636
internal var key : AnyObject {
615
- _precondition ( currentKeyIndex < allKeys. value,
616
- " Attempting to access Dictionary elements using an invalid index " )
617
- return allKeys [ currentKeyIndex]
637
+ @_effects ( readonly)
638
+ get {
639
+ _precondition ( storage. currentKeyIndex < storage. allKeys. value,
640
+ " Attempting to access Dictionary elements using an invalid index " )
641
+ return storage. allKeys [ storage. currentKeyIndex]
642
+ }
618
643
}
619
644
620
- @usableFromInline
645
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
621
646
@nonobjc
622
647
internal var age : Int32 {
623
- @_effects ( releasenone )
648
+ @_effects ( readonly )
624
649
get {
625
- return _HashTable. age ( for: base. object)
650
+ return _HashTable. age ( for: storage . base. object)
626
651
}
627
652
}
628
653
}
629
654
630
655
extension _CocoaDictionary . Index : Equatable {
631
- @inlinable
656
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
657
+ @_effects ( readonly)
632
658
internal static func == (
633
659
lhs: _CocoaDictionary . Index ,
634
660
rhs: _CocoaDictionary . Index
635
661
) -> Bool {
636
- _precondition ( lhs. base. object === rhs. base. object,
662
+ _precondition ( lhs. storage . base. object === rhs. storage . base. object,
637
663
" Comparing indexes from different dictionaries " )
638
- return lhs. currentKeyIndex == rhs. currentKeyIndex
664
+ return lhs. storage . currentKeyIndex == rhs. storage . currentKeyIndex
639
665
}
640
666
}
641
667
642
668
extension _CocoaDictionary . Index : Comparable {
643
- @inlinable
669
+ @usableFromInline // FIXME(cocoa-index): Make inlinable
670
+ @_effects ( readonly)
644
671
internal static func < (
645
672
lhs: _CocoaDictionary . Index ,
646
673
rhs: _CocoaDictionary . Index
647
674
) -> Bool {
648
- _precondition ( lhs. base. object === rhs. base. object,
675
+ _precondition ( lhs. storage . base. object === rhs. storage . base. object,
649
676
" Comparing indexes from different dictionaries " )
650
- return lhs. currentKeyIndex < rhs. currentKeyIndex
677
+ return lhs. storage . currentKeyIndex < rhs. storage . currentKeyIndex
651
678
}
652
679
}
653
680
0 commit comments