acl4のページ0017

  • (by K, 2026.04.23)

(1) 概要

  • a4_0017 は、 acl4v1 にとっての2番目のライブラリプログラムになります。
  • 提供される主な機能は、以下の通りです。
    • (1-1)vector<char> を参考にして作った VecChr クラス(動的可変長配列)
    • (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
Last-modified: 2026-04-23 (木) 15:06:28 (53d)