コードの圧縮を試みる

C++だと似たようなコードを繰り返し書いていたので、コードの圧縮を考えてみる。

#include <string>
#include <map>

#include "hello.h"

using std::string;
using std::map;

class MyMap : public DataWrapper<MyMap> {

  std::map<string, string> m;

  DEF(initialize, (0, ())) {
    return Qnil;
  }

  DEF(get, (1, (key))) {
    Check_Type(key, T_STRING);
    string k(RSTRING_PTR(key));
    return rb_str_new2(m[k].c_str());
  }

  DEF(set, (2, (key, val))) {
    Check_Type(key, T_STRING);
    string k(RSTRING_PTR(key));
    string v(RSTRING_PTR(val));
    m[k] = v;
    return Qnil;
  }

public:
  static void Init() {
    VALUE clazz = define_class();

    DEFINE_METHOD(clazz, initialize, 0);
    DEFINE_NAMED_METHOD(clazz, "[]", get, 1);
    DEFINE_NAMED_METHOD(clazz, "[]=", set, 2);
  }

};

extern "C"
__declspec(dllexport)
void Init_hello() {
  MyMap::Init();
}
require 'hello'

m = MyMap.new
m["foo"] = "bar"
puts  m["foo"]

うーん、いまいち…。

ヘッダはこんな感じ。

#include <typeinfo>

#include <ruby.h>

#define __F(f) (reinterpret_cast<VALUE (__cdecl *)(...)>(f))
#define DEFINE_METHOD(clazz, name, n) \
  rb_define_method((clazz), (#name), __F(&_##name), (n))
#define DEFINE_NAMED_METHOD(clazz, name, func, n) \
  rb_define_method((clazz), (name), __F(&_##func), (n))

#define DEF(name, x) static VALUE _##name DEF_ARGS x { return data_get(self)->name DEF_VARGS x ; } VALUE name DEF_XARGS x

#define DEF_ARGS(n, x) DEF_ARG##n x
#define DEF_ARG0()                             (VALUE self)
#define DEF_ARG1(arg1)                         (VALUE self, VALUE arg1)
#define DEF_ARG2(arg1, arg2)                   (VALUE self, VALUE arg1, VALUE arg2)
#define DEF_ARG3(arg1, arg2, arg3)             (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
#define DEF_ARG4(arg1, arg2, arg3, arg4)       (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4)
#define DEF_ARG5(arg1, arg2, arg3, arg4, arg5) (VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5)

#define DEF_XARGS(n, x) DEF_XARG##n x
#define DEF_XARG0()                             ()
#define DEF_XARG1(arg1)                         (VALUE arg1)
#define DEF_XARG2(arg1, arg2)                   (VALUE arg1, VALUE arg2)
#define DEF_XARG3(arg1, arg2, arg3)             (VALUE arg1, VALUE arg2, VALUE arg3)
#define DEF_XARG4(arg1, arg2, arg3, arg4)       (VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4)
#define DEF_XARG5(arg1, arg2, arg3, arg4, arg5) (VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5)

#define DEF_VARGS(n, x) DEF_VARG##n x
#define DEF_VARG0()                             ()
#define DEF_VARG1(arg1)                         (arg1)
#define DEF_VARG2(arg1, arg2)                   (arg1, arg2)
#define DEF_VARG3(arg1, arg2, arg3)             (arg1, arg2, arg3)
#define DEF_VARG4(arg1, arg2, arg3, arg4)       (arg1, arg2, arg3, arg4)
#define DEF_VARG5(arg1, arg2, arg3, arg4, arg5) (arg1, arg2, arg3, arg4, arg5)

template <class T>
class DataWrapper {
protected:
  static void free(T *p) {
    delete p;
  }

  static VALUE alloc(VALUE klass) {
    T *p = new T;
    return Data_Wrap_Struct(klass, 0, &free, p);
  }

  static VALUE define_class(VALUE module = Qnil, VALUE super = rb_cObject) {
    char* name = const_cast<char *>(typeid(T).name());
    for (; *name != ' '; name++);
    name++;
    VALUE clazz = NIL_P(module) ? rb_define_class(name, super) : rb_define_class_under(module, name, super);
    rb_define_alloc_func(clazz, &alloc);
    return clazz;
  }

  static T* data_get(VALUE self) {
    T *p;
    Data_Get_Struct(self, T, p);
    return p;
  }
};

探せばもっとちゃんとしたライブラリがありそうだなー。