kclib1のページ#4
(8) KPtrPool
- ポインタプールという簡単な仕組みを提供する関数群です。ポインタプールは川合が適当につけた名前です。
- ポインタプールは、あるサイズのオブジェクトへのポインタを、溜めておいたり取り出したりできるプールです。サイズ固定のmalloc/freeだと思って使えます。
- 管理はLIFOで行われるので、allocでは最後にfreeしたものが出てくることになります。これはキャッシュのヒット率を上げて高速化するためにやっています。
- initの際にf, optを指定するのは、プールが空の時にallocが来たらメモリを確保しなければいけないのですが、その際にどの関数を使ってメモリを確保するのかを指定するためのものです。
- まあたいていはmallocでしょうけど、そうじゃない関数にしたいときもあるだろうと思うので。
- void KPtrPool_init(KPtrPool *w, int s, void *f, void *opt)
- 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 *f, *opt;
#if (KPTRPOOL_REPORT != 0)
int a, u;
#endif
} KPtrPool;
- [内部実装]
#include "kclib1.h"
#include <stdlib.h>
void KPtrPool_init(KPtrPool *w, int s, void *f, void *opt)
{
if (s < (int) sizeof (void *))
s = sizeof (void *);
w->n = 64 * 1024 / s;
w->s = s;
if ((64 * 1024) % s > 0)
w->n++;
w->p = 0;
w->f = f;
w->opt = opt;
#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 = w->f;
p = f(w->opt, 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 *opt, int s)
{
void *p = malloc(s);
(void) opt;
if (p == 0)
kerrorExit("KPtrPool_f_malloc: out of memory");
return p;
}
こめんと欄
|