BeInteractive!

«Prev | 1 | Next»
2006年 04月 18日

暖かくて通学中の自転車の上で眠ってしまいそうな今日この頃ですが、昨日のエントリで凄いミスを犯していたので訂正します。

というのも、昨日のバイトコード、引数をスタックに逆順で積まなければならない所を、見事にそのまま積んでいたので、コンストラクタには引数が全てひっくり返って渡されてしまっていました。正しいスクリプトはこちらになります。

__bytecode__("8E2E00637265617465496E7374616E636546726F6D537472696E67000200062A0001706174680002706172616D7300570096020004011C8701000317960A000402006C656E677468004e870100041796020004048701000517960200040551870100059605000700000000489d02000d00960400040204054e990200dbff9605000404040303533e");

見やすくするとこう。

    function2 createInstanceFromString (r:1='path', r:2='params') ()
      push r:path
      getVariable
      setRegister r:3
      pop
      push r:params, 'length'
      getMember
      setRegister r:4
      pop
      push r:4
      setRegister r:5
      pop
     label1:
      push r:5
      decrement
      setRegister r:5
      push 0
      lessThan
      branchIfTrue label2
      push r:params, r:5
      getMember
      branch label1
     label2:
      push r:4, r:3, UNDEF
      newMethod
      return
    end // of function createInstanceFromString

うっかりしてましたスイマセン。

2006年 04月 17日

何かアクセスが増えてると思ったら、fladdict.netさんからトラックバックが来てた。スクリプトエンジンで(一部の)ビルトインクラスのnewが上手くいかないので汎用ファクトリを作ろうという話です。

何気なしに考えてたら、(あまり美しくは無いですが)バイトコード直書き(Cのインラインアセンブラみたいなの)で実現できることに気付いたので書いておきます。

まず、次のコードを1フレーム目とかに書いておきます。長いですが、区切ったり改行入れたりしないで下さい。

__bytecode__("8E2E00637265617465496E7374616E636546726F6D537472696E67000200062A0001706174680002706172616D73005B0096020004011C8701000317960A000402006C656E677468004e8701000417960500070000000087010005179604000405040448129d02001800960400040204054e9602000405508701000517990200daff9605000404040303533e");

これを書くと、createInstanceFromString()というメソッドが定義されます。ので、次のようにして使います。

import flash.display.BitmapData;

var b:BitmapData = createInstanceFromString("flash.display.BitmapData", [10, 10]);

第1引数にクラスのコンストラクタへのパスを文字列で、第2引数にコンストラクタに渡す引数を配列にして呼び出します(要素は何個でも大丈夫です)。すると、オブジェクトが生成されて返ってきます。以上。

実際どんなことをやっているか、flasmで見やすくしたバイトコードを載せておきます。

    function2 createInstanceFromString (r:1='path', r:2='params') ()
      push r:path
      getVariable
      setRegister r:3
      pop
      push r:params, 'length'
      getMember
      setRegister r:4
      pop
      push 0
      setRegister r:5
      pop
     label1:
      push r:5, r:4
      lessThan
      not
      branchIfTrue label2
      push r:params, r:5
      getMember
      push r:5
      increment
      setRegister r:5
      pop
      branch label1
     label2:
      push r:4, r:3, UNDEF
      newMethod
      return
    end // of function createInstanceFromString

要は配列の要素を push してスタックに積んで、 newMethod を呼んでるだけです。


追記

上のコードバグってました。ストリングからクラスのインスタンスを作る 訂正をご覧下さい。

2006年 04月 01日

4月1日ですが、ActionScript3で、Namespaceを使ってオーバーロードをスマートに実現する方法を思いついたので書きます。

今回、ちょっとコードが長いので、FlexBuilder2 Beta2用のプロジェクトをそのまま固めてアップしました。ダウンロードはこちら。これを見ながら読み進めてください。

このプロジェクトには、org.be_interactive.overloadパッケージと、サンプル用のOverload.asが含まれます。

org.be_interactive.overloadパッケージには、

  • OverloadExtensionクラス
  • 4つのネームスペース

が定義されています。

とりあえず使い方ですが、まず

import org.be_interactive.overload.OverloadExtension;
import org.be_interactive.overload.overload_String;
import org.be_interactive.overload.overload_Int;

クラスと必要なネームスペースを読み込んで、

class Hoge
{
    import flash.util.trace;

    overload_String function fuga (str:String) : void
    {
        trace('String', str);
    }
    overload_Int function fuga (n:int) : void
    {
        trace('Int', n);
    }
}

引数の型に合わせてネームスペースを変え、同じ関数名でオーバーロード用のメソッドを定義します。そして、

    public function fuga (...args) : void
    {
        OverloadExtension.execute(this, 'fuga', args);
    }

実際に呼び出されるpublicメソッドを作り、 OverloadExtension.execute(ターゲット, 呼び出すメソッド名, 引数配列) で呼び出します。これで準備完了。なんとこれだけで、オーバーロードが可能になります。

var h:Hoge = new Hoge();
h.fuga('hello, world'); // 出力:String hello, world
h.fuga(1); // 出力:int 1

但し、デフォルトでは 引数なし/String/Int/String+Int のオーバーロードしかサポートされていないので、これを拡張する方法を紹介します。

まず、オーバーロード用の適切なネームスペースを用意します。ネームスペース名は引数の型を並べるのがいいかと思いますが、実際は何でも構いません。

public namespace overload_String_String = 'http://www.be-interactive.org/OverloadExtension/String/String';

次に、OverloadExtensionクラスにネームスペースを登録します。これは初期化段階で1度呼び出せばOKです(例えばDocumentRootのコンストラクタ)。

OverloadExtension.register(overload_String_String, String, String);
// 引数は、(ネームスペースへの参照, Class, Class, ...)

最後に、先ほどと同じようにメソッドを定義すれば完了です。

    overload_String_String function fuga (str:String, str2:String) : void
    {
        trace('StringString', str, str2);
    }

デフォルトでは、初期化段階(OverloadExtension#initializer)で次のように4つ登録されています。ここは自由に変更してもらって構いません。

register(overload_default);
register(overload_String, String);
register(overload_Int, int);
register(overload_String_Int, String, int);

OverloadExtensionの実装の説明は省きます。興味がある人はコードを読んでくださいな。ちなみに、このライブラリは自由に使用/改変してもらって構いませんが、できればパッケージは変えないでください。

«Prev | 1 | Next»

About

Author
Yoshihiro Shindo (yossy)
Bio
「三度の飯より ActionScript」なフリーランス ActionScript エンジニア。1988年生まれ。Spark project 運営中。iPhone アプリ も開発中。

Twitter

カテゴリ

タグ

アーカイブ

最新コメント

最新トラックバック

Syndications