/src/ghostpdl/base/gxbcache.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 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, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Bitmap cache implementation */ |
18 | | #include "memory_.h" |
19 | | #include "stdint_.h" |
20 | | #include "gx.h" |
21 | | #include "gxobj.h" |
22 | | #include "gsmdebug.h" |
23 | | #include "gxbcache.h" |
24 | | |
25 | | /* ------ Entire cache ------ */ |
26 | | |
27 | | /* Initialize a cache. The caller must allocate and initialize */ |
28 | | /* the first chunk. */ |
29 | | void |
30 | | gx_bits_cache_init(gx_bits_cache * bc, gx_bits_cache_chunk * bck) |
31 | 175k | { |
32 | 175k | bck->next = bck; |
33 | 175k | bc->chunks = bck; |
34 | 175k | bc->cnext = 0; |
35 | 175k | bc->bsize = 0; |
36 | 175k | bc->csize = 0; |
37 | 175k | } |
38 | | |
39 | | /* ------ Chunks ------ */ |
40 | | |
41 | | /* Initialize a chunk. The caller must allocate it and its data. */ |
42 | | void |
43 | | gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck, byte * data, uint size) |
44 | 177k | { |
45 | 177k | bck->next = 0; |
46 | 177k | bck->data = data; |
47 | 177k | bck->size = size; |
48 | 177k | bck->allocated = 0; |
49 | 177k | if (data != 0) { |
50 | 163k | gx_cached_bits_head *cbh = (gx_cached_bits_head *) data; |
51 | | |
52 | 163k | cbh->size = size; |
53 | 163k | cb_head_set_free(cbh); |
54 | 163k | } |
55 | 177k | } |
56 | | |
57 | | /* ------ Individual entries ------ */ |
58 | | |
59 | | /* Attempt to allocate an entry. If successful, set *pcbh and return 0. */ |
60 | | /* If there isn't enough room, set *pcbh to an entry requiring freeing, */ |
61 | | /* or to 0 if we are at the end of the chunk, and return -1. */ |
62 | | int |
63 | | gx_bits_cache_alloc(gx_bits_cache * bc, ulong lsize0, gx_cached_bits_head ** pcbh) |
64 | 578k | { |
65 | 578k | ulong lsize = ROUND_UP(lsize0, obj_align_mod); |
66 | | |
67 | 4.49M | #define ssize ((uint)lsize) |
68 | 578k | ulong lsize1 = lsize + sizeof(gx_cached_bits_head); |
69 | | |
70 | 3.13M | #define ssize1 ((uint)lsize1) |
71 | 578k | uint cnext = bc->cnext; |
72 | 578k | gx_bits_cache_chunk *bck = bc->chunks; |
73 | 578k | uint left = bck->size - cnext; |
74 | 578k | gx_cached_bits_head *cbh; |
75 | 578k | gx_cached_bits_head *cbh_next; |
76 | 578k | uint fsize = 0; |
77 | | |
78 | 578k | if (lsize1 > bck->size - cnext && lsize != left) { /* Not enough room to allocate in this chunk. */ |
79 | 3.01k | *pcbh = 0; |
80 | 3.01k | return -1; |
81 | 3.01k | } |
82 | | /* Look for and/or free enough space. */ |
83 | 575k | cbh = cbh_next = (gx_cached_bits_head *) (bck->data + cnext); |
84 | 1.56M | while (fsize < ssize1 && fsize != ssize) { |
85 | 1.07M | if (!cb_head_is_free(cbh_next)) { /* Ask the caller to free the entry. */ |
86 | 84.2k | if (fsize) |
87 | 80.5k | cbh->size = fsize; |
88 | 84.2k | *pcbh = cbh_next; |
89 | 84.2k | return -1; |
90 | 84.2k | } |
91 | 990k | fsize += cbh_next->size; |
92 | 990k | if_debug2('K', "[K]merging free bits "PRI_INTPTR"(%u)\n", |
93 | 990k | (intptr_t)cbh_next, cbh_next->size); |
94 | 990k | cbh_next = (gx_cached_bits_head *) ((byte *) cbh + fsize); |
95 | 990k | } |
96 | 491k | if (fsize > ssize) { /* fsize >= ssize1 */ |
97 | 473k | cbh_next = (gx_cached_bits_head *) ((byte *) cbh + ssize); |
98 | 473k | cbh_next->size = fsize - ssize; |
99 | 473k | cb_head_set_free(cbh_next); |
100 | 473k | if_debug2('K', "[K]shortening bits "PRI_INTPTR" by %u (initial)\n", |
101 | 473k | (intptr_t)cbh, fsize - ssize); |
102 | 473k | } |
103 | 491k | gs_alloc_fill(cbh, gs_alloc_fill_block, ssize); |
104 | 491k | cbh->size = ssize; |
105 | 491k | bc->bsize += ssize; |
106 | 491k | bc->csize++; |
107 | 491k | bc->cnext += ssize; |
108 | 491k | bck->allocated += ssize; |
109 | 491k | *pcbh = cbh; |
110 | 491k | return 0; |
111 | 575k | #undef ssize |
112 | 575k | #undef ssize1 |
113 | 575k | } |
114 | | |
115 | | /* Shorten an entry by a given amount. */ |
116 | | void |
117 | | gx_bits_cache_shorten(gx_bits_cache * bc, gx_cached_bits_head * cbh, |
118 | | uint diff, gx_bits_cache_chunk * bck) |
119 | 262k | { |
120 | 262k | gx_cached_bits_head *next; |
121 | | |
122 | 262k | if ((byte *) cbh + cbh->size == bck->data + bc->cnext && |
123 | 262k | bck == bc->chunks |
124 | 262k | ) |
125 | 262k | bc->cnext -= diff; |
126 | 262k | bc->bsize -= diff; |
127 | 262k | bck->allocated -= diff; |
128 | 262k | cbh->size -= diff; |
129 | 262k | next = (gx_cached_bits_head *) ((byte *) cbh + cbh->size); |
130 | 262k | cb_head_set_free(next); |
131 | 262k | next->size = diff; |
132 | 262k | } |
133 | | |
134 | | /* Free an entry. The caller is responsible for removing the entry */ |
135 | | /* from any other structures (like a hash table). */ |
136 | | void |
137 | | gx_bits_cache_free(gx_bits_cache * bc, gx_cached_bits_head * cbh, |
138 | | gx_bits_cache_chunk * bck) |
139 | 345k | { |
140 | 345k | uint size = cbh->size; |
141 | | |
142 | 345k | bc->csize--; |
143 | 345k | bc->bsize -= size; |
144 | 345k | bck->allocated -= size; |
145 | 345k | gs_alloc_fill(cbh, gs_alloc_fill_deleted, size); |
146 | 345k | cbh->size = size; /* gs_alloc_fill may have overwritten */ |
147 | 345k | cb_head_set_free(cbh); |
148 | 345k | } |
149 | | |
150 | | #ifdef DEBUG |
151 | | /* A useful bit of code to dump the contents of the bitmap cache. Not |
152 | | * currently called. Current position is indicated with a '>'. */ |
153 | | void |
154 | | gx_bits_cache_dump(gx_bits_cache * bc) |
155 | | { |
156 | | gx_bits_cache_chunk *bck = bc->chunks; |
157 | | gx_bits_cache_chunk *first = bck; |
158 | | |
159 | | dlprintf2("%d entries making %d bytes\n", bc->csize, bc->bsize); |
160 | | |
161 | | do { |
162 | | gx_cached_bits_head *cbh; |
163 | | uint pos = 0; |
164 | | |
165 | | dlprintf2(" chunk of %d bytes (%d allocated)\n", bck->size, bck->allocated); |
166 | | |
167 | | cbh = (gx_cached_bits_head *)bck->data; |
168 | | while (pos != bck->size) { |
169 | | dlprintf3(" %csize=%d depth=%d\n", |
170 | | pos == bc->cnext && bck == bc->chunks ? '>' : ' ', |
171 | | cbh->size, cbh->depth); |
172 | | pos += cbh->size; |
173 | | cbh = (gx_cached_bits_head *)(((byte *)cbh) + cbh->size); |
174 | | } |
175 | | bck = bck->next; |
176 | | } while (bck != first); |
177 | | |
178 | | bck=bck; |
179 | | } |
180 | | #endif |