SwiftNRC

main

Swift Objects without Reference Counting
joehinkle11/SwiftNRC

Swift No Reference Counting (NRC)

Swift objects without ARC/reference counting.

This is an experimental idea to provide objects in Swift without having the overhead of reference counting and other features baked into native Swift classes.

The core concept is to just to use Swift macros to prettify the usage of UnsafeMutablePointer and UnsafeMutableRawPointer to create a simple object system.

Setup

    
    dependencies: [
        .package(
            url: "https://github.com/joehinkle11/SwiftNRC",
            .upToNextMajor(from: "1.0.0")),
    ],
    targets: [
        .target(
            name: "YourTarget",
            plugins: ["SwiftNRC"]
        ),
    ]

Examples

@NRC(
    members: [
        "var y": Int.self,
        "private var x": Double.self,
        "internal var z": Bool.self,
    ]
)
struct Example: SwiftNRCObject {
    
    init() {
        self = Self.allocate((
            y: 5,
            x: 4.3,
            z: true
        ))
    }
    
    func flipZ() {
        self.z.toggle()
    }
    
    func delete() {
        self.deallocate()
    }
}

let example = Example()
// XCTAssertEqual(example.x, 4.3) // no access, x is private
XCTAssertEqual(example.y, 5)
XCTAssertEqual(example.z, true)
example.z = false
XCTAssertEqual(example.z, false)
func scoped(_ copiedRef: Example) {
    copiedRef.y = 100
}
XCTAssertEqual(example.y, 5)
scoped(example)
XCTAssertEqual(example.y, 100)

Static Array Support

You can also now allocate a static array between/among other properties in your object like in a c struct:

@NRC(
    members: [
        "let before" : String.self,
        "var myArray": NRCStaticArray(Int.self, 10),
        "let after" : String.self,
    ]
)
struct ExampleStaticArray: SwiftNRCObject {
    
    init?(_ numbers: Int...) {
        guard numbers.count == Self.myArrayCount else {
            return nil
        }
        self = .allocate()
        self.initialize_before(to: "before string")
        for (i, number) in numbers.enumerated() {
            self.myArray.initialize(index: i, to: number)
        }
        self.initialize_after(to: "after string")
    }
    func delete() {
        self.deallocate()
    }
    
}

func arrayUsage() {
    let exampleStaticArray = ExampleStaticArray(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)!
    for i in 0..<10 {
        XCTAssertEqual(exampleStaticArray.myArray[i], 9 - i)
        exampleStaticArray.myArray[i] = i
    }
    let pointerToFirstElement = exampleStaticArray.myArrayPointer
}

All static array values (and properties for that matter) will be contiguous in memory. This means that you can pass a pointer to the first element of the array to a c function and it will be able to read all the values in the array.

Use Cases

Uses these non-reference counted objects is more performant than traditional classes in Swift. In a performance critical application, this objects of this sort can help reduce the overhead associated with ARC.

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

Last updated: Mon Apr 15 2024 16:06:58 GMT-0900 (Hawaii-Aleutian Daylight Time)