//===----------------------------------------------------------------------===// // // 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 } @frozen // 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 internal struct _StringSwitchContext { internal let cases: [StaticString] internal let cachePtr: UnsafeMutablePointer<_StringSwitchCache> internal init( cases: [StaticString], cachePtr: UnsafeMutablePointer<_StringSwitchCache> ){ self.cases = cases self.cachePtr = cachePtr } } /// 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.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) _internalInvariant( MemoryLayout<_StringSwitchCache>.size <= MemoryLayout.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) }