From 9933d28b3f5e3101c023067d6fcff876cd8cadac Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 18 Jun 2024 14:05:25 -0700 Subject: [PATCH 1/4] Add `IdentifiedCollection` protocol --- .../IdentifiedArray+IdentifiedCollection.swift | 5 +++++ .../IdentifiedCollection.swift | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift create mode 100644 Sources/IdentifiedCollections/IdentifiedCollection.swift diff --git a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift new file mode 100644 index 0000000..da1914f --- /dev/null +++ b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift @@ -0,0 +1,5 @@ +import OrderedCollections + +extension IdentifiedArray: IdentifiedCollection {} + +extension IdentifiedArray: MutableIdentifiedCollection {} diff --git a/Sources/IdentifiedCollections/IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedCollection.swift new file mode 100644 index 0000000..41ba41b --- /dev/null +++ b/Sources/IdentifiedCollections/IdentifiedCollection.swift @@ -0,0 +1,13 @@ +public protocol IdentifiedCollection: Collection { + associatedtype ID: Hashable + + associatedtype IDs: Collection + + var ids: IDs { get } + + subscript(id id: ID) -> Element? { get } +} + +public protocol MutableIdentifiedCollection: IdentifiedCollection { + subscript(id id: ID) -> Element? { get set } +} From 00141778b8e74a92c5d92b4edcc31e15d42dbc13 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 18 Jun 2024 14:14:15 -0700 Subject: [PATCH 2/4] wip --- ...IdentifiedArray+IdentifiedCollection.swift | 43 ++++++++++++++++++- .../IdentifiedArray/IdentifiedArray.swift | 39 ----------------- .../IdentifiedCollection.swift | 8 ++++ 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift index da1914f..afefd4f 100644 --- a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift +++ b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift @@ -1,5 +1,44 @@ import OrderedCollections -extension IdentifiedArray: IdentifiedCollection {} +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 {} +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 index 41ba41b..84b1525 100644 --- a/Sources/IdentifiedCollections/IdentifiedCollection.swift +++ b/Sources/IdentifiedCollections/IdentifiedCollection.swift @@ -1,13 +1,21 @@ +/// 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 } } public protocol MutableIdentifiedCollection: IdentifiedCollection { + /// Accesses the value associated with the given id for reading. subscript(id id: ID) -> Element? { get set } } From 1e6d425ea662b3285f4a2975fb432f639ab0913a Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 18 Jun 2024 14:30:35 -0700 Subject: [PATCH 3/4] wip --- Sources/IdentifiedCollections/IdentifiedCollection.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/IdentifiedCollections/IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedCollection.swift index 84b1525..ac8fda8 100644 --- a/Sources/IdentifiedCollections/IdentifiedCollection.swift +++ b/Sources/IdentifiedCollections/IdentifiedCollection.swift @@ -15,7 +15,8 @@ public protocol IdentifiedCollection: Collection { subscript(id id: ID) -> Element? { get } } -public protocol MutableIdentifiedCollection: IdentifiedCollection { +/// 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 } } From 24d35933054307409ea51fe52f1df3bb8ba97c6e Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 18 Jun 2024 14:36:18 -0700 Subject: [PATCH 4/4] Underscore for first release --- .../IdentifiedArray+IdentifiedCollection.swift | 4 ++-- Sources/IdentifiedCollections/IdentifiedCollection.swift | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift index afefd4f..3a3fd22 100644 --- a/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift +++ b/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+IdentifiedCollection.swift @@ -1,6 +1,6 @@ import OrderedCollections -extension IdentifiedArray: IdentifiedCollection { +extension IdentifiedArray: _IdentifiedCollection { /// A read-only collection view for the ids contained in this array, as an `OrderedSet`. /// /// - Complexity: O(1) @@ -9,7 +9,7 @@ extension IdentifiedArray: IdentifiedCollection { public var ids: OrderedSet { self._dictionary.keys } } -extension IdentifiedArray: MutableIdentifiedCollection { +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 diff --git a/Sources/IdentifiedCollections/IdentifiedCollection.swift b/Sources/IdentifiedCollections/IdentifiedCollection.swift index ac8fda8..242c803 100644 --- a/Sources/IdentifiedCollections/IdentifiedCollection.swift +++ b/Sources/IdentifiedCollections/IdentifiedCollection.swift @@ -1,5 +1,5 @@ /// A collection of elements that can be uniquely identified. -public protocol IdentifiedCollection: Collection { +public protocol _IdentifiedCollection: Collection { /// A type that uniquely identifies elements in the collection. associatedtype ID: Hashable @@ -16,7 +16,8 @@ public protocol IdentifiedCollection: Collection { } /// A mutable collection of elements that can be uniquely identified. -public protocol MutableIdentifiedCollection: IdentifiedCollection, MutableCollection { +public protocol _MutableIdentifiedCollection: _IdentifiedCollection, MutableCollection +{ /// Accesses the value associated with the given id for reading. subscript(id id: ID) -> Element? { get set } }