/*
*
* This code is under public domain (CC0)
* .
*
* To the extent possible under law, dearblue has waived all copyright
* and related or neighboring rights to this work.
*
* dearblue
*/
#ifndef RBX_HASHARGS_H
#define RBX_HASHARGS_H 1
#include
#include
#define RBX_SCANHASH_ELEMENTOF(v) (sizeof((v)) / sizeof((v)[0]))
#define RBX_SCANHASH_ENDOF(v) ((v) + RBX_SCANHASH_ELEMENTOF(v))
#if defined(__cplusplus__)
# define RBX_SCANHASH_CEXTERN extern "C"
# define RBX_SCANHASH_CEXTERN_BEGIN RBX_SCANHASH_CEXTERN {
# define RBX_SCANHASH_CEXTERN_END }
#else
# define RBX_SCANHASH_CEXTERN
# define RBX_SCANHASH_CEXTERN_BEGIN
# define RBX_SCANHASH_CEXTERN_END
#endif
RBX_SCANHASH_CEXTERN_BEGIN
struct rbx_scanhash_arg
{
ID name;
VALUE *dest;
VALUE initval;
};
/*
* RBX_SCANHASH マクロから呼ばれる
*/
VALUE rbx_scanhash(VALUE hash, VALUE rest, struct rbx_scanhash_arg *args, struct rbx_scanhash_arg *end);
/**
* メソッドが受け取るキーワード引数を解析します。
*
* マクロ引数はそれぞれが一度だけ評価されます (多重評価はされません)。
*
* 可変長部分の引数 (第3引数以降) の評価順は全ての環境で左から右に固定されます。
*
* 第1引数と第2引数の評価順は環境依存となります。
*
* @param hash
* 解析対象のハッシュオブジェクト。nil の場合、受け取り変数を初期化するだけです。
* @param rest
* 解析後に残ったキーワードを受け取るハッシュオブジェクトを指定します。
* true を指定した場合、内部で新規ハッシュオブジェクトを用意します。
* NULL / false / nil の場合、任意キーワードの受け取りを認めません。
* @param ...
* RBX_SCANHASH_ARG[SI] が並びます。終端を表すものの記述は不要です。
* @return
* 受け取り対象外のハッシュオブジェクト (rest で与えたもの) が返ります。
*
* @sample
*
* // 走査するハッシュオブジェクト
* VALUE user_hash_object = rb_hash_new();
*
* VALUE a, b, c, d, e, f; // これらの変数に受け取る
* RBX_SCANHASH(user_hash_object, Qnil,
* RBX_SCANHASH_ARGS("a", &a, Qnil),
* RBX_SCANHASH_ARGS("b", &b, Qtrue),
* RBX_SCANHASH_ARGS("c", &c, rb_str_new_cstr("abcdefg")),
* RBX_SCANHASH_ARGS("d", &d, INT2FIX(5)));
*
* RBX_SCANHASH_ARG 系の第2引数に NULL を与えると、名前の確認だけして、Cレベルの変数への代入は行わない。
* RBX_SCANHASH_ARGS("e", NULL, Qnil)
*
* RBX_SCANHASH_ARG 系の第3引数に Qundef を与えると、省略不可キーワード引数となる
* RBX_SCANHASH_ARGS("f", &f, Qundef)
*/
#define RBX_SCANHASH(hash, rest, ...) \
({ \
struct rbx_scanhash_arg RBX_SCANHASH_argv[] = { __VA_ARGS__ }; \
rbx_scanhash((hash), (rest), RBX_SCANHASH_argv, \
RBX_SCANHASH_ENDOF(RBX_SCANHASH_argv)); \
}) \
/*
* 評価順は左から右に固定される。
*
* [name] C の文字列を与える
* [dest] キーワード引数の代入先。NULL を指定した場合、名前の確認だけして、Cレベルの変数への代入は行わない
* [vdefault] 規定値。Qundef を指定した場合、省略不可キーワードとなる
*/
#define RBX_SCANHASH_ARGS(name, dest, vdefault) { rb_intern((name)), (dest), (vdefault), }
/*
* 評価順は左から右に固定される。
*
* [name] ruby の ID をあたえる。
* [dest] キーワード引数の代入先。NULL を指定した場合、名前の確認だけして、Cレベルの変数への代入は行わない
* [vdefault] 規定値。Qundef を指定した場合、省略不可キーワードとなる
*/
#define RBX_SCANHASH_ARGI(name, dest, vdefault) { (name), (dest), (vdefault), }
RBX_SCANHASH_CEXTERN_END
#endif /* !defined(RBX_HASHARGS_H) */