Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IdentifiedCollection protocol #74

Merged
merged 4 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
21 changes: 21 additions & 0 deletions Sources/IdentifiedCollections/IdentifiedCollection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// 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 }
}

public protocol MutableIdentifiedCollection<ID, Element>: IdentifiedCollection {
/// Accesses the value associated with the given id for reading.
subscript(id id: ID) -> Element? { get set }
}