Files
swift-mirror/test/stdlib/SmallString.swift
Michael Ilseman cb9dc84d72 [string] Initial small string implementation.
This adds a small string representation capable of holding up to 15
ASCII code units directly in registers. This is extendable to UTF-8 in
the future.

It is intended to be the preferred representation whenever possible
for String, and is intended to be a String fast-path. Future small
forms may be added in the future (likely off the fast-path).

Small strings are available on 64-bit, where they are most beneficial
and well accomodated by limited address spaces. They are unavailable
on 32-bit, where they are less of a win and would require much more
hackery due to full address spaces.
2018-03-27 14:00:55 -07:00

156 lines
4.1 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: objc_interop
// REQUIRES: CPU=arm64 || CPU=x86_64
//
// Tests for small strings
//
import StdlibUnittest
import Foundation
var SmallStringTests = TestSuite("SmallStringTests")
extension String: Error {}
func verifySmallString(_ small: _SmallUTF8String, _ input: String) {
expectEqual(_SmallUTF8String.capacity, small.count + small.unusedCapacity)
let tiny = Array(input.utf8)
expectEqual(tiny.count, small.count)
for (lhs, rhs) in zip(tiny, small) {
expectEqual(lhs, rhs)
}
small.withTranscodedUTF16CodeUnits {
let codeUnits = Array(input.utf16)
expectEqualSequence(codeUnits, $0)
}
let smallFromUTF16 = _SmallUTF8String(Array(input.utf16))
expectNotNil(smallFromUTF16)
expectEqualSequence(small, smallFromUTF16!)
// Test slicing
//
for i in 0..<small.count {
for j in i...small.count {
expectEqualSequence(tiny[i..<j], small[i..<j])
if j < small.count {
expectEqualSequence(tiny[i...j], small[i...j])
}
}
}
}
SmallStringTests.test("FitsInSmall") {
func runTest(_ input: String) throws {
let tiny = Array(input.utf8)
// Constructed from UTF-8 code units
guard let small = _SmallUTF8String(tiny) else {
throw "Didn't fit"
}
verifySmallString(small, input)
// Constructed from UTF-16 code units
guard let fromUTF16Small = _SmallUTF8String(Array(input.utf16)) else {
throw "Failed from utf-16"
}
verifySmallString(fromUTF16Small, input)
}
// Pass tests
//
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTest("ab😇c") })
expectDoesNotThrow({ try runTest("0123456789abcde") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTest("👨👦") })
expectDoesNotThrow({ try runTest("") })
// Fail tests
//
expectThrows("Didn't fit", { try runTest("0123456789abcdef") })
expectThrows("Didn't fit", { try runTest("👩‍👦‍👦") })
}
SmallStringTests.test("Bridging") {
// Test bridging retains small string form
func bridge(_ small: _SmallUTF8String) -> String {
return _bridgeToCocoa(small) as! String
}
func runTestSmall(_ input: String) throws {
// Constructed through CF
guard let fromCocoaSmall = _SmallUTF8String(
_cocoaString: input as NSString
) else {
throw "Didn't fit"
}
verifySmallString(fromCocoaSmall, input)
verifySmallString(fromCocoaSmall, bridge(fromCocoaSmall))
}
// Pass tests
//
expectDoesNotThrow({ try runTestSmall("abc") })
expectDoesNotThrow({ try runTestSmall("0123456789abcde") })
expectDoesNotThrow({ try runTestSmall("\u{0}") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTestSmall("👨👦") })
expectDoesNotThrow({ try runTestSmall("") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTestSmall("👨👦abcd") })
// Fail tests
//
expectThrows("Didn't fit", { try runTestSmall("👨‍👩‍👦") })
expectThrows("Didn't fit", { try runTestSmall("👨👦abcde") })
}
SmallStringTests.test("Append, repeating") {
let strings = [
"",
"a",
"bc",
"def",
"hijk",
"lmnop",
"qrstuv",
"xyzzzzz",
"01234567",
"890123456",
"7890123456",
"78901234567",
"890123456789",
"0123456789012",
"34567890123456",
"789012345678901",
]
let smallstrings = strings.compactMap {
_SmallUTF8String(Array($0.utf8))
}
expectEqual(strings.count, smallstrings.count)
for (small, str) in zip(smallstrings, strings) {
verifySmallString(small, str)
}
for i in 0..<smallstrings.count {
for j in i..<smallstrings.count {
let lhs = smallstrings[i]
let rhs = smallstrings[j]
if lhs.count + rhs.count > _SmallUTF8String.capacity {
continue
}
verifySmallString(lhs._appending(rhs)!, (strings[i] + strings[j]))
verifySmallString(rhs._appending(lhs)!, (strings[j] + strings[i]))
}
}
for i in 0..<smallstrings.count {
for c in 2...15 {
let str = String(repeating: strings[i], count: c)
if let small = smallstrings[i]._repeated(c) {
verifySmallString(small, str)
} else {
expectTrue(str.utf8.count > 15)
}
}
}
}
runAllTests()