Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Protocol to easily implement copy-on-write behaviour for your large value types.
protocol Copyable {
func copy() -> Self
}
/// A protocol for value types which gives them copy-on-write behaviour. This means that when multiple variables are pointing to the type, they point to the same underlying data to avoid excessive copying. When one of them modifies the type, it copies the type, therefore keeping value semantics.
@dynamicMemberLookup
protocol CopyOnWrite {
associatedtype Storage: AnyObject & Copyable
/// The underlying storage of the type, which is a reference type.
var _storage: Storage { get set }
}
extension CopyOnWrite {
subscript<Value>(dynamicMember keypath: ReferenceWritableKeyPath<Storage, Value>) -> Value {
get {
return _storage[keyPath: keypath]
}
set {
if !isKnownUniquelyReferenced(&_storage) {
_storage = _storage.copy()
}
self._storage[keyPath: keypath] = newValue
}
}
}
struct LargeType: CopyOnWrite {
typealias Storage = _Storage
var _storage: _Storage
init(value: String) {
self._storage = _Storage(value: value)
}
final class _Storage: Copyable { // requires `copy()` method
var value: String
init(value: String) {
self.value = value
}
func copy() -> _Storage {
return .init(value: self.value)
}
}
}
var first = LargeType(value: "first")
print(first.value) // first
var second = first
print(second.value) // first
print(first._storage === second._storage) // true
second.value = "second"
print(first.value) // first
print(second.value) // second
print(first._storage === second._storage) // false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment