無料Wikiサービス | デモページ
Linuxなどのメモ書き

V8 JavaScriptエンジン - オブジェクトの追加


V8 JavaScriptエンジンの組み込み - オブジェクトの追加

V8 JavaScriptエンジン - 変数の追加の続き。今度は、グローバル領域へオブジェクト({}リテラルで定義するもの)を追加してみる。追加するオブジェクトは以下のとおり。

オブジェクト名:LunchTime

内容:時、分の二つの値を格納するオブジェクト。

プロパティ:

  • hour
  • min


オブジェクトを追加する場合は、専用のオブジェクトテンプレートを一つ作成(下記ソースではtime_templ)し、そこにプロパティ名とアクセサを登録する。そして、作成したオブジェクトテンプレートをglobal領域用のオブジェクトテンプレートにオブジェクト名(下記ソースではLunchTime)と関連づけて登録する。

各プロパティのアクセサ(set/get_hour(),set/get_min())では、GetInternalField(0)(*1)でオブジェクトに対応するTimeクラスのインスタンスを取り出し、そこからメンバ変数にアクセスする。

(*1)GetInternalField(0)は0番目の内部フィールドの値を取得するという意味。Index0の内部フィールドにはSetInternalField(0, External::New(p))でTimeクラスのインスタンスが事前登録されているため、GetInternalField(0)でインスタンスを取り出すことができる。

#include <v8.h>
#include <iostream>
#include <string>

using namespace v8;

static void read_file(std::istream& ifs, std::string &content)
{
  content = "";
  std::string t;
  while (!ifs.eof()) {
    getline(std::cin, t);
    content += t + "\n";
  }
}

// log()が呼ばれた時のコールバックルーチン
static Handle<Value> log_callback(const Arguments& args) {
  if (args.Length() < 1)
    return v8::Undefined();

  HandleScope scope;
  Handle<Value> arg = args[0];
  String::Utf8Value value(arg);
  std::cout << "log: " << *value <<  std::endl;

  return v8::Undefined();
}

// 追加するオブジェクトに対応するclass
class Time {
public:
  Time() : hour(0), min(0) {}
  int hour;
  int min;
};

// オブジェクトのプロパティのアクセサ
Handle<Value> get_hour(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<Time*>(ptr)->hour;
  return Integer::New(value);
}
void set_hour(Local<String> property, Local<Value> value,
	      const AccessorInfo& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  static_cast<Time*>(ptr)->hour = value->Int32Value();
}

Handle<Value> get_min(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<Time*>(ptr)->min;
  return Integer::New(value);
}
void set_min(Local<String> property, Local<Value> value,
	      const AccessorInfo& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  static_cast<Time*>(ptr)->min = value->Int32Value();
}


int main(int argc, char* argv[])
{
  std::string js_str;
  read_file(std::cin, js_str);

  // Create a stack-allocated handle scope.
  HandleScope handle_scope;

  Handle<ObjectTemplate> global = ObjectTemplate::New();
  // log()関数のコールバックを指定
  global->Set(String::New("log"), FunctionTemplate::New(log_callback));

  // Create a new context.
  //Persistent<Context> context = Context::New();
  Persistent<Context> context = Context::New(NULL, global);

  // Enter the created context for compiling and
  // running the hello world script. 
  Context::Scope context_scope(context);

  // オブジェクトの定義
  Handle<ObjectTemplate> time_templ = ObjectTemplate::New();
  time_templ->SetInternalFieldCount(1);
  time_templ->SetAccessor(String::New("hour"), get_hour, set_hour);  // プロパティとアクセサ指定
  time_templ->SetAccessor(String::New("min"), get_min,  set_min);

  // オブジェクトに対応するC++のインスタンスを作成して登録
  Time* p = new Time;
  p->hour = 12; p->min = 0;  // 初期値
  Local<Object> obj = time_templ->NewInstance();
  obj->SetInternalField(0, External::New(p));
  context->Global()->Set(String::New("LunchTime"), obj);  // globalにLunchTimeオブジェクト登録

  // Create a string containing the JavaScript source code.
  Handle<String> source = String::New(js_str.c_str());

  // Compile the source code.
  Handle<Script> script = Script::Compile(source);

  // Run the script to get the result.
  Handle<Value> result = script->Run();

  // Dispose the persistent context.
  context.Dispose();

  // Convert the result to an ASCII string and print it.
  String::AsciiValue ascii(result);
  printf("%s\n", *ascii);
  return 0;
}

以下のtest4.jsを読み込んで実行してみる。

test4.js

function dump_obj(obj)
{
  for (var field in obj) {
    log(field + ":" + obj[field]);
  }
}

log(typeof LunchTime);
dump_obj(LunchTime);  // プロパティを列挙
LunchTime.hour = 11;  // writeのテスト
LunchTime.min  = 10;
dump_obj(LunchTime);

実行結果

# ./a.out < test4.js
log: object    <-- 型を確認
log: min:0     <-- プロパティが列挙できることを確認
log: hour:12
log: min:10    <-- プロパティの書き換えを確認
log: hour:11
undefined

for inでLunchTimeオブジェクトのプロパティが列挙できている。またプロパティの更新もできている。


最終更新 2012/08/30 10:11:51 - kztomita
(2012/08/28 21:33:11 作成)