// RUN: %target-run-simple-swift // REQUIRES: executable_test import StdlibUnittest defer { runAllTests() } var StringDeconstructTests = TestSuite("StringDeconstructTests") enum ExpectedDeconstruction { case scratchIfAvailable case interiorPointer case extraAllocation } func expectDeconstruct( _ str: String, _ expectDeconstruct: ExpectedDeconstruction, stackTrace: SourceLocStack = SourceLocStack(), showFrame: Bool = true, file: String = #file, line: UInt = #line ) { var stackTrace = stackTrace.pushIf(showFrame, file: file, line: line) let expectBytes = Array(str.utf8) _ = Array(unsafeUninitializedCapacity: 16) { buffer, initializedCount in // Deconstruct with a provided scratch space // WS == with scratch, N == nil let scratch = UnsafeMutableRawBufferPointer(buffer) let (ownerWS, ptrWS, lengthWS, usedScratchWS, allocatedMemoryWS) : (AnyObject?, UnsafePointer, Int, Bool, Bool) = str._deconstructUTF8(scratch: scratch) let (ownerN, ptrN, lengthN, usedScratchN, allocatedMemoryN) : (AnyObject?, UnsafePointer, Int, Bool, Bool) = str._deconstructUTF8(scratch: nil) let rawBytesWS = UnsafeRawBufferPointer(start: ptrWS, count: lengthWS) let rawBytesN = UnsafeRawBufferPointer(start: ptrN, count: lengthN) expectEqualSequence(expectBytes, rawBytesWS, stackTrace: stackTrace) expectEqualSequence(rawBytesWS, rawBytesN, stackTrace: stackTrace) switch expectDeconstruct { case .scratchIfAvailable: expectNil(ownerWS, stackTrace: stackTrace) expectNotNil(ownerN, stackTrace: stackTrace) expectEqual(scratch.baseAddress, rawBytesWS.baseAddress, stackTrace: stackTrace) expectNotEqual(scratch.baseAddress, rawBytesN.baseAddress, stackTrace: stackTrace) expectTrue(lengthWS < scratch.count, stackTrace: stackTrace) expectTrue(lengthN < scratch.count, stackTrace: stackTrace) expectTrue(usedScratchWS, stackTrace: stackTrace) expectFalse(usedScratchN, stackTrace: stackTrace) expectFalse(allocatedMemoryWS, stackTrace: stackTrace) expectTrue(allocatedMemoryN, stackTrace: stackTrace) case .interiorPointer: // TODO: owner == (immortal ? nil : StringObject.largeAddress) expectTrue(str.isContiguousUTF8, stackTrace: stackTrace) var copy = str copy.withUTF8 { expectEqual($0.baseAddress, ptrWS, stackTrace: stackTrace) expectEqual($0.baseAddress, ptrN, stackTrace: stackTrace) expectEqual($0.count, lengthWS, stackTrace: stackTrace) expectEqual($0.count, lengthN, stackTrace: stackTrace) } expectFalse(usedScratchWS, stackTrace: stackTrace) expectFalse(usedScratchN, stackTrace: stackTrace) expectFalse(allocatedMemoryWS, stackTrace: stackTrace) expectFalse(allocatedMemoryN, stackTrace: stackTrace) case .extraAllocation: expectFalse(str.isContiguousUTF8, stackTrace: stackTrace) expectNotNil(ownerWS, stackTrace: stackTrace) expectNotNil(ownerN, stackTrace: stackTrace) expectFalse(usedScratchWS, stackTrace: stackTrace) expectFalse(usedScratchN, stackTrace: stackTrace) expectTrue(allocatedMemoryWS, stackTrace: stackTrace) expectTrue(allocatedMemoryN, stackTrace: stackTrace) } } } @inline(never) func id(_ a: T) -> T { a } StringDeconstructTests.test("deconstruct") { let smallASCII = "abcd" #if arch(i386) || arch(arm) || arch(arm64_32) || arch(wasm32) let smallUTF8 = "ジッパ" #else let smallUTF8 = "ジッパー" #endif let large = "the quick fox jumped over the lazy brown dog" var largeMortal = large largeMortal.append(id("🧟‍♀️")) largeMortal.append(id(largeMortal.last!)) expectDeconstruct(smallASCII, .scratchIfAvailable) expectDeconstruct(smallUTF8, .scratchIfAvailable) expectDeconstruct(large, .interiorPointer) expectDeconstruct(largeMortal, .interiorPointer) } #if _runtime(_ObjC) import Foundation StringDeconstructTests.test("deconstruct cocoa") { let smallCocoa: NSString = "aaa" let largeASCIICocoa: NSString = "the quick fox jumped over the lazy brown dog" let largeCocoa: NSString = "the quick 🧟‍♀️ ate the slow 🧠" #if arch(i386) || arch(arm) || arch(arm64_32) || arch(wasm32) expectDeconstruct(smallCocoa as String, .interiorPointer) #else expectDeconstruct(smallCocoa as String, .scratchIfAvailable) #endif expectDeconstruct(largeASCIICocoa as String, .interiorPointer) expectDeconstruct(largeCocoa as String, .extraAllocation) } #endif