Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
67 changes: 67 additions & 0 deletions Sources/OneWay/PropertyWrappers/CopyOnWrite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// OneWay
// The MIT License (MIT)
//
// Copyright (c) 2022-2024 SeungYeop Yeom ( https://github.com/DevYeom ).
//

/// A property wrapper that allows for an easy way to eliminate the cost of copying large values
/// adopt copy-on-write behavior.
///
/// When applied to a field, the corresponding value will always be heap-allocated. This happens
/// because this wrapper is a class and classes are always heap-allocated. Use of this wrapper is
/// required on large value types because they can overflow the Swift runtime stack.
///
/// - SeeAlso: [Advice: Use copy-on-write semantics for large values](https://github.com/apple/swift/blob/main/docs/OptimizationTips.rst#advice-use-copy-on-write-semantics-for-large-values)
@propertyWrapper
public struct CopyOnWrite<Value> {
fileprivate final class Reference {
var value: Value

init(_ value: Value) {
self.value = value
}
}

public var wrappedValue: Value {
get {
reference.value
}
set {
if isKnownUniquelyReferenced(&reference) {
reference.value = newValue
} else {
reference = Reference(newValue)
}
}
}

private var reference: Reference

public init(wrappedValue: Value) {
reference = Reference(wrappedValue)
}
}

extension CopyOnWrite: CustomStringConvertible {
public var description: String {
String(describing: reference.value)
}
}

extension CopyOnWrite: Sendable where Value: Sendable { }
extension CopyOnWrite: Equatable where Value: Equatable {
public static func == (lhs: CopyOnWrite, rhs: CopyOnWrite) -> Bool {
lhs.wrappedValue == rhs.wrappedValue
}
}
extension CopyOnWrite: Hashable where Value : Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(wrappedValue)
}
}

extension CopyOnWrite.Reference: @unchecked Sendable where Value: Sendable { }

@available(*, deprecated, renamed: "CopyOnWrite")
public typealias Heap = CopyOnWrite
64 changes: 0 additions & 64 deletions Sources/OneWay/PropertyWrappers/Heap.swift

This file was deleted.

6 changes: 3 additions & 3 deletions Tests/OneWayTests/PropertyWrappersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ final class PropertyWrappersTests: XCTestCase {
super.setUp()
}

func test_heap() {
func test_copyOnWrite() {
struct Storage {
@Heap var value: Int
@Heap var optionalValue: Int?
@CopyOnWrite var value: Int
@CopyOnWrite var optionalValue: Int?
}

do {
Expand Down