/// A basic stack type implementing the LIFO principle - only the last inserted element can be accessed and removed. public struct Stack { private var elements = [Element]() /// Creates an empty `Stack`. public init() { /* Publish no-op initializer */ } /// The number of elements in this stack. public var count: Int { elements.count } /// Pushes (appends) an element onto the stack. /// /// - parameter element: The element to push onto the stack. public mutating func push(_ element: Element) { elements.append(element) } /// Removes and returns the last element of the stack. /// /// - returns: The last element of the stack if the stack is not empty; otherwise, nil. @discardableResult public mutating func pop() -> Element? { elements.popLast() } /// Returns the last element of the stack if the stack is not empty; otherwise, nil. public func peek() -> Element? { elements.last } /// Check whether the sequence contains an element that satisfies the given predicate. /// /// - parameter predicate: A closure that takes an element of the sequence /// and returns whether it represents a match. /// - returns: `true` if the sequence contains an element that satisfies `predicate`. public func contains(where predicate: (Element) -> Bool) -> Bool { elements.contains(where: predicate) } /// Modify the last element. /// /// - parameter modifier: A function to be applied to the last element to modify the same in place. public mutating func modifyLast(by modifier: (inout Element) -> Void) { if elements.isNotEmpty { modifier(&elements[count - 1]) } } } extension Stack: Collection { public var startIndex: Int { elements.startIndex } public var endIndex: Int { elements.endIndex } public subscript(position: Int) -> Element { elements[position] } public func index(after index: Int) -> Int { elements.index(after: index) } } extension Stack: CustomDebugStringConvertible where Element: CustomDebugStringConvertible { public var debugDescription: String { let intermediateElements = count > 1 ? elements[1 ..< count - 1] : [] return """ Stack with \(count) elements: first: \(elements.first?.debugDescription ?? "") intermediate: \(intermediateElements.map(\.debugDescription).joined(separator: ", ")) last: \(peek()?.debugDescription ?? "") """ } }