File: StringUTF8.swift

package info (click to toggle)
swiftlang 6.1.3-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,791,644 kB
  • sloc: cpp: 9,901,738; ansic: 2,201,433; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (121 lines) | stat: -rw-r--r-- 3,467 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// RUN: %empty-directory(%t)
// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowString/NSSlowString.m -c -o %t/NSSlowString.o
// RUN: %target-build-swift -I %S/Inputs/NSSlowString/ %t/NSSlowString.o %s -o %t/String

// RUN: %target-codesign %t/String
// RUN: %target-run %t/String
// REQUIRES: executable_test
// XFAIL: interpret
// UNSUPPORTED: freestanding

import StdlibUnittest
import StdlibCollectionUnittest
import StdlibUnicodeUnittest

#if _runtime(_ObjC)
import NSSlowString
import Foundation  // For NSRange
#endif

extension String {
  func withFastUTF8IfAvailable<R>(
    _ f: (UnsafeBufferPointer<UInt8>) throws -> R
  ) rethrows -> R? {
    return try utf8.withContiguousStorageIfAvailable(f)
  }
  var isFastUTF8: Bool {
    return withFastUTF8IfAvailable({ _ in return 0 }) != nil
  }

  // Prevent that the optimizer removes 'self += ""' in makeNative()
  @inline(never)
  static func emptyString() -> String { return "" }

  mutating func makeNative() { self += String.emptyString() }

  var isASCII: Bool { return utf8.allSatisfy { $0 < 0x7f } }
}

var UTF8Tests = TestSuite("StringUTF8Tests")

var strings: Array<String> = [
  "abcd",
  "abcdefghijklmnop",
  "abcde\u{301}fghijk",
  "a\u{301}",
  "👻",
  "Spooky long string. 👻",
  "в чащах юга жил-был цитрус? да, но фальшивый экземпляр",
  "日",
]

let kCFStringEncodingASCII: UInt32 = 0x0600

#if _runtime(_ObjC)

var utf16ByteSequences = utf16Tests.flatMap { $0.value }.map { $0.encoded }

private func testForeignContiguous(slowString: NSSlowString, string: String) {
  // Lazily bridged strings are not contiguous UTF-8
  var slowString = NSSlowString(string: string) as String
  expectFalse(slowString.isFastUTF8)
  expectEqualSequence(string.utf8, slowString.utf8)
  
  // They become fast when mutated
  slowString.makeNative()
  expectTrue(slowString.isFastUTF8)
  expectEqualSequence(
    string.utf8, slowString.withFastUTF8IfAvailable(Array.init)!)
  
  // Contiguous ASCII CFStrings provide access, even if lazily bridged
  if string.isASCII {
    let cfString = string.withCString {
      CFStringCreateWithCString(nil, $0, kCFStringEncodingASCII)!
      } as String
    expectTrue(cfString.isFastUTF8)
    expectEqualSequence(
      string.utf8, cfString.withFastUTF8IfAvailable(Array.init)!)
  }
}

#endif

UTF8Tests.test("Contiguous Access") {
  for string in strings {
    print(string)

    // Native strings are contiguous UTF-8
    expectTrue(string.isFastUTF8)
    expectEqualSequence(
      Array(string.utf8), string.withFastUTF8IfAvailable(Array.init)!)

    // FIXME: Bridge small non-ASCII as StringStorage
    // expectTrue(((string as NSString) as String).isFastUTF8)

    var copy = string
    expectTrue(copy.isFastUTF8)
    copy.makeNative()
    expectTrue(copy.isFastUTF8)

    // FIXME: Bridge small non-ASCII as StringStorage
    // expectTrue(((copy as NSString) as String).isFastUTF8)

#if _runtime(_ObjC)
    testForeignContiguous(slowString: NSSlowString(string: string),
                          string: string)
#endif
  }
#if _runtime(_ObjC)
  for bytes in utf16ByteSequences {
    bytes.withContiguousStorageIfAvailable {
      let slowString = NSSlowString(characters: $0.baseAddress!,
                                    length: UInt($0.count))
      let string = String(decoding: $0, as: UTF16.self)
      testForeignContiguous(slowString: slowString, string: string)
    }
  }
#endif
}

runAllTests()