参照カウント
Xtalでは参照カウント方式を採用しています。
そのためアチコチで参照カウントが上げ下げされているのですが、ちょっと問題に思っていることがあります。
今回の説明に必要な部分だけを、説明にいいように変形して抜き出したコードが次になります。
enum{ TYPE_NULL = 0, //... TYPE_INT = 4, //... TYPE_BASE = 8, //... }; struct Any{ int_t type; union{ Base* pvalue; int_t ivalue; }; }; struct Base{ uint_t ref_count; };
整数は
Any intv = {TYPE_INT, 100};
として持たれ、オブジェクトは
Any objv = {TYPE_BASE, new Base()};
として持たれるという実装になってます。
これだと、参照カウントは次のようにifで分岐をする必要が出てしまいます。
Any any = foo(); // anyに入っているのがTYPE_BASEのときだけ if(any.type==TYPE_BASE){ any.pvalue->ref_count++; }
分岐は最近のCPUだと遅いので、if文無しで参照カウントする方法を考えていました。
このたび思いついたのが次の方法です。
// ((any.type>>3)&1) は、 // typeがTYPE_BASE(=8)以上ならば、1となり、 // それ未満なら0となる。 // よって、mask1は、typeがTYPE_BASE以上ならば0xffffffffとなり、 // それ未満なら0x00000000となる。 uint_t mask1 = 0-((any.type>>3)&1); // mask1を反転 uint_t mask2 = ~mask1; uint_t dummy; // typeがTYPE_BASE以上ならばany.pvalue->ref_countアドレスが、 // それ未満ならdummyローカル変数へのアドレスが入る uint_t* address = reinterpret_cast<uint_t*>( (mask1 & (reinterpret_cast<uint_t>(any.pvalue) + offsetof(Base, ref_count))) | (mask2 & reinterpret_cast<uint_t>(&dummy)) ); // 参照カウンタをインクリメント ++*address;
うーんもっといい方法はないもんか。