//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

/// This file is copied from swift-collections and should not be modified here.
/// Rather all changes should be made to swift-collections and copied back.

import Swift

extension _Deque {
  /// Creates a deque with the specified capacity, then calls the given
  /// closure with a buffer covering the array's uninitialized memory.
  ///
  /// Inside the closure, set the `initializedCount` parameter to the number of
  /// elements that are initialized by the closure. The memory in the range
  /// `buffer[0..<initializedCount]` must be initialized at the end of the
  /// closure's execution, and the memory in the range
  /// `buffer[initializedCount...]` must be uninitialized. This postcondition
  /// must hold even if the `initializer` closure throws an error.
  ///
  /// - Note: While the resulting deque may have a capacity larger than the
  ///   requested amount, the buffer passed to the closure will cover exactly
  ///   the requested number of elements.
  ///
  /// - Parameters:
  ///   - unsafeUninitializedCapacity: The number of elements to allocate
  ///     space for in the new deque.
  ///   - initializer: A closure that initializes elements and sets the count
  ///     of the new deque.
  ///     - Parameters:
  ///       - buffer: A buffer covering uninitialized memory with room for the
  ///         specified number of elements.
  ///       - initializedCount: The count of initialized elements in the deque,
  ///         which begins as zero. Set `initializedCount` to the number of
  ///         elements you initialize.
  init(
    unsafeUninitializedCapacity capacity: Int,
    initializingWith initializer:
      (inout UnsafeMutableBufferPointer<Element>, inout Int) throws -> Void
  ) rethrows {
    self._storage = .init(minimumCapacity: capacity)
    try unsafe _storage.update { handle in
      unsafe handle.startSlot = .zero
      var count = 0
      var buffer = unsafe handle.mutableBuffer(for: .zero ..< _Slot(at: capacity))
      defer {
        precondition(count <= capacity,
          "Initialized count set to greater than specified capacity")
        let b = unsafe handle.mutableBuffer(for: .zero ..< _Slot(at: capacity))
        unsafe precondition(buffer.baseAddress == b.baseAddress && buffer.count == b.count,
          "Initializer relocated Deque storage")
        unsafe handle.count = count
      }
      try unsafe initializer(&buffer, &count)
    }
  }
}

extension _Deque {
  /// Removes and returns the first element of this deque, if it exists.
  ///
  /// - Returns: The first element of the original collection if the collection
  ///    isn't empty; otherwise, `nil`.
  ///
  /// - Complexity: O(1) when this instance has a unique reference to its
  ///    underlying storage; O(`count`) otherwise.
  mutating func popFirst() -> Element? {
    // FIXME: Add this to the stdlib on BidirectionalCollection
    // where Self == Self.SubSequence
    guard count > 0 else { return nil }
    _storage.ensureUnique()
    return unsafe _storage.update {
      unsafe $0.uncheckedRemoveFirst()
    }
  }

  // Note: `popLast` is implemented by the stdlib as a
  // `RangeReplaceableCollection` extension, defined in terms of
  // `_customRemoveLast`.


  /// Adds a new element at the front of the deque.
  ///
  /// Use this method to append a single element to the front of a deque.
  ///
  ///     var numbers: Deque = [1, 2, 3, 4, 5]
  ///     numbers.prepend(100)
  ///     print(numbers)
  ///     // Prints "[100, 1, 2, 3, 4, 5]"
  ///
  /// Because deques increase their allocated capacity using an exponential
  /// strategy, prepending a single element to a deque is an O(1) operation when
  /// averaged over many calls to the `prepend(_:)` method. When a deque has
  /// additional capacity and is not sharing its storage with another instance,
  /// prepending an element is O(1). When a deque needs to reallocate storage
  /// before prepending or its storage is shared with another copy, prepending
  /// is O(`count`).
  ///
  /// - Parameter newElement: The element to prepend to the deque.
  ///
  /// - Complexity: Amortized O(1).
  ///
  /// - SeeAlso: `append(_:)`
  mutating func prepend(_ newElement: Element) {
    _storage.ensureUnique(minimumCapacity: count + 1)
    return unsafe _storage.update {
      unsafe $0.uncheckedPrepend(newElement)
    }
  }

  /// Adds the elements of a collection to the front of the deque.
  ///
  /// Use this method to prepend the elements of a collection to the front of
  /// this deque. This example prepends the elements of a `Range<Int>` instance
  /// to a deque of integers.
  ///
  ///     var numbers: Deque = [1, 2, 3, 4, 5]
  ///     numbers.prepend(contentsOf: 10...15)
  ///     print(numbers)
  ///     // Prints "[10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5]"
  ///
  /// - Parameter newElements: The elements to prepend to the deque.
  ///
  /// - Complexity: Amortized O(`newElements.count`).
  ///
  /// - SeeAlso: `append(contentsOf:)`
  mutating func prepend<C: Collection>(contentsOf newElements: C) where C.Element == Element {
    let done: Void? = unsafe newElements._withContiguousStorageIfAvailable_SR14663 { source in
      _storage.ensureUnique(minimumCapacity: count + source.count)
      unsafe _storage.update { unsafe $0.uncheckedPrepend(contentsOf: source) }
    }
    guard done == nil else { return }

    let c = newElements.count
    guard c > 0 else { return }
    _storage.ensureUnique(minimumCapacity: count + c)
    unsafe _storage.update { target in
      let gaps = unsafe target.availableSegments().suffix(c)
      unsafe gaps.initialize(from: newElements)
      unsafe target.count += c
      unsafe target.startSlot = unsafe target.slot(target.startSlot, offsetBy: -c)
    }
  }

  /// Adds the elements of a sequence to the front of the deque.
  ///
  /// Use this method to prepend the elements of a sequence to the front of this
  /// deque. This example prepends the elements of a `Range<Int>` instance to a
  /// deque of integers.
  ///
  ///     var numbers: Deque = [1, 2, 3, 4, 5]
  ///     numbers.prepend(contentsOf: 10...15)
  ///     print(numbers)
  ///     // Prints "[10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5]"
  ///
  /// - Parameter newElements: The elements to prepend to the deque.
  ///
  /// - Complexity: Amortized O(`newElements.count`).
  ///
  /// - SeeAlso: `append(contentsOf:)`
  mutating func prepend<S: Sequence>(contentsOf newElements: S) where S.Element == Element {
    let done: Void? = unsafe newElements._withContiguousStorageIfAvailable_SR14663 { source in
      _storage.ensureUnique(minimumCapacity: count + source.count)
      unsafe _storage.update { unsafe $0.uncheckedPrepend(contentsOf: source) }
    }
    guard done == nil else { return }

    let originalCount = self.count
    self.append(contentsOf: newElements)
    let newCount = self.count
    let c = newCount - originalCount
    unsafe _storage.update { target in
      unsafe target.startSlot = unsafe target.slot(forOffset: originalCount)
      unsafe target.count = unsafe target.capacity
      unsafe target.closeGap(offsets: c ..< c + (target.capacity - newCount))
      unsafe assert(target.count == newCount)
    }
  }
}
