【Red Data Tools開発者に聞け!】(第15回) each_raw_record 実装編 ~C++ のクラス、メソッド定義~

Red Data Tools

【Red Data Tools開発者に聞け!】第15回目の振り返り記事になります。

今回から each_raw_record の実装に入っていきます!実装の参考となるように既存のソースコードを読みながら、C++ でのクラスやメソッドの実装はどのように行われるか?を中心に学んでいきます!

Red Data Tools開発者に聞け!第15回 (Rubyバインディングに新機能を追加するシリーズpart10)

今回主に触れるソースコードは以下になります。お手元で併せて読んで頂けると理解が深まるのではないかと思います。

arrow/ruby/red-arrow/ext/arrow/raw-records.cpp at 9b3bf08f78f690605394ad3815177ece931f06d3 · apache/arrow
Apache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing - apache/arrow

yield を実装する

each_raw_record では引数としてブロックを受け取り、各要素に対して逐次ブロックを呼び出した結果を返すメソッドとして実装します。

そのためには ruby だったら yield を呼び出せばいいですが、Ruby の C API を利用する場合は rb_yield をコールします。

Ruby C API には ruby のメソッドに rb_ の prefix をつけたインターフェースが多く用意されているので、実装の際にはこの規則に従ってメソッドを探してみると良いかもしれません。

C++ のコンストラクタ

新しく実装するメソッドの参考にするために、既存の table_raw_records を読んでいきます。このメソッドにおいて Arrow::Table から ruby の Array への変換を実際に行なっているのは以下の部分になります。

RawRecordsBuilder builder(records, n_columns);
builder.build(*table);

まず初めに RawRecordsBuilder オブジェクトを生成しています。このクラスの定義を見ていきましょう。

class RawRecordsBuilder : private Converter, public arrow::ArrayVisitor {
  public:
    explicit RawRecordsBuilder(VALUE records, int n_columns)
      : Converter(),
        records_(records),
        n_columns_(n_columns) {
      }

↑のコードがこのクラスのコンストラクタになっています。3行目の部分で初期化変数を定義します。このクラスは records, n_columns として2つの初期化変数を受け取ることができます。

5~6 行目ではクラスのメンバ変数を宣言しています。このクラスは records_, n_columns_ の2つのメンバを持っています。また、records_(records) のように書くことでメンバの定義をするとともに、その値の初期化を行うことができます。

C++ のメソッド定義とオーバーロード

次に table_raw_records 内でコールされている RawRecordsBuilder のメソッド、 build の実装を見ていきましょう。C++ では返り値の型、メソッド名、引数の順に指定してメソッドを定義を行います。

void build(const arrow::RecordBatch& record_batch) {
  //...
}

void build(const arrow::Table& table) {
  //...
}

RawRecordsBuilder クラスには2つの build メソッドが定義されています。C++ ではメソッドのオーバーロードが可能です。

先に挙げた build メソッドは引数に RecordBatch クラスの引数を与えた場合に実行され、もう一方は Table クラスの引数を与えた場合に実行されます。

配列の生成

build メソッドの実装を見ていきましょう。

このメソッドで初めに行っているのは ruby の Array を生成する処理です。

const auto n_rows = table.num_rows();
for (int64_t i = 0; i < n_rows; ++i) {
  auto record = rb_ary_new_capa(n_columns_);
  rb_ary_push(records_, record);
}

rb_ary_new_capaArray を生成することができます。このメソッドは整数型の引数を受け取って、コンパイル時にあらかじめ指定された数値の長さのメモリ領域を確保して配列を生成します。このような配列を静的配列と言います。

逆にプログラムの実行時に長さを伸び縮みできるように宣言した配列を動的配列と言います。静的配列の方が実行速度が速く、また動的配列は実行時にメモリが割り当てられなくなる危険性があるため大きなデータは扱いずらいという欠点があります。

もし、あらかじめ配列の長さがわかっているケースでは今回のように静的配列を生成した方が良いです。

次回

次回も build メソッドの実装を読み進めていきます。有名なデザインパターンの一つである Visitor パターンの解説にも入っていきますので、引き続き動画のチェックしてみてもらえたらと思います!

コメント

タイトルとURLをコピーしました