// // Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public struct OrderedSet where Element: Hashable { public private(set) var orderedMembers: [Element] = [] private var set: Set = [] public init(_ members: [Element]) { set = [] orderedMembers = [] for element in members { append(element) } } @discardableResult public mutating func append(_ element: Element) -> (Bool, Element) { let (wasInserted, elementAfterInsert) = set.insert(element) if wasInserted { orderedMembers.append(element) } return (wasInserted, elementAfterInsert) } public mutating func remove(_ element: Element) { set.remove(element) orderedMembers = orderedMembers.filter { $0 != element } } public mutating func remove(_ elements: [Element]) { for element in elements { remove(element) } } public func contains(_ element: Element) -> Bool { return set.contains(element) } public var isEmpty: Bool { return set.isEmpty } public var count: Int { return set.count } public var first: Element? { return orderedMembers.first } public static func == (lhs: OrderedSet, rhs: OrderedSet) -> Bool { lhs.set == rhs.set } public static func != (lhs: OrderedSet, rhs: OrderedSet) -> Bool { lhs.set != rhs.set } // TODO: I only implemented the minimum API that I needed. There's lots more that could // reasonably be added to an OrderedSet (union, etc.) } extension OrderedSet: ExpressibleByArrayLiteral { public typealias ArrayLiteralElement = Element public init(arrayLiteral elements: Element...) { self.init(elements) } }