Skip to content

[stdlib] Add custom implementations of removeLast and remove(at:) to Array #14273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 80 additions & 61 deletions stdlib/public/core/Arrays.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1493,17 +1493,6 @@ extension ${Self} : RangeReplaceableCollection, ArrayProtocol {
}

%if Self == 'ArraySlice':
/// Removes and returns the last element of the array.
///
/// The array must not be empty. This example removes the last number from an
/// array of `Double` values.
///
/// var measurements: [Double] = [1.1, 1.5, 2.9, 1.2, 1.5, 1.3, 1.2]
/// let removed = measurements.removeLast()
/// print(measurements)
/// // Prints "[1.1, 1.5, 2.9, 1.2, 1.5, 1.3]"
///
/// - Returns: The element that was removed.
@_inlineable
public mutating func _customRemoveLast() -> Element? {
_precondition(count > 0, "Can't removeLast from an empty ${Self}")
Expand All @@ -1519,31 +1508,58 @@ extension ${Self} : RangeReplaceableCollection, ArrayProtocol {
self.replaceSubrange((i &- 1)..<i, with: EmptyCollection())
return result
}
%end

/// Inserts a new element at the specified position.
///
/// The new element is inserted before the element currently at the specified
/// index. If you pass the array's `endIndex` property as the `index`
/// parameter, the new element is appended to the array.

/// Removes and returns the element at the specified position.
///
/// var numbers = [1, 2, 3, 4, 5]
/// numbers.insert(100, at: 3)
/// numbers.insert(200, at: numbers.endIndex)
/// All the elements following the specified position are moved up to
/// close the gap.
///
/// print(numbers)
/// // Prints "[1, 2, 3, 100, 4, 5, 200]"
/// var measurements: [Double] = [1.1, 1.5, 2.9, 1.2, 1.5, 1.3, 1.2]
/// let removed = measurements.remove(at: 2)
/// print(measurements)
/// // Prints "[1.1, 1.5, 1.2, 1.5, 1.3, 1.2]"
///
/// - Parameter newElement: The new element to insert into the array.
/// - Parameter i: The position at which to insert the new element.
/// `index` must be a valid index of the array or equal to its `endIndex`
/// property.
/// - Parameter index: The position of the element to remove. `index` must
/// be a valid index of the array.
/// - Returns: The element at the specified index.
///
/// - Complexity: O(*n*), where *n* is the length of the array.
@_inlineable
public mutating func insert(_ newElement: Element, at i: Int) {
_checkIndex(i)
self.replaceSubrange(i..<i, with: CollectionOfOne(newElement))
@discardableResult
public mutating func remove(at index: Int) -> Element {
let result = self[index]
self.replaceSubrange(index..<(index + 1), with: EmptyCollection())
return result
}

%else:
/// Removes and returns the last element of the array.
///
/// - Returns: The last element of the array if the array is not empty;
/// otherwise, `nil`.
///
/// - Complexity: O(*n*) if the array is bridged, where *n* is the length
/// of the array; otherwise, O(1).
@_inlineable
public mutating func popLast() -> Element? {
let newCount = _getCount() - 1
guard newCount >= 0 else { return nil }
_makeUniqueAndReserveCapacityIfNotUnique()
let pointer = (_buffer.firstElementAddress + newCount)
let element = pointer.move()
_buffer.count = newCount
return element
}

@_inlineable
public mutating func _customRemoveLast() -> Element? {
let newCount = _getCount() - 1
_precondition(newCount >= 0, "Can't removeLast from an empty ${Self}")
_makeUniqueAndReserveCapacityIfNotUnique()
let pointer = (_buffer.firstElementAddress + newCount)
let element = pointer.move()
_buffer.count = newCount
return element
}

/// Removes and returns the element at the specified position.
Expand All @@ -1564,10 +1580,42 @@ extension ${Self} : RangeReplaceableCollection, ArrayProtocol {
@_inlineable
@discardableResult
public mutating func remove(at index: Int) -> Element {
let result = self[index]
self.replaceSubrange(index..<(index + 1), with: EmptyCollection())
_precondition(index < endIndex, "Index out of range")
_precondition(index >= startIndex, "Index out of range")
_makeUniqueAndReserveCapacityIfNotUnique()
let newCount = _getCount() - 1
let pointer = (_buffer.firstElementAddress + index)
let result = pointer.move()
pointer.moveInitialize(from: pointer + 1, count: newCount - index)
_buffer.count = newCount
return result
}
%end

/// Inserts a new element at the specified position.
///
/// The new element is inserted before the element currently at the specified
/// index. If you pass the array's `endIndex` property as the `index`
/// parameter, the new element is appended to the array.
///
/// var numbers = [1, 2, 3, 4, 5]
/// numbers.insert(100, at: 3)
/// numbers.insert(200, at: numbers.endIndex)
///
/// print(numbers)
/// // Prints "[1, 2, 3, 100, 4, 5, 200]"
///
/// - Parameter newElement: The new element to insert into the array.
/// - Parameter i: The position at which to insert the new element.
/// `index` must be a valid index of the array or equal to its `endIndex`
/// property.
///
/// - Complexity: O(*n*), where *n* is the length of the array.
@_inlineable
public mutating func insert(_ newElement: Element, at i: Int) {
_checkIndex(i)
self.replaceSubrange(i..<i, with: CollectionOfOne(newElement))
}

/// Removes all elements from the array.
///
Expand Down Expand Up @@ -2358,35 +2406,6 @@ extension Array {
}
#endif

extension Array {
/// Removes and returns the last element of the array.
///
/// - Returns: The last element of the array if the array is not empty;
/// otherwise, `nil`.
///
/// - Complexity: O(*n*) if the array is bridged, where *n* is the length
/// of the array; otherwise, O(1).
@_inlineable
public mutating func popLast() -> Element? {
guard !isEmpty else { return nil }
return removeLast()
}
}

extension ContiguousArray {
/// Removes and returns the last element of the array.
///
/// - Returns: The last element of the array if the array is not empty;
/// otherwise, `nil`.
///
/// - Complexity: O(1)
@_inlineable
public mutating func popLast() -> Element? {
guard !isEmpty else { return nil }
return removeLast()
}
}

extension ArraySlice {
@_inlineable
public // @testable
Expand Down