mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
369 lines
10 KiB
Plaintext
369 lines
10 KiB
Plaintext
%{
|
|
from SwiftAtomics import (
|
|
loadOrderings, storeOrderings, updateOrderings,
|
|
boolOperations, integerOperations, lowerFirst, argLabel)
|
|
}%
|
|
|
|
/// Exercises all operations in a single-threaded context, verifying
|
|
/// they provide the expected results.
|
|
|
|
import Synchronization
|
|
import StdlibUnittest
|
|
|
|
% for label, type, a, b in types:
|
|
let suite = TestSuite("BasicAtomic${label}Tests")
|
|
|
|
extension Unmanaged: @retroactive Equatable { // FIXME: This is terrible
|
|
public static func ==(left: Self, right: Self) -> Bool {
|
|
left.toOpaque() == right.toOpaque()
|
|
}
|
|
}
|
|
|
|
struct Foo: Equatable, CustomStringConvertible {
|
|
var value: Int
|
|
init(_ value: Int) { self.value = value }
|
|
var description: String { "Foo(\(value))" }
|
|
}
|
|
|
|
class Bar: Equatable, CustomStringConvertible {
|
|
var value: Int
|
|
init(_ value: Int) { self.value = value }
|
|
var description: String { "Bar(\(value))" }
|
|
static func ==(left: Bar, right: Bar) -> Bool {
|
|
left === right
|
|
}
|
|
}
|
|
|
|
enum Fred: Int, AtomicRepresentable {
|
|
case one
|
|
case two
|
|
}
|
|
|
|
struct Hyacinth: RawRepresentable, Equatable, AtomicOptionalRepresentable {
|
|
var rawValue: UnsafeRawPointer
|
|
|
|
init(rawValue: UnsafeRawPointer) {
|
|
self.rawValue = rawValue
|
|
}
|
|
|
|
static let bucket: Hyacinth = Hyacinth(
|
|
rawValue: UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 8))
|
|
}
|
|
|
|
% if label == "Pointer" or label == "OptionalPointer" or label == "MutablePointer" or label == "OptionalMutablePointer":
|
|
let _mfoo1: UnsafeMutablePointer<Foo> = {
|
|
let p = UnsafeMutablePointer<Foo>.allocate(capacity: 1)
|
|
p.initialize(to: Foo(1))
|
|
return p
|
|
}()
|
|
let _mfoo2: UnsafeMutablePointer<Foo> = {
|
|
let p = UnsafeMutablePointer<Foo>.allocate(capacity: 1)
|
|
p.initialize(to: Foo(2))
|
|
return p
|
|
}()
|
|
|
|
var _foo1: UnsafePointer<Foo> { UnsafePointer(_mfoo1) }
|
|
var _foo2: UnsafePointer<Foo> { UnsafePointer(_mfoo2) }
|
|
% elif label == "RawPointer" or label == "OptionalRawPointer" or label == "MutableRawPointer" or label == "OptionalMutableRawPointer":
|
|
let _mraw1 = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
|
|
let _mraw2 = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
|
|
|
|
var _raw1: UnsafeRawPointer { UnsafeRawPointer(_mraw1) }
|
|
var _raw2: UnsafeRawPointer { UnsafeRawPointer(_mraw2) }
|
|
% elif label == "Unmanaged" or label == "OptionalUnmanaged":
|
|
let _bar1 = Unmanaged<Bar>.passRetained(Bar(1))
|
|
let _bar2 = Unmanaged<Bar>.passRetained(Bar(2))
|
|
% elif label == "Reference" or label == "OptionalReference":
|
|
let _baz1 = Baz(1)
|
|
let _baz2 = Baz(2)
|
|
% end
|
|
|
|
if #available(SwiftStdlib 6.0, *) {
|
|
|
|
suite.test("Atomic${label} creation") {
|
|
let v = Atomic<${type}>(${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
let w = Atomic<${type}>(${b})
|
|
expectEqual(w.load(ordering: .relaxed), ${b})
|
|
}
|
|
|
|
% for (order, _, _, _) in loadOrderings:
|
|
suite.test("Atomic${label} load ${order}") {
|
|
let v = Atomic<${type}>(${a})
|
|
expectEqual(v.load(ordering: .${order}), ${a})
|
|
|
|
let w = Atomic<${type}>(${b})
|
|
expectEqual(w.load(ordering: .${order}), ${b})
|
|
}
|
|
% end
|
|
|
|
% for (order, _, _, _) in storeOrderings:
|
|
suite.test("Atomic${label} store ${order}") {
|
|
let v = Atomic<${type}>(${a})
|
|
v.store(${b}, ordering: .${order})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
let w = Atomic<${type}>(${b})
|
|
w.store(${a}, ordering: .${order})
|
|
expectEqual(w.load(ordering: .relaxed), ${a})
|
|
}
|
|
% end
|
|
|
|
% for (order, _, _, _, _) in updateOrderings:
|
|
suite.test("Atomic${label} exchange ${order}") {
|
|
let v = Atomic<${type}>(${a})
|
|
|
|
expectEqual(v.exchange(${a}, ordering: .${order}), ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
expectEqual(v.exchange(${b}, ordering: .${order}), ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
expectEqual(v.exchange(${b}, ordering: .${order}), ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
}
|
|
% end
|
|
|
|
% for (order, _, _, _, _) in updateOrderings:
|
|
suite.test("Atomic${label} compareExchange ${order}") {
|
|
let v = Atomic<${type}>(${a})
|
|
|
|
var (exchanged, original): (Bool, ${type}) = v.compareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
ordering: .${order})
|
|
expectTrue(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
ordering: .${order})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
ordering: .${order})
|
|
expectTrue(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
ordering: .${order})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
}
|
|
|
|
% end
|
|
|
|
% for (order, _, _, _, _) in updateOrderings:
|
|
suite.test("Atomic${label} weakCompareExchange ${order}") {
|
|
let v = Atomic<${type}>(${a})
|
|
|
|
var (exchanged, original): (Bool, ${type})
|
|
|
|
repeat {
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
ordering: .${order})
|
|
} while !exchanged
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
ordering: .${order})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
repeat {
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
ordering: .${order})
|
|
} while !exchanged
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
ordering: .${order})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
}
|
|
|
|
% end
|
|
|
|
% for (successorder, _, _, _, _) in updateOrderings:
|
|
% for (failorder, _, _, _) in loadOrderings:
|
|
suite.test("Atomic${label} compareExchange success: ${successorder} failure: ${failorder}") {
|
|
let v = Atomic<${type}>(${a})
|
|
|
|
var (exchanged, original): (Bool, ${type}) = v.compareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectTrue(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectTrue(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
(exchanged, original) = v.compareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
}
|
|
% end
|
|
% end
|
|
|
|
% for (successorder, _, _, _, _) in updateOrderings:
|
|
% for (failorder, _, _, _) in loadOrderings:
|
|
suite.test("Atomic${label} weakCompareExchange success: ${successorder} failure: ${failorder}") {
|
|
let v = Atomic<${type}>(${a})
|
|
|
|
var (exchanged, original): (Bool, ${type})
|
|
repeat {
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
} while !exchanged
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${a},
|
|
desired: ${b},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${b})
|
|
|
|
repeat {
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
} while !exchanged
|
|
expectEqual(original, ${b})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
|
|
(exchanged, original) = v.weakCompareExchange(
|
|
expected: ${b},
|
|
desired: ${a},
|
|
successOrdering: .${successorder},
|
|
failureOrdering: .${failorder})
|
|
expectFalse(exchanged)
|
|
expectEqual(original, ${a})
|
|
expectEqual(v.load(ordering: .relaxed), ${a})
|
|
}
|
|
% end
|
|
% end
|
|
|
|
|
|
% if type == "Bool":
|
|
// Bool operations
|
|
% for (name, _, operator, _) in boolOperations:
|
|
% for (order, _, _, _, _) in updateOrderings:
|
|
suite.test("AtomicBool ${name} ${order}") {
|
|
let v = Atomic<Bool>(false)
|
|
|
|
// The truth tables are super tiny, so just check every value
|
|
for a in [false, true] {
|
|
for b in [false, true] {
|
|
v.store(a, ordering: .relaxed)
|
|
let r = v.${lowerFirst(name)}(b, ordering: .${order})
|
|
expectEqual(r.oldValue, a, "a = \(a), b = \(b)")
|
|
expectEqual(r.newValue, a ${operator} b, "a = \(a), b = \(b)")
|
|
expectEqual(
|
|
v.load(ordering: .relaxed),
|
|
a ${operator} b,
|
|
"a = \(a), b =\(b)")
|
|
}
|
|
}
|
|
}
|
|
|
|
% end
|
|
% end
|
|
% end
|
|
|
|
% if type.startswith("Int") or type.startswith("UInt"):
|
|
// Integer operations
|
|
% for (name, _, operator, _) in integerOperations:
|
|
% for (order, _, _, _, _) in updateOrderings:
|
|
suite.test("Atomic${label} ${name} ${order}") {
|
|
let a: ${type} = 3
|
|
let b: ${type} = 8
|
|
let c: ${type} = 12
|
|
% if name == "Min" or name == "Max":
|
|
let result1: ${type} = Swift.${lowerFirst(name)}(a, b)
|
|
let result2: ${type} = Swift.${lowerFirst(name)}(result1, c)
|
|
% else:
|
|
let result1: ${type} = a ${operator} b
|
|
let result2: ${type} = result1 ${operator} c
|
|
% end
|
|
|
|
let v = Atomic<${type}>(a)
|
|
|
|
let val1 = v.${lowerFirst(name)}(b, ordering: .${order})
|
|
expectEqual(val1.oldValue, a)
|
|
expectEqual(val1.newValue, result1)
|
|
expectEqual(v.load(ordering: .relaxed), result1)
|
|
|
|
let val2 = v.${lowerFirst(name)}(c, ordering: .${order})
|
|
expectEqual(val2.oldValue, result1)
|
|
expectEqual(val2.newValue, result2)
|
|
expectEqual(v.load(ordering: .relaxed), result2)
|
|
}
|
|
|
|
% end
|
|
% end
|
|
% end
|
|
} // if #available(SwiftStdlib 6.0, *)
|
|
% end
|
|
%{
|
|
# Local Variables:
|
|
# mode: swift
|
|
# End:
|
|
}%
|
|
|
|
runAllTests()
|