kclib1について#3

  • (by K, 2019.04.09)

(1) KPtrPool

  • ポインタプールという簡単な仕組みを提供する関数群です。ポインタプールは川合が適当につけた名前です。
  • ポインタプールは、あるサイズのオブジェクトへのポインタを、溜めておいたり取り出したりできるプールです。サイズ固定のmalloc/freeだと思って使えます。
  • 管理はLIFOで行われるので、allocでは最後にfreeしたものが出てくることになります。これはキャッシュのヒット率を上げて高速化するためにやっています。
  • 実装例の末尾についているKPtrPool_fw_mallocはinitの際のfwに指定するために使います。
    • 標準ライブラリでは、任意の関数を指定するとき、単に関数のポインタを渡しています。例えばqsortなどです。
    • しかしkclib1では、任意の関数を指定するときは、関数のポインタを先頭に含むオブジェクトを渡します。そしてその関数を呼び出すときには、そのオブジェクトへのポインタも第一引数で渡すことになっています。
    • これは関数に任意のパラメータを簡単に渡せるようにするためです。
    • 慣れないとややこしく見えると思いますが、慣れてしまうと平凡なやり方が不便でしょうがないです。
  • initの際にfwを指定するのは、プールが空の時にallocされたときにモリを確保しなければいけないのですが、その際にどの関数を使ってメモリを確保するのかを指定するためのものです。
    • まあたいていはmallocでしょうけど、そうじゃない関数にしたいときもあるだろうと思うので。

  • void KPtrPool_init(KPtrPool *w, int s, void *fw)
    • 初期化時にサイズsを指定します。
  • void KPtrPool_free(KPtrPool *w, void *p)
    • やっていることはたったの3行です。だから速いに決まっていますね。
  • void *KPtrPool_alloc(KPtrPool *w)
    • プール内にポインタがあれば、やることはたったの5行です。だから速いわけです。

#define KPTRPOOL_REPORT 1

typedef struct KPtrPool_ {
    int s, n;
    void *p;
    void *fw;
    #if (KPTRPOOL_REPORT != 0)
        int a, u;
    #endif
} KPtrPool;

#include "kclib1.h"
#include <stdlib.h>

void KPtrPool_init(KPtrPool *w, int s, void *fw)
{
    if (s < (int) sizeof (void *))
        s = sizeof (void *);
    w->n = 64 * 1024 / s;
    w->s = s;
    if (w->n < 1)
        w->n = 1;
    w->p = 0;
    w->fw = fw;
    #if (KPTRPOOL_REPORT != 0)
        w->a = w->u = 0;
    #endif
}

void KPtrPool_free(KPtrPool *w, void *p)
{
    *((void **) p) = w->p;
    w->p = p;
    #if (KPTRPOOL_REPORT != 0)
        w->u--;
    #endif
}

void *KPtrPool_alloc(KPtrPool *w)
{
    char *p;
    void *(*f)(void *, int);
    if (w->p == 0) {
        int i;
        f = *((void **) w->fw);
        p = f(w->fw, w->n * w->s);
        if (p == 0) goto fin;
        p += w->n * w->s;
        for (i = 0; i < w->n; i++) {
            p -= w->s;
            KPtrPool_free(w, p);
        }
        #if (KPTRPOOL_REPORT != 0)
            w->a += w->n;
            w->u += w->n;
        #endif
    }
    p = w->p;
    w->p = *(void **) p;
    #if (KPTRPOOL_REPORT != 0)
        w->u++;
    #endif
fin:
    return p;
}

void *KPtrPool_f_malloc(void *w, int s)
{
    void *p = malloc(s);
    (void) w;
    if (p == 0)
        kerrorExit("KPtrPool_f_malloc: out of memory");
    return p;
}

void *KPtrPool_fw_malloc[1] = { (void *) &KPtrPool_f_malloc };

こめんと欄


コメントお名前NameLink

リロード   新規 編集 差分 添付   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS
Last-modified: 2019-04-10 (水) 07:17:26 (189d)