blob: 28cab78643fcf0d777482cd9398eef1c700f317b [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// This file contains compiler intrinsics for optimized string switch
// implementations. All functions and types declared in this file are not
// intended to be used by switch source directly.
/// The compiler intrinsic which is called to lookup a string in a table
/// of static string case values.
@_semantics("findStringSwitchCase")
public // COMPILER_INTRINSIC
func _findStringSwitchCase(
cases: [StaticString],
string: String) -> Int {
for (idx, s) in cases.enumerated() {
if String(_builtinStringLiteral: s.utf8Start._rawValue,
utf8CodeUnitCount: s._utf8CodeUnitCount,
isASCII: s.isASCII._value) == string {
return idx
}
}
return -1
}
@_fixed_layout // needs known size for static allocation
public // used by COMPILER_INTRINSIC
struct _OpaqueStringSwitchCache {
var a: Builtin.Word
var b: Builtin.Word
}
internal typealias _StringSwitchCache = Dictionary<String, Int>
internal struct _StringSwitchContext {
internal init(
cases: [StaticString],
cachePtr: UnsafeMutablePointer<_StringSwitchCache>
){
self.cases = cases
self.cachePtr = cachePtr
}
internal let cases: [StaticString]
internal let cachePtr: UnsafeMutablePointer<_StringSwitchCache>
}
/// The compiler intrinsic which is called to lookup a string in a table
/// of static string case values.
///
/// The first time this function is called, a cache is built and stored
/// in \p cache. Consecutive calls use the cache for faster lookup.
/// The \p cases array must not change between subsequent calls with the
/// same \p cache.
@_semantics("findStringSwitchCaseWithCache")
public // COMPILER_INTRINSIC
func _findStringSwitchCaseWithCache(
cases: [StaticString],
string: String,
cache: inout _OpaqueStringSwitchCache) -> Int {
return withUnsafeMutableBytes(of: &cache) {
(bufPtr: UnsafeMutableRawBufferPointer) -> Int in
let oncePtr = bufPtr.baseAddress!
let cacheRawPtr = oncePtr + MemoryLayout<Builtin.Word>.stride
let cachePtr = cacheRawPtr.bindMemory(to: _StringSwitchCache.self, capacity: 1)
var context = _StringSwitchContext(cases: cases, cachePtr: cachePtr)
withUnsafeMutablePointer(to: &context) { (context) -> () in
Builtin.onceWithContext(oncePtr._rawValue, _createStringTableCache,
context._rawValue)
}
let cache = cachePtr.pointee;
if let idx = cache[string] {
return idx
}
return -1
}
}
/// Builds the string switch case.
internal func _createStringTableCache(_ cacheRawPtr: Builtin.RawPointer) {
let context = UnsafePointer<_StringSwitchContext>(cacheRawPtr).pointee
var cache = _StringSwitchCache()
cache.reserveCapacity(context.cases.count)
assert(MemoryLayout<_StringSwitchCache>.size <= MemoryLayout<Builtin.Word>.size)
for (idx, s) in context.cases.enumerated() {
let key = String(_builtinStringLiteral: s.utf8Start._rawValue,
utf8CodeUnitCount: s._utf8CodeUnitCount,
isASCII: s.isASCII._value)
cache[key] = idx
}
context.cachePtr.initialize(to: cache)
}