Swiftの配列で重複を削除する

純粋な言語のオマージュ

func nub<T:Equatable>(_ array: [T] ) -> [T] {
    return array.reduce([]) { $0.contains($1) ? $0 : $0 + [$1] }
}

func nub<T>(_ array: [T], isEquivalent: (T,T) -> Bool ) -> [T] {
    return array.reduce([]) {
        ( xs: [T], x: T ) -> [T] in
        xs.filter( { isEquivalent( $0, x ) } ).count != 0 ? xs : xs + [x]
    }
}
let foo = [1,1,2,2,2,3,3,3,4,4]
let bar = nub(foo)
// bar == [1, 2, 3, 4]
let barbar = nub(foo,isEquivalent:{$0==$1})
// barbar == [1, 2, 3, 4]

順番を変えてしまっていたのでケシケシ。
間違いに気付いて再度ケシケシ。
Set(array).countで足りることに気付いて再びケシケシ。

Swiftで行列の積

前回は幼稚な感動を記事にしたわけですが、今回も引き続きそんなノリです。

protocol VectorProtocol {
    typealias ComponentType
    init( _ component : ( index : UInt ) ->ComponentType )
    static func dot( lhs: Self , _ rhs: Self ) -> ComponentType
}

protocol MatrixProtocol {
    typealias ComponentType
    typealias RowType
    typealias ColType
    func row( index : UInt ) -> RowType
    func col( index : UInt ) -> ColType
    init( _ component : ( row : UInt, col : UInt ) -> ComponentType )
}

func * < T : MatrixProtocol, U : MatrixProtocol
    where T.RowType : VectorProtocol,
    T.RowType == U.ColType, T.ColType == U.RowType,
    T.ComponentType == T.RowType.ComponentType >
    ( lhs: T, rhs: U ) -> T
{
    return T() { T.RowType.dot( lhs.row( $0 ), rhs.col( $1 ) ) }
}

row majorだろうが、column majorだろうが、2x3と3x4だろうが、各種正方行列だろうが、要素の型がなんであろうが、これからはプロトコル準拠するだけで済むのかぁ。良い時代だなぁ、しかし。ちょーでかい行列は使わないのでわかりません。

protocolにextensionが書けるって素敵

個人的にGLSLやOpenCLなんかのswizzeringが好きで、オレオレのベクタ型にはそれっぽいのを必ず用意してたりします。
SwiftはずーっとTLの狼狽を眺めてばかりでやり過ごしてたのですが、このswizzeringを一番そっくりに使えそうなのに気づいてすこし格闘してました。最悪の場合、type毎に、別の言語でソースコード生成してしまおうかとボンヤリしてたら、ふっと、「もしかして?」みたいな感じで、protocolにextensionを書いてみたところ、ばっちり動いてくれました。
Swift情報に疎く、ほぼSwift初心者なので、ネットに頼らず自力で発見できたことが嬉しくて、記録として残そうと思った次第です。

CGPointだけだと過剰ですな。でも、3要素や4要素あるベクタが複数あるとき、あるいは色々試したいとき、これからは楽できそう。

protocol Component2Swizzering {
    typealias ItemType
    typealias Component2Type
    var x: ItemType { get set }
    var y: ItemType { get set }
    func C2_INIT( x x: ItemType, y: ItemType ) -> Component2Type
    func X_C2( c : Component2Type ) -> ItemType
    func Y_C2( c : Component2Type ) -> ItemType
}
extension Component2Swizzering {

    var xy : Component2Type {
        get { return C2_INIT( x: x, y: y ) }
        set(p) { x = X_C2(p); y = Y_C2(p) }
    }

    var yx : Component2Type {
        get { return C2_INIT( x: y, y: x ) }
        set(p) { x = Y_C2(p); y = X_C2(p) }
    }

    var xx : Component2Type {
        get { return C2_INIT( x: x, y: x ) }
    }

    var yy : Component2Type {
        get { return C2_INIT( x: y, y: y ) }
    }
    
}
extension CGPoint : Component2Swizzering{

    typealias Component2Type = CGPoint

    func C2_INIT(x x:ItemType,y:ItemType) -> Component2Type {
        return CGPoint( x: x, y: y )
    }

    func X_C2(c : Component2Type ) -> ItemType {
        return c.x
    }

    func Y_C2(c : Component2Type ) -> ItemType {
        return c.y
    }

}
var point : CGPoint = CGPointMake(10, 20) // point変数に(10.0,20.0)が入ってる
print( point.yz ) // だけど(20.0,10.0) と表示される

+stringWithFormat:

+stringWithFormat:って、大量に使うとソースコードが読みにくくて仕方ないことしばしば。

そこで最近は以下のようなマクロをよく使っています。

#define FORMAT( ... ) [NSString stringWithFormat:__VA_ARGS__]
[NSString stringWithFormat:@"HOGEHOGE %@ %@",obj0,obj1]

とするかわりに、

FORMAT(@"HOGEHOGE %@ %@",obj0,obj1)

と書いてます。

ろっく

Mac OS XOpenGL contextがマルチスレッド対応になりまっせと発表があって久しいわけですが、
どうマルチスレッド対応してるのかなんとなく不思議ではありました。
使う側の注意としては、コンテキストをロックするべしっていうのが正解みたいです。

とりあえず僕は以下のようにしてます。NSOpenGLViewをサブクラス化したクラスでつかっているメソッドの一部です。
正確なところはサンプルコードやリファレンスあさってください。
間違いがあるようであればこっそり教えて頂けると嬉しいです。

- (void)openGLDraw
{	
	CGLContextObj ctx = [[self openGLContext] CGLContextObj];
	CGLLockContext(ctx);
	[[self openGLContext] makeCurrentContext];
	
        // draw something.

	CGLFlushDrawable(ctx);
	CGLUnlockContext(ctx);
}

glのapiのエントリーポイント的にそりゃそーかって感じですな。

color wellっぽいcell

NSColorWellみたいなNSCellがほしいなーと探せどもみつからず。
で、つくってみた。
単に色を表示するだけです。

#import <Foundation/Foundation.h>


@interface NJColorCell : NSCell {
@private
    
}

@end
@implementation NJColorCell

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }
    
    return self;
}

- (void)dealloc
{
    [super dealloc];
}

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
	NSRect outsideRect = CGRectInset(cellFrame, 1, 1);
	NSRect insideRect = CGRectInset(cellFrame, 5, 5);
	[NSBezierPath setDefaultLineWidth:1.0];
	[[NSColor darkGrayColor] setStroke];
	[[NSBezierPath bezierPathWithRect:outsideRect] stroke];
	NSGradient* aGradient = [[[NSGradient alloc]
							  initWithColorsAndLocations:
							  [NSColor colorWithCalibratedWhite:1.0 alpha:1.0], (CGFloat)0.0,
							  [NSColor colorWithCalibratedWhite:0.83 alpha:1.0], (CGFloat)0.2,
							  [NSColor colorWithCalibratedWhite:1.0 alpha:1.0], (CGFloat)1.0,
							  nil] autorelease];
	[aGradient drawInRect:outsideRect angle:90.0];
	[[NSColor grayColor] setStroke];
	[[self objectValue] setFill];
	[[NSBezierPath bezierPathWithRect:insideRect] stroke];
	[[NSBezierPath bezierPathWithRect:insideRect] fill];
	
}

@end

NSOutlineViewなんかでの、クリック時はdelegateメソッドの- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
で拾い、delegateクラスでNSColorPanel呼び出しもろもろをゴニョゴニョする方針。
だけどこれだとなんか反応が悪い。何使うのがベストなんでしょうかー?