1/* ocache.h -- a minimal object caching implementation. */
2
3/* Copyright (C) 2002 Free Software Foundation, Inc.
4
5   This file is part of GNU Bash, the Bourne Again SHell.
6
7   Bash is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21#if !defined (_OCACHE_H_)
22#define	_OCACHE_H_ 1
23
24#ifndef PTR_T
25
26#if defined (__STDC__)
27#  define PTR_T void *
28#else
29#  define PTR_T char *
30#endif
31
32#endif /* PTR_T */
33
34#define OC_MEMSET(memp, xch, nbytes)					\
35do {									\
36  if ((nbytes) <= 32) {							\
37    register char * mzp = (char *)(memp);				\
38    unsigned long mctmp = (nbytes);					\
39    register long mcn;							\
40    if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp &= 7; }	\
41    switch (mctmp) {							\
42      case 0: for(;;) { *mzp++ = xch;					\
43      case 7:	   *mzp++ = xch;					\
44      case 6:	   *mzp++ = xch;					\
45      case 5:	   *mzp++ = xch;					\
46      case 4:	   *mzp++ = xch;					\
47      case 3:	   *mzp++ = xch;					\
48      case 2:	   *mzp++ = xch;					\
49      case 1:	   *mzp++ = xch; if(mcn <= 0) break; mcn--; }		\
50    }									\
51  } else								\
52    memset ((memp), (xch), (nbytes));					\
53} while(0)
54
55typedef struct objcache {
56	PTR_T	data;
57	int	cs;		/* cache size, number of objects */
58	int	nc;		/* number of cache entries */
59} sh_obj_cache_t;
60
61/* Create an object cache C of N pointers to OTYPE. */
62#define ocache_create(c, otype, n) \
63	do { \
64		(c).data = xmalloc((n) * sizeof (otype *)); \
65		(c).cs = (n); \
66		(c).nc = 0; \
67	} while (0)
68
69/* Destroy an object cache C. */
70#define ocache_destroy(c) \
71	do { \
72		if ((c).data) \
73			xfree ((c).data); \
74		(c).data = 0; \
75		(c).cs = (c).nc = 0; \
76	} while (0)
77
78/* Free all cached items, which are pointers to OTYPE, in object cache C. */
79#define ocache_flush(c, otype) \
80	do { \
81		while ((c).nc > 0) \
82			xfree (((otype **)((c).data))[--(c).nc]); \
83	} while (0)
84
85/*
86 * Allocate a new item of type pointer to OTYPE, using data from object
87 * cache C if any cached items exist, otherwise calling xmalloc.  Return
88 * the object in R.
89 */
90#define ocache_alloc(c, otype, r) \
91	do { \
92		if ((c).nc > 0) { \
93			(r) = (otype *)((otype **)((c).data))[--(c).nc]; \
94		} else \
95			(r) = (otype *)xmalloc (sizeof (otype)); \
96	} while (0)
97
98/*
99 * Free an item R of type pointer to OTYPE, adding to object cache C if
100 * there is room and calling xfree if the cache is full.  If R is added
101 * to the object cache, the contents are scrambled.
102 */
103#define ocache_free(c, otype, r) \
104	do { \
105		if ((c).nc < (c).cs) { \
106			OC_MEMSET ((r), 0xdf, sizeof(otype)); \
107			((otype **)((c).data))[(c).nc++] = (r); \
108		} else \
109			xfree (r); \
110	} while (0)
111
112/*
113 * One may declare and use an object cache as (for instance):
114 *
115 *	sh_obj_cache_t wdcache = {0, 0, 0};
116 *	sh_obj_cache_t wlcache = {0, 0, 0};
117 *
118 *	ocache_create(wdcache, WORD_DESC, 30);
119 *	ocache_create(wlcache, WORD_LIST, 30);
120 *
121 *	WORD_DESC *wd;
122 *	ocache_alloc (wdcache, WORD_DESC, wd);
123 *
124 *	WORD_LIST *wl;
125 *	ocache_alloc (wlcache, WORD_LIST, wl);
126 *
127 *	ocache_free(wdcache, WORD_DESC, wd);
128 *	ocache_free(wlcache, WORD_LIST, wl);
129 *
130 * The use is almost arbitrary.
131 */
132
133#endif /* _OCACHE_H  */
134