Skip to content

Instantly share code, notes, and snippets.

@nikitamounier
Last active April 3, 2021 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikitamounier/0e754f4d1e430952d7f010565cc279e9 to your computer and use it in GitHub Desktop.
Save nikitamounier/0e754f4d1e430952d7f010565cc279e9 to your computer and use it in GitHub Desktop.
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