Skip to content

Commit

Permalink
Add IdentifiedCollection protocol (#74)
Browse files Browse the repository at this point in the history
* Add `IdentifiedCollection` protocol

* wip

* wip

* Underscore for first release
  • Loading branch information
stephencelis authored Jun 18, 2024
1 parent 3953620 commit 2f5ab6e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -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<ID> { 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"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,13 +272,6 @@ public struct IdentifiedArray<ID: Hashable, Element> {
@usableFromInline
var _dictionary: OrderedDictionary<ID, Element>

/// 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<ID> { self._dictionary.keys }

/// A read-only collection view for the elements contained in this array, as an `Array`.
///
/// - Complexity: O(1)
Expand All @@ -297,38 +290,6 @@ public struct IdentifiedArray<ID: Hashable, Element> {
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
Expand Down
23 changes: 23 additions & 0 deletions Sources/IdentifiedCollections/IdentifiedCollection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// A collection of elements that can be uniquely identified.
public protocol _IdentifiedCollection<ID, Element>: 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<ID>

/// 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<ID, Element>: _IdentifiedCollection, MutableCollection
{
/// Accesses the value associated with the given id for reading.
subscript(id id: ID) -> Element? { get set }
}

0 comments on commit 2f5ab6e

Please sign in to comment.