diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index be40f43902092..e24ad5107d6e3 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -39,7 +39,9 @@ set(SWIFT_BENCH_MODULES single-source/ArrayOfRef single-source/ArrayRemoveAll single-source/ArraySetElement + single-source/ArraySliceTests single-source/ArraySubscript + single-source/ArrayTests single-source/AsyncTree single-source/BinaryFloatingPointConversionFromBinaryInteger single-source/BinaryFloatingPointProperties @@ -65,6 +67,7 @@ set(SWIFT_BENCH_MODULES single-source/ClassArrayGetter single-source/CodableTest single-source/Combos + single-source/ContiguousArrayTests single-source/CountAlgo single-source/DataBenchmarks single-source/DeadArray diff --git a/benchmark/single-source/ArraySliceTests.swift b/benchmark/single-source/ArraySliceTests.swift new file mode 100644 index 0000000000000..af526562d379e --- /dev/null +++ b/benchmark/single-source/ArraySliceTests.swift @@ -0,0 +1,46 @@ +//===--- ArraySliceTests.swift --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let benchmarks = [ + BenchmarkInfo(name: "ArraySliceEqualUnique", runFunction: run_ArraySliceEqualUnique, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ArraySliceEqualShared", runFunction: run_ArraySliceEqualShared, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ArraySliceIdentical", runFunction: run_ArraySliceIdentical, tags: [.validation, .api, .Array]), +] + +@inline(never) +public func run_ArraySliceEqualUnique(_ n: Int) { + let a1 = ArraySlice(0 ..< n) + let a2 = ArraySlice(0 ..< n) + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ArraySliceEqualShared(_ n: Int) { + let a1 = ArraySlice(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ArraySliceIdentical(_ n: Int) { + let a1 = ArraySlice(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1.isIdentical(to: a2)) + } +} diff --git a/benchmark/single-source/ArrayTests.swift b/benchmark/single-source/ArrayTests.swift new file mode 100644 index 0000000000000..f619e33b3c237 --- /dev/null +++ b/benchmark/single-source/ArrayTests.swift @@ -0,0 +1,46 @@ +//===--- ArrayTests.swift -------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let benchmarks = [ + BenchmarkInfo(name: "ArrayEqualUnique", runFunction: run_ArrayEqualUnique, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ArrayEqualShared", runFunction: run_ArrayEqualShared, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ArrayIdentical", runFunction: run_ArrayIdentical, tags: [.validation, .api, .Array]), +] + +@inline(never) +public func run_ArrayEqualUnique(_ n: Int) { + let a1 = Array(0 ..< n) + let a2 = Array(0 ..< n) + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ArrayEqualShared(_ n: Int) { + let a1 = Array(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ArrayIdentical(_ n: Int) { + let a1 = Array(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1.isIdentical(to: a2)) + } +} diff --git a/benchmark/single-source/ContiguousArrayTests.swift b/benchmark/single-source/ContiguousArrayTests.swift new file mode 100644 index 0000000000000..f42860f8248db --- /dev/null +++ b/benchmark/single-source/ContiguousArrayTests.swift @@ -0,0 +1,46 @@ +//===--- ContiguousArrayTests.swift ---------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let benchmarks = [ + BenchmarkInfo(name: "ContiguousArrayEqualUnique", runFunction: run_ContiguousArrayEqualUnique, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ContiguousArrayEqualShared", runFunction: run_ContiguousArrayEqualShared, tags: [.validation, .api, .Array]), + BenchmarkInfo(name: "ContiguousArrayIdentical", runFunction: run_ContiguousArrayIdentical, tags: [.validation, .api, .Array]), +] + +@inline(never) +public func run_ContiguousArrayEqualUnique(_ n: Int) { + let a1 = ContiguousArray(0 ..< n) + let a2 = ContiguousArray(0 ..< n) + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ContiguousArrayEqualShared(_ n: Int) { + let a1 = ContiguousArray(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1 == a2) + } +} + +@inline(never) +public func run_ContiguousArrayIdentical(_ n: Int) { + let a1 = ContiguousArray(0 ..< n) + let a2 = a1 + for _ in 0 ..< 100_000 { + check(a1.isIdentical(to: a2)) + } +} diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index 6d866f8092825..55528833a045f 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -27,7 +27,9 @@ import ArrayOfPOD import ArrayOfRef import ArrayRemoveAll import ArraySetElement +import ArraySliceTests import ArraySubscript +import ArrayTests import AsyncTree import BinaryFloatingPointConversionFromBinaryInteger import BinaryFloatingPointProperties @@ -53,6 +55,7 @@ import Chars import ClassArrayGetter import CodableTest import Combos +import ContiguousArrayTests import CountAlgo import CreateObjects // rdar://128520766 @@ -228,7 +231,9 @@ register(ArrayOfPOD.benchmarks) register(ArrayOfRef.benchmarks) register(ArrayRemoveAll.benchmarks) register(ArraySetElement.benchmarks) +register(ArraySliceTests.benchmarks) register(ArraySubscript.benchmarks) +register(ArrayTests.benchmarks) register(AsyncTree.benchmarks) register(BinaryFloatingPointConversionFromBinaryInteger.benchmarks) register(BinaryFloatingPointProperties.benchmarks) @@ -253,8 +258,10 @@ register(CharacterRecognizer.benchmarks) register(Chars.benchmarks) register(CodableTest.benchmarks) register(Combos.benchmarks) +register(ContiguousArrayTests.benchmarks) register(CountAlgo.benchmarks) register(ClassArrayGetter.benchmarks) +register(ContiguousArrayTests.benchmarks) register(CreateObjects.benchmarks) // rdar://128520766 // register(CxxSetToCollection.benchmarks) diff --git a/stdlib/public/core/Array.swift b/stdlib/public/core/Array.swift index 322ea361b5cf6..ff37a36b2666d 100644 --- a/stdlib/public/core/Array.swift +++ b/stdlib/public/core/Array.swift @@ -2157,3 +2157,33 @@ internal struct _ArrayAnyHashableBox } extension Array: @unchecked Sendable where Element: Sendable { } + +extension Array { + /// Returns a boolean value indicating whether this array is identical to + /// `other`. + /// + /// Two array values are identical if there is no way to distinguish between + /// them. + /// + /// Comparing arrays this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// array storage object. Therefore, identical arrays are guaranteed to + /// compare equal with `==`, but not all equal arrays are considered + /// identical. + /// + /// - Performance: O(1) + @_alwaysEmitIntoClient + public func isIdentical(to other: Self) -> Bool { + let lhsCount = self.count + if lhsCount != other.count { + return false + } + + // Test referential equality. + if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity { + return true + } + + return false + } +} diff --git a/stdlib/public/core/ArraySlice.swift b/stdlib/public/core/ArraySlice.swift index b525e2d646f47..e40205e1e9a98 100644 --- a/stdlib/public/core/ArraySlice.swift +++ b/stdlib/public/core/ArraySlice.swift @@ -1607,3 +1607,33 @@ extension ArraySlice { } } #endif + +extension ArraySlice { + /// Returns a boolean value indicating whether this array is identical to + /// `other`. + /// + /// Two array values are identical if there is no way to distinguish between + /// them. + /// + /// Comparing arrays this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// array storage object. Therefore, identical arrays are guaranteed to + /// compare equal with `==`, but not all equal arrays are considered + /// identical. + /// + /// - Performance: O(1) + @_alwaysEmitIntoClient + public func isIdentical(to other: Self) -> Bool { + let lhsCount = self.count + if lhsCount != other.count { + return false + } + + // Test referential equality. + if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity { + return true + } + + return false + } +} diff --git a/stdlib/public/core/ContiguousArray.swift b/stdlib/public/core/ContiguousArray.swift index 475c46c406df2..cc08456ac43b4 100644 --- a/stdlib/public/core/ContiguousArray.swift +++ b/stdlib/public/core/ContiguousArray.swift @@ -1515,3 +1515,33 @@ extension ContiguousArray { extension ContiguousArray: @unchecked Sendable where Element: Sendable { } + +extension ContiguousArray { + /// Returns a boolean value indicating whether this array is identical to + /// `other`. + /// + /// Two array values are identical if there is no way to distinguish between + /// them. + /// + /// Comparing arrays this way includes comparing (normally) hidden + /// implementation details such as the memory location of any underlying + /// array storage object. Therefore, identical arrays are guaranteed to + /// compare equal with `==`, but not all equal arrays are considered + /// identical. + /// + /// - Performance: O(1) + @_alwaysEmitIntoClient + public func isIdentical(to other: Self) -> Bool { + let lhsCount = self.count + if lhsCount != other.count { + return false + } + + // Test referential equality. + if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity { + return true + } + + return false + } +} diff --git a/test/stdlib/ArraySliceTests.swift b/test/stdlib/ArraySliceTests.swift new file mode 100644 index 0000000000000..6eba953c0a5e7 --- /dev/null +++ b/test/stdlib/ArraySliceTests.swift @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// RUN: %target-run-simple-swift(-parse-as-library) +// REQUIRES: executable_test +// END. +// +//===----------------------------------------------------------------------===// + +import StdlibUnittest + +@main +enum ArraySliceTests { + static func main() { + let testSuite = TestSuite("ArraySliceTests") + testSuite.test("Identical", testIdentical) + runAllTests() + } + + static func testIdentical() { + let a1: ArraySlice = [0, 1, 2, 3] + expectTrue(a1.isIdentical(to: a1)) + + let a2: ArraySlice = a1 + expectTrue(a1.isIdentical(to: a2)) + + var a3: ArraySlice = a2 + a3.reserveCapacity(0) + expectFalse(a1.isIdentical(to: a3)) + + let a4: ArraySlice = [0, 1, 2, 3] + expectFalse(a1.isIdentical(to: a4)) + } +} diff --git a/test/stdlib/ArrayTests.swift b/test/stdlib/ArrayTests.swift new file mode 100644 index 0000000000000..90a1036901dc4 --- /dev/null +++ b/test/stdlib/ArrayTests.swift @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// RUN: %target-run-simple-swift(-parse-as-library) +// REQUIRES: executable_test +// END. +// +//===----------------------------------------------------------------------===// + +import StdlibUnittest + +@main +enum ArrayTests { + static func main() { + let testSuite = TestSuite("ArrayTests") + testSuite.test("Identical", testIdentical) + runAllTests() + } + + static func testIdentical() { + let a1: Array = [0, 1, 2, 3] + expectTrue(a1.isIdentical(to: a1)) + + let a2: Array = a1 + expectTrue(a1.isIdentical(to: a2)) + + var a3: Array = a2 + a3.reserveCapacity(0) + expectFalse(a1.isIdentical(to: a3)) + + let a4: Array = [0, 1, 2, 3] + expectFalse(a1.isIdentical(to: a4)) + } +} diff --git a/test/stdlib/ContiguousArrayTests.swift b/test/stdlib/ContiguousArrayTests.swift new file mode 100644 index 0000000000000..8f08d926bc800 --- /dev/null +++ b/test/stdlib/ContiguousArrayTests.swift @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// RUN: %target-run-simple-swift(-parse-as-library) +// REQUIRES: executable_test +// END. +// +//===----------------------------------------------------------------------===// + +import StdlibUnittest + +@main +enum ContiguousArrayTests { + static func main() { + let testSuite = TestSuite("ContiguousArrayTests") + testSuite.test("Identical", testIdentical) + runAllTests() + } + + static func testIdentical() { + let a1: ContiguousArray = [0, 1, 2, 3] + expectTrue(a1.isIdentical(to: a1)) + + let a2: ContiguousArray = a1 + expectTrue(a1.isIdentical(to: a2)) + + var a3: ContiguousArray = a2 + a3.reserveCapacity(0) + expectFalse(a1.isIdentical(to: a3)) + + let a4: ContiguousArray = [0, 1, 2, 3] + expectFalse(a1.isIdentical(to: a4)) + } +}