Files
swift-mirror/stdlib/public/core/Misc.swift
Anna Zaks 4ba7e418cb [runtime] Fortify the swift_demangle API.
Remove the reference to String, which leaks internal implementation details,
check for invalid inputs, and make the API more flexible. Remove the similar
Swift API, since it provides no additional value.
2016-04-14 11:01:57 -07:00

146 lines
4.5 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// Extern C functions
//===----------------------------------------------------------------------===//
// FIXME: Once we have an FFI interface, make these have proper function bodies
@_transparent
@warn_unused_result
public // @testable
func _countLeadingZeros(_ value: Int64) -> Int64 {
return Int64(Builtin.int_ctlz_Int64(value._value, false._value))
}
/// Returns if `x` is a power of 2.
@_transparent
@warn_unused_result
public // @testable
func _isPowerOf2(_ x: UInt) -> Bool {
if x == 0 {
return false
}
// Note: use unchecked subtraction because we have checked that `x` is not
// zero.
return x & (x &- 1) == 0
}
/// Returns if `x` is a power of 2.
@_transparent
@warn_unused_result
public // @testable
func _isPowerOf2(_ x: Int) -> Bool {
if x <= 0 {
return false
}
// Note: use unchecked subtraction because we have checked that `x` is not
// `Int.min`.
return x & (x &- 1) == 0
}
#if _runtime(_ObjC)
@_transparent
public func _autorelease(_ x: AnyObject) {
Builtin.retain(x)
Builtin.autorelease(x)
}
#endif
/// Invoke `body` with an allocated, but uninitialized memory suitable for a
/// `String` value.
///
/// This function is primarily useful to call various runtime functions
/// written in C++.
func _withUninitializedString<R>(
_ body: (UnsafeMutablePointer<String>) -> R
) -> (R, String) {
let stringPtr = UnsafeMutablePointer<String>(allocatingCapacity: 1)
let bodyResult = body(stringPtr)
let stringResult = stringPtr.move()
stringPtr.deallocateCapacity(1)
return (bodyResult, stringResult)
}
// FIXME(ABI): this API should allow controlling different kinds of
// qualification separately: qualification with module names and qualification
// with type names that we are nested in.
@_silgen_name("swift_getTypeName")
public func _getTypeName(_ type: Any.Type, qualified: Bool)
-> (UnsafePointer<UInt8>, Int)
/// Returns the demangled qualified name of a metatype.
@warn_unused_result
public // @testable
func _typeName(_ type: Any.Type, qualified: Bool = true) -> String {
let (stringPtr, count) = _getTypeName(type, qualified: qualified)
return ._fromWellFormedCodeUnitSequence(UTF8.self,
input: UnsafeBufferPointer(start: stringPtr, count: count))
}
@_silgen_name("swift_getTypeByMangledName")
func _getTypeByMangledName(
_ name: UnsafePointer<UInt8>,
_ nameLength: UInt)
-> Any.Type?
/// Lookup a class given a name. Until the demangled encoding of type
/// names is stabilized, this is limited to top-level class names (Foo.bar).
@warn_unused_result
public // SPI(Foundation)
func _typeByName(_ name: String) -> Any.Type? {
let components = name.characters.split{$0 == "."}.map(String.init)
guard components.count == 2 else {
return nil
}
// Note: explicitly build a class name to match on, rather than matching
// on the result of _typeName(), to ensure the type we are resolving is
// actually a class.
var name = "C"
if components[0] == "Swift" {
name += "s"
} else {
name += String(components[0].characters.count) + components[0]
}
name += String(components[1].characters.count) + components[1]
let nameUTF8 = Array(name.utf8)
return nameUTF8.withUnsafeBufferPointer { (nameUTF8) in
let type = _getTypeByMangledName(nameUTF8.baseAddress!,
UInt(nameUTF8.endIndex))
return type
}
}
/// Returns `floor(log(x))`. This equals to the position of the most
/// significant non-zero bit, or 63 - number-of-zeros before it.
///
/// The function is only defined for positive values of `x`.
///
/// Examples:
///
/// floorLog2(1) == 0
/// floorLog2(2) == floorLog2(3) == 1
/// floorLog2(9) == floorLog2(15) == 3
///
/// TODO: Implement version working on Int instead of Int64.
@warn_unused_result
@_transparent
public // @testable
func _floorLog2(_ x: Int64) -> Int {
_sanityCheck(x > 0, "_floorLog2 operates only on non-negative integers")
// Note: use unchecked subtraction because we this expression cannot
// overflow.
return 63 &- Int(_countLeadingZeros(x))
}