1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gxbcache.c 8022 2007-06-05 22:23:38Z giles $ */
15 /* Bitmap cache implementation */
16 #include "memory_.h"
17 #include "gx.h"
18 #include "gsmdebug.h"
19 #include "gxbcache.h"
20 
21 /* ------ Entire cache ------ */
22 
23 /* Initialize a cache.  The caller must allocate and initialize */
24 /* the first chunk. */
25 void
gx_bits_cache_init(gx_bits_cache * bc,gx_bits_cache_chunk * bck)26 gx_bits_cache_init(gx_bits_cache * bc, gx_bits_cache_chunk * bck)
27 {
28     bck->next = bck;
29     bc->chunks = bck;
30     bc->cnext = 0;
31     bc->bsize = 0;
32     bc->csize = 0;
33 }
34 
35 /* ------ Chunks ------ */
36 
37 /* Initialize a chunk.  The caller must allocate it and its data. */
38 void
gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck,byte * data,uint size)39 gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck, byte * data, uint size)
40 {
41     bck->next = 0;
42     bck->data = data;
43     bck->size = size;
44     bck->allocated = 0;
45     if (data != 0) {
46 	gx_cached_bits_head *cbh = (gx_cached_bits_head *) data;
47 
48 	cbh->size = size;
49 	cb_head_set_free(cbh);
50     }
51 }
52 
53 /* ------ Individual entries ------ */
54 
55 /* Attempt to allocate an entry.  If successful, set *pcbh and return 0. */
56 /* If there isn't enough room, set *pcbh to an entry requiring freeing, */
57 /* or to 0 if we are at the end of the chunk, and return -1. */
58 int
gx_bits_cache_alloc(gx_bits_cache * bc,ulong lsize,gx_cached_bits_head ** pcbh)59 gx_bits_cache_alloc(gx_bits_cache * bc, ulong lsize, gx_cached_bits_head ** pcbh)
60 {
61 #define ssize ((uint)lsize)
62     ulong lsize1 = lsize + sizeof(gx_cached_bits_head);
63 
64 #define ssize1 ((uint)lsize1)
65     uint cnext = bc->cnext;
66     gx_bits_cache_chunk *bck = bc->chunks;
67     uint left = bck->size - cnext;
68     gx_cached_bits_head *cbh;
69     gx_cached_bits_head *cbh_next;
70     uint fsize = 0;
71 
72     if (lsize1 > bck->size - cnext && lsize != left) {	/* Not enough room to allocate in this chunk. */
73 	*pcbh = 0;
74 	return -1;
75     }
76     /* Look for and/or free enough space. */
77     cbh = cbh_next = (gx_cached_bits_head *) (bck->data + cnext);
78     while (fsize < ssize1 && fsize != ssize) {
79 	if (!cb_head_is_free(cbh_next)) {	/* Ask the caller to free the entry. */
80 	    if (fsize)
81 		cbh->size = fsize;
82 	    *pcbh = cbh_next;
83 	    return -1;
84 	}
85 	fsize += cbh_next->size;
86 	if_debug2('K', "[K]merging free bits 0x%lx(%u)\n",
87 		  (ulong) cbh_next, cbh_next->size);
88 	cbh_next = (gx_cached_bits_head *) ((byte *) cbh + fsize);
89     }
90     if (fsize > ssize) {	/* fsize >= ssize1 */
91 	cbh_next = (gx_cached_bits_head *) ((byte *) cbh + ssize);
92 	cbh_next->size = fsize - ssize;
93 	cb_head_set_free(cbh_next);
94 	if_debug2('K', "[K]shortening bits 0x%lx by %u (initial)\n",
95 		  (ulong) cbh, fsize - ssize);
96     }
97     gs_alloc_fill(cbh, gs_alloc_fill_block, ssize);
98     cbh->size = ssize;
99     bc->bsize += ssize;
100     bc->csize++;
101     bc->cnext += ssize;
102     bck->allocated += ssize;
103     *pcbh = cbh;
104     return 0;
105 #undef ssize
106 #undef ssize1
107 }
108 
109 /* Shorten an entry by a given amount. */
110 void
gx_bits_cache_shorten(gx_bits_cache * bc,gx_cached_bits_head * cbh,uint diff,gx_bits_cache_chunk * bck)111 gx_bits_cache_shorten(gx_bits_cache * bc, gx_cached_bits_head * cbh,
112 		      uint diff, gx_bits_cache_chunk * bck)
113 {
114     gx_cached_bits_head *next;
115 
116     if ((byte *) cbh + cbh->size == bck->data + bc->cnext &&
117 	bck == bc->chunks
118 	)
119 	bc->cnext -= diff;
120     bc->bsize -= diff;
121     bck->allocated -= diff;
122     cbh->size -= diff;
123     next = (gx_cached_bits_head *) ((byte *) cbh + cbh->size);
124     cb_head_set_free(next);
125     next->size = diff;
126 }
127 
128 /* Free an entry.  The caller is responsible for removing the entry */
129 /* from any other structures (like a hash table). */
130 void
gx_bits_cache_free(gx_bits_cache * bc,gx_cached_bits_head * cbh,gx_bits_cache_chunk * bck)131 gx_bits_cache_free(gx_bits_cache * bc, gx_cached_bits_head * cbh,
132 		   gx_bits_cache_chunk * bck)
133 {
134     uint size = cbh->size;
135 
136     bc->csize--;
137     bc->bsize -= size;
138     bck->allocated -= size;
139     gs_alloc_fill(cbh, gs_alloc_fill_deleted, size);
140     cbh->size = size;		/* gs_alloc_fill may have overwritten */
141     cb_head_set_free(cbh);
142 }
143