Files
swift-mirror/stdlib/core/VarArgs.swift
Dave Abrahams 6c07fb4ad1 [stdlib] Revert UnsafePointer casting change
The syntax being reverted added busywork and noise to the common case
where you want to say "I have the right address, but the wrong type,"
without adding any real safety.

Also it eliminated the ability to write UnsafePointer<T>(otherPointer),
without adding ".self" to T.  Overall, it was not a win.

This reverts commits r21324 and r21342

Swift SVN r21424
2014-08-22 21:53:12 +00:00

222 lines
5.3 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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
//
//===----------------------------------------------------------------------===//
public protocol CVarArgType {
func encode() -> [Word]
}
#if arch(x86_64)
let _x86_64CountGPRegisters = 6
let _x86_64CountSSERegisters = 8
let _x86_64SSERegisterWords = 2
let _x86_64RegisterSaveWords = _x86_64CountGPRegisters + _x86_64CountSSERegisters * _x86_64SSERegisterWords
#endif
public func withVaList<R>(args: [CVarArgType], f: (CVaListPointer)->R) -> R {
var builder = VaListBuilder()
for a in args {
builder.append(a)
}
return withVaList(builder, f)
}
public func withVaList<R>(builder: VaListBuilder, f: (CVaListPointer)->R) -> R {
let result = f(builder.va_list())
_fixLifetime(builder)
return result
}
public func getVaList(args: [CVarArgType]) -> CVaListPointer {
var builder = VaListBuilder()
for a in args {
builder.append(a)
}
// FIXME: Use some Swift equivalent of NS_RETURNS_INNER_POINTER if we get one.
Builtin.retain(builder)
Builtin.autorelease(builder)
return builder.va_list()
}
public func _encodeBitsAsWords<T: CVarArgType>(x: T) -> [Word] {
var result = [Word](
count: (sizeof(T.self) + sizeof(Word.self) - 1) / sizeof(Word.self),
repeatedValue: 0)
var tmp = x
_memcpy(dest: UnsafeMutablePointer(result._baseAddressIfContiguous),
src: UnsafeMutablePointer(Builtin.addressof(&tmp)),
size: UInt(sizeof(T.self)))
return result
}
// CVarArgType conformances for the integer types. Everything smaller
// than a CInt must be promoted to CInt or CUnsignedInt before
// encoding.
// Signed types
extension Int : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension Int64 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension Int32 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension Int16 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(CInt(self))
}
}
extension Int8 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(CInt(self))
}
}
// Unsigned types
extension UInt : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension UInt64 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension UInt32 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension UInt16 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(CUnsignedInt(self))
}
}
extension UInt8 : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(CUnsignedInt(self))
}
}
extension COpaquePointer : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
extension Float : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(Double(self))
}
}
extension Double : CVarArgType {
public func encode() -> [Word] {
return _encodeBitsAsWords(self)
}
}
#if !arch(x86_64)
final public
class VaListBuilder {
func append(arg: CVarArgType) {
for x in arg.encode() {
storage.append(x)
}
}
func va_list() -> CVaListPointer {
return CVaListPointer(
fromUnsafeMutablePointer: UnsafeMutablePointer<Void>(
storage._baseAddressIfContiguous))
}
var storage = [Word]()
}
#else
final public
class VaListBuilder {
struct Header {
var gp_offset = CUnsignedInt(0)
var fp_offset = CUnsignedInt(_x86_64CountGPRegisters * strideof(Word.self))
var overflow_arg_area: UnsafeMutablePointer<Word> = nil
var reg_save_area: UnsafeMutablePointer<Word> = nil
}
init() {
// prepare the register save area
storage = Array(count: _x86_64RegisterSaveWords, repeatedValue: 0)
}
func append(arg: CVarArgType) {
var encoded = arg.encode()
if ((arg.dynamicType is Float.Type) || (arg.dynamicType is Double.Type))
&& sseRegistersUsed < _x86_64CountSSERegisters {
var startIndex = _x86_64CountGPRegisters
+ (sseRegistersUsed * _x86_64SSERegisterWords)
for w in encoded {
storage[startIndex] = w
++startIndex
}
++sseRegistersUsed
}
else if encoded.count == 1 && gpRegistersUsed < _x86_64CountGPRegisters {
storage[gpRegistersUsed++] = encoded[0]
}
else {
for w in encoded {
storage.append(w)
}
}
}
func va_list() -> CVaListPointer {
header.reg_save_area = storage._baseAddressIfContiguous
header.overflow_arg_area
= storage._baseAddressIfContiguous + _x86_64RegisterSaveWords
return CVaListPointer(
fromUnsafeMutablePointer: UnsafeMutablePointer<Void>(
Builtin.addressof(&self.header)))
}
var gpRegistersUsed = 0
var sseRegistersUsed = 0
final // Property must be final since it is used by Builtin.addressof.
var header = Header()
var storage: [Word]
}
#endif