diff --git a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift new file mode 100644 index 0000000..3a3fd22 --- /dev/null +++ b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift @@ -0,0 +1,44 @@ +import OrderedCollections + +extension IdentifiedArray: _IdentifiedCollection { + /// A read-only collection view for the ids contained in this array, as an `OrderedSet`. + /// + /// - Complexity: O(1) + @inlinable + @inline(__always) + public var ids: OrderedSet { self._dictionary.keys } +} + +extension IdentifiedArray: _MutableIdentifiedCollection { + /// Accesses the value associated with the given id for reading and writing. + /// + /// This *id-based* subscript returns the element identified by the given id if found in the + /// array, or `nil` if no element is found. + /// + /// When you assign an element for an id and that element already exists, the array overwrites the + /// existing value in place. If the array doesn't contain the element, it is appended to the + /// array. + /// + /// If you assign `nil` for a given id, the array removes the element identified by that id. + /// + /// - Parameter id: The id to find in the array. + /// - Returns: The element associated with `id` if found in the array; otherwise, `nil`. + /// - Complexity: Looking up values in the array through this subscript has an expected complexity + /// of O(1) hashing/comparison operations on average, if `ID` implements high-quality hashing. + /// Updating the array also has an amortized expected complexity of O(1) -- although individual + /// updates may need to copy or resize the array's underlying storage. + /// - Postcondition: Element identity must remain constant over modification. Modifying an + /// element's id will cause a crash. + @inlinable + @inline(__always) + public subscript(id id: ID) -> Element? { + _read { yield self._dictionary[id] } + _modify { + yield &self._dictionary[id] + precondition( + self._dictionary[id].map { self._id($0) == id } ?? true, + "Element identity must remain constant" + ) + } + } +} diff --git a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray.swift b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray.swift index 36b1b8e..14e3624 100644 --- a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray.swift +++ b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray.swift @@ -272,13 +272,6 @@ public struct IdentifiedArray { @usableFromInline var _dictionary: OrderedDictionary - /// A read-only collection view for the ids contained in this array, as an `OrderedSet`. - /// - /// - Complexity: O(1) - @inlinable - @inline(__always) - public var ids: OrderedSet { self._dictionary.keys } - /// A read-only collection view for the elements contained in this array, as an `Array`. /// /// - Complexity: O(1) @@ -297,38 +290,6 @@ public struct IdentifiedArray { self._dictionary = _dictionary } - /// Accesses the value associated with the given id for reading and writing. - /// - /// This *id-based* subscript returns the element identified by the given id if found in the - /// array, or `nil` if no element is found. - /// - /// When you assign an element for an id and that element already exists, the array overwrites the - /// existing value in place. If the array doesn't contain the element, it is appended to the - /// array. - /// - /// If you assign `nil` for a given id, the array removes the element identified by that id. - /// - /// - Parameter id: The id to find in the array. - /// - Returns: The element associated with `id` if found in the array; otherwise, `nil`. - /// - Complexity: Looking up values in the array through this subscript has an expected complexity - /// of O(1) hashing/comparison operations on average, if `ID` implements high-quality hashing. - /// Updating the array also has an amortized expected complexity of O(1) -- although individual - /// updates may need to copy or resize the array's underlying storage. - /// - Postcondition: Element identity must remain constant over modification. Modifying an - /// element's id will cause a crash. - @inlinable - @inline(__always) - public subscript(id id: ID) -> Element? { - _read { yield self._dictionary[id] } - _modify { - yield &self._dictionary[id] - precondition( - self._dictionary[id].map { self._id($0) == id } ?? true, - "Element identity must remain constant" - ) - } - } - @inlinable public func contains(_ element: Element) -> Bool { self._dictionary[self._id(element)] != nil diff --git a/Sources/IdentifiedCollections/IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedCollection.swift new file mode 100644 index 0000000..242c803 --- /dev/null +++ b/Sources/IdentifiedCollections/IdentifiedCollection.swift @@ -0,0 +1,23 @@ +/// A collection of elements that can be uniquely identified. +public protocol _IdentifiedCollection: Collection { + /// A type that uniquely identifies elements in the collection. + associatedtype ID: Hashable + + /// A type that describes all of the ids in the collection. + associatedtype IDs: Collection + + /// A collection of ids associated with elements in the collection. + /// + /// This collection must contain elements equal to `map(\.id)`. + var ids: IDs { get } + + /// Accesses the value associated with the given id for reading. + subscript(id id: ID) -> Element? { get } +} + +/// A mutable collection of elements that can be uniquely identified. +public protocol _MutableIdentifiedCollection: _IdentifiedCollection, MutableCollection +{ + /// Accesses the value associated with the given id for reading. + subscript(id id: ID) -> Element? { get set } +}