* acl4のページ0017
-(by [[K]], 2026.04.23)

** (1) 概要
-a4_0017 は、 acl4v1 にとっての2番目のライブラリプログラムになります。
-提供される主な機能は、以下の通りです。
--(1-1)vector<char> を参考にして作った VecChr クラス(動的可変長配列)
--(1-2)簡単な Key-Value-Store を提供する Set0 クラス
--(1-2)簡単な Key-Value Store を提供する Set0 クラス
-以下、それぞれについてもう少し詳しく説明します。

~

-(1-1)vector<char> を参考にして作った VecChr クラス(動的可変長配列)
--管理情報としては、配列の先頭位置 p と、配列の現状のサイズ N 、領域をとりあえずどこまで確保しているかの N1 があります。本来この3つを管理しようとすれば、 sizeof (VecChr) はポインタ3個分のサイズになるはずですが、少々小細工をして sizeof (VecChr) はポインタ1つ分のサイズになっています(リリースモード時)。
--これは大して重要ではないと思われるかもしれませんが、VecChrの配列などを作ったときには、アドレス計算がだいぶシンプルになって、多少高速化されるのではないかと考えています。
-(1-2)簡単な Key-Value-Store を提供する Set0 クラス
--簡単な二分探索で探索します。 find は O(logN) 、add や rmv は O(N) になります。
--大規模なデータ量が想定されるときは、もっと複雑で高速なやつを作るべきだと思われます。


** (2) デモ




** (3) ライブラリプログラム
 #if (a_Version >= 1)
     #define VecChr              a_VecChr
     #define VecChr_N            a_VecChr_N
     #define VecChr_N1           a_VecChr_N1
     #define VecChr_ini          a_VecChr_ini
     #define VecChr_ini4         a_VecChr_ini4
     #define VecChr_din          a_VecChr_din
     #define VecChr_din4         a_VecChr_din4
     #define VecChr_getN         a_VecChr_getN
     #define VecChr_setN         a_VecChr_setN
     #define VecChr_reserve      a_VecChr_reserve
     #define VecChr_resize       a_VecChr_resize
     #define VecChr_resizeDiff   a_VecChr_resizeDiff
     #define VecChr_reserveDiff  a_VecChr_reserveDiff
     #define VecChr_reserve0     a_VecChr_reserve0
     #define VecChr_resize0      a_VecChr_resize0
     #define VecChr_shrink       a_VecChr_shrink
 #endif
 
 a_class(a_VecChr) { char *p; a_DbgLv1( a_DbgObjInf doi[1]; ) };
 a_static intptr_t a_VecChr_p0[2] = { 0, 0 };
 
 #define a_VecChr_N(w)           ((intptr_t *) (w)->p)[-1]
 #define a_VecChr_N1(w)	         ((intptr_t *) (w)->p)[-2]
 
 a_static void a_VecChr_ini(_aDef_  a_VecChr *w)
 {
     w->p = (char *) &a_VecChr_p0[2];
     a_DbgLv2( a_DbgObjInf_ini(_aThr, w->doi, "VecChr"); )
 }
 
 a_static void a_VecChr_din(_aDef_  a_VecChr *w)
 {
     a_DbgLv2( a_DbgObjInf_din(_aThr, w->doi); )
     if (w->p != (char *) &a_VecChr_p0[2]) {
         intptr_t *p = (intptr_t *) w->p;
         a_free(_a_  p - 2, p[-2] + 2 * sizeof (intptr_t));
     }
 }
 
 a_static void a_VecChr_ini4(_aDef_  a_VecChr *w0, a_VecChr *w1, a_VecChr *w2, a_VecChr *w3)
 {
     if (w0 != NULL) a_VecChr_ini(_aThr_ w0);
     if (w1 != NULL) a_VecChr_ini(_aThr_ w1);
     if (w2 != NULL) a_VecChr_ini(_aThr_ w2);
     if (w3 != NULL) a_VecChr_ini(_aThr_ w3);
 }
 
 a_static void a_VecChr_din4(_aDef_ a_VecChr *w0, a_VecChr *w1, a_VecChr *w2, a_VecChr *w3)
 {
     if (w0 != NULL) a_VecChr_din(_aThr_ w0);
     if (w1 != NULL) a_VecChr_din(_aThr_ w1);
     if (w2 != NULL) a_VecChr_din(_aThr_ w2);
     if (w3 != NULL) a_VecChr_din(_aThr_ w3);
 }
 
 a_static intptr_t a_VecChr_getN(a_VecChr *w) { return a_VecChr_N(w); }
 a_static void a_VecChr_setN(a_VecChr *w, intptr_t n) { a_VecChr_N(w) = n; }
 
 a_static void a_VecChr_reserve(a_VecChr *w, intptr_t n)
 {
     intptr_t n1nsz = 2 * sizeof (intptr_t);
     if (a_VecChr_N1(w) < n) { 
         intptr_t n1 = a_VecChr_N1(w);
         if (n1 < 16/2) n1 = 16/2;
         do {
             n1 *= 2;
         } while (n1 < n);
         if (w->p != (char *) &a_VecChr_p0[2])
             w->p = a_realloc(_a_  w->p - n1nsz, a_VecChr_N1(w) + n1nsz, n1 + n1nsz);
         else {
             w->p = a_malloc(_a_  n1 + n1nsz);
             ((intptr_t *) w->p)[1] = 0; // n = 0.
         }
         ((intptr_t *) w->p)[0] = n1; // n1 = n1.
         w->p += n1nsz;
     }
 }
 
 a_static void a_VecChr_resize(a_VecChr *w, intptr_t n)
 {
     #if (a_DbgLv >= 2)
         if (n < 0)
             a_errExit("VecChr_resize: bad size: n=%d", n);
     #endif
     a_VecChr_reserve(w, n); a_VecChr_N(w) = n;
 }
 
 a_static void a_VecChr_resizeDiff(a_VecChr *w, intptr_t d)
 {
     #if (a_DbgLv >= 2)
         if (a_VecChr_N(w) + d < 0)
             a_errExit("a_VecChr_resizeDiff: bad diff: d=%d", d);
     #endif
     a_VecChr_resize(w, a_VecChr_N(w) + d);
 }
 
 a_static void a_VecChr_reserveDiff(a_VecChr *w, intptr_t d) { a_VecChr_reserve(w, a_VecChr_N(w) + d); }
 a_static void a_VecChr_reserve0(a_VecChr *w) { a_VecChr_reserveDiff(w, 1); w->p[a_VecChr_N(w)] = '\0'; }
 
 a_static void a_VecChr_resize0(a_VecChr *w, intptr_t n)
 {
     intptr_t n0 = a_VecChr_N(w);
     if (n > n0) {
         a_VecChr_resize(w, n);
         memset(w->p + n0, 0, n - n0);
     }
 }
 
 a_static void a_VecChr_shrink(a_VecChr *w, intptr_t r)
 {
     intptr_t n1nsz = 2 * sizeof (intptr_t);
     #if (a_DbgLv >= 2)
         if (r < 0)
             a_errExit("VecChr_shrink: bad reserve: r=%d", r);
     #endif
     w->p = (char *) a_realloc(_a_  w->p - n1nsz, a_VecChr_N1(w) +  n1nsz, a_VecChr_N(w) + r + n1nsz) + n1nsz;
     a_VecChr_N1(w) = a_VecChr_N(w) + r;
 }
 
 #if (a_Version >= 1)
     #define fnv1a32     a_fnv1a32
     #define Set0        a_Set0
     #define SetElm      a_SetElm
     #define Set0_ini    a_Set0_ini
     #define Set0_din    a_Set0_din
     #define Set0_add    a_Set0_add
     #define Set0_find   a_Set0_find
     #define Set0_rmv    a_Set0_rmv
     #define Set0_findKn a_Set0_findKn
 #endif
 
 a_static uint32_t a_fnv1a32(const void *p, intptr_t n)
 {
     uint32_t h = 2166136261U;
     intptr_t i;
     for (i = 0; i < n; i++) {
         h ^= ((const unsigned char *) p)[i];
         h *= 16777619U;
     }
     return h;
 }
 
 a_class(a_Set0) { a_VecChr tbl[1]; void (*elm_din)(void *); a_DbgLv1( a_DbgObjInf doi[1]; ) };
 a_class(a_SetElm) { const void *k; intptr_t n, h; };
 
 a_static void a_Set0_ini(_aDef_ a_Set0 *w, void (*elm_din)(void *))
 {
     a_VecChr_ini(_a_  w->tbl);
     w->elm_din = elm_din;
     a_DbgLv2( a_DbgObjInf_ini(_aThr, w->doi, "Set0"); )
 }
 
 a_static void a_Set0_din(_aDef_ a_Set0 *w)
 {
     a_DbgLv2( a_DbgObjInf_din(_aThr_ w->doi); )
     if (w->elm_din != NULL) {
         intptr_t i = a_VecChr_getN(w->tbl) / sizeof (void *) - 1;
         void **p = (void *) w->tbl->p;
         for (; i >= 0; i--)
             w->elm_din(p[i]);
     }
     a_VecChr_din(_aThr_ w->tbl);
 }
 
 a_static intptr_t a_Set0_cmp(a_SetElm *a, a_SetElm *b)
 {
     if (a->h != b->h) return a->h - b->h;
     if (a->n != b->n) return a->n - b->n;
     return memcmp(a->k, b->k, a->n);
 }
 
 a_static void *a_Set0_add(a_Set0 *w, a_SetElm *elm)
 { 
     elm->h = a_fnv1a32(elm->k, elm->n) & 0x7fffffff;
     intptr_t i = 0, n = a_VecChr_getN(w->tbl) / sizeof (a_SetElm *), a, b, m, c;
     a_SetElm **tbl = (a_SetElm **) w->tbl->p, *p;
     if (n == 0) goto ins;
     p = tbl[0]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
     if (c < 0) goto ins;
     i = 1; if (n == 1) goto ins;
     p = tbl[n - 1]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
     i = n; if (c > 0) goto ins;
     a = 0; b = n - 1; m = a + ((b - a) >> 1);
     i = b; if (m == a) goto ins;
     do {
         p = tbl[m]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
         if (c < 0) { b = m; } else { a = m; }
         m = a + ((b - a) >> 1);
     } while (m > a);
     i = b;
 ins:
     a_VecChr_resizeDiff(w->tbl, sizeof (a_SetElm *));
     tbl = (a_SetElm **) w->tbl->p;
     if (i < n)
         memmove(&tbl[i + 1], &tbl[i], (n - i) * sizeof (a_SetElm *));
     tbl[i] = elm;
     return NULL;
 fin: return p;
 }
 
 a_static void *a_Set0_find(a_Set0 *w, a_SetElm *elm)
 { 
     elm->h = a_fnv1a32(elm->k, elm->n) & 0x7fffffff;
     intptr_t n = a_VecChr_getN(w->tbl) / sizeof (a_SetElm *), a, b, m, c;
     a_SetElm **tbl = (a_SetElm **) w->tbl->p, *p;
     if (n == 0) goto ins;
     p = tbl[0]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
     if (c < 0) goto ins;
     if (n == 1) goto ins;
     p = tbl[n - 1]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
     if (c > 0) goto ins;
     a = 0; b = n - 1; m = a + ((b - a) >> 1);
     if (m == a) goto ins;
     do {
         p = tbl[m]; c = a_Set0_cmp(elm, p); if (c == 0) goto fin;
         if (c < 0) { b = m; } else { a = m; }
         m = a + ((b - a) >> 1);
     } while (m > a);
 ins: return NULL;
 fin: return p;
 }
 
 a_static void *a_Set0_rmv(a_Set0 *w, a_SetElm *elm)
 { 
     elm->h = a_fnv1a32(elm->k, elm->n) & 0x7fffffff;
     intptr_t i, n = a_VecChr_getN(w->tbl) / sizeof (a_SetElm *), a, b, m, c;
     a_SetElm **tbl = (a_SetElm **) w->tbl->p, *p;
     if (n == 0) goto ins;
     i = 0; c = a_Set0_cmp(elm, tbl[0]); if (c == 0) goto fin;
     if (c < 0) goto ins;
     if (n == 1) goto ins;
     i = n - 1; c = a_Set0_cmp(elm, tbl[n - 1]); if (c == 0) goto fin;
     if (c > 0) goto ins;
     a = 0; b = n - 1; m = a + ((b - a) >> 1);
     if (m == a) goto ins;
     do {
         i = m; c = a_Set0_cmp(elm, tbl[m]); if (c == 0) goto fin;
         if (c < 0) { b = m; } else { a = m; }
         m = a + ((b - a) >> 1);
     } while (m > a);
 ins: return NULL;
 fin:
     p = tbl[i];
     if (i + 1 < n)
         memmove(&tbl[i], &tbl[i + 1], (n - i - 1) * sizeof (a_SetElm *));
     a_VecChr_resizeDiff(w->tbl, - (intptr_t) sizeof (a_SetElm *));
     return p;
 }
 
 a_static void *a_Set0_findKn(a_Set0 *w, const void *k, intptr_t n)
 {
     a_SetElm elm[1];
     elm->k = k;
     elm->n = n;
     return a_Set0_find(w, elm);
 }


** (99) 更新履歴
-2026.04.23(木) 初版

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS