2009年5月24日日曜日

v8とC++オブジェクト

JavascriptのオブジェクトとC++のオブジェクトをつなげてみる。
まともに使うとなるとやることはたくさんあるが、
最低限必要なものはわかった。

SetInternalFieldでJavascriptからは見えない、C++ポインタを設定するのがみそ。

main内で明示的に初期化と終了をしているのは、
main前後に持ってくると不都合な場合があるから。
listが自動開放になっているのは手抜きです。

メモリリークチェックしてないや。
コメントがないのは、わざとです。

using namespace v8;

class TestX : public smart_ptr::ref_counted<TestX>
{
public:
    TestX()
    {
    }

    ~TestX()
    {
    }

    static bool initialize();
    static void terminate();

    static Handle<ObjectTemplate> make();

    static Handle<Value> GetPointX(
        Local<String> property,
        const AccessorInfo &info);

    static void SetPointX(
        Local<String> property,
        Local<Value> value,
        const AccessorInfo& info);

    static Handle<Value> constructor(const Arguments& args);

    int x_;

    static Persistent<ObjectTemplate> template_;
    typedef std::list<smart_ptr::intrusive_ptr<TestX> > InstanceList;
    static InstanceList instanceList_;
};

Persistent<ObjectTemplate> TestX::template_;
TestX::InstanceList TestX::instanceList_;

bool TestX::initialize()
{
    if(template_.IsEmpty()){
        HandleScope handle_scope;

        Handle<ObjectTemplate> templ= ObjectTemplate::New();

        templ->SetInternalFieldCount(1);

        templ->SetAccessor(String::NewSymbol("x"), GetPointX, SetPointX);

        template_ = Persistent<ObjectTemplate>::New( handle_scope.Close(templ) );
    }
    return true;
}

void TestX::terminate()
{
    template_.Dispose();
}

Handle<Value> TestX::GetPointX(Local<String> property,
                        const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    int value = static_cast<TestX*>(ptr)->x_;
    return Integer::New(value);
}

void TestX::SetPointX(Local<String> property, Local<Value> value,
               const AccessorInfo& info)
{
    Local<Object> self = info.Holder();
    int i = self->InternalFieldCount();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    static_cast<TestX*>(ptr)->x_ = value->Int32Value();
}

Handle<Value> TestX::constructor(const Arguments& args)
{
    if(!args.IsConstructCall()){
        return v8::Undefined();
    }

    Handle<ObjectTemplate> temp = template_;
    Local<Object> obj = temp->NewInstance();
    smart_ptr::intrusive_ptr<TestX> p( new TestX );
    instanceList_.push_back(p);

    obj->SetInternalField(0, External::New(p.get()));

    return obj;
}

Handle<Value> Print(const Arguments& args)
{
  if (args.Length() < 1) return v8::Undefined();
  HandleScope scope;
  Handle<Value> arg = args[0];
  String::Utf8Value value(arg);

  std::cout << "print: " << *value << std::endl;
  return v8::Undefined();
}


int main(int argc, char** argv)
{
    HandleScope handle_scope;

    TestX::initialize();

    Handle<ObjectTemplate> global = ObjectTemplate::New();
    global->Set(String::New("print"), FunctionTemplate::New(Print));
    global->Set(String::New("TestX"), FunctionTemplate::New(TestX::constructor));

    Persistent<Context> context = Context::New(NULL, global);

    Context::Scope context_scope(context);

    Handle<String> source = String::New("print(\’Hello\’);var p = new TestX();p.x = 1;var p2 = new TestX(); p2.x = 2;");

    Handle<Script> script = Script::Compile(source);

    Handle<Value> result = script->Run();

    TestX::terminate();

    context.Dispose();

    String::AsciiValue ascii(result);
    std::cout << *ascii << std::endl;

    return 0;
}

0 件のコメント:

コメントを投稿