OSSチャレンジPart3

目的

学んだことを忘れないようにメモ!

間違えたことを書いている可能性あるので、注意してください!

あと、全部教えてもらいながらやったことを書いてるだけなので、自分の実力ではないです。

やってること

Apache Arrow の C++に、Unicode正規化の機能を追加したい。

github.com

レビューを頂いた部分の修正の際に調べたことをメモ

修正項目

新たにヒープ領域を割り当てないようにした方が良いのではないか。

ARROW-14205: [C++] Add unicode normalization to scalar string by okadakk · Pull Request #11298 · apache/arrow · GitHub

前提知識

ヒープ領域: 動的に確保と解放を繰り返せるメモリ領域のこと

ヒープメモリ確保には3種類の関数と、解放する1種類の関数がある。

#include <stdlib.h>

// 確保
void * malloc(size_t size);
void * calloc(size_t num, size_t size);
void * realloc(void * mem, size_t size);

// 解放
void free(void * mem);
  • malloc
    • 確保したいメモリサイズを引数として受け取り、確保されたヒープメモリのポインタが返される
    • メモリ確保に失敗したらNullが返ってくる
  • calloc
    • 確保したい個数と、一個あたりのメモリサイズを引数とする以外は、mallocと一緒。
    • 1点だけ異なり、確保されたヒープ領域の値が「0」の値にされている。(0初期化というらしい)
  • realloc
    • mallocなどで確保したメモリ領域をサイズを変えて再確保できる。
    • メモリ確保に失敗したらNullが返るので、memory = malloc(memory, 500)は避けること。後でメモリ領域を解放できなくなる。
    • 再割り当てというより、そのメモリ領域にあるデータをコピーして、新しいメモリ領域を確保する感じなので、注意!

元のjuliaのコードを読む

utf8proc_map_custom

utf8proc/utf8proc.c at master · JuliaStrings/utf8proc · GitHub

  1. utf8proc_decompose_custom を実行して、与えられた文字を正規化した時の文字数を取得する。
  2. その文字数の数だけint32のメモリ領域を確保して、その領域のポインタを取得する。
  3. utf8proc_decompose_custom を実行して、確保した領域に正規化した文字を保存する。
  4. utf8proc_reencode を実行して、
  5. reencodeの結果、変更された文字数に応じて、メモリ領域をサイズを変えて再確保する。
  6. この関数の第3引数に渡されたポインタが指すメモリ領域に、再確保したメモリ領域の値をコピーする。
  7. 正規化された文字数を返り値として処理終了!!

utf8proc_decompose_custom

utf8proc/utf8proc.c at master · JuliaStrings/utf8proc · GitHub

ざっくりいうと正規分解及びに互換分解をしている

utf8proc_reencode

utf8proc/utf8proc.c at master · JuliaStrings/utf8proc · GitHub

  1. utf8proc_normalize_utf32 を実行して、正規合成を行い代入して、文字数を取得する。
  2. 文字数分ループを回し、その位置にある文字を取得して、1文字づつ utf8proc_encode_char を実行し、UTF-8にencodeした文字を代入&文字数を取得する。
  3. bufferの最後に、null終端ということで、0を入れて、合計の文字数を返す。

やりたいこと

分解と合成のロジックはjuliaのライブラリを使って良さそう。

  1. 与えられたメモリアドレスが示す場所に入っている文字列に対して、utf8proc_decompose_customして、UTF-32でencodeした場合の文字数を取得し、メモリ領域を再確保する。
  2. 確保したメモリ領域に対して、与えられた文字列をutf8proc_decompose_customにして、今度は結果をメモリ領域に代入する。
  3. 分解した文字列を、utf8proc_reencode を行い、合成(合成だから、文字数が増えることはないので、メモリ領域が増えないはず)して、UTF-8に変換してメモリ領域に代入して、その文字数を返す。
  4. メモリ領域をutf-8でencodeした文字 * 文字数分だけ、再確保する。
  5. UTF-8でencodeした時の文字数を返す。(メモリ領域は渡したものをそのまま利用してるので、返す必要はない)