@@ -400,6 +400,28 @@ extension Array {
400
400
return _DependenceToken ( )
401
401
}
402
402
403
+ /// Check that the given `index` is valid for subscripting, i.e.
404
+ /// `0 ≤ index < count`, but only in debug buikds.
405
+ @inlinable
406
+ @_semantics ( " array.check_subscript " )
407
+ @_effects ( notEscaping self.** )
408
+ public // @testable
409
+ func _debugCheckSubscript(
410
+ _ index: Int , wasNativeTypeChecked: Bool
411
+ ) -> _DependenceToken {
412
+ #if _runtime(_ObjC)
413
+ // There is no need to do bounds checking for the non-native case because
414
+ // ObjectiveC arrays do bounds checking by their own.
415
+ // And in the native-non-type-checked case, it's also not needed to do bounds
416
+ // checking here, because it's done in ArrayBuffer._getElementSlowPath.
417
+ if _fastPath ( wasNativeTypeChecked) {
418
+ _buffer. _native. _debugCheckValidSubscript ( index)
419
+ }
420
+ #else
421
+ _buffer. _debugCheckValidSubscript ( index)
422
+ #endif
423
+ return _DependenceToken ( )
424
+ }
403
425
/// Check that the given `index` is valid for subscripting, i.e.
404
426
/// `0 ≤ index < count`.
405
427
///
@@ -411,6 +433,17 @@ extension Array {
411
433
_buffer. _checkValidSubscriptMutating ( index)
412
434
}
413
435
436
+ /// Check that the given `index` is valid for subscripting, i.e.
437
+ /// `0 ≤ index < count`, but only in debug configurations.
438
+ ///
439
+ /// - Precondition: The buffer must be uniquely referenced and native.
440
+ @_alwaysEmitIntoClient
441
+ @_semantics ( " array.check_subscript " )
442
+ @_effects ( notEscaping self.** )
443
+ internal func _debugCheckSubscript_mutating( _ index: Int ) {
444
+ _buffer. _debugCheckValidSubscriptMutating ( index)
445
+ }
446
+
414
447
/// Check that the specified `index` is valid, i.e. `0 ≤ index ≤ count`.
415
448
@inlinable
416
449
@_semantics ( " array.check_index " )
@@ -420,6 +453,16 @@ extension Array {
420
453
_precondition ( index >= startIndex, " Negative Array index is out of range " )
421
454
}
422
455
456
+ /// Check that the specified `index` is valid, i.e. `0 ≤ index ≤ count`,
457
+ /// but only in debug configurations.
458
+ @inlinable
459
+ @_semantics ( " array.check_index " )
460
+ @_effects ( notEscaping self.** )
461
+ internal func _debugCheckIndex( _ index: Int ) {
462
+ _debugPrecondition ( index <= endIndex, " Array index is out of range " )
463
+ _debugPrecondition ( index >= startIndex, " Negative Array index is out of range " )
464
+ }
465
+
423
466
@_semantics ( " array.get_element " )
424
467
@_effects ( notEscaping self. value**)
425
468
@_effects ( escaping self. value** . class* . value** - > return . value**)
@@ -761,6 +804,38 @@ extension Array: RandomAccessCollection, MutableCollection {
761
804
}
762
805
}
763
806
807
+ /// Accesses the element at the specified position without bounds
808
+ /// checking.
809
+ ///
810
+ /// This unsafe operation should only be used when performance analysis
811
+ /// has determined that the bounds checks are not being eliminated
812
+ /// by the optimizer despite being ensured by a higher-level invariant.
813
+ @inlinable @_alwaysEmitIntoClient
814
+ public subscript( unchecked index: Int ) -> Element {
815
+ get {
816
+ // This call may be hoisted or eliminated by the optimizer. If
817
+ // there is an inout violation, this value may be stale so needs to be
818
+ // checked again below.
819
+ let wasNativeTypeChecked = _hoistableIsNativeTypeChecked ( )
820
+
821
+ // Make sure the index is in range and wasNativeTypeChecked is
822
+ // still valid.
823
+ let token = _debugCheckSubscript (
824
+ index, wasNativeTypeChecked: wasNativeTypeChecked)
825
+
826
+ return _getElement (
827
+ index, wasNativeTypeChecked: wasNativeTypeChecked,
828
+ matchingSubscriptCheck: token)
829
+ }
830
+ _modify {
831
+ _makeMutableAndUnique ( ) // makes the array native, too
832
+ _debugCheckSubscript_mutating ( index)
833
+ let address = _buffer. mutableFirstElementAddress + index
834
+ defer { _endMutation ( ) }
835
+ yield & address. pointee
836
+ }
837
+ }
838
+
764
839
/// Accesses a contiguous subrange of the array's elements.
765
840
///
766
841
/// The returned `ArraySlice` instance uses the same indices for the same
@@ -804,6 +879,31 @@ extension Array: RandomAccessCollection, MutableCollection {
804
879
}
805
880
}
806
881
882
+ /// Accesses a contiguous subrange of the array's elements without
883
+ /// bounds checks on the range.
884
+ ///
885
+ /// This unsafe operation should only be used when performance analysis
886
+ /// has determined that the bounds checks are not being eliminated
887
+ /// by the optimizer despite being ensured by a higher-level invariant.
888
+ @inlinable @_alwaysEmitIntoClient
889
+ public subscript( uncheckedBounds bounds: Range < Int > ) -> ArraySlice < Element > {
890
+ get {
891
+ _debugCheckIndex ( bounds. lowerBound)
892
+ _debugCheckIndex ( bounds. upperBound)
893
+ return ArraySlice ( _buffer: _buffer [ bounds] )
894
+ }
895
+ set ( rhs) {
896
+ _debugCheckIndex ( bounds. lowerBound)
897
+ _debugCheckIndex ( bounds. upperBound)
898
+ // If the replacement buffer has same identity, and the ranges match,
899
+ // then this was a pinned in-place modification, nothing further needed.
900
+ if self [ bounds] . _buffer. identity != rhs. _buffer. identity
901
+ || bounds != rhs. startIndex..< rhs. endIndex {
902
+ self . replaceSubrange ( bounds, with: rhs)
903
+ }
904
+ }
905
+ }
906
+
807
907
/// The number of elements in the array.
808
908
@inlinable
809
909
@_semantics ( " array.get_count " )
0 commit comments