From 684e9ebf0ca473617817fcc9a345f1e3b190b257 Mon Sep 17 00:00:00 2001 From: smonteiro2 Date: Wed, 10 Jul 2024 17:05:19 +0100 Subject: [PATCH] [cxx-interop] Implements CxxMutableSpan, created from an UnsafeMutableBufferPointer * Added tests for generic functions * Add some tests for mutable spans * Initialize ConstSpan from UnsafeMutableBufferPointer * Change hardening flag --- include/swift/AST/KnownProtocols.def | 1 + lib/AST/ASTContext.cpp | 1 + .../ClangDerivedConformances.cpp | 27 +- lib/IRGen/GenMeta.cpp | 1 + stdlib/public/Cxx/CxxSpan.swift | 25 + test/Interop/Cxx/stdlib/Inputs/std-span.h | 39 +- test/Interop/Cxx/stdlib/use-std-span.swift | 472 ++++++++++++++---- 7 files changed, 461 insertions(+), 105 deletions(-) diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index 61e68a29d5863..3deb73d595ee8 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -136,6 +136,7 @@ PROTOCOL(CxxSequence) PROTOCOL(CxxUniqueSet) PROTOCOL(CxxVector) PROTOCOL(CxxSpan) +PROTOCOL(CxxMutableSpan) PROTOCOL(UnsafeCxxInputIterator) PROTOCOL(UnsafeCxxMutableInputIterator) PROTOCOL(UnsafeCxxRandomAccessIterator) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4b190a4e12f90..cd7f81e28d1e9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1406,6 +1406,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const { case KnownProtocolKind::CxxUniqueSet: case KnownProtocolKind::CxxVector: case KnownProtocolKind::CxxSpan: + case KnownProtocolKind::CxxMutableSpan: case KnownProtocolKind::UnsafeCxxInputIterator: case KnownProtocolKind::UnsafeCxxMutableInputIterator: case KnownProtocolKind::UnsafeCxxRandomAccessIterator: diff --git a/lib/ClangImporter/ClangDerivedConformances.cpp b/lib/ClangImporter/ClangDerivedConformances.cpp index 544e56f3a4339..0c95a16ce1054 100644 --- a/lib/ClangImporter/ClangDerivedConformances.cpp +++ b/lib/ClangImporter/ClangDerivedConformances.cpp @@ -1164,23 +1164,22 @@ void swift::conformToCxxSpanIfNeeded(ClangImporter::Implementation &impl, if (!elementType || !sizeType) return; - auto constPointerTypeDecl = - lookupNestedClangTypeDecl(clangDecl, "const_pointer"); + auto pointerTypeDecl = lookupNestedClangTypeDecl(clangDecl, "pointer"); auto countTypeDecl = lookupNestedClangTypeDecl(clangDecl, "size_type"); - if (!constPointerTypeDecl || !countTypeDecl) + if (!pointerTypeDecl || !countTypeDecl) return; - // create fake variable for constPointer (constructor arg 1) - auto constPointerType = clangCtx.getTypeDeclType(constPointerTypeDecl); - auto fakeConstPointerVarDecl = clang::VarDecl::Create( + // create fake variable for pointer (constructor arg 1) + clang::QualType pointerType = clangCtx.getTypeDeclType(pointerTypeDecl); + auto fakePointerVarDecl = clang::VarDecl::Create( clangCtx, /*DC*/ clangCtx.getTranslationUnitDecl(), clang::SourceLocation(), clang::SourceLocation(), /*Id*/ nullptr, - constPointerType, clangCtx.getTrivialTypeSourceInfo(constPointerType), + pointerType, clangCtx.getTrivialTypeSourceInfo(pointerType), clang::StorageClass::SC_None); - auto fakeConstPointer = new (clangCtx) clang::DeclRefExpr( - clangCtx, fakeConstPointerVarDecl, false, constPointerType, + auto fakePointer = new (clangCtx) clang::DeclRefExpr( + clangCtx, fakePointerVarDecl, false, pointerType, clang::ExprValueKind::VK_LValue, clang::SourceLocation()); // create fake variable for count (constructor arg 2) @@ -1197,8 +1196,7 @@ void swift::conformToCxxSpanIfNeeded(ClangImporter::Implementation &impl, // Use clangSema.BuildCxxTypeConstructExpr to create a CXXTypeConstructExpr, // passing constPointer and count - SmallVector constructExprArgs = {fakeConstPointer, - fakeCount}; + SmallVector constructExprArgs = {fakePointer, fakeCount}; auto clangDeclTyInfo = clangCtx.getTrivialTypeSourceInfo( clang::QualType(clangDecl->getTypeForDecl(), 0)); @@ -1226,5 +1224,10 @@ void swift::conformToCxxSpanIfNeeded(ClangImporter::Implementation &impl, elementType->getUnderlyingType()); impl.addSynthesizedTypealias(decl, ctx.getIdentifier("Size"), sizeType->getUnderlyingType()); - impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxSpan}); + + if (pointerType->getPointeeType().isConstQualified()) { + impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxSpan}); + } else { + impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxMutableSpan}); + } } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index c865ffe82a8bd..fd7ab1e89edc2 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -6878,6 +6878,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) { case KnownProtocolKind::CxxUniqueSet: case KnownProtocolKind::CxxVector: case KnownProtocolKind::CxxSpan: + case KnownProtocolKind::CxxMutableSpan: case KnownProtocolKind::UnsafeCxxInputIterator: case KnownProtocolKind::UnsafeCxxMutableInputIterator: case KnownProtocolKind::UnsafeCxxRandomAccessIterator: diff --git a/stdlib/public/Cxx/CxxSpan.swift b/stdlib/public/Cxx/CxxSpan.swift index 7b11898176658..b0835b731d707 100644 --- a/stdlib/public/Cxx/CxxSpan.swift +++ b/stdlib/public/Cxx/CxxSpan.swift @@ -29,4 +29,29 @@ extension CxxSpan { "UnsafeBufferPointer should not point to nil") self.init(unsafeBufferPointer.baseAddress!, Size(unsafeBufferPointer.count)) } + + @inlinable + public init(_ unsafeMutableBufferPointer: UnsafeMutableBufferPointer) { + precondition(unsafeMutableBufferPointer.baseAddress != nil, + "UnsafeMutableBufferPointer should not point to nil") + self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count)) + } +} + +public protocol CxxMutableSpan { + associatedtype Element + associatedtype Size: BinaryInteger + + init() + init(_ unsafeMutablePointer : UnsafeMutablePointer, _ count: Size) +} + +extension CxxMutableSpan { + /// Creates a C++ span from a Swift UnsafeMutableBufferPointer + @inlinable + public init(_ unsafeMutableBufferPointer: UnsafeMutableBufferPointer) { + precondition(unsafeMutableBufferPointer.baseAddress != nil, + "UnsafeMutableBufferPointer should not point to nil") + self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count)) + } } diff --git a/test/Interop/Cxx/stdlib/Inputs/std-span.h b/test/Interop/Cxx/stdlib/Inputs/std-span.h index 14ae583380372..306ce0e11ff9c 100644 --- a/test/Interop/Cxx/stdlib/Inputs/std-span.h +++ b/test/Interop/Cxx/stdlib/Inputs/std-span.h @@ -5,24 +5,51 @@ #include #include -using Span = std::span; -using SpanOfString = std::span; +using ConstSpan = std::span; +using Span = std::span; +using ConstSpanOfString = std::span; +using SpanOfString = std::span; static int iarray[]{1, 2, 3}; static std::string sarray[]{"", "ab", "abc"}; +static ConstSpan icspan = {iarray}; static Span ispan = {iarray}; +static ConstSpanOfString scspan = {sarray}; static SpanOfString sspan = {sarray}; struct SpanBox { - std::span ispan; - std::span sspan; + ConstSpan icspan; + Span ispan; + ConstSpanOfString scspan; + SpanOfString sspan; }; -inline Span initSpan() { +class CppApi { +public: + ConstSpan getConstSpan(); + Span getSpan(); +}; + +ConstSpan CppApi::getConstSpan() { + ConstSpan sp{new int[2], 2}; + return sp; +} + +Span CppApi::getSpan() { + Span sp{new int[2], 2}; + return sp; +} + +inline ConstSpan initConstSpan() { const int a[]{1, 2, 3}; + return ConstSpan(a); +} + +inline Span initSpan() { + int a[]{1, 2, 3}; return Span(a); } -inline struct SpanBox getStructSpanBox() { return {iarray, sarray}; } +inline struct SpanBox getStructSpanBox() { return {iarray, iarray, sarray, sarray}; } #endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_SPAN_H diff --git a/test/Interop/Cxx/stdlib/use-std-span.swift b/test/Interop/Cxx/stdlib/use-std-span.swift index 193d15725bf3a..6613a8da418f1 100644 --- a/test/Interop/Cxx/stdlib/use-std-span.swift +++ b/test/Interop/Cxx/stdlib/use-std-span.swift @@ -1,5 +1,5 @@ // RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20) -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20 -Xcc -D_LIBCPP_ENABLE_HARDENED_MODE) +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++20 -Xcc -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST) // FIXME swift-ci linux tests do not support std::span // UNSUPPORTED: OS=linux-gnu @@ -14,16 +14,39 @@ import CxxStdlib var StdSpanTestSuite = TestSuite("StdSpan") -func takesSpanOfInt(_ s: Span) { +func checkSpan(_ s : T, _ arr: [E]) + where T.Index == Int, T.Element == E { + expectFalse(s.isEmpty) + expectEqual(s.count, arr.count) + + for i in 0.. Span { + +func takesSpanOfString(_ s: inout SpanOfString) { + expectEqual(s.size(), 3) + expectFalse(s.empty()) + + expectEqual(s[0], "") + expectEqual(s[1], "ab") + s[2] = "abcd" + expectEqual(s[2], "abcd") + + s[2] = "abc" + expectEqual(s[2], "abc") +} + +func returnsConstSpanOfInt() -> ConstSpan { let arr: [Int32] = [1, 2, 3] return arr.withUnsafeBufferPointer { ubpointer in - return Span(ubpointer) + return ConstSpan(ubpointer) } } -func returnsSpanOfInt(_ arr: [Int32]) -> Span { +func returnsConstSpanOfInt(_ arr: inout [Int32]) -> ConstSpan { return arr.withUnsafeBufferPointer { ubpointer in + return ConstSpan(ubpointer) + } +} + +func returnsSpanOfInt() -> Span { + var arr: [Int32] = [1, 2, 3] + return arr.withUnsafeMutableBufferPointer { ubpointer in return Span(ubpointer) } } -func returnsSpanOfString() -> SpanOfString { +func returnsSpanOfInt(_ arr: inout [Int32]) -> Span { + return arr.withUnsafeMutableBufferPointer { ubpointer in + return Span(ubpointer) + } +} + +func returnsConstSpanOfString() -> ConstSpanOfString { let arr: [std.string] = ["", "a", "ab", "abc"] return arr.withUnsafeBufferPointer { ubpointer in - return SpanOfString(ubpointer) + return ConstSpanOfString(ubpointer) } } -func returnsSpanOfString(_ arr: [std.string]) -> SpanOfString { +func returnsConstSpanOfString(_ arr: inout [std.string]) -> ConstSpanOfString { return arr.withUnsafeBufferPointer { ubpointer in + return ConstSpanOfString(ubpointer) + } +} + +func returnsSpanOfString() -> SpanOfString { + var arr: [std.string] = ["", "a", "ab", "abc"] + return arr.withUnsafeMutableBufferPointer { ubpointer in + return SpanOfString(ubpointer) + } +} + +func returnsSpanOfString(_ arr: inout [std.string]) -> SpanOfString { + return arr.withUnsafeMutableBufferPointer { ubpointer in return SpanOfString(ubpointer) } } +func accessSpanAsGenericParam(_ col: T) + where T.Index == Int, T.Element == Int32 { + expectEqual(col.count, 3) + expectFalse(col.isEmpty) + + expectEqual(col[0], 1) + expectEqual(col[1], 2) + expectEqual(col[2], 3) +} + +func accessSpanAsGenericParam(_ col: T) + where T.Index == Int, T.Element == std.string { + expectEqual(col.count, 3) + expectFalse(col.isEmpty) + + expectEqual(col[0], "") + expectEqual(col[1], "ab") + expectEqual(col[2], "abc") +} + +func accessSpanAsSomeGenericParam(_ col: some CxxRandomAccessCollection) { + expectEqual(col.count, 3) + expectFalse(col.isEmpty) + + if let el = col[0] as? Int32 { + expectEqual(el, 1) + expectEqual(col[1] as! Int32, 2) + expectEqual(col[2] as! Int32, 3) + } else if let el = col[0] as? std.string { + expectEqual(el, "") + expectEqual(col[1] as! std.string, "ab") + expectEqual(col[2] as! std.string, "abc") + } +} + StdSpanTestSuite.test("EmptySpan") { let s = Span() expectEqual(s.size(), 0) expectTrue(s.empty()) + + let cs = ConstSpan() + expectEqual(cs.size(), 0) + expectTrue(cs.empty()) } StdSpanTestSuite.test("Init SpanOfInt") { let s = initSpan() expectEqual(s.size(), 3) expectFalse(s.empty()) + + let cs = initConstSpan() + expectEqual(cs.size(), 3) + expectFalse(cs.empty()) } StdSpanTestSuite.test("Access static SpanOfInt") { + expectEqual(icspan.size(), 3) + expectFalse(icspan.empty()) + + expectEqual(icspan[0], 1) + expectEqual(icspan[1], 2) + expectEqual(icspan[2], 3) + expectEqual(ispan.size(), 3) expectFalse(ispan.empty()) expectEqual(ispan[0], 1) expectEqual(ispan[1], 2) + ispan[2] = 4 + expectEqual(ispan[2], 4) + + ispan[2] = 3 expectEqual(ispan[2], 3) } StdSpanTestSuite.test("Access static SpanOfString") { + expectEqual(scspan.size(), 3) + expectFalse(scspan.empty()) + + expectEqual(scspan[0], "") + expectEqual(scspan[1], "ab") + expectEqual(scspan[2], "abc") + expectEqual(sspan.size(), 3) expectFalse(sspan.empty()) expectEqual(sspan[0], "") expectEqual(sspan[1], "ab") + sspan[2] = "abcd" + expectEqual(sspan[2], "abcd") + + sspan[2] = "abc" expectEqual(sspan[2], "abc") } StdSpanTestSuite.test("SpanOfInt as Param") { - takesSpanOfInt(ispan) + takesConstSpanOfInt(icspan) + takesSpanOfInt(&ispan) } StdSpanTestSuite.test("SpanOfString as Param") { - takesSpanOfString(sspan) + takesConstSpanOfString(scspan) + takesSpanOfString(&sspan) } StdSpanTestSuite.test("Return SpanOfInt") { + let cs1 = returnsConstSpanOfInt() + expectEqual(cs1.size(), 3) + expectFalse(cs1.empty()) + let s1 = returnsSpanOfInt() expectEqual(s1.size(), 3) expectFalse(s1.empty()) - let arr: [Int32] = [4, 5, 6, 7] - let s2 = returnsSpanOfInt(arr) - expectEqual(s2.size(), 4) - expectFalse(s2.empty()) + var arr: [Int32] = [4, 5, 6, 7] + let cs2 = returnsConstSpanOfInt(&arr) + checkSpan(cs2, arr) - expectEqual(s2[0], 4) - expectEqual(s2[1], 5) - expectEqual(s2[2], 6) - expectEqual(s2[3], 7) + let s2 = returnsSpanOfInt(&arr) + checkSpan(s2, arr) } StdSpanTestSuite.test("Return SpanOfString") { + let cs1 = returnsConstSpanOfString() + expectEqual(cs1.size(), 4) + expectFalse(cs1.empty()) let s1 = returnsSpanOfString() expectEqual(s1.size(), 4) expectFalse(s1.empty()) - let arr: [std.string] = ["", "a", "ab"] - let s2 = returnsSpanOfString(arr) - expectEqual(s2.size(), 3) - expectFalse(s2.empty()) + var arr: [std.string] = ["", "a", "ab"] + let cs2 = returnsConstSpanOfString(&arr) + checkSpan(cs2, arr) - expectEqual(s2[0], "") - expectEqual(s2[1], "a") - expectEqual(s2[2], "ab") + let s2 = returnsSpanOfString(&arr) + checkSpan(s2, arr) } StdSpanTestSuite.test("SpanOfInt.init(addr, count)") { - let arr: [Int32] = [1, 2, 3] + var arr: [Int32] = [1, 2, 3] arr.withUnsafeBufferPointer { ubpointer in - let s = Span(ubpointer.baseAddress!, ubpointer.count) - - expectEqual(s.size(), 3) - expectFalse(s.empty()) + let cs = ConstSpan(ubpointer.baseAddress!, ubpointer.count) + checkSpan(cs, arr) + } - expectEqual(s[0], 1) - expectEqual(s[1], 2) - expectEqual(s[2], 3) + let arrCopy = arr + arr.withUnsafeMutableBufferPointer { ubpointer in + let s = Span(ubpointer.baseAddress!, ubpointer.count) + checkSpan(s, arrCopy) + let cs = ConstSpan(ubpointer.baseAddress!, ubpointer.count) + checkSpan(cs, arrCopy) } } StdSpanTestSuite.test("SpanOfInt.init(ubpointer)") { - let arr: [Int32] = [1, 2, 3] - arr.withUnsafeBufferPointer { ubpointer in - let s = Span(ubpointer) - - expectEqual(s.size(), 3) - expectFalse(s.empty()) + var arr: [Int32] = [1, 2, 3] + arr.withUnsafeBufferPointer { ubpointer in + let cs = ConstSpan(ubpointer) + checkSpan(cs, arr) + } - expectEqual(s[0], 1) - expectEqual(s[1], 2) - expectEqual(s[2], 3) + let arrCopy = arr + arr.withUnsafeMutableBufferPointer { umbpointer in + let s = Span(umbpointer) + checkSpan(s, arrCopy) + let cs = ConstSpan(umbpointer) + checkSpan(cs, arrCopy) } } StdSpanTestSuite.test("SpanOfString.init(addr, count)") { - let arr: [std.string] = ["", "a", "ab", "abc"] - arr.withUnsafeBufferPointer { ubpointer in - let s = SpanOfString(ubpointer.baseAddress!, ubpointer.count) - - expectEqual(s.size(), 4) - expectFalse(s.empty()) + var arr: [std.string] = ["", "a", "ab", "abc"] + arr.withUnsafeBufferPointer { ubpointer in + let cs = ConstSpanOfString(ubpointer.baseAddress!, ubpointer.count) + checkSpan(cs, arr) + } - expectEqual(s[0], "") - expectEqual(s[1], "a") - expectEqual(s[2], "ab") - expectEqual(s[3], "abc") + let arrCopy = arr + arr.withUnsafeMutableBufferPointer { ubpointer in + let cs = ConstSpanOfString(ubpointer.baseAddress!, ubpointer.count) + checkSpan(cs, arrCopy) + let s = SpanOfString(ubpointer.baseAddress!, ubpointer.count) + checkSpan(s, arrCopy) } } StdSpanTestSuite.test("SpanOfString.init(ubpointer)") { - let arr: [std.string] = ["", "a", "ab", "abc"] + var arr: [std.string] = ["", "a", "ab", "abc"] arr.withUnsafeBufferPointer { ubpointer in - let s = SpanOfString(ubpointer) - - expectEqual(s.size(), 4) - expectFalse(s.empty()) + let cs = ConstSpanOfString(ubpointer) + checkSpan(cs, arr) + } - expectEqual(s[0], "") - expectEqual(s[1], "a") - expectEqual(s[2], "ab") - expectEqual(s[3], "abc") + let arrCopy = arr + arr.withUnsafeMutableBufferPointer { ubpointer in + let s = SpanOfString(ubpointer) + checkSpan(s, arrCopy) + let cs = ConstSpanOfString(ubpointer) + checkSpan(cs, arrCopy) } } StdSpanTestSuite.test("SpanOfInt for loop") { - let arr: [Int32] = [1, 2, 3] + var arr: [Int32] = [1, 2, 3] arr.withUnsafeBufferPointer { ubpointer in - let s = Span(ubpointer) + let cs = ConstSpan(ubpointer) + var count: Int32 = 1 + for e in cs { + expectEqual(e, count) + count += 1 + } + expectEqual(count, 4) + } + arr.withUnsafeMutableBufferPointer { ubpointer in + let s = Span(ubpointer) var count: Int32 = 1 for e in s { expectEqual(e, count) count += 1 } - expectEqual(count, 4) } } StdSpanTestSuite.test("SpanOfString for loop") { - let arr: [std.string] = ["", "a", "ab", "abc"] + var arr: [std.string] = ["", "a", "ab", "abc"] arr.withUnsafeBufferPointer { ubpointer in - let s = SpanOfString(ubpointer) - + let s = ConstSpanOfString(ubpointer) var count = 0 for e in s { count += e.length(); } + expectEqual(count, 6) + } + arr.withUnsafeMutableBufferPointer { ubpointer in + let s = SpanOfString(ubpointer) + var count = 0 + for e in s { + count += e.length(); + } expectEqual(count, 6) } } StdSpanTestSuite.test("SpanOfInt.map") { - let arr: [Int32] = [1, 2, 3] + var arr: [Int32] = [1, 2, 3] arr.withUnsafeBufferPointer { ubpointer in + let s = ConstSpan(ubpointer) + let result = s.map { $0 + 5 } + expectEqual(result, [6, 7, 8]) + } + + arr.withUnsafeMutableBufferPointer { ubpointer in let s = Span(ubpointer) let result = s.map { $0 + 5 } expectEqual(result, [6, 7, 8]) @@ -224,8 +383,14 @@ StdSpanTestSuite.test("SpanOfInt.map") { } StdSpanTestSuite.test("SpanOfString.map") { - let arr: [std.string] = ["", "a", "ab", "abc"] + var arr: [std.string] = ["", "a", "ab", "abc"] arr.withUnsafeBufferPointer { ubpointer in + let s = ConstSpanOfString(ubpointer) + let result = s.map { $0.length() } + expectEqual(result, [0, 1, 2, 3]) + } + + arr.withUnsafeMutableBufferPointer { ubpointer in let s = SpanOfString(ubpointer) let result = s.map { $0.length() } expectEqual(result, [0, 1, 2, 3]) @@ -233,8 +398,15 @@ StdSpanTestSuite.test("SpanOfString.map") { } StdSpanTestSuite.test("SpanOfInt.filter") { - let arr: [Int32] = [1, 2, 3, 4, 5] + var arr: [Int32] = [1, 2, 3, 4, 5] arr.withUnsafeBufferPointer { ubpointer in + let s = ConstSpan(ubpointer) + let result = s.filter { $0 > 3 } + expectEqual(result.count, 2) + expectEqual(result, [4, 5]) + } + + arr.withUnsafeMutableBufferPointer { ubpointer in let s = Span(ubpointer) let result = s.filter { $0 > 3 } expectEqual(result.count, 2) @@ -243,8 +415,15 @@ StdSpanTestSuite.test("SpanOfInt.filter") { } StdSpanTestSuite.test("SpanOfString.filter") { - let arr: [std.string] = ["", "a", "ab", "abc"] + var arr: [std.string] = ["", "a", "ab", "abc"] arr.withUnsafeBufferPointer { ubpointer in + let s = ConstSpanOfString(ubpointer) + let result = s.filter { $0.length() > 1} + expectEqual(result.count, 2) + expectEqual(result, ["ab", "abc"]) + } + + arr.withUnsafeMutableBufferPointer { ubpointer in let s = SpanOfString(ubpointer) let result = s.filter { $0.length() > 1} expectEqual(result.count, 2) @@ -253,21 +432,40 @@ StdSpanTestSuite.test("SpanOfString.filter") { } StdSpanTestSuite.test("Initialize Array from SpanOfInt") { - let arr: [Int32] = [1, 2, 3] - let span: Span = returnsSpanOfInt(arr) - let newArr = Array(span) - - expectEqual(arr.count, newArr.count) - expectEqual(arr, newArr) + var arr: [Int32] = [1, 2, 3] + let cspan: ConstSpan = returnsConstSpanOfInt(&arr) + let newArr1 = Array(cspan) + expectEqual(arr.count, newArr1.count) + expectEqual(arr, newArr1) + + let span: Span = returnsSpanOfInt(&arr) + let newArr2 = Array(span) + expectEqual(arr.count, newArr2.count) + expectEqual(arr, newArr2) } StdSpanTestSuite.test("Initialize Array from SpanOfString") { - let arr: [std.string] = ["", "a", "ab"] - let span: SpanOfString = returnsSpanOfString(arr) - let newArr = Array(span) + var arr: [std.string] = ["", "a", "ab"] + let cspan: ConstSpanOfString = returnsConstSpanOfString(&arr) + let newArr1 = Array(cspan) + expectEqual(arr.count, newArr1.count) + expectEqual(arr, newArr1) + + let span: SpanOfString = returnsSpanOfString(&arr) + let newArr2 = Array(span) + expectEqual(arr.count, newArr2.count) + expectEqual(arr, newArr2) +} + +StdSpanTestSuite.test("rdar://126570011") { + var cp = CppApi() + let span = cp.getSpan() + expectFalse(span.empty()) + expectEqual(span.size(), 2) - expectEqual(arr.count, newArr.count) - expectEqual(arr, newArr) + let constSpan = cp.getConstSpan() + expectFalse(constSpan.empty()) + expectEqual(constSpan.size(), 2) } StdSpanTestSuite.test("Span inside C++ struct") { @@ -303,43 +501,143 @@ StdSpanTestSuite.test("Span inside C++ struct") { expectEqual(sfilterResult, ["ab", "abc"]) } +StdSpanTestSuite.test("Span inside C++ struct") { + let spb = getStructSpanBox() + expectEqual(spb.icspan.size(), 3) + expectFalse(spb.icspan.empty()) + expectEqual(spb.ispan.size(), 3) + expectFalse(spb.ispan.empty()) + expectEqual(spb.sspan.size(), 3) + expectFalse(spb.sspan.empty()) + expectEqual(spb.scspan.size(), 3) + expectFalse(spb.scspan.empty()) + + var icount: Int32 = 1 + for e in spb.icspan { + expectEqual(e, icount) + icount += 1 + } + + icount = 1 + for e in spb.ispan { + expectEqual(e, icount) + icount += 1 + } + + var scount = 0 + for e in spb.scspan { + scount += e.length(); + } + + scount = 0 + for e in spb.sspan { + scount += e.length(); + } + + let icmapResult = spb.icspan.map { $0 + 5 } + expectEqual(icmapResult, [6, 7, 8]) + let imapResult = spb.ispan.map { $0 + 5 } + expectEqual(imapResult, [6, 7, 8]) + + let scmapResult = spb.scspan.map { $0.length() } + expectEqual(scmapResult, [0, 2, 3]) + let smapResult = spb.sspan.map { $0.length() } + expectEqual(smapResult, [0, 2, 3]) + + let icfilterResult = spb.icspan.filter { $0 > 2 } + expectEqual(icfilterResult.count, 1) + expectEqual(icfilterResult, [3]) + let ifilterResult = spb.ispan.filter { $0 > 2 } + expectEqual(ifilterResult.count, 1) + expectEqual(ifilterResult, [3]) + + let scfilterResult = spb.scspan.filter { $0.length() > 1} + expectEqual(scfilterResult.count, 2) + expectEqual(scfilterResult, ["ab", "abc"]) + let sfilterResult = spb.sspan.filter { $0.length() > 1} + expectEqual(sfilterResult.count, 2) + expectEqual(sfilterResult, ["ab", "abc"]) +} + StdSpanTestSuite.test("Span inside Swift struct") { struct SpanBox { + var icspan: ConstSpan var ispan: Span + var scspan: ConstSpanOfString var sspan: SpanOfString } - let spb = SpanBox(ispan: ispan, sspan: sspan) + let spb = SpanBox( + icspan: icspan, + ispan: ispan, + scspan: scspan, + sspan: sspan) + + expectEqual(spb.icspan.size(), 3) + expectFalse(spb.icspan.empty()) expectEqual(spb.ispan.size(), 3) expectFalse(spb.ispan.empty()) expectEqual(spb.sspan.size(), 3) expectFalse(spb.sspan.empty()) + expectEqual(spb.scspan.size(), 3) + expectFalse(spb.scspan.empty()) var icount: Int32 = 1 + for e in spb.icspan { + expectEqual(e, icount) + icount += 1 + } + + icount = 1 for e in spb.ispan { expectEqual(e, icount) icount += 1 } var scount = 0 - for e in spb.sspan { - scount += e.length(); - } + for e in spb.scspan { + scount += e.length(); + } + scount = 0 + for e in spb.sspan { + scount += e.length(); + } + + let icmapResult = spb.icspan.map { $0 + 5 } + expectEqual(icmapResult, [6, 7, 8]) let imapResult = spb.ispan.map { $0 + 5 } expectEqual(imapResult, [6, 7, 8]) let smapResult = spb.sspan.map { $0.length() } expectEqual(smapResult, [0, 2, 3]) + let scmapResult = spb.scspan.map { $0.length() } + expectEqual(scmapResult, [0, 2, 3]) + let icfilterResult = spb.icspan.filter { $0 > 2 } + expectEqual(icfilterResult.count, 1) + expectEqual(icfilterResult, [3]) let ifilterResult = spb.ispan.filter { $0 > 2 } expectEqual(ifilterResult.count, 1) expectEqual(ifilterResult, [3]) + let scfilterResult = spb.scspan.filter { $0.length() > 1} + expectEqual(scfilterResult.count, 2) + expectEqual(scfilterResult, ["ab", "abc"]) let sfilterResult = spb.sspan.filter { $0.length() > 1} expectEqual(sfilterResult.count, 2) expectEqual(sfilterResult, ["ab", "abc"]) } +StdSpanTestSuite.test("Span as arg to generic func") { + accessSpanAsGenericParam(icspan) + accessSpanAsGenericParam(ispan) + accessSpanAsGenericParam(scspan) + accessSpanAsGenericParam(sspan) + accessSpanAsSomeGenericParam(icspan) + accessSpanAsSomeGenericParam(ispan) + accessSpanAsSomeGenericParam(scspan) + accessSpanAsSomeGenericParam(sspan) +} runAllTests()