diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Headers/AGGraph.h b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Headers/AGGraph.h index e97e9c88..7dfc2183 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Headers/AGGraph.h +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Headers/AGGraph.h @@ -79,15 +79,16 @@ uint64_t AGGraphGetCounter(AGGraphRef graph, AGGraphCounterQueryType query) AG_S // MARK: Main handler +typedef void (*AGGraphMainThreadHandler)(void (*trampoline_thunk)(const void *trampoline AG_SWIFT_CONTEXT) + AG_SWIFT_CC(swift), + const void *trampoline, const void *_Nullable context AG_SWIFT_CONTEXT) + AG_SWIFT_CC(swift); + AG_EXPORT AG_REFINED_FOR_SWIFT void AGGraphWithMainThreadHandler(AGGraphRef graph, void (*body)(const void *context AG_SWIFT_CONTEXT) AG_SWIFT_CC(swift), - const void *body_context, - void (*main_thread_handler)(void (*trampoline_thunk)(const void *), - const void *trampoline, - const void *context AG_SWIFT_CONTEXT) - AG_SWIFT_CC(swift), + const void *body_context, AGGraphMainThreadHandler main_thread_handler, const void *main_thread_handler_context); // MARK: Subgraphs diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64-apple-ios-macabi.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64-apple-ios-macabi.swiftinterface index ab42a006..69e5c48f 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64-apple-ios-macabi.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64-apple-ios-macabi.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64e-apple-ios-macabi.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64e-apple-ios-macabi.swiftinterface index 147789ad..2eab46e6 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64e-apple-ios-macabi.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/arm64e-apple-ios-macabi.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/x86_64-apple-ios-macabi.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/x86_64-apple-ios-macabi.swiftinterface index e43ee101..487f78ac 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/x86_64-apple-ios-macabi.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/maccatalyst-arm64_arm64e_x86_64/AttributeGraph.framework/Modules/AttributeGraph.swiftmodule/x86_64-apple-ios-macabi.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Headers/AGGraph.h b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Headers/AGGraph.h index e97e9c88..7dfc2183 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Headers/AGGraph.h +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Headers/AGGraph.h @@ -79,15 +79,16 @@ uint64_t AGGraphGetCounter(AGGraphRef graph, AGGraphCounterQueryType query) AG_S // MARK: Main handler +typedef void (*AGGraphMainThreadHandler)(void (*trampoline_thunk)(const void *trampoline AG_SWIFT_CONTEXT) + AG_SWIFT_CC(swift), + const void *trampoline, const void *_Nullable context AG_SWIFT_CONTEXT) + AG_SWIFT_CC(swift); + AG_EXPORT AG_REFINED_FOR_SWIFT void AGGraphWithMainThreadHandler(AGGraphRef graph, void (*body)(const void *context AG_SWIFT_CONTEXT) AG_SWIFT_CC(swift), - const void *body_context, - void (*main_thread_handler)(void (*trampoline_thunk)(const void *), - const void *trampoline, - const void *context AG_SWIFT_CONTEXT) - AG_SWIFT_CC(swift), + const void *body_context, AGGraphMainThreadHandler main_thread_handler, const void *main_thread_handler_context); // MARK: Subgraphs diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64-apple-macos.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64-apple-macos.swiftinterface index 618db751..fbed5933 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64-apple-macos.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64-apple-macos.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64e-apple-macos.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64e-apple-macos.swiftinterface index 2f2bc818..40ef7377 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64e-apple-macos.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/arm64e-apple-macos.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/x86_64-apple-macos.swiftinterface b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/x86_64-apple-macos.swiftinterface index 4ed6c39a..9f7cbb4c 100644 --- a/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/x86_64-apple-macos.swiftinterface +++ b/CompatibilityTesting/Frameworks/AttributeGraph.xcframework/macos-arm64_arm64e_x86_64/AttributeGraph.framework/Versions/A/Modules/AttributeGraph.swiftmodule/x86_64-apple-macos.swiftinterface @@ -40,10 +40,6 @@ extension AttributeGraph.AnyAttribute : @retroactive Swift.CustomStringConvertib get } } -extension AttributeGraph.AnyAttribute : @retroactive Swift.Equatable { -} -extension AttributeGraph.AnyAttribute : @retroactive Swift.Hashable { -} extension AttributeGraph.AnyAttribute { public typealias _ObjectiveCType = AttributeGraph.AnyAttribute.RawValue } @@ -669,7 +665,11 @@ extension AttributeGraph.Metadata : @retroactive Swift.Hashable { extension AttributeGraph.Signature : @retroactive Swift.Equatable { public static func == (lhs: AttributeGraph.Signature, rhs: AttributeGraph.Signature) -> Swift.Bool } -public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_silgen_name("AGTupleWithBuffer") +public func AGTupleWithBuffer(of type: AttributeGraph.TupleType, count: Swift.Int, body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) +@_alwaysEmitIntoClient public func withUnsafeTuple(of type: AttributeGraph.TupleType, count: Swift.Int, _ body: (AttributeGraph.UnsafeMutableTuple) -> Swift.Void) { + AGTupleWithBuffer(of: type, count: count, body: body) +} extension AttributeGraph.TupleType { public init(_ types: [any Any.Type]) public init(_ type: any Any.Type) @@ -688,48 +688,116 @@ extension AttributeGraph.TupleType { public func setElement(in tupleValue: Swift.UnsafeMutableRawPointer, at index: Swift.Int, from sourceValue: Swift.UnsafePointer, options: AttributeGraph.TupleType.CopyOptions) } extension AttributeGraph.UnsafeTuple { - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress + @_alwaysEmitIntoClient unsafeAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.UnsafeMutableTuple { - public init(with tupleType: AttributeGraph.TupleType) - public func deallocate(initialized: Swift.Bool) - public func initialize(at index: Swift.Int, to element: T) - public func deinitialize() + @_alwaysEmitIntoClient public init(with tupleType: AttributeGraph.TupleType) { + self.init( + type: tupleType, + value: UnsafeMutableRawPointer.allocate( + byteCount: tupleType.size, + alignment: -1 + ) + ) + } + @_alwaysEmitIntoClient public func deallocate(initialized: Swift.Bool) { + if initialized { + deinitialize() + } + value.deallocate() + } + @_alwaysEmitIntoClient public func initialize(at index: Swift.Int, to element: T) { + withUnsafePointer(to: element) { elementPointer in + type.setElement( + in: value, + at: index, + from: elementPointer, + options: .initCopy + ) + } + } + @_alwaysEmitIntoClient public func deinitialize() { + type.destroy(value) + } public func deinitialize(at index: Swift.Int) - public var count: Swift.Int { - get + @_alwaysEmitIntoClient public var count: Swift.Int { + get { + return type.count + } } - public var isEmpty: Swift.Bool { - get + @_alwaysEmitIntoClient public var isEmpty: Swift.Bool { + get { + return type.isEmpty + } } - public var indices: Swift.Range { - get + @_alwaysEmitIntoClient public var indices: Swift.Range { + get { + return type.indices + } } - public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer - public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> Swift.UnsafeMutablePointer { + guard type.type == expectedType else { + preconditionFailure() + } + return value.assumingMemoryBound(to: expectedType) + } + @_alwaysEmitIntoClient public func address(of index: Swift.Int, as elementType: T.Type) -> Swift.UnsafeMutablePointer { + return value.advanced( + by: type.elementOffset(at: index, type: Metadata(elementType)) + ) + .assumingMemoryBound(to: elementType) + } public subscript() -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(as: T.self) + } } public subscript(index: Swift.Int) -> T { - unsafeAddress - nonmutating unsafeMutableAddress + @_alwaysEmitIntoClient unsafeAddress { + return UnsafePointer(address(of: index, as: T.self)) + } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { + return address(of: index, as: T.self) + } } } extension AttributeGraph.Attribute : Swift.Sendable {} diff --git a/CompatibilityTesting/Package.swift b/CompatibilityTesting/Package.swift index 6d8fe8df..949d86cc 100644 --- a/CompatibilityTesting/Package.swift +++ b/CompatibilityTesting/Package.swift @@ -28,10 +28,24 @@ let package = Package( ], linkerSettings: [.linkedLibrary("swiftDemangle")] ), + .testTarget( + name: "ComputeSwiftCompatibilityTests", + dependencies: [ + "AttributeGraph", + .product(name: "_ComputeTestSupport", package: "Compute"), + .product(name: "Algorithms", package: "swift-algorithms"), + ], + swiftSettings: [ + .define("COMPATIBILITY_TESTS"), + .enableExperimentalFeature("Extern"), + ], + linkerSettings: [.linkedLibrary("swiftDemangle")] + ), .testTarget( name: "ComputeLayoutDescriptorCompatibilityTests", dependencies: [ - "AttributeGraph" + "AttributeGraph", + .product(name: "_ComputeTestSupport", package: "Compute"), ], swiftSettings: [ .define("COMPATIBILITY_TESTS"), diff --git a/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shared b/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shared new file mode 120000 index 00000000..9d71b7e9 --- /dev/null +++ b/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shared @@ -0,0 +1 @@ +../../../Tests/ComputeSwiftTests/Shared \ No newline at end of file diff --git a/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shims.swift b/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shims.swift new file mode 100644 index 00000000..c16037dc --- /dev/null +++ b/CompatibilityTesting/Tests/ComputeSwiftCompatibilityTests/Shims.swift @@ -0,0 +1,5 @@ +@_exported public import AttributeGraph + +let prefetchLayoutsEnvironmentVariable = "AG_PREFETCH_LAYOUTS" +let asyncLayoutsEnvironmentVariable = "AG_ASYNC_LAYOUTS" +let printLayoutsEnvironmentVariable = "AG_PRINT_LAYOUTS" diff --git a/Package.swift b/Package.swift index e9f8e06a..491f9eab 100644 --- a/Package.swift +++ b/Package.swift @@ -49,11 +49,14 @@ let package = Package( dependencies: ["ComputeCxx"], swiftSettings: [ .enableExperimentalFeature("Extern"), - .unsafeFlags([ - "-enable-library-evolution", - // When -enable-library-evolution is specified verify-emitted-module-interface command fails - "-no-verify-emitted-module-interface", - ]), + .unsafeFlags( + [ + "-enable-library-evolution", + // When -enable-library-evolution is specified verify-emitted-module-interface command fails + "-no-verify-emitted-module-interface", + ], + .when(platforms: [.macOS, .macCatalyst, .iOS, .tvOS, .watchOS, .visionOS]) + ), ], linkerSettings: [ .linkedLibrary("crypto", .when(platforms: [.linux])) @@ -75,7 +78,8 @@ let package = Package( .testTarget( name: "ComputeLayoutDescriptorTests", dependencies: [ - "Compute" + "Compute", + "_ComputeTestSupport", ], swiftSettings: [ .enableExperimentalFeature("Extern") diff --git a/Sources/Compute/Attribute/AnyAttribute.swift b/Sources/Compute/Attribute/AnyAttribute.swift index 2f68e170..beddef60 100644 --- a/Sources/Compute/Attribute/AnyAttribute.swift +++ b/Sources/Compute/Attribute/AnyAttribute.swift @@ -16,7 +16,6 @@ func IAGGraphSearch( ) -> Bool extension AnyAttribute { - public static var current: AnyAttribute? { let attribute = __IAGGraphGetCurrentAttribute() return attribute == .nil ? nil : attribute @@ -95,21 +94,14 @@ extension AnyAttribute { public var valueType: Any.Type { return info.type.pointee.value_id.type } - } extension AnyAttribute: @retroactive CustomStringConvertible { - public var description: String { return "#\(rawValue)" } - } -extension AnyAttribute: @retroactive Equatable {} - -extension AnyAttribute: @retroactive Hashable {} - extension AnyAttribute { public typealias _ObjectiveCType = Self.RawValue // Fixes compiler crash } diff --git a/Sources/Compute/Runtime/Tuple.swift b/Sources/Compute/Runtime/Tuple.swift index 6643a5bd..47a09094 100644 --- a/Sources/Compute/Runtime/Tuple.swift +++ b/Sources/Compute/Runtime/Tuple.swift @@ -1,22 +1,22 @@ import ComputeCxx @_silgen_name("IAGTupleWithBuffer") -func IAGTupleWithBuffer( +public func IAGTupleWithBuffer( of type: TupleType, count: Int, body: (UnsafeMutableTuple) -> Void ) +@_alwaysEmitIntoClient public func withUnsafeTuple( of type: TupleType, count: Int, - body: (UnsafeMutableTuple) -> Void + _ body: (UnsafeMutableTuple) -> Void ) { - return IAGTupleWithBuffer(of: type, count: count, body: body) + IAGTupleWithBuffer(of: type, count: count, body: body) } extension TupleType { - public init(_ types: [Any.Type]) { self.init(count: types.count, elements: types.map(Metadata.init)) } @@ -78,23 +78,25 @@ extension TupleType { options ) } - } extension UnsafeTuple { - + @_alwaysEmitIntoClient public var count: Int { return type.count } + @_alwaysEmitIntoClient public var isEmpty: Bool { return type.isEmpty } + @_alwaysEmitIntoClient public var indices: Range { return type.indices } + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> UnsafePointer { guard type.type == expectedType else { preconditionFailure() @@ -102,6 +104,7 @@ extension UnsafeTuple { return value.assumingMemoryBound(to: expectedType) } + @_alwaysEmitIntoClient public func address( of index: Int, as elementType: T.Type @@ -115,21 +118,22 @@ extension UnsafeTuple { } public subscript() -> T { + @_alwaysEmitIntoClient unsafeAddress { return address(as: T.self) } } public subscript(_ index: Int) -> T { + @_alwaysEmitIntoClient unsafeAddress { return address(of: index, as: T.self) } } - } extension UnsafeMutableTuple { - + @_alwaysEmitIntoClient public init(with tupleType: TupleType) { self.init( type: tupleType, @@ -140,6 +144,7 @@ extension UnsafeMutableTuple { ) } + @_alwaysEmitIntoClient public func deallocate(initialized: Bool) { if initialized { deinitialize() @@ -147,6 +152,7 @@ extension UnsafeMutableTuple { value.deallocate() } + @_alwaysEmitIntoClient public func initialize(at index: Int, to element: T) { withUnsafePointer(to: element) { elementPointer in type.setElement( @@ -158,6 +164,7 @@ extension UnsafeMutableTuple { } } + @_alwaysEmitIntoClient public func deinitialize() { type.destroy(value) } @@ -166,18 +173,22 @@ extension UnsafeMutableTuple { type.destroy(value, at: index) } + @_alwaysEmitIntoClient public var count: Int { return type.count } + @_alwaysEmitIntoClient public var isEmpty: Bool { return type.isEmpty } + @_alwaysEmitIntoClient public var indices: Range { return type.indices } + @_alwaysEmitIntoClient public func address(as expectedType: T.Type) -> UnsafeMutablePointer { guard type.type == expectedType else { preconditionFailure() @@ -185,6 +196,7 @@ extension UnsafeMutableTuple { return value.assumingMemoryBound(to: expectedType) } + @_alwaysEmitIntoClient public func address( of index: Int, as elementType: T.Type @@ -198,21 +210,24 @@ extension UnsafeMutableTuple { } public subscript() -> T { + @_alwaysEmitIntoClient unsafeAddress { return UnsafePointer(address(as: T.self)) } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { return address(as: T.self) } } public subscript(_ index: Int) -> T { + @_alwaysEmitIntoClient unsafeAddress { return UnsafePointer(address(of: index, as: T.self)) } + @_alwaysEmitIntoClient nonmutating unsafeMutableAddress { return address(of: index, as: T.self) } } - } diff --git a/Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.cpp b/Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.cpp index a0b4a2bd..0c36c276 100644 --- a/Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.cpp +++ b/Sources/ComputeCxx/Attribute/AttributeData/Node/IndirectNode.cpp @@ -16,7 +16,7 @@ const MutableIndirectNode &IndirectNode::to_mutable() const { void IndirectNode::modify(WeakAttributeID source, size_t offset) { _source = source; - _offset = offset; + _offset = (unsigned int)offset; } } // namespace IAG diff --git a/Sources/ComputeCxx/Attribute/AttributeData/Node/Node.h b/Sources/ComputeCxx/Attribute/AttributeData/Node/Node.h index 4d7fffe0..8bf8e21d 100644 --- a/Sources/ComputeCxx/Attribute/AttributeData/Node/Node.h +++ b/Sources/ComputeCxx/Attribute/AttributeData/Node/Node.h @@ -26,8 +26,7 @@ enum class NodeState : uint8_t { RequiresMainThread = 1 << 3, ValueInitialized = 1 << 4, SelfInitialized = 1 << 5, - Updating = 1 << 6, - UpdatingCyclic = 1 << 7, + CountMask = (1 << 6) | (1 << 7), }; inline NodeState operator|(NodeState a, NodeState b) { return static_cast(static_cast(a) | static_cast(b)); @@ -103,9 +102,17 @@ class Node { _state = value ? _state | NodeState::SelfInitialized : _state & ~NodeState::SelfInitialized; } - bool is_updating() const { return (_state & (NodeState::Updating | NodeState::UpdatingCyclic)) != (NodeState)0; }; - void set_updating(bool value) { _state = value ? _state | NodeState::Updating : _state & ~NodeState::Updating; } + bool is_updating() const { return (_state & NodeState::CountMask) != (NodeState)0; }; + uint8_t count() const { return (uint8_t)_state >> 6; }; + void increment_count() { + assert(count() < 3); + _state = (NodeState)((uint8_t)_state + 0x40); + }; + void decrement_count() { + assert(count() > 0); + _state = (NodeState)((uint8_t)_state - 0x40); + }; // TODO: test this IAGValueState flags() const { diff --git a/Sources/ComputeCxx/Comparison/Compare.cpp b/Sources/ComputeCxx/Comparison/Compare.cpp index 5533e53c..5027d06b 100644 --- a/Sources/ComputeCxx/Comparison/Compare.cpp +++ b/Sources/ComputeCxx/Comparison/Compare.cpp @@ -190,9 +190,8 @@ bool Compare::operator()(ValueLayout layout, const unsigned char *lhs, const uns continue; } case ValueLayoutEntryKind::CompactNested: { - uint32_t nested_layout_relative_pointer = reader.read_bytes(); - ValueLayout nested_layout = reinterpret_cast( - /* &base_address */ 0x1e3e6ab60 + nested_layout_relative_pointer); + int32_t nested_layout_relative_pointer = reader.read_bytes(); + ValueLayout nested_layout = reinterpret_cast(&base_address + nested_layout_relative_pointer); uint16_t nested_size = reader.read_bytes(); diff --git a/Sources/ComputeCxx/Comparison/LayoutDescriptor.cpp b/Sources/ComputeCxx/Comparison/LayoutDescriptor.cpp index caf5261e..3353d96b 100644 --- a/Sources/ComputeCxx/Comparison/LayoutDescriptor.cpp +++ b/Sources/ComputeCxx/Comparison/LayoutDescriptor.cpp @@ -702,9 +702,8 @@ Partial find_partial(ValueLayout layout, size_t range_location, size_t range_siz continue; } case ValueLayoutEntryKind::CompactNested: { - uint32_t nested_layout_relative_pointer = reader.read_bytes(); - ValueLayout nested_layout = reinterpret_cast( - /* &base_address */ 0x1e3e6ab60 + nested_layout_relative_pointer); + int32_t nested_layout_relative_pointer = reader.read_bytes(); + ValueLayout nested_layout = reinterpret_cast(&base_address + nested_layout_relative_pointer); uint16_t nested_size = reader.read_bytes(); @@ -859,9 +858,8 @@ void print(std::string &output, ValueLayout layout) { continue; } case ValueLayoutEntryKind::CompactNested: { - uint32_t nested_layout_relative_pointer = reader.read_bytes(); - ValueLayout nested_layout = reinterpret_cast( - /* &base_address */ 0x1e3e6ab60 + nested_layout_relative_pointer); + int32_t nested_layout_relative_pointer = reader.read_bytes(); + ValueLayout nested_layout = reinterpret_cast(&base_address + nested_layout_relative_pointer); uint16_t nested_size = reader.read_bytes(); @@ -1306,12 +1304,12 @@ void Builder::Emitter>::operator()(const Ne _data->push_back(c); } } else { - uintptr_t layout_relative_address = (uintptr_t)item.layout - /* (uintptr_t)&base_address */ 0x1e3e6ab60; - if ((uint32_t)layout_relative_address == layout_relative_address && item.size < 0xffff) { + ptrdiff_t layout_relative_address = (intptr_t)item.layout - (intptr_t)&base_address; + if ((int32_t)layout_relative_address == layout_relative_address && item.size < 0xffff) { _data->push_back((unsigned char)ValueLayoutEntryKind::CompactNested); // layout address in 4 bytes - emit_value((uint32_t)layout_relative_address); + emit_value((int32_t)layout_relative_address); // size in two bytes emit_value((uint16_t)item.size); diff --git a/Sources/ComputeCxx/Graph/Graph.cpp b/Sources/ComputeCxx/Graph/Graph.cpp index d9c28ce0..29cd279e 100644 --- a/Sources/ComputeCxx/Graph/Graph.cpp +++ b/Sources/ComputeCxx/Graph/Graph.cpp @@ -45,6 +45,8 @@ Graph::Graph() : _heap(nullptr, 0, 0), _interned_types(nullptr, nullptr, nullptr, nullptr, &_heap), _contexts_by_id(nullptr, nullptr, nullptr, nullptr, &_heap), _id(IAGMakeUniqueID()) { + data::table::ensure_shared(); + static platform_once_t make_keys; platform_once(&make_keys, []() { pthread_key_create(&Graph::_current_update_key, 0); @@ -192,7 +194,7 @@ bool Graph::is_context_updating(uint64_t context_id) { #pragma mark - Main handler -void Graph::with_main_handler(ClosureFunctionVV body, MainHandler _Nullable main_handler, +void Graph::with_main_handler(ClosureFunctionVV body, IAGGraphMainThreadHandler _Nullable main_handler, const void *main_handler_context) { auto old_main_handler = _main_handler; @@ -216,7 +218,7 @@ void Graph::call_main_handler(void *context, void (*body)(void *)) { void *context; void (*handler)(void *); - static void thunk(const void *arg) { + static void thunk(const void *arg IAG_SWIFT_CONTEXT) IAG_SWIFT_CC(swift) { auto trampoline = reinterpret_cast(arg); trampoline->handler(trampoline->context); }; @@ -1001,6 +1003,7 @@ bool Graph::breadth_first_search(AttributeID attribute, IAGSearchOptions options } auto seen = std::set(); + seen.insert(resolved.attribute()); auto queue = std::deque(); queue.push_back(resolved.attribute()); @@ -1192,6 +1195,7 @@ Graph::UpdateStatus Graph::update_attribute(data::ptr node, IAGGraphUpdate call_main_handler(&context, [](void *void_context) { auto inner_context = reinterpret_cast *>(void_context); util::tagged_ptr previous = Graph::current_update(); + Graph::set_current_update(util::tagged_ptr(inner_context->first)); inner_context->second = inner_context->first->update(); Graph::set_current_update(previous); }); @@ -1535,9 +1539,10 @@ void *Graph::input_value_ref_slow(data::ptr node, AttributeID input, } if (index == UINT32_MAX) { - node.assert_valid(); - if (AttributeID(node).subgraph() == nullptr || AttributeID(node).subgraph()->graph() != this) { - precondition_failure("accessing attribute in a different namespace: %u", node); + input.validate_data_offset(); + auto input_subgraph = input.subgraph(); + if (input_subgraph == nullptr || input_subgraph->graph() != this) { + precondition_failure("accessing attribute in a different namespace: %u", input); } if (!node->is_dirty()) { auto resolved = input.resolve( @@ -1547,17 +1552,23 @@ void *Graph::input_value_ref_slow(data::ptr node, AttributeID input, return nullptr; } + auto resolved_subgraph = resolved.attribute().subgraph(); + if (resolved_subgraph == nullptr || resolved_subgraph->graph() != this) { + precondition_failure("accessing attribute in a different namespace: %u", resolved.attribute()); + } + update_attribute(resolved.attribute().get_node(), IAGGraphUpdateOptionsNone); } - index = add_input(node, input, subgraph_id != 0, input_options & IAGInputOptionsUnprefetched); + index = add_input(node, input, subgraph_id != 0, + input_options & (IAGInputOptionsUnprefetched | IAGInputOptionsChanged)); if (index == UINT32_MAX) { return nullptr; } } InputEdge &input_edge = node->input_edges()[index]; - input_edge.options |= input_options & IAGInputOptionsUnprefetched; + input_edge.options |= input_options & (IAGInputOptionsUnprefetched | IAGInputOptionsChanged); input_edge.options |= IAGInputOptionsEnabled; OffsetAttributeID resolved = input_edge.attribute.resolve( @@ -1581,7 +1592,7 @@ void *Graph::input_value_ref_slow(data::ptr node, AttributeID input, } if (input_options & IAGInputOptionsSyncMainRef && input_node->is_main_ref() && !value_type.getValueWitnesses()->isPOD()) { - input_node->set_requires_main_thread(true); + node->set_requires_main_thread(true); *flags_out |= IAGChangedValueFlagsRequiresMainThread; } diff --git a/Sources/ComputeCxx/Graph/Graph.h b/Sources/ComputeCxx/Graph/Graph.h index 8421b627..bc1f5949 100644 --- a/Sources/ComputeCxx/Graph/Graph.h +++ b/Sources/ComputeCxx/Graph/Graph.h @@ -72,9 +72,6 @@ class Graph { NeedsCallMainHandler = 3, }; - typedef void (*MainHandler)(void (*trampoline_thunk)(const void *), const void *trampoline, - const void *_Nullable context IAG_SWIFT_CONTEXT) IAG_SWIFT_CC(swift); - class ProfileData { public: class Data { @@ -171,7 +168,7 @@ class Graph { vector _traces; // Main thread handler - MainHandler _Nullable _main_handler = nullptr; + IAGGraphMainThreadHandler _Nullable _main_handler = nullptr; const void *_Nullable _main_handler_context = nullptr; // Metrics @@ -310,7 +307,7 @@ class Graph { bool has_main_handler() const { return _main_handler != nullptr; } - void with_main_handler(ClosureFunctionVV body, MainHandler _Nullable main_handler, + void with_main_handler(ClosureFunctionVV body, IAGGraphMainThreadHandler _Nullable main_handler, const void *_Nullable main_handler_context); // MARK: Tree diff --git a/Sources/ComputeCxx/Graph/IAGGraph.cpp b/Sources/ComputeCxx/Graph/IAGGraph.cpp index d1867f21..e56d067c 100644 --- a/Sources/ComputeCxx/Graph/IAGGraph.cpp +++ b/Sources/ComputeCxx/Graph/IAGGraph.cpp @@ -153,11 +153,7 @@ uint64_t IAGGraphGetCounter(IAGGraphRef graph, IAGGraphCounterQueryType query) { void IAGGraphWithMainThreadHandler(IAGGraphRef graph, void (*body)(const void *context IAG_SWIFT_CONTEXT) IAG_SWIFT_CC(swift), - const void *body_context, - void (*main_thread_handler)(void (*trampoline_thunk)(const void *), - const void *trampoline, - const void *context IAG_SWIFT_CONTEXT) - IAG_SWIFT_CC(swift), + const void *body_context, IAGGraphMainThreadHandler main_thread_handler, const void *main_thread_handler_context) { auto graph_context = IAG::Graph::Context::from_cf(graph); graph_context->graph().with_main_handler(IAG::ClosureFunctionVV(body, body_context), main_thread_handler, diff --git a/Sources/ComputeCxx/Graph/UpdateStack.cpp b/Sources/ComputeCxx/Graph/UpdateStack.cpp index b34ed9dc..0290f807 100644 --- a/Sources/ComputeCxx/Graph/UpdateStack.cpp +++ b/Sources/ComputeCxx/Graph/UpdateStack.cpp @@ -30,7 +30,7 @@ Graph::UpdateStack::UpdateStack(Graph *graph, IAGGraphUpdateOptions options) Graph::UpdateStack::~UpdateStack() { for (auto &frame : _frames) { - frame.attribute->set_updating(false); + frame.attribute->decrement_count(); } if (_thread != _graph->_current_update_thread) { @@ -80,7 +80,7 @@ bool Graph::UpdateStack::cancelled() { bool Graph::UpdateStack::push(data::ptr node_ptr, Node &node, bool ignore_cycles, bool initialize_value) { if (!node.is_updating() && _frames.size() + 1 <= _frames.capacity()) { - node.set_updating(true); + node.increment_count(); Frame frame = Frame(node_ptr); if (node.is_pending() || (!node.is_value_initialized() && initialize_value)) { @@ -95,9 +95,9 @@ bool Graph::UpdateStack::push(data::ptr node_ptr, Node &node, bool ignore_ } bool Graph::UpdateStack::push_slow(data::ptr node_ptr, Node &node, bool ignore_cycles, bool initialize_value) { - NodeState old_state = node.state(); + uint8_t old_count = node.count(); - if ((old_state & (NodeState::Updating | old_state & NodeState::UpdatingCyclic)) != NodeState(0)) { + if (old_count != 0) { if (ignore_cycles) { return false; } @@ -133,18 +133,18 @@ bool Graph::UpdateStack::push_slow(data::ptr node_ptr, Node &node, bool ig } } - if ((old_state & NodeState::UpdatingCyclic) != NodeState(0)) { + if (old_count == 3) { precondition_failure("cyclic graph: %u", node_ptr); } } - node.set_updating(true); + node.increment_count(); Frame frame = Frame(node_ptr); if (node.is_pending() || (!node.is_value_initialized() && initialize_value)) { frame.pending = true; } - if ((old_state & (NodeState::Updating | old_state & NodeState::UpdatingCyclic)) != NodeState(0)) { + if (old_count != 0) { frame.cyclic = true; } _frames.push_back(frame); @@ -180,15 +180,16 @@ Graph::UpdateStatus Graph::UpdateStack::update() { callback(reinterpret_cast(&attribute_type), self); changed = true; } + } - if (node->is_value_initialized()) { - node->set_updating(false); + if (node->is_value_initialized()) { + node->decrement_count(); - _frames.pop_back(); - if (_frames.empty()) { - return changed ? UpdateStatus::Changed : UpdateStatus::Unchanged; - } + _frames.pop_back(); + if (_frames.empty()) { + return changed ? UpdateStatus::Changed : UpdateStatus::Unchanged; } + continue; } } @@ -197,7 +198,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { frame.pending = true; } - // Push inputs + // Push prefetched inputs for (auto input_index = frame.num_pushed_inputs, num_inputs = node->input_edges().size(); input_index != num_inputs; ++input_index) { @@ -228,7 +229,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { if (!input_node->is_value_initialized() || input_node->is_dirty()) { - if (!(input_edge.options & IAGInputOptionsChanged) && input_attribute.subgraph()->is_valid()) { + if (!(input_edge.options & IAGInputOptionsUnprefetched) && input_attribute.subgraph()->is_valid()) { frame.num_pushed_inputs = input_index + 1; if (push(input_node, *input_node.get(), true, true)) { // go to top @@ -244,6 +245,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { // Update value bool changed = false; + if (frame.pending) { if (_graph->has_main_handler() && node->is_main_thread()) { return Graph::UpdateStatus::NeedsCallMainHandler; @@ -313,7 +315,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { } } - node->set_updating(false); + node->decrement_count(); if (reset_node_flags) { if (node->is_self_modified()) { @@ -323,7 +325,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { _graph->foreach_trace([&frame](Trace &trace) { trace.set_dirty(frame.attribute, false); }); node->set_dirty(false); } - node->set_main_thread(node->requires_main_thread()); + node->set_main_thread(node->is_main_thread() && node->requires_main_thread()); } if (node->is_pending()) { @@ -333,7 +335,7 @@ Graph::UpdateStatus Graph::UpdateStack::update() { _frames.pop_back(); if (_frames.empty()) { - return UpdateStatus::Changed; + return changed ? UpdateStatus::Changed : UpdateStatus::Unchanged; } } } diff --git a/Sources/ComputeCxx/Subgraph/Subgraph.cpp b/Sources/ComputeCxx/Subgraph/Subgraph.cpp index 96490066..4f34c2d4 100644 --- a/Sources/ComputeCxx/Subgraph/Subgraph.cpp +++ b/Sources/ComputeCxx/Subgraph/Subgraph.cpp @@ -371,28 +371,21 @@ void Subgraph::remove_child(Subgraph &child, bool suppress_trace) { } bool Subgraph::ancestor_of(const Subgraph &other) { - auto untraversed_parents = std::stack>(); - const Subgraph *candidate = &other; - while (true) { - if (candidate == nullptr) { - // previous candidate was a top-level subgraph - if (untraversed_parents.empty()) { - return false; - } - candidate = untraversed_parents.top(); - untraversed_parents.pop(); - } - + auto candidates = std::stack>(); + candidates.push(&other); + while (!candidates.empty()) { + auto candidate = candidates.top(); + candidates.pop(); + if (candidate == this) { return true; } - // partition parents into first and remaining - candidate = candidate->_parents.empty() ? nullptr : candidate->_parents.front(); - for (Subgraph *parent : std::ranges::drop_view(other._parents, 1)) { - untraversed_parents.push(parent); + for (Subgraph *parent : candidate->_parents) { + candidates.push(parent); } } + return false; } #pragma mark - Flags @@ -650,7 +643,7 @@ void Subgraph::update(IAGAttributeFlags mask) { continue; } - if (subgraph->is_valid() && subgraph->_dirty_flags & mask) { + while (subgraph->is_valid() && subgraph->_dirty_flags & mask) { subgraph->_dirty_flags &= ~mask; if (mask == 0 || intersects(mask)) { diff --git a/Sources/ComputeCxx/Swift/IAGTuple.cpp b/Sources/ComputeCxx/Swift/IAGTuple.cpp index daa540b5..560b08bf 100644 --- a/Sources/ComputeCxx/Swift/IAGTuple.cpp +++ b/Sources/ComputeCxx/Swift/IAGTuple.cpp @@ -9,7 +9,7 @@ IAGTupleType IAGNewTupleType(size_t count, const IAGTypeID *elements) { return elements[0]; } auto metadata_elements = reinterpret_cast(elements); - auto response = ::swift::swift_getTupleTypeMetadata(::swift::MetadataRequest(), + auto response = ::swift::swift_getTupleTypeMetadata(::swift::MetadataRequest(::swift::MetadataState::Complete), ::swift::TupleTypeFlags().withNumElements((unsigned int)count), metadata_elements, nullptr, nullptr); if (response.State != ::swift::MetadataState::Complete) { @@ -179,6 +179,7 @@ void IAGTupleDestroyElement(IAGTupleType tuple_type, void *tuple_value, size_t i IAG::precondition_failure("index out of range: %d", index); } metadata->vw_destroy(reinterpret_cast<::swift::OpaqueValue *>(tuple_value)); + return; } auto tuple_metadata = static_cast(metadata); if (index >= tuple_metadata->NumElements) { @@ -204,6 +205,7 @@ void IAGTupleWithBuffer(IAGTupleType tuple_type, size_t count, if (buffer == nullptr) { IAG::precondition_failure("memory allocation failure"); } + bzero((void *)buffer, buffer_size); IAGUnsafeMutableTuple tuple = {tuple_type, buffer}; function(tuple, context); free(buffer); diff --git a/Sources/ComputeCxx/include/ComputeCxx/IAGGraph.h b/Sources/ComputeCxx/include/ComputeCxx/IAGGraph.h index 7896b899..fdf45880 100644 --- a/Sources/ComputeCxx/include/ComputeCxx/IAGGraph.h +++ b/Sources/ComputeCxx/include/ComputeCxx/IAGGraph.h @@ -79,15 +79,16 @@ uint64_t IAGGraphGetCounter(IAGGraphRef graph, IAGGraphCounterQueryType query) I // MARK: Main handler +typedef void (*IAGGraphMainThreadHandler)(void (*trampoline_thunk)(const void *trampoline IAG_SWIFT_CONTEXT) + IAG_SWIFT_CC(swift), + const void *trampoline, const void *_Nullable context IAG_SWIFT_CONTEXT) + IAG_SWIFT_CC(swift); + IAG_EXPORT IAG_REFINED_FOR_SWIFT void IAGGraphWithMainThreadHandler(IAGGraphRef graph, void (*body)(const void *context IAG_SWIFT_CONTEXT) IAG_SWIFT_CC(swift), - const void *body_context, - void (*main_thread_handler)(void (*trampoline_thunk)(const void *), - const void *trampoline, - const void *context IAG_SWIFT_CONTEXT) - IAG_SWIFT_CC(swift), + const void *body_context, IAGGraphMainThreadHandler main_thread_handler, const void *main_thread_handler_context); // MARK: Subgraphs diff --git a/Sources/Utilities/include/Utilities/Heap.h b/Sources/Utilities/include/Utilities/Heap.h index 21d16e9c..6b36ccdb 100644 --- a/Sources/Utilities/include/Utilities/Heap.h +++ b/Sources/Utilities/include/Utilities/Heap.h @@ -10,12 +10,12 @@ namespace util { class Heap { protected: typedef struct Node { - struct Node *next; + struct Node *_Nullable next; void *buffer; } Node; size_t _increment; - Node *_node; + Node *_Nullable _node; char *_free_start; size_t _capacity; diff --git a/Sources/_ComputeTestSupport/AssertEqualWithDiff.swift b/Sources/_ComputeTestSupport/AssertEqualWithDiff.swift index eb6509e9..81458dbd 100644 --- a/Sources/_ComputeTestSupport/AssertEqualWithDiff.swift +++ b/Sources/_ComputeTestSupport/AssertEqualWithDiff.swift @@ -67,6 +67,38 @@ public func assertStringsEqualWithDiff( ) } +/// Asserts that the a string is equal to any expected string, providing Unix `diff`-style output if they are not. +/// +/// - Parameters: +/// - actual: The actual string. +/// - expected: The expected strings. +/// - message: An optional description of the failure. +/// - additionalInfo: Additional information about the failed test case that will be printed after the diff +/// - file: The file in which failure occurred. Defaults to the file name of the test case in +/// which this function was called. +/// - line: The line number on which failure occurred. Defaults to the line number on which this +/// function was called. +public func assertStringEqualToAnyStringWithDiff( + _ actual: String, + _ expected: [String], + _ message: String = "", + additionalInfo: @autoclosure () -> String? = nil, + sourceLocation: SourceLocation = #_sourceLocation +) { + if expected.contains(actual) { + return + } + for candidate in expected { + failStringsEqualWithDiff( + actual, + candidate, + message, + additionalInfo: additionalInfo(), + sourceLocation: sourceLocation + ) + } +} + /// `Issue.record` with `diff`-style output. public func failStringsEqualWithDiff( _ actual: String, diff --git a/Tests/ComputeLayoutDescriptorTests/Shared/PrefetchCompareValuesTests.swift b/Tests/ComputeLayoutDescriptorTests/Shared/PrefetchCompareValuesTests.swift index c382bf09..446090b0 100644 --- a/Tests/ComputeLayoutDescriptorTests/Shared/PrefetchCompareValuesTests.swift +++ b/Tests/ComputeLayoutDescriptorTests/Shared/PrefetchCompareValuesTests.swift @@ -1,11 +1,11 @@ import Foundation import Testing +import _ComputeTestSupport // This suite relies heavily on process isolation, which does not complete on Linux. #if !os(Linux) public struct ValueLayout: CustomStringConvertible, Equatable { - let storage: UnsafePointer static var trivial: ValueLayout { @@ -15,7 +15,6 @@ public struct ValueLayout: CustomStringConvertible, Equatable { public var description: String { return "\(storage)".replacing(/^0x0+/, with: "0x") } - } extension Optional: @retroactive CustomStringConvertible where Wrapped == ValueLayout { @@ -72,21 +71,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: Never.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == nil) + #expect(layout1 == nil, "expected `layout1` to be nil, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: Never.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == nil) + #expect(layout2 == nil, "expected `layout2` to be nil, but was \(layout2) instead") await #expect(processExitsWith: .success) { var output3 = "" @@ -97,14 +96,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Never, 0 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 0 #:type Never)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Never, 0 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 0 #:type Never)) - """ + """ ) } } @@ -116,7 +116,7 @@ struct PrefetchCompareValuesTests { for options in allOptions { let layout = ValueLayout.prefetch(of: Void.self, options: options, priority: 0) - #expect(layout == .trivial) + #expect(layout == .trivial, "expected `layout` to be the trivial value, but was \(layout) instead") } } } @@ -132,21 +132,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: Bool.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: Bool.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == .trivial) + #expect(layout2 == .trivial, "expected `layout2` to be the trivial value, but was \(layout2) instead") var output3 = "" let layout3 = await reprintingStandardError(to: &output3) { @@ -156,14 +156,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Bool, 1 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 1 #:type Bool)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Bool, 1 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 1 #:type Bool)) - """ + """ ) } } @@ -181,21 +182,30 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect( + layout0 == .trivial, + "expected `layout0` to be the trivial value, but was \(layout0) instead" + ) let layout1 = ValueLayout.prefetch( of: type, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect( + layout1 == .trivial, + "expected `layout1` to be the trivial value, but was \(layout1) instead" + ) let layout2 = ValueLayout.prefetch( of: type, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == .trivial) + #expect( + layout2 == .trivial, + "expected `layout2` to be the trivial value, but was \(layout2) instead" + ) } } } @@ -210,14 +220,15 @@ struct PrefetchCompareValuesTests { let layout = await reprintingStandardError(to: &output) { ValueLayout.prefetch(of: Int.self, options: ComparisonOptions(mode: .equatableAlways), priority: 0) } - #expect(layout != nil) - #expect( - output == """ - == Int, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout)) - (== #:size 8 #:type Int)) + #expect(layout != nil, "expected `layout` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output, + """ + == Int, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout)) + (== #:size 8 #:type Int)) - """ + """ ) } } @@ -236,14 +247,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout != nil) - #expect( - output == """ - == Double, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout)) - (== #:size 8 #:type Double)) + #expect(layout != nil, "expected `layout` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output, + """ + == Double, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout)) + (== #:size 8 #:type Double)) - """ + """ ) } } @@ -262,14 +274,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout != nil) - #expect( - output == """ - == Float, 4 bytes == - (layout #:length 18 #:address \(String(describing: layout)) - (== #:size 4 #:type Float)) + #expect(layout != nil, "expected `layout` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output, + """ + == Float, 4 bytes == + (layout #:length 18 #:address \(String(describing: layout)) + (== #:size 4 #:type Float)) - """ + """ ) } } @@ -285,14 +298,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: String.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") var output2 = "" let layout2 = await reprintingStandardError(to: &output2) { @@ -302,14 +315,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == String, 16 bytes == - (layout #:length 18 #:address \(String(describing: layout2)) - (== #:size 16 #:type String)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == String, 16 bytes == + (layout #:length 18 #:address \(String(describing: layout2)) + (== #:size 16 #:type String)) - """ + """ ) var output3 = "" @@ -320,14 +334,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == String, 16 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 16 #:type String)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == String, 16 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 16 #:type String)) - """ + """ ) } } @@ -339,7 +354,7 @@ struct PrefetchCompareValuesTests { for options in allOptions { let layout = ValueLayout.prefetch(of: StaticString.self, options: options, priority: 0) - #expect(layout == .trivial) + #expect(layout == .trivial, "expected `layout` to be the trivial value, but was \(layout) instead") } } } @@ -354,7 +369,7 @@ struct PrefetchCompareValuesTests { struct EmptyStruct {} let layout = ValueLayout.prefetch(of: EmptyStruct.self, options: options, priority: 0) - #expect(layout == nil) + #expect(layout == nil, "expected `layout` to be nil, but was \(layout) instead") } @Test("Layout for struct enclosing single element equals the layout of the enclosed element") @@ -371,21 +386,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: StructEnclosingSingleElement.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: StructEnclosingSingleElement.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == .trivial) + #expect(layout2 == .trivial, "expected `layout2` to be the trivial value, but was \(layout2) instead") let innerLayout = ValueLayout.prefetch( of: Int.self, @@ -401,7 +416,10 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 == innerLayout) + #expect( + layout3 == innerLayout, + "expected `layout3` to equal \(innerLayout), but was \(layout3) instead" + ) } } @@ -421,21 +439,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: TrivialStruct.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: TrivialStruct.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == .trivial) + #expect(layout2 == .trivial, "expected `layout2` to be the trivial value, but was \(layout2) instead") let _ = ValueLayout.prefetch( of: Int.self, @@ -451,15 +469,16 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == TrivialStruct, 16 bytes == - (layout #:length 35 #:address \(String(describing: layout3)) - (== #:size 8 #:type Int) - (== #:size 8 #:type Int)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == TrivialStruct, 16 bytes == + (layout #:length 35 #:address \(String(describing: layout3)) + (== #:size 8 #:type Int) + (== #:size 8 #:type Int)) - """ + """ ) } } @@ -483,16 +502,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ - == StructWithAlignedElement, 16 bytes == - (layout #:length 4 #:address \(String(describing: layout0)) - (read 1) - (skip 7) - (read 8)) + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output0, + """ + == StructWithAlignedElement, 16 bytes == + (layout #:length 4 #:address \(String(describing: layout0)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -505,16 +525,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == StructWithAlignedElement, 16 bytes == - (layout #:length 4 #:address \(String(describing: layout1)) - (read 1) - (skip 7) - (read 8)) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == StructWithAlignedElement, 16 bytes == + (layout #:length 4 #:address \(String(describing: layout1)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -527,16 +548,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == StructWithAlignedElement, 16 bytes == - (layout #:length 4 #:address \(String(describing: layout2)) - (read 1) - (skip 7) - (read 8)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == StructWithAlignedElement, 16 bytes == + (layout #:length 4 #:address \(String(describing: layout2)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -560,16 +582,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == StructWithAlignedElement, 16 bytes == - (layout #:length 36 #:address \(String(describing: layout3)) - (== #:size 1 #:type Int8) - (skip 7) - (== #:size 8 #:type Int64)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == StructWithAlignedElement, 16 bytes == + (layout #:length 36 #:address \(String(describing: layout3)) + (== #:size 1 #:type Int8) + (skip 7) + (== #:size 8 #:type Int64)) - """ + """ ) } } @@ -600,16 +623,29 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringEqualToAnyStringWithDiff( + output0, + [ + // Relative layout encoded as relative pointer + """ == StructWithComplexProperty, 19 bytes == - (layout #:length 13 #:address \(String(describing: layout0)) + (layout #:length 10 #:address \(String(describing: layout0)) (read 1) (skip 7) (nested #:size 11 #:layout \(String(describing: nestedLayout0)))) + """, + // Relative layout encoded as absolute pointer """ + == StructWithComplexProperty, 19 bytes == + (layout #:length 13 #:address \(String(describing: layout0)) + (read 1) + (skip 7) + (nested #:size 11 #:layout \(String(describing: nestedLayout0)))) + + """, + ] ) } @@ -628,16 +664,29 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringEqualToAnyStringWithDiff( + output1, + [ + // Relative layout encoded as relative pointer + """ == StructWithComplexProperty, 19 bytes == - (layout #:length 13 #:address \(String(describing: layout1)) + (layout #:length 10 #:address \(String(describing: layout1)) (read 1) (skip 7) (nested #:size 11 #:layout \(String(describing: nestedLayout1)))) + """, + // Relative layout encoded as absolute pointer """ + == StructWithComplexProperty, 19 bytes == + (layout #:length 13 #:address \(String(describing: layout1)) + (read 1) + (skip 7) + (nested #:size 11 #:layout \(String(describing: nestedLayout1)))) + + """, + ] ) } @@ -656,16 +705,29 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringEqualToAnyStringWithDiff( + output2, + [ + // Relative layout encoded as relative pointer + """ == StructWithComplexProperty, 19 bytes == - (layout #:length 13 #:address \(String(describing: layout2)) + (layout #:length 10 #:address \(String(describing: layout2)) (read 1) (skip 7) (nested #:size 11 #:layout \(String(describing: nestedLayout2)))) + """, + // Relative layout encoded as absolute pointer """ + == StructWithComplexProperty, 19 bytes == + (layout #:length 13 #:address \(String(describing: layout2)) + (read 1) + (skip 7) + (nested #:size 11 #:layout \(String(describing: nestedLayout2)))) + + """, + ] ) } @@ -689,16 +751,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == StructWithComplexProperty, 19 bytes == - (layout #:length 36 #:address \(String(describing: layout3)) - (== #:size 1 #:type Int8) - (skip 7) - (== #:size 11 #:type Optional>>)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == StructWithComplexProperty, 19 bytes == + (layout #:length 36 #:address \(String(describing: layout3)) + (== #:size 1 #:type Int8) + (skip 7) + (== #:size 11 #:type Optional>>)) - """ + """ ) } } @@ -715,7 +778,7 @@ struct PrefetchCompareValuesTests { class EmptyClass {} let layout = ValueLayout.prefetch(of: EmptyClass.self, options: options, priority: 0) - #expect(layout == nil) + #expect(layout == nil, "expected `layout` to be nil, but was \(layout) instead") } @Test(arguments: allOptions) @@ -727,7 +790,7 @@ struct PrefetchCompareValuesTests { } let layout = ValueLayout.prefetch(of: TrivialClass.self, options: options, priority: 0) - #expect(layout == nil) + #expect(layout == nil, "expected `layout` to be nil, but was \(layout) instead") } @Test @@ -742,7 +805,7 @@ struct PrefetchCompareValuesTests { for options in allOptions { let layout = ValueLayout.prefetch(of: StructWithWeakVar.self, options: options, priority: 0) - #expect(layout == .trivial) + #expect(layout == .trivial, "expected `layout` to be the trivial value, but was \(layout) instead") } } } @@ -759,7 +822,7 @@ struct PrefetchCompareValuesTests { enum EmptyEnum {} let layout = ValueLayout.prefetch(of: EmptyEnum.self, options: options, priority: 0) - #expect(layout == nil) + #expect(layout == nil, "expected `layout` to be nil, but was \(layout) instead") } @Test @@ -777,21 +840,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: BasicEnum.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == nil) + #expect(layout1 == nil, "expected `layout1` to be nil, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: BasicEnum.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == nil) + #expect(layout2 == nil, "expected `layout2` to be nil, but was \(layout2) instead") await #expect(processExitsWith: .success) { var output3 = "" @@ -802,14 +865,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == BasicEnum, 1 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 1 #:type BasicEnum)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == BasicEnum, 1 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 1 #:type BasicEnum)) - """ + """ ) } } @@ -829,21 +893,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: IntEnum.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == nil) + #expect(layout1 == nil, "expected `layout1` to be nil, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: IntEnum.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == nil) + #expect(layout2 == nil, "expected `layout2` to be nil, but was \(layout2) instead") await #expect(processExitsWith: .success) { var output3 = "" @@ -854,14 +918,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == IntEnum, 1 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 1 #:type IntEnum)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == IntEnum, 1 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 1 #:type IntEnum)) - """ + """ ) } } @@ -886,18 +951,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ - == TaggedUnionEnum, 17 bytes == - (layout #:length 14 #:address \(String(describing: layout0)) - (enum #:size 17 #:type TaggedUnionEnum - (case 0 - (read 8)) - (case 1 - (read 16)))) + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output0, + """ + == TaggedUnionEnum, 17 bytes == + (layout #:length 14 #:address \(String(describing: layout0)) + (enum #:size 17 #:type TaggedUnionEnum + (case 0 + (read 8)) + (case 1 + (read 16)))) - """ + """ ) } @@ -910,18 +976,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == TaggedUnionEnum, 17 bytes == - (layout #:length 14 #:address \(String(describing: layout1)) - (enum #:size 17 #:type TaggedUnionEnum - (case 0 - (read 8)) - (case 1 - (read 16)))) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == TaggedUnionEnum, 17 bytes == + (layout #:length 14 #:address \(String(describing: layout1)) + (enum #:size 17 #:type TaggedUnionEnum + (case 0 + (read 8)) + (case 1 + (read 16)))) - """ + """ ) } @@ -940,18 +1007,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == TaggedUnionEnum, 17 bytes == - (layout #:length 30 #:address \(String(describing: layout2)) - (enum #:size 17 #:type TaggedUnionEnum - (case 0 - (read 8)) - (case 1 - (== #:size 16 #:type String)))) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == TaggedUnionEnum, 17 bytes == + (layout #:length 30 #:address \(String(describing: layout2)) + (enum #:size 17 #:type TaggedUnionEnum + (case 0 + (read 8)) + (case 1 + (== #:size 16 #:type String)))) - """ + """ ) } @@ -975,18 +1043,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == TaggedUnionEnum, 17 bytes == - (layout #:length 46 #:address \(String(describing: layout3)) - (enum #:size 17 #:type TaggedUnionEnum - (case 0 - (== #:size 8 #:type Int)) - (case 1 - (== #:size 16 #:type String)))) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == TaggedUnionEnum, 17 bytes == + (layout #:length 46 #:address \(String(describing: layout3)) + (enum #:size 17 #:type TaggedUnionEnum + (case 0 + (== #:size 8 #:type Int)) + (case 1 + (== #:size 16 #:type String)))) - """ + """ ) } } @@ -1010,18 +1079,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ - == IndirectEnum, 8 bytes == - (layout #:length 14 #:address \(String(describing: layout0)) - (enum #:size 8 #:type IndirectEnum - (case 0 - (read 8)) - (case 1 - (read 8)))) + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output0, + """ + == IndirectEnum, 8 bytes == + (layout #:length 14 #:address \(String(describing: layout0)) + (enum #:size 8 #:type IndirectEnum + (case 0 + (read 8)) + (case 1 + (read 8)))) - """ + """ ) } @@ -1034,18 +1104,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == IndirectEnum, 8 bytes == - (layout #:length 46 #:address \(String(describing: layout1)) - (enum #:size 8 #:type IndirectEnum - (case 0 - (indirect #:size 16 #:type String)) - (case 1 - (indirect #:size 8 #:type (child: IndirectEnum))))) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == IndirectEnum, 8 bytes == + (layout #:length 46 #:address \(String(describing: layout1)) + (enum #:size 8 #:type IndirectEnum + (case 0 + (indirect #:size 16 #:type String)) + (case 1 + (indirect #:size 8 #:type (child: IndirectEnum))))) - """ + """ ) } @@ -1058,18 +1129,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == IndirectEnum, 8 bytes == - (layout #:length 46 #:address \(String(describing: layout2)) - (enum #:size 8 #:type IndirectEnum - (case 0 - (indirect #:size 16 #:type String)) - (case 1 - (indirect #:size 8 #:type (child: IndirectEnum))))) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == IndirectEnum, 8 bytes == + (layout #:length 46 #:address \(String(describing: layout2)) + (enum #:size 8 #:type IndirectEnum + (case 0 + (indirect #:size 16 #:type String)) + (case 1 + (indirect #:size 8 #:type (child: IndirectEnum))))) - """ + """ ) } @@ -1082,18 +1154,19 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == IndirectEnum, 8 bytes == - (layout #:length 46 #:address \(String(describing: layout3)) - (enum #:size 8 #:type IndirectEnum - (case 0 - (indirect #:size 16 #:type String)) - (case 1 - (indirect #:size 8 #:type (child: IndirectEnum))))) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == IndirectEnum, 8 bytes == + (layout #:length 46 #:address \(String(describing: layout3)) + (enum #:size 8 #:type IndirectEnum + (case 0 + (indirect #:size 16 #:type String)) + (case 1 + (indirect #:size 8 #:type (child: IndirectEnum))))) - """ + """ ) } } @@ -1125,16 +1198,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ - == Stack, 8 bytes == - (layout #:length 12 #:address \(String(describing: layout0)) - (enum #:size 8 #:type Stack - (case 0 - (read 8)))) + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output0, + """ + == Stack, 8 bytes == + (layout #:length 12 #:address \(String(describing: layout0)) + (enum #:size 8 #:type Stack + (case 0 + (read 8)))) - """ + """ ) } @@ -1147,16 +1221,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == Stack, 8 bytes == - (layout #:length 28 #:address \(String(describing: layout1)) - (enum #:size 8 #:type Stack - (case 0 - (indirect #:size 40 #:type (value: Node, next: Stack))))) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == Stack, 8 bytes == + (layout #:length 28 #:address \(String(describing: layout1)) + (enum #:size 8 #:type Stack + (case 0 + (indirect #:size 40 #:type (value: Node, next: Stack))))) - """ + """ ) } @@ -1169,16 +1244,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Stack, 8 bytes == - (layout #:length 28 #:address \(String(describing: layout2)) - (enum #:size 8 #:type Stack - (case 0 - (indirect #:size 40 #:type (value: Node, next: Stack))))) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Stack, 8 bytes == + (layout #:length 28 #:address \(String(describing: layout2)) + (enum #:size 8 #:type Stack + (case 0 + (indirect #:size 40 #:type (value: Node, next: Stack))))) - """ + """ ) } @@ -1191,16 +1267,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Stack, 8 bytes == - (layout #:length 28 #:address \(String(describing: layout3)) - (enum #:size 8 #:type Stack - (case 0 - (indirect #:size 40 #:type (value: Node, next: Stack))))) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Stack, 8 bytes == + (layout #:length 28 #:address \(String(describing: layout3)) + (enum #:size 8 #:type Stack + (case 0 + (indirect #:size 40 #:type (value: Node, next: Stack))))) - """ + """ ) } } @@ -1221,14 +1298,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: (Int, String).self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") let _ = ValueLayout.prefetch( of: String.self, @@ -1244,15 +1321,16 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == (Int, String), 24 bytes == - (layout #:length 19 #:address \(String(describing: layout2)) - (read 8) - (== #:size 16 #:type String)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == (Int, String), 24 bytes == + (layout #:length 19 #:address \(String(describing: layout2)) + (read 8) + (== #:size 16 #:type String)) - """ + """ ) let _ = ValueLayout.prefetch( @@ -1274,15 +1352,16 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == (Int, String), 24 bytes == - (layout #:length 35 #:address \(String(describing: layout3)) - (== #:size 8 #:type Int) - (== #:size 16 #:type String)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == (Int, String), 24 bytes == + (layout #:length 35 #:address \(String(describing: layout3)) + (== #:size 8 #:type Int) + (== #:size 16 #:type String)) - """ + """ ) } } @@ -1301,16 +1380,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout0 != nil) - #expect( - output0 == """ - == (Int8, Int64), 16 bytes == - (layout #:length 4 #:address \(String(describing: layout0)) - (read 1) - (skip 7) - (read 8)) + #expect(layout0 != nil, "expected `layout0` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output0, + """ + == (Int8, Int64), 16 bytes == + (layout #:length 4 #:address \(String(describing: layout0)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -1323,16 +1403,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == (Int8, Int64), 16 bytes == - (layout #:length 4 #:address \(String(describing: layout1)) - (read 1) - (skip 7) - (read 8)) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == (Int8, Int64), 16 bytes == + (layout #:length 4 #:address \(String(describing: layout1)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -1345,16 +1426,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == (Int8, Int64), 16 bytes == - (layout #:length 4 #:address \(String(describing: layout2)) - (read 1) - (skip 7) - (read 8)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == (Int8, Int64), 16 bytes == + (layout #:length 4 #:address \(String(describing: layout2)) + (read 1) + (skip 7) + (read 8)) - """ + """ ) } @@ -1378,16 +1460,17 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == (Int8, Int64), 16 bytes == - (layout #:length 36 #:address \(String(describing: layout3)) - (== #:size 1 #:type Int8) - (skip 7) - (== #:size 8 #:type Int64)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == (Int8, Int64), 16 bytes == + (layout #:length 36 #:address \(String(describing: layout3)) + (== #:size 1 #:type Int8) + (skip 7) + (== #:size 8 #:type Int64)) - """ + """ ) } } @@ -1408,14 +1491,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: Array.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") var output2 = "" let layout2 = await reprintingStandardError(to: &output2) { @@ -1425,14 +1508,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Array, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout2)) - (== #:size 8 #:type Array)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Array, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout2)) + (== #:size 8 #:type Array)) - """ + """ ) var output3 = "" @@ -1443,14 +1527,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Array, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 8 #:type Array)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Array, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 8 #:type Array)) - """ + """ ) } } @@ -1464,7 +1549,7 @@ struct PrefetchCompareValuesTests { for options in allOptions { let layout = ValueLayout.prefetch(of: Array.self, options: options, priority: 0) - #expect(layout == .trivial) + #expect(layout == .trivial, "expected `layout` to be the trivial value, but was \(layout) instead") } } } @@ -1480,14 +1565,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: Dictionary.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") var output2 = "" let layout2 = await reprintingStandardError(to: &output2) { @@ -1497,14 +1582,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Dictionary, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout2)) - (== #:size 8 #:type Dictionary)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Dictionary, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout2)) + (== #:size 8 #:type Dictionary)) - """ + """ ) var output3 = "" @@ -1515,14 +1601,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Dictionary, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 8 #:type Dictionary)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Dictionary, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 8 #:type Dictionary)) - """ + """ ) } } @@ -1540,7 +1627,7 @@ struct PrefetchCompareValuesTests { options: options, priority: 0 ) - #expect(layout == .trivial) + #expect(layout == .trivial, "expected `layout` to be the trivial value, but was \(layout) instead") } } } @@ -1556,14 +1643,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: Set.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") var output2 = "" let layout2 = await reprintingStandardError(to: &output2) { @@ -1573,14 +1660,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Set, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout2)) - (== #:size 8 #:type Set)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Set, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout2)) + (== #:size 8 #:type Set)) - """ + """ ) var output3 = "" @@ -1591,14 +1679,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Set, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 8 #:type Set)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Set, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 8 #:type Set)) - """ + """ ) } } @@ -1626,21 +1715,21 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == .trivial) + #expect(layout0 == .trivial, "expected `layout0` to be the trivial value, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: EquatableStruct.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == .trivial) + #expect(layout1 == .trivial, "expected `layout1` to be the trivial value, but was \(layout1) instead") let layout2 = ValueLayout.prefetch( of: EquatableStruct.self, options: ComparisonOptions(mode: .equatableUnlessPOD), priority: 0 ) - #expect(layout2 == .trivial) + #expect(layout2 == .trivial, "expected `layout2` to be the trivial value, but was \(layout2) instead") var output3 = "" let layout3 = await reprintingStandardError(to: &output3) { @@ -1650,14 +1739,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == EquatableStruct, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 8 #:type EquatableStruct)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == EquatableStruct, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 8 #:type EquatableStruct)) - """ + """ ) } } @@ -1679,14 +1769,14 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") let layout1 = ValueLayout.prefetch( of: EquatableClass.self, options: ComparisonOptions(mode: .indirect), priority: 0 ) - #expect(layout1 == nil) + #expect(layout1 == nil, "expected `layout1` to be nil, but was \(layout1) instead") await #expect(processExitsWith: .success) { var output2 = "" @@ -1697,14 +1787,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == EquatableClass, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout2)) - (== #:size 8 #:type EquatableClass)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == EquatableClass, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout2)) + (== #:size 8 #:type EquatableClass)) - """ + """ ) } @@ -1717,14 +1808,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == EquatableClass, 8 bytes == - (layout #:length 18 #:address \(String(describing: layout3)) - (== #:size 8 #:type EquatableClass)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == EquatableClass, 8 bytes == + (layout #:length 18 #:address \(String(describing: layout3)) + (== #:size 8 #:type EquatableClass)) - """ + """ ) } } @@ -1740,21 +1832,22 @@ struct PrefetchCompareValuesTests { setenv(printLayoutsEnvironmentVariable, "1", 1) let layout0 = ValueLayout.prefetch(of: Any.self, options: ComparisonOptions(mode: .bitwise), priority: 0) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") await #expect(processExitsWith: .success) { var output1 = "" let layout1 = await reprintingStandardError(to: &output1) { ValueLayout.prefetch(of: Any.self, options: ComparisonOptions(mode: .indirect), priority: 0) } - #expect(layout1 != nil) - #expect( - output1 == """ - == Any, 32 bytes == - (layout #:length 10 #:address \(String(describing: layout1)) - (existential #:size 32 #:type Any)) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == Any, 32 bytes == + (layout #:length 10 #:address \(String(describing: layout1)) + (existential #:size 32 #:type Any)) - """ + """ ) } @@ -1767,14 +1860,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Any, 32 bytes == - (layout #:length 10 #:address \(String(describing: layout2)) - (existential #:size 32 #:type Any)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Any, 32 bytes == + (layout #:length 10 #:address \(String(describing: layout2)) + (existential #:size 32 #:type Any)) - """ + """ ) } @@ -1783,14 +1877,15 @@ struct PrefetchCompareValuesTests { let layout3 = await reprintingStandardError(to: &output3) { ValueLayout.prefetch(of: Any.self, options: ComparisonOptions(mode: .equatableAlways), priority: 0) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Any, 32 bytes == - (layout #:length 10 #:address \(String(describing: layout3)) - (existential #:size 32 #:type Any)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Any, 32 bytes == + (layout #:length 10 #:address \(String(describing: layout3)) + (existential #:size 32 #:type Any)) - """ + """ ) } } @@ -1805,7 +1900,7 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") await #expect(processExitsWith: .success) { var output1 = "" @@ -1816,14 +1911,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout1 != nil) - #expect( - output1 == """ - == Error, 8 bytes == - (layout #:length 10 #:address \(String(describing: layout1)) - (existential #:size 8 #:type Error)) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == Error, 8 bytes == + (layout #:length 10 #:address \(String(describing: layout1)) + (existential #:size 8 #:type Error)) - """ + """ ) } @@ -1836,14 +1932,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == Error, 8 bytes == - (layout #:length 10 #:address \(String(describing: layout2)) - (existential #:size 8 #:type Error)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == Error, 8 bytes == + (layout #:length 10 #:address \(String(describing: layout2)) + (existential #:size 8 #:type Error)) - """ + """ ) } @@ -1856,14 +1953,15 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == Error, 8 bytes == - (layout #:length 10 #:address \(String(describing: layout3)) - (existential #:size 8 #:type Error)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == Error, 8 bytes == + (layout #:length 10 #:address \(String(describing: layout3)) + (existential #:size 8 #:type Error)) - """ + """ ) } } @@ -1885,22 +1983,23 @@ struct PrefetchCompareValuesTests { options: ComparisonOptions(mode: .bitwise), priority: 0 ) - #expect(layout0 == nil) + #expect(layout0 == nil, "expected `layout0` to be nil, but was \(layout0) instead") await #expect(processExitsWith: .success) { var output1 = "" let layout1 = await reprintingStandardError(to: &output1) { ValueLayout.prefetch(of: Function.self, options: ComparisonOptions(mode: .indirect), priority: 0) } - #expect(layout1 != nil) - #expect( - output1 == """ - == () -> (), 16 bytes == - (layout #:length 3 #:address \(String(describing: layout1)) - (read 8) - (capture-ref)) + #expect(layout1 != nil, "expected `layout1` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output1, + """ + == () -> (), 16 bytes == + (layout #:length 3 #:address \(String(describing: layout1)) + (read 8) + (capture-ref)) - """ + """ ) } @@ -1913,15 +2012,16 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout2 != nil) - #expect( - output2 == """ - == () -> (), 16 bytes == - (layout #:length 3 #:address \(String(describing: layout2)) - (read 8) - (capture-ref)) + #expect(layout2 != nil, "expected `layout2` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output2, + """ + == () -> (), 16 bytes == + (layout #:length 3 #:address \(String(describing: layout2)) + (read 8) + (capture-ref)) - """ + """ ) } @@ -1934,15 +2034,16 @@ struct PrefetchCompareValuesTests { priority: 0 ) } - #expect(layout3 != nil) - #expect( - output3 == """ - == () -> (), 16 bytes == - (layout #:length 3 #:address \(String(describing: layout3)) - (read 8) - (capture-ref)) + #expect(layout3 != nil, "expected `layout3` to have a value, but was nil instead") + assertStringsEqualWithDiff( + output3, + """ + == () -> (), 16 bytes == + (layout #:length 3 #:address \(String(describing: layout3)) + (read 8) + (capture-ref)) - """ + """ ) } } diff --git a/Tests/ComputeTests/Shared/Attribute/AttributeSearchTests.swift b/Tests/ComputeTests/Shared/Attribute/AttributeSearchTests.swift new file mode 100644 index 00000000..74b41f79 --- /dev/null +++ b/Tests/ComputeTests/Shared/Attribute/AttributeSearchTests.swift @@ -0,0 +1,171 @@ +import Testing + +@Suite(.serialized(for: \Subgraph.Type.current)) +struct AttributeSearchTests { + @Suite + struct SearchResultTests { + @Test + func searchWithMatchReturnsTrue() { + withGraph { + let attribute = Attribute(value: 1) + let input = Attribute(value: 2) + attribute.addInput(input, options: [], token: 0) + + var visitCount = 0 + let found = attribute.breadthFirstSearch(options: [.searchInputs]) { candidate in + visitCount += 1 + return candidate == input.identifier + } + + #expect(visitCount == 2) + #expect(found == true) + } + } + + @Test + func searchWithNoMatchReturnsFalse() { + withGraph { + let attribute = Attribute(value: 1) + let input = Attribute(value: 2) + attribute.addInput(input, options: [], token: 0) + + let unrelated = Attribute(value: 3) + + var visitCount = 0 + let found = attribute.breadthFirstSearch(options: [.searchInputs, .searchOutputs]) { candidate in + visitCount += 1 + return candidate == unrelated.identifier + } + + #expect(visitCount == 2) + #expect(found == false) + } + } + + @Test + func searchThatNeverMatchesReturnsFalse() { + withGraph { + let attribute = Attribute(value: 1) + let input = Attribute(value: 2) + attribute.addInput(input, options: [], token: 0) + + var visitCount = 0 + let found = attribute.breadthFirstSearch(options: [.searchInputs]) { _ in + visitCount += 1 + return false + } + + #expect(visitCount == 2) + #expect(found == false) + } + } + + @Test + func searchOfIsolatedAttributeReturnsFalse() { + withGraph { + let attribute = Attribute(value: 1) + + var visitCount = 0 + let found = attribute.breadthFirstSearch(options: [.searchInputs, .searchOutputs]) { _ in + visitCount += 1 + return false + } + + #expect(visitCount == 1) + #expect(found == false) + } + } + } + + @Suite + struct AttributeResolutionTests { + @Test + func offsetAttributeInputIsResolvedBeforeVisiting() { + struct Pair { + var first: Int + var second: Int + } + + withGraph { + let source = Attribute(value: Pair(first: 1, second: 2)) + let offset = source.unsafeOffset(at: MemoryLayout.size, as: Int.self) + + let destination = Attribute(value: 0) + destination.addInput(offset, options: [], token: 0) + + var visited: [AnyAttribute] = [] + let found = destination.breadthFirstSearch(options: [.searchInputs]) { candidate in + visited.append(candidate) + return false + } + + #expect(found == false) + #expect(visited.contains(destination.identifier)) + #expect(visited.contains(source.identifier)) + #expect(!visited.contains(offset.identifier)) + } + } + + @Test + func indirectAttributeSourceIsResolvedBeforeVisiting() { + withGraph { + let source = Attribute(value: 1) + let indirect = IndirectAttribute(source: source) + + let destination = Attribute(value: 0) + destination.addInput(indirect.attribute, options: [], token: 0) + + var visited: [AnyAttribute] = [] + let found = destination.breadthFirstSearch(options: [.searchInputs]) { candidate in + visited.append(candidate) + return false + } + + #expect(found == false) + #expect(visited.contains(source.identifier)) + #expect(!visited.contains(indirect.identifier)) + } + } + } + + @Suite + struct AttributeCycleTests { + @Test + func rootIsVisitedOnceWhenNoCycleExists() { + withGraph { + let a = Attribute(value: 1) + let b = Attribute(value: 2) + a.addInput(b, options: [], token: 0) + + var visited: [AnyAttribute] = [] + _ = a.breadthFirstSearch(options: [.searchInputs]) { candidate in + visited.append(candidate) + return false + } + + #expect(visited == [a.identifier, b.identifier]) + } + } + + @Test + func rootIsVisitedOnceWhenCycleExists() { + withGraph { + let a = Attribute(value: 1) + let b = Attribute(value: 2) + + // a <- b <- a + a.addInput(b, options: [], token: 0) + b.addInput(a, options: [], token: 0) + + var visited: [AnyAttribute] = [] + let found = a.breadthFirstSearch(options: [.searchInputs]) { candidate in + visited.append(candidate) + return false + } + + #expect(found == false) + #expect(visited == [a.identifier, b.identifier]) + } + } + } +} diff --git a/Tests/ComputeTests/Shared/Subgraph/SubgraphTests.swift b/Tests/ComputeTests/Shared/Subgraph/SubgraphTests.swift index 72871fc9..6ddcd8d4 100644 --- a/Tests/ComputeTests/Shared/Subgraph/SubgraphTests.swift +++ b/Tests/ComputeTests/Shared/Subgraph/SubgraphTests.swift @@ -325,7 +325,25 @@ struct SubgraphTests { #expect(subgraph.isValid == false) #expect(child.isValid == false) } + + @Test + func ancestorOfTraversesParentsOfAllIntermediateSubgraphs() { + let graph = Graph() + let root1 = Subgraph(graph: graph) + let root2 = Subgraph(graph: graph) + let intermediate = Subgraph(graph: graph) + let child = Subgraph(graph: graph) + + root1.addChild(intermediate) + root2.addChild(intermediate) + intermediate.addChild(child) + #expect(intermediate.parentCount == 2) + #expect(child.parentCount == 1) + + #expect(root1.isAncestor(of: child) == true) + #expect(root2.isAncestor(of: child) == true) + } } @Suite diff --git a/Tests/ComputeTests/Shared/Subgraph/SubgraphUpdateTests.swift b/Tests/ComputeTests/Shared/Subgraph/SubgraphUpdateTests.swift new file mode 100644 index 00000000..d2883ce0 --- /dev/null +++ b/Tests/ComputeTests/Shared/Subgraph/SubgraphUpdateTests.swift @@ -0,0 +1,64 @@ +import Testing + +@Suite +struct SubgraphUpdateTests { + @Test + func updateIterativelyEvaluatesDirtiedAttributesDuringTheSamePass() { + class Counter { + var ruleACount = 0 + var ruleBCount = 0 + } + + struct RuleA: Rule { + let counter: Counter + var value: Int { + counter.ruleACount += 1 + return counter.ruleACount + } + } + + struct RuleB: Rule { + let counter: Counter + let sibling: Attribute + var value: Int { + counter.ruleBCount += 1 + if counter.ruleBCount > 1 { + sibling.invalidateValue() + } + return counter.ruleBCount + } + } + + withGraph { + let subgraph = Subgraph.current! + + let counter = Counter() + let attributeA = Attribute(RuleA(counter: counter)) + let attributeB = Attribute(RuleB(counter: counter, sibling: attributeA)) + + attributeA.flags = Subgraph.Flags(rawValue: 1) + attributeB.flags = Subgraph.Flags(rawValue: 1) + + #expect(attributeA.value == 1) + #expect(attributeB.value == 1) + #expect(attributeA.valueState.contains(.dirty) == false) + #expect(attributeB.valueState.contains(.dirty) == false) + + attributeB.invalidateValue() + + // Only Attribute B should be dirty + #expect(attributeA.valueState.contains(.dirty) == false) + #expect(attributeB.valueState.contains(.dirty) == true) + #expect(subgraph.isDirty(flags: Subgraph.Flags(rawValue: 1)) == true) + + subgraph.update(flags: Subgraph.Flags(rawValue: 1)) + + // Both attributes should be re-evaluated in the same pass + #expect(attributeA.value == 2) + #expect(attributeB.value == 2) + #expect(attributeA.valueState.contains(.dirty) == false) + #expect(attributeB.valueState.contains(.dirty) == false) + #expect(subgraph.isDirty(flags: Subgraph.Flags(rawValue: 1)) == false) + } + } +} diff --git a/Tests/UtilitiesTests/HashTableTests.swift b/Tests/UtilitiesTests/HashTableTests.swift index d6c25561..baaab517 100644 --- a/Tests/UtilitiesTests/HashTableTests.swift +++ b/Tests/UtilitiesTests/HashTableTests.swift @@ -119,7 +119,6 @@ struct HashTableTests { // Count iterations via for_each - if there's a cycle, this will exceed count // or hang forever. We use a manual iteration limit to detect cycles. var iterationCount = 0 - let maxIterations = 1000 // Way more than count, to detect infinite loop table.for_each( { _, _, context in diff --git a/Xcode/Scripts/process_headers_inputs.xcfilelist b/Xcode/Scripts/process_headers_inputs.xcfilelist index 75d81de5..75858dd7 100644 --- a/Xcode/Scripts/process_headers_inputs.xcfilelist +++ b/Xcode/Scripts/process_headers_inputs.xcfilelist @@ -6,9 +6,11 @@ $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGCachedValueOptions.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGChangedValue.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGClosure.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGComparison.h +$(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGDebugServer.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGDescription.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGGraph.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGGraphCounterQueryType.h +$(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGGraphProfiling.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGGraphTracing.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGInputOptions.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGSearchOptions.h @@ -21,5 +23,6 @@ $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGTuple.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGType.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGUniqueID.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGValue.h +$(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGVersion.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/IAGWeakAttribute.h $(SRCROOT)/../Sources/ComputeCxx/include/ComputeCxx/ComputeCxx.h diff --git a/Xcode/Scripts/process_headers_outputs.xcfilelist b/Xcode/Scripts/process_headers_outputs.xcfilelist index 00539816..fbb32902 100644 --- a/Xcode/Scripts/process_headers_outputs.xcfilelist +++ b/Xcode/Scripts/process_headers_outputs.xcfilelist @@ -6,9 +6,11 @@ $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGCachedValueOptions.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGChangedValue.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGClosure.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGComparison.h +$(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGDebugServer.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGDescription.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGGraph.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGGraphCounterQueryType.h +$(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGGraphProfiling.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGGraphTracing.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGInputOptions.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGSearchOptions.h @@ -21,5 +23,6 @@ $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGTuple.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGType.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGUniqueID.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGValue.h +$(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGVersion.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/IAGWeakAttribute.h $(BUILT_PRODUCTS_DIR)/$(PUBLIC_HEADERS_FOLDER_PATH)/Compute.h