|
| 1 | +// |
| 2 | +// UnsafeHeterogeneousBuffer.swift |
| 3 | +// OpenSwiftUICore |
| 4 | +// |
| 5 | +// Audited for iOS 18.0 |
| 6 | +// Status: Complete |
| 7 | +// ID: 568350FE259575B5E1AAA52AD722AAAC (SwiftUICore) |
| 8 | + |
| 9 | +package struct UnsafeHeterogeneousBuffer: Collection { |
| 10 | + var buf: UnsafeMutableRawPointer! |
| 11 | + var available: Int32 |
| 12 | + var _count: Int32 |
| 13 | + |
| 14 | + package typealias VTable = _UnsafeHeterogeneousBuffer_VTable |
| 15 | + package typealias Element = _UnsafeHeterogeneousBuffer_Element |
| 16 | + |
| 17 | + package struct Index: Equatable, Comparable { |
| 18 | + var index: Int32 |
| 19 | + var offset: Int32 |
| 20 | + |
| 21 | + package static func < (lhs: Index, rhs: Index) -> Bool { |
| 22 | + lhs.index < rhs.index |
| 23 | + } |
| 24 | + |
| 25 | + package static func == (a: Index, b: Index) -> Bool { |
| 26 | + a.index == b.index && a.offset == b.offset |
| 27 | + } |
| 28 | + } |
| 29 | + |
| 30 | + package struct Item { |
| 31 | + let vtable: _UnsafeHeterogeneousBuffer_VTable.Type |
| 32 | + let size: Int32 |
| 33 | + var flags: UInt32 |
| 34 | + } |
| 35 | + |
| 36 | + package var count: Int { Int(_count) } |
| 37 | + package var isEmpty: Bool { _count == 0 } |
| 38 | + |
| 39 | + package var startIndex: Index { |
| 40 | + Index(index: 0, offset: 0) |
| 41 | + } |
| 42 | + package var endIndex: Index { |
| 43 | + Index(index: _count, offset: 0) |
| 44 | + } |
| 45 | + |
| 46 | + package init() { |
| 47 | + buf = nil |
| 48 | + available = 0 |
| 49 | + _count = 0 |
| 50 | + } |
| 51 | + |
| 52 | + private mutating func allocate(_ bytes: Int) -> UnsafeMutableRawPointer { |
| 53 | + var count = _count |
| 54 | + var offset = 0 |
| 55 | + var size = 0 |
| 56 | + while count != 0 { |
| 57 | + let itemSize = buf |
| 58 | + .advanced(by: offset) |
| 59 | + .assumingMemoryBound(to: Item.self) |
| 60 | + .pointee |
| 61 | + .size |
| 62 | + offset &+= Int(itemSize) |
| 63 | + count &-= 1 |
| 64 | + offset = count == 0 ? 0 : offset |
| 65 | + size &+= Int(itemSize) |
| 66 | + } |
| 67 | + // Grow buffer if needed |
| 68 | + if Int(available) < bytes { |
| 69 | + growBuffer(by: bytes, capacity: size + Int(available)) |
| 70 | + } |
| 71 | + let ptr = buf.advanced(by: size) |
| 72 | + available = available - Int32(bytes) |
| 73 | + return ptr |
| 74 | + } |
| 75 | + |
| 76 | + private mutating func growBuffer(by size: Int, capacity: Int) { |
| 77 | + let expectedSize = size + capacity |
| 78 | + var allocSize = Swift.max(capacity &* 2, 64) |
| 79 | + while allocSize < expectedSize { |
| 80 | + allocSize &*= 2 |
| 81 | + } |
| 82 | + let allocatedBuffer = UnsafeMutableRawPointer.allocate( |
| 83 | + byteCount: allocSize, |
| 84 | + alignment: .zero |
| 85 | + ) |
| 86 | + if let buf { |
| 87 | + var count = _count |
| 88 | + if count != 0 { |
| 89 | + var itemSize: Int32 = 0 |
| 90 | + var oldBuffer = buf |
| 91 | + var newBuffer = allocatedBuffer |
| 92 | + repeat { |
| 93 | + count &-= 1 |
| 94 | + let newItemPointer = newBuffer.assumingMemoryBound(to: Item.self) |
| 95 | + let oldItemPointer = oldBuffer.assumingMemoryBound(to: Item.self) |
| 96 | + |
| 97 | + if count == 0 { |
| 98 | + itemSize = 0 |
| 99 | + } else { |
| 100 | + itemSize &+= oldItemPointer.pointee.size |
| 101 | + } |
| 102 | + newItemPointer.initialize(to: oldItemPointer.pointee) |
| 103 | + oldItemPointer.pointee.vtable.moveInitialize( |
| 104 | + elt: .init(item: newItemPointer), |
| 105 | + from: .init(item: oldItemPointer) |
| 106 | + ) |
| 107 | + let size = Int(oldItemPointer.pointee.size) |
| 108 | + oldBuffer += size |
| 109 | + newBuffer += size |
| 110 | + } while count != 0 || itemSize != 0 |
| 111 | + |
| 112 | + } |
| 113 | + buf.deallocate() |
| 114 | + } |
| 115 | + buf = allocatedBuffer |
| 116 | + available += Int32(allocSize - capacity) |
| 117 | + } |
| 118 | + |
| 119 | + package func destroy() { |
| 120 | + defer { buf?.deallocate() } |
| 121 | + guard _count != 0 else { |
| 122 | + return |
| 123 | + } |
| 124 | + var count = _count |
| 125 | + var offset = 0 |
| 126 | + while count != 0 { |
| 127 | + let itemPointer = buf |
| 128 | + .advanced(by: offset) |
| 129 | + .assumingMemoryBound(to: Item.self) |
| 130 | + itemPointer.pointee.vtable.deinitialize(elt: .init(item: itemPointer)) |
| 131 | + offset &+= Int(itemPointer.pointee.size) |
| 132 | + count &-= 1 |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + package func formIndex(after index: inout Index) { |
| 137 | + index = self.index(after: index) |
| 138 | + } |
| 139 | + |
| 140 | + package func index(after index: Index) -> Index { |
| 141 | + let item = self[index].item.pointee |
| 142 | + let newIndex = index.index &+ 1 |
| 143 | + if newIndex == _count { |
| 144 | + return Index(index: newIndex, offset: 0) |
| 145 | + } else { |
| 146 | + let newOffset = index.offset &+ item.size |
| 147 | + return Index(index: newIndex, offset: newOffset) |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + package subscript(index: Index) -> Element { |
| 152 | + .init(item: buf |
| 153 | + .advanced(by: Int(index.offset)) |
| 154 | + .assumingMemoryBound(to: Item.self) |
| 155 | + ) |
| 156 | + } |
| 157 | + |
| 158 | + @discardableResult |
| 159 | + package mutating func append<T>(_ value: T, vtable: VTable.Type) -> Index { |
| 160 | + let bytes = MemoryLayout<T>.size + MemoryLayout<UnsafeHeterogeneousBuffer.Item>.size |
| 161 | + let pointer = allocate(bytes) |
| 162 | + let element = _UnsafeHeterogeneousBuffer_Element(item: pointer.assumingMemoryBound(to: Item.self)) |
| 163 | + element.item.initialize(to: Item(vtable: vtable, size: Int32(bytes), flags: 0)) |
| 164 | + element.body(as: T.self).initialize(to: value) |
| 165 | + let index = Index(index: _count, offset: Int32(pointer - buf)) |
| 166 | + _count += 1 |
| 167 | + return index |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +@_spi(ForOpenSwiftUIOnly) |
| 172 | +public struct _UnsafeHeterogeneousBuffer_Element { |
| 173 | + var item: UnsafeMutablePointer<UnsafeHeterogeneousBuffer.Item> |
| 174 | + |
| 175 | + package func hasType<T>(_ type: T.Type) -> Bool { |
| 176 | + item.pointee.vtable.hasType(type) |
| 177 | + } |
| 178 | + |
| 179 | + package func vtable<T>(as type: T.Type) -> T.Type where T: _UnsafeHeterogeneousBuffer_VTable { |
| 180 | + address.assumingMemoryBound(to: Swift.type(of: type)).pointee |
| 181 | + } |
| 182 | + |
| 183 | + package func body<T>(as type: T.Type) -> UnsafeMutablePointer<T> { |
| 184 | + UnsafeMutableRawPointer(item.advanced(by: 1)).assumingMemoryBound(to: type) |
| 185 | + } |
| 186 | + |
| 187 | + package var flags: UInt32 { |
| 188 | + get { item.pointee.flags } |
| 189 | + nonmutating set { item.pointee.flags = newValue } |
| 190 | + } |
| 191 | + |
| 192 | + package var address: UnsafeRawPointer { |
| 193 | + UnsafeRawPointer(item) |
| 194 | + } |
| 195 | +} |
| 196 | + |
| 197 | +@_spi(ForOpenSwiftUIOnly) |
| 198 | +@available(*, unavailable) |
| 199 | +extension _UnsafeHeterogeneousBuffer_Element: Sendable {} |
| 200 | + |
| 201 | +@_spi(ForOpenSwiftUIOnly) |
| 202 | +open class _UnsafeHeterogeneousBuffer_VTable { |
| 203 | + open class func hasType<T>(_ type: T.Type) -> Bool { |
| 204 | + false |
| 205 | + } |
| 206 | + |
| 207 | + open class func moveInitialize(elt: _UnsafeHeterogeneousBuffer_Element, from: _UnsafeHeterogeneousBuffer_Element) { |
| 208 | + preconditionFailure("") |
| 209 | + } |
| 210 | + |
| 211 | + open class func deinitialize(elt: _UnsafeHeterogeneousBuffer_Element) { |
| 212 | + preconditionFailure("") |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +@_spi(ForOpenSwiftUIOnly) |
| 217 | +@available(*, unavailable) |
| 218 | +extension _UnsafeHeterogeneousBuffer_VTable: Sendable {} |
0 commit comments