File: StringUTF8.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (121 lines) | stat: -rw-r--r-- 3,467 bytes parent folder | download
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()