Skip to content

Commit bf02f2f

Browse files
committed
feat: Add ThreadSafeArray and ThreadSafeDictionary
Implements thread-safe wrappers for standard Swift collection types using the ThreadSafe<T> pattern.
1 parent 0ee578f commit bf02f2f

2 files changed

Lines changed: 185 additions & 0 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// DesignAlgorithmsKit
2+
// Structural Pattern: ThreadSafe Array
3+
//
4+
// A thread-safe wrapper around a standard Swift Array.
5+
// Uses ThreadSafe<[Element]> internally.
6+
7+
import Foundation
8+
9+
/// A thread-safe array wrapper.
10+
/// Provides safe concurrent access to an array using an internal lock.
11+
public final class ThreadSafeArray<Element>: @unchecked Sendable {
12+
private let storage: ThreadSafe<[Element]>
13+
14+
public init(_ array: [Element] = []) {
15+
self.storage = ThreadSafe(array)
16+
}
17+
18+
/// The number of elements in the array.
19+
public var count: Int {
20+
storage.read { $0.count }
21+
}
22+
23+
/// A Boolean value indicating whether the collection is empty.
24+
public var isEmpty: Bool {
25+
storage.read { $0.isEmpty }
26+
}
27+
28+
/// Adds a new element at the end of the array.
29+
public func append(_ newElement: Element) {
30+
storage.write { $0.append(newElement) }
31+
}
32+
33+
/// Adds the elements of a sequence to the end of the array.
34+
public func append<S>(contentsOf newElements: S) where S : Sequence, Element == S.Element {
35+
storage.write { $0.append(contentsOf: newElements) }
36+
}
37+
38+
/// Removes and returns the element at the specified position.
39+
public func remove(at index: Int) -> Element {
40+
storage.write { $0.remove(at: index) }
41+
}
42+
43+
/// Removes all elements from the array.
44+
public func removeAll(keepingCapacity keepCapacity: Bool = false) {
45+
storage.write { $0.removeAll(keepingCapacity: keepCapacity) }
46+
}
47+
48+
/// Accesses the element at the specified position.
49+
/// Note: This is not efficient for iteration. Use `read` or `map` for batch operations.
50+
public subscript(index: Int) -> Element {
51+
get {
52+
storage.read { $0[index] }
53+
}
54+
set {
55+
storage.write { $0[index] = newValue }
56+
}
57+
}
58+
59+
/// Returns an array containing the results of mapping the given closure over the sequence’s elements.
60+
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] {
61+
try storage.read { try $0.map(transform) }
62+
}
63+
64+
/// Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.
65+
public func compactMap<T>(_ transform: (Element) throws -> T?) rethrows -> [T] {
66+
try storage.read { try $0.compactMap(transform) }
67+
}
68+
69+
/// Returns an array containing, in order, the elements of the sequence that satisfy the given predicate.
70+
public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element] {
71+
try storage.read { try $0.filter(isIncluded) }
72+
}
73+
74+
/// Returns the first element of the sequence that satisfies the given predicate.
75+
public func first(where predicate: (Element) throws -> Bool) rethrows -> Element? {
76+
try storage.read { try $0.first(where: predicate) }
77+
}
78+
79+
/// Returns a Boolean value indicating whether the sequence contains an element that satisfies the given predicate.
80+
public func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool {
81+
try storage.read { try $0.contains(where: predicate) }
82+
}
83+
84+
/// Returns a new array containing the elements of this array.
85+
public var allElements: [Element] {
86+
storage.read { $0 }
87+
}
88+
89+
/// Execute a block with the array for reading
90+
public func read<Result>(_ block: ([Element]) throws -> Result) rethrows -> Result {
91+
try storage.read(block)
92+
}
93+
94+
/// Execute a block with the array for writing
95+
public func write<Result>(_ block: (inout [Element]) throws -> Result) rethrows -> Result {
96+
try storage.write(block)
97+
}
98+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// DesignAlgorithmsKit
2+
// Structural Pattern: ThreadSafe Dictionary
3+
//
4+
// A thread-safe wrapper around a standard Swift Dictionary.
5+
// Uses ThreadSafe<[Key: Value]> internally.
6+
7+
import Foundation
8+
9+
/// A thread-safe dictionary wrapper.
10+
/// Provides safe concurrent access to a dictionary using an internal lock.
11+
public final class ThreadSafeDictionary<Key: Hashable, Value>: @unchecked Sendable {
12+
private let storage: ThreadSafe<[Key: Value]>
13+
14+
public init(_ dictionary: [Key: Value] = [:]) {
15+
self.storage = ThreadSafe(dictionary)
16+
}
17+
18+
/// The number of key-value pairs in the dictionary.
19+
public var count: Int {
20+
storage.read { $0.count }
21+
}
22+
23+
/// A Boolean value indicating whether the dictionary is empty.
24+
public var isEmpty: Bool {
25+
storage.read { $0.isEmpty }
26+
}
27+
28+
/// Accesses the value associated with the given key for reading and writing.
29+
public subscript(key: Key) -> Value? {
30+
get {
31+
storage.read { $0[key] }
32+
}
33+
set {
34+
storage.write { $0[key] = newValue }
35+
}
36+
}
37+
38+
/// Accesses the value with the given key. If the dictionary doesn’t contain the given key, accesses the provided default value as if the key and default value existed in the dictionary.
39+
public subscript(key: Key, default defaultValue: @autoclosure () -> Value) -> Value {
40+
get {
41+
storage.read { $0[key, default: defaultValue()] }
42+
}
43+
set {
44+
storage.write { $0[key, default: defaultValue()] = newValue }
45+
}
46+
}
47+
48+
/// Updates the value stored in the dictionary for the given key, or adds a new key-value pair if the key does not exist.
49+
public func updateValue(_ value: Value, forKey key: Key) -> Value? {
50+
storage.write { $0.updateValue(value, forKey: key) }
51+
}
52+
53+
/// Removes the value associated with the given key.
54+
public func removeValue(forKey key: Key) -> Value? {
55+
storage.write { $0.removeValue(forKey: key) }
56+
}
57+
58+
/// Removes all key-value pairs from the dictionary.
59+
public func removeAll(keepingCapacity keepCapacity: Bool = false) {
60+
storage.write { $0.removeAll(keepingCapacity: keepCapacity) }
61+
}
62+
63+
/// Returns a new dictionary containing the keys and values of this dictionary.
64+
public var all: [Key: Value] {
65+
storage.read { $0 }
66+
}
67+
68+
/// Returns a collection containing just the keys of the dictionary.
69+
public var keys: [Key] {
70+
storage.read { Array($0.keys) }
71+
}
72+
73+
/// Returns a collection containing just the values of the dictionary.
74+
public var values: [Value] {
75+
storage.read { Array($0.values) }
76+
}
77+
78+
/// Execute a block with the dictionary for reading
79+
public func read<Result>(_ block: ([Key: Value]) throws -> Result) rethrows -> Result {
80+
try storage.read(block)
81+
}
82+
83+
/// Execute a block with the dictionary for writing
84+
public func write<Result>(_ block: (inout [Key: Value]) throws -> Result) rethrows -> Result {
85+
try storage.write(block)
86+
}
87+
}

0 commit comments

Comments
 (0)