LoginSignup
2
3

More than 5 years have passed since last update.

paiza POH ando #_poh ツリ目セットチャレンジ (withVaList() on Swift Linux)

Last updated at Posted at 2015-12-08

181226

import CoreFoundationはだめになったらしいです。詳細は https://qiita.com/cielavenir/items/63df19f876b384c1e1f2

160408追記

AtCoderではCoreFoundationに対応しましたのでこの怪奇な場合分けは不要です。念のため。

160329追記

どうもCoreFoundationはOSXでしか使えないらしい?とりあえず現状はこうすれば良いです。

//import CoreFoundation
#if _runtime(_ObjC)
import Darwin
#else
import Glibc
#endif

この状態で、vscanf等、正常に使えます。paizaやAtCoderが進化したのはわしのおかげじゃな(ふぉふぉふぉ)

もし_runtime(_ObjC)が弾かれるならos(OSX)にする。まあ、Swift処理系がiOSに入っているわけはないので大きな問題にはならないかと。

151213追記

withVaList()を追加するプルリクが本体にマージされましたので、Swift 2.3以降ではここで紹介するハックは不要です。


URL
解答集 http://qiita.com/cielavenir/items/2fd430a3468a068feef5
withVaList()を書いた話 http://qiita.com/cielavenir/items/2598d47b97a7c9caf970
水着チャレンジ(のrobustな解法) http://qiita.com/cielavenir/items/46f873191b37736d5062

まあ、Rubyだとputs 'Ann'*gets.to_iで瞬殺なのですが、今回はSwiftが主体らしいので。

しかし、Swift、入力がきつい。
NSString(data:stdIn.availableData。 encoding:NSUTF8StringEncoding)とNSScannerを組み合わせるとなると、入力を読み切る必要がある。
なので私はwithUnsafePointer(&n){vscanf("%d",getVaList([COpaquePointer($0)]))}を使っている。なお、scanfは不可。

しかし。オープンソース版のSwiftには、 getVaList()は存在しない。
ソースコードのpublic/core/VarArgs.swiftによると、

// Excluded due to use of dynamic casting and Builtin.autorelease, neither
// of which correctly work without the ObjC Runtime right now.

だそうです。悲惨。

というわけで、ソースを適当に改変してwithVaList()だけでも活かせるようにした。かなり大変でした^^;;

ただし、(autoreleaseについては気にしなくて良さそうですが)dynamic castingが怪しいので、競技プログラミング以外では使わないほうが良いかも。

というわけでまだ1問しか解けていないわけですが、これからがんばります…

tyama_paizapoh7a1.swift
//usr/bin/env xcrun swift $0 $@;exit

#if os(OSX)
//_runtime(_ObjC)

#else

//import CoreFoundation
// even if not using ObjC runtime, withValist() is possible.

/// Instances of conforming types can be encoded, and appropriately
/// passed, as elements of a C `va_list`.
///
/// This protocol is useful in presenting C "varargs" APIs natively in
/// Swift.  It only works for APIs that have a `va_list` variant, so
/// for example, it isn't much use if all you have is:
///
///     int f(int n, ...)
///
/// Given a version like this, though,
///
///     int f(int, va_list arguments)
///
/// you can write:
///
///     func swiftF(x: Int, arguments: CVarArgType...) -> Int {
///       return withVaList(arguments) { f(x, $0) }
///     }
public protocol CVarArgType {
  // Note: the protocol is public, but its requirement is stdlib-private.
  // That's because there are APIs operating on CVarArgType instances, but
  // defining conformances to CVarArgType outside of the standard library is
  // not supported.

  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  var _cVarArgEncoding: [Int] { get }
}

/// Floating point types need to be passed differently on x86_64
/// systems.  CoreGraphics uses this to make CGFloat work properly.
public // SPI(CoreGraphics)
protocol _CVarArgPassedAsDouble : CVarArgType {}

/// Some types require alignment greater than Int on some architectures.
public // SPI(CoreGraphics)
protocol _CVarArgAlignedType : CVarArgType {
  /// Return the required alignment in bytes of 
  /// the value returned by `_cVarArgEncoding`.
  var _cVarArgAlignment: Int { get }
}

#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

/// Invoke `f` with a C `va_list` argument derived from `args`.
public func withVaList<R>(args: [CVarArgType],
  _ f: CVaListPointer -> R) -> R {
  let builder = VaListBuilder()
  for a in args {
    builder.append(a)
  }
  return withVaList(builder, f)
}

/// Invoke `f` with a C `va_list` argument derived from `builder`.
public func withVaList<R>(builder: VaListBuilder,
  _ f: CVaListPointer -> R) -> R {
#if arch(x86_64)
  builder.header.reg_save_area = builder.storage._baseAddressIfContiguous
  builder.header.overflow_arg_area
    = builder.storage._baseAddressIfContiguous + _x86_64RegisterSaveWords
  let result = withUnsafeMutablePointer(&builder.header) {
    return f(CVaListPointer(_fromUnsafeMutablePointer:$0))
  }
#else
  let result = withUnsafeMutablePointer(&builder.storage) {
    return f(CVaListPointer(_fromUnsafeMutablePointer:$0))
  }
#endif
  _fixLifetime(builder)
  return result
}

@warn_unused_result
public func _encodeBitsAsWords<T : CVarArgType>(x: T) -> [Int] {
  let result = [Int](
    count: (sizeof(T.self) + sizeof(Int.self) - 1) / sizeof(Int.self),
    repeatedValue: 0)
  var tmp = x
  withUnsafeMutablePointer(&tmp) {
    UnsafeMutablePointer(result._baseAddressIfContiguous).assignFrom($0,count:sizeof(T.self)/sizeof(Int.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 {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension Int64 : CVarArgType, _CVarArgAlignedType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }

  /// Return the required alignment in bytes of 
  /// the value returned by `_cVarArgEncoding`.
  public var _cVarArgAlignment: Int {
    // FIXME: alignof differs from the ABI alignment on some architectures
    return alignofValue(self)
  }
}

extension Int32 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension Int16 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(CInt(self))
  }
}

extension Int8 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(CInt(self))
  }
}

// Unsigned types
extension UInt : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension UInt64 : CVarArgType, _CVarArgAlignedType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }

  /// Return the required alignment in bytes of 
  /// the value returned by `_cVarArgEncoding`.
  public var _cVarArgAlignment: Int {
    // FIXME: alignof differs from the ABI alignment on some architectures
    return alignofValue(self)
  }
}

extension UInt32 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension UInt16 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(CUnsignedInt(self))
  }
}

extension UInt8 : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(CUnsignedInt(self))
  }
}

extension COpaquePointer : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension UnsafePointer : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension UnsafeMutablePointer : CVarArgType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }
}

extension Float : _CVarArgPassedAsDouble, _CVarArgAlignedType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(Double(self))
  }

  /// Return the required alignment in bytes of 
  /// the value returned by `_cVarArgEncoding`.
  public var _cVarArgAlignment: Int {
    // FIXME: alignof differs from the ABI alignment on some architectures
    return alignofValue(Double(self))
  }
}

extension Double : _CVarArgPassedAsDouble, _CVarArgAlignedType {
  /// Transform `self` into a series of machine words that can be
  /// appropriately interpreted by C varargs.
  public var _cVarArgEncoding: [Int] {
    return _encodeBitsAsWords(self)
  }

  /// Return the required alignment in bytes of 
  /// the value returned by `_cVarArgEncoding`.
  public var _cVarArgAlignment: Int {
    // FIXME: alignof differs from the ABI alignment on some architectures
    return alignofValue(self)
  }
}

#if !arch(x86_64)

/// An object that can manage the lifetime of storage backing a
/// `CVaListPointer`.
final public class VaListBuilder {

  func append(arg: CVarArgType) {
    // Write alignment padding if necessary.
    // This is needed on architectures where the ABI alignment of some 
    // supported vararg type is greater than the alignment of Int.
    // FIXME: this implementation is not portable because
    // alignof differs from the ABI alignment on some architectures
#if os(watchOS) && arch(arm)   // FIXME: rdar://21203036 should be arch(armv7k)
    if let arg = arg as? _CVarArgAlignedType {
      let alignmentInWords = arg._cVarArgAlignment / sizeof(Int)
      let misalignmentInWords = count % alignmentInWords
      if misalignmentInWords != 0 {
        let paddingInWords = alignmentInWords - misalignmentInWords
        appendWords([Int](count: paddingInWords, repeatedValue: -1))
      }
    }
#endif

    // Write the argument's value itself.
    appendWords(arg._cVarArgEncoding)
  }

  // Manage storage that is accessed as Words 
  // but possibly more aligned than that.
  // FIXME: this should be packaged into a better storage type

  func appendWords(words: [Int]) {
    let newCount = count + words.count
    if newCount > allocated {
      let oldAllocated = allocated
      let oldStorage = storage
      let oldCount = count

      allocated = max(newCount, allocated * 2)
      storage = allocStorage(wordCount: allocated)
      // count is updated below

      if oldStorage != nil {
        storage.moveInitializeFrom(oldStorage, count:oldCount)
        deallocStorage(wordCount: oldAllocated, 
          storage: oldStorage)
      }
    }

    for word in words {
      storage[count++] = word
    }
  }

  @warn_unused_result
  func rawSizeAndAlignment(wordCount: Int) -> (Builtin.Word, Builtin.Word) {
    return ((wordCount * strideof(Int.self))._builtinWordValue, 
      requiredAlignmentInBytes._builtinWordValue)
  }

  @warn_unused_result
  func allocStorage(wordCount wordCount: Int) -> UnsafeMutablePointer<Int> {
    let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
    let rawStorage = Builtin.allocRaw(rawSize, rawAlignment)
    return UnsafeMutablePointer<Int>(rawStorage)
  }

  func deallocStorage(
    wordCount wordCount: Int,
    storage: UnsafeMutablePointer<Int>
  ) {
    let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
    Builtin.deallocRaw(storage._rawValue, rawSize, rawAlignment)
  }

  deinit {
    if storage != nil {
      deallocStorage(wordCount: allocated, storage: storage)
    }
  }

  // FIXME: alignof differs from the ABI alignment on some architectures
  let requiredAlignmentInBytes = alignof(Double.self)
  var count = 0
  var allocated = 0
  var storage: UnsafeMutablePointer<Int> = nil
}

#else

/// An object that can manage the lifetime of storage backing a
/// `CVaListPointer`.
final public class VaListBuilder {

  struct Header {
    var gp_offset = CUnsignedInt(0)
    var fp_offset = CUnsignedInt(_x86_64CountGPRegisters * strideof(Int.self))
    var overflow_arg_area: UnsafeMutablePointer<Int> = nil
    var reg_save_area: UnsafeMutablePointer<Int> = nil
  }

  init() {
    // prepare the register save area
    storage = Array(count: _x86_64RegisterSaveWords, repeatedValue: 0)
  }

  func append(arg: CVarArgType) {
    var encoded = arg._cVarArgEncoding

    if arg is _CVarArgPassedAsDouble
      && 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)
      }
    }
  }

  var gpRegistersUsed = 0
  var sseRegistersUsed = 0

  final  // Property must be final since it is used by Builtin.addressof.
  var header = Header()
  var storage: [Int]
}

#endif

#endif // _runtime(_ObjC)

import CoreFoundation

var n=0;
for withUnsafeMutablePointer(&n){withVaList([COpaquePointer($0)]){vscanf("%d",$0)}};n>0;n-- {
    print("Ann",terminator:"")
}
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3