3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Unsafe<Mutable>Pointerの自由なcastingを実現

Last updated at Posted at 2016-08-09

元のソースをすこしアップグレードして、swift3b6への適用も完了しました。
https://gist.github.com/singcodes/15614c428b83d8eb47dd42f3de1bf4cd

###swift 3

  • mutable関数を削除し、全ての機能をcast関数で含めました。
  • pointeeの短いバージョンのo変数を追加しました。
    • mutable pointerの場合setが出来、ただのpointerの場合、エラーなしで無視されます。
    • ただし、無視されるのはswift的のことではないので、どう修正すればいいか考えています。できれば、protocolのextension中で解決したいんですが…いい考えがある方は是非お願いします。
  • raw pointerへの変更も出来るように、castRaw関数を追加しました。
//
//  Castable.swift
//  Castable
//
//  Created by jayios on 2016. 6. 23..
//  Copyright © 2016년 ngenii. All rights reserved.
//

import Foundation
import CoreGraphics

public protocol PointerCastable {}

public protocol UnsafePointerable {
    init(_ other: UnsafePointer<Pointee>)
    init?(_ other: UnsafePointer<Pointee>?)
    init(_ other: UnsafeMutablePointer<Pointee>)
    init?(_ other: UnsafeMutablePointer<Pointee>?)
    associatedtype Pointee
    var pointee: Pointee { get }
    func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
}

public protocol PointerShortener {
    associatedtype Pointee
    /// meaning for o(bject)
    var o: Pointee { get set }
    var pointee: Pointee { get }
}

extension PointerShortener where Self: UnsafePointerable {
    public var o: Pointee {
        set {
            if let mutable = self as? UnsafeMutablePointer<Pointee> {
                mutable.pointee = newValue
            }
        }
        get {
            return self.pointee
        }
    }
}

extension UnsafePointer: PointerCastable, UnsafePointerable, PointerShortener {}
extension UnsafeMutablePointer: PointerCastable, UnsafePointerable, PointerShortener {}

public protocol UnsafeRawPointerable{
    init<T>(_ other: UnsafePointer<T>)
    init?<T>(_ other: UnsafePointer<T>?)
    init<T>(_ other: UnsafeMutablePointer<T>)
    init?<T>(_ other: UnsafeMutablePointer<T>?)
}

extension UnsafeRawPointer: UnsafeRawPointerable, PointerCastable {}
extension UnsafeMutableRawPointer: UnsafeRawPointerable, PointerCastable {}

extension PointerCastable where Self: UnsafePointerable {
    public func cast<P: UnsafePointerable, M>() -> P? where P.Pointee == M {
        if self is P {
            return self as? P
        }
        let ptr = self.withMemoryRebound(to: M.self, capacity: MemoryLayout<M>.stride){$0}
        return P(ptr)
    }
    public func cast<P: UnsafePointerable, M>() -> P where P.Pointee == M {
        if self is P {
            return self as! P
        }
        let ptr = self.withMemoryRebound(to: M.self, capacity: MemoryLayout<M>.stride){$0}
        return P(ptr)
    }
    public func castRaw<R: UnsafeRawPointerable, T>(from: T.Type) -> R? {
        if R.self == UnsafeRawPointer.self {
            let ptr: UnsafePointer<T> = self.cast()
            return R(ptr)
        }
        let ptr: UnsafeMutablePointer<T> = self.cast()
        return R(ptr)
    }
    public func castRaw<R: UnsafeRawPointerable, T>(from: T.Type) -> R {
        if R.self == UnsafeRawPointer.self {
            let ptr: UnsafePointer<T> = self.cast()
            return R(ptr)
        }
        let ptr: UnsafeMutablePointer<T> = self.cast()
        return R(ptr)
    }
}

extension PointerCastable where Self: UnsafeRawPointerable {
    public func cast<P: UnsafePointerable, M>(to: M.Type) -> P where P.Pointee == M {
        if self is UnsafeRawPointer {
            let raw = self as! UnsafeRawPointer
            let ptr = raw.assumingMemoryBound(to: M.self)
            return P(ptr)
        } else {
            let raw: UnsafeMutableRawPointer = self as! UnsafeMutableRawPointer
            let ptr = raw.assumingMemoryBound(to: M.self)
            return P(ptr)
        }
    }
}

###swift 2
Usage:

let a = malloc(sizeof(Int)) -> Intのサイズを持つUnsafePointer<Void>を作成
let b: UnsafeMutablePointer<Int> = a.mutable() -> UnsafeMutablePointer<Int>にキャストされます。

gist url

protocol Castable {}

protocol UnsafePointerProtocol: NilLiteralConvertible {
    associatedtype Memory
    init(nilLiteral: ())
    init<Memory>(_ from: UnsafeMutablePointer<Memory>)
    init<Memory>(_ from: UnsafePointer<Memory>)
    var memory: Memory { get }
    func mutable<M>() -> UnsafeMutablePointer<M>
}

extension UnsafeMutablePointer : UnsafePointerProtocol, Castable{}
extension UnsafePointer : UnsafePointerProtocol, Castable{}

extension UnsafePointerProtocol where Self: Castable {
    func cast<P: UnsafePointerProtocol, M where M == P.Memory>() -> P {
        switch self {
        case let ptr as UnsafePointer<Memory>:
            return P(ptr)
        case let ptr as UnsafeMutablePointer<Memory>:
            return P(ptr)
        default:
            return nil
        }
    }
    
    func mutable<M>() -> UnsafeMutablePointer<M> {
        switch self {
        case let ptr as UnsafePointer<Memory>:
            return UnsafeMutablePointer<M>(ptr)
        case let ptr as UnsafeMutablePointer<Memory>:
            return UnsafeMutablePointer<M>(ptr)
        default:
            return nil
        }
    }
}


protocol Pointerable {
    associatedtype Element
    var pointer: UnsafePointer<Element> {get}
}

extension Array : Pointerable {}
extension ArraySlice : Pointerable {
    func array() -> Array<Element> {
        return Array<Element>(self)
    }
}

extension Pointerable where Self: SequenceType {
    var pointer: UnsafePointer<Element> {
        switch self {
        case let a as Array<Element>:
            return UnsafePointer<Element>(a)
        case let s as ArraySlice<Element>:
            return UnsafePointer<Element>(s.array())
        default:
            return nil
        }
    }
}
3
4
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
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?