SDSの基本

SDS文字列の型は、単なる文字ポインターchar *です。ただし、SDSはヘッダーファイルでchar *の別名としてsds型を定義しています。変数がC文字列ではなくSDS文字列を保持していることを忘れないよう、sds型を使うとよいでしょう。ただし、必須ではありません。

何らかの処理を行うSDSプログラムの、最も簡単な例です。

sds mystring = sdsnew("Hello World!");
printf("%s\n", mystring);
sdsfree(mystring);

output> Hello World!

この短いプログラムだけでも、SDSの重要な点がいくつか分かります。

  • SDS文字列は、sdsnew()関数や、この後に説明する同様の関数で作成し、ヒープ上に確保します。
  • SDS文字列は、ほかのC文字列と同じようにprintf()へ渡せます。
  • SDS文字列はヒープ上に確保されるため、sdsfree()で解放する必要があります。

SDS文字列の作成

sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init);
sds sdsempty(void);
sds sdsdup(const sds s);

SDS文字列には、さまざまな作成方法があります。

  • sdsnew関数は、NUL終端されたC文字列からSDS文字列を作成します。前の例で、その使い方を示しました。
  • sdsnewlen関数はsdsnewに似ていますが、入力文字列がNUL終端されていると仮定せず、長さを表す追加の引数を受け取ります。そのため、バイナリーデータからも文字列を作れます。
    char buf[3];
    sds mystring;
    
    buf[0] = 'A';
    buf[1] = 'B';
    buf[2] = 'C';
    mystring = sdsnewlen(buf,3);
    printf("%s of len %d\n", mystring, (int) sdslen(mystring));
    
    output> ABC of len 3
    

注:sdslenはsize_t型を返すため、戻り値をintへキャストしています。キャストする代わりに、適切なprintf書式指定子を使うこともできます。

  • sdsempty()関数は、長さが0の空文字列を作成します。

    sds mystring = sdsempty();
    printf("%d\n", (int) sdslen(mystring));
    
    output> 0
    
  • sdsdup()関数は、既存のSDS文字列を複製します。

    sds s1, s2;
    
    s1 = sdsnew("Hello");
    s2 = sdsdup(s1);
    printf("%s %s\n", s1, s2);
    
    output> Hello Hello
    

文字列の長さの取得

size_t sdslen(const sds s);

ここまでの例では、文字列の長さを得るためにsdslen関数を使いました。この関数はlibcのstrlenと同様に働きますが、次の違いがあります。

  • 長さがSDS文字列の接頭部に格納されているため、一定時間で処理できます。したがって、非常に長い文字列でも、sdslen呼び出しの負担は大きくありません。
  • ほかのSDS文字列関数と同じくバイナリーセーフなので、内容にかかわらず実際の文字列長を返します。途中にNUL終端文字が含まれていても問題ありません。

SDS文字列のバイナリーセーフな性質を示すために、次のコードを実行できます。

sds s = sdsnewlen("A\0\0B",4);
printf("%d\n", (int) sdslen(s));

output> 4

SDS文字列の末尾は常にNUL終端されています。そのため、この場合もs[4]はNUL終端文字です。ただし、printfで文字列を出力すると、libcはSDS文字列を通常のC文字列として扱うため、"A"だけが出力されます。

文字列の破棄

void sdsfree(sds s);

SDS文字列を破棄するには、文字列ポインターを渡してsdsfreeを呼ぶだけです。ただし、sdsemptyで作成した空文字列も破棄する必要があります。そうしないと、メモリーリークになります。

sdsfree関数は、SDS文字列のポインターの代わりにNULLを渡した場合、何もしません。したがって、呼び出す前にNULLかどうかを明示的に確認する必要はありません。

if (string) sdsfree(string); /* Not needed. */
sdsfree(string); /* Same effect but simpler. */

文字列の連結

動的なC文字列ライブラリーを使うとき、最もよく行う操作は、文字列へ別の文字列を連結することになるでしょう。SDSには、既存の文字列へ文字列を連結するための複数の関数があります。

sds sdscatlen(sds s, const void *t, size_t len);
sds sdscat(sds s, const char *t);

主な文字列連結関数はsdscatlenとsdscatで、動作は同じです。唯一の違いは、sdscatがNUL終端文字列を想定するため、明示的な長さの引数を持たないことです。

sds s = sdsempty();
s = sdscat(s, "Hello ");
s = sdscat(s, "World!");
printf("%s\n", s);

output> Hello World!

あるSDS文字列を別のSDS文字列へ連結したい場合があります。この場合、長さを指定する必要はありませんが、連結する文字列にはNUL終端を要求せず、任意のバイナリーデータを含められるようにしたいものです。そのための専用関数があります。

sds sdscatsds(sds s, const sds t);

使い方は簡単です。

sds s1 = sdsnew("aaa");
sds s2 = sdsnew("bbb");
s1 = sdscatsds(s1,s2);
sdsfree(s2);
printf("%s\n", s1);

output> aaabbb

特定のデータを追加するのではなく、文字列全体が少なくとも指定したバイト数になるようにしたい場合もあります。

sds sdsgrowzero(sds s, size_t len);

sdsgrowzero関数は、現在の文字列長がすでにlenバイトなら何もせず、それ以外の場合はゼロバイトで埋めて長さをlenまで増やします。

sds s = sdsnew("Hello");
s = sdsgrowzero(s,6);
s[5] = '!'; /* We are sure this is safe because of sdsgrowzero() */
printf("%s\n', s);

output> Hello!