1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* Bitmap cache implementation */
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gsmdebug.h"
21 #include "gxbcache.h"
22
23 /* ------ Entire cache ------ */
24
25 /* Initialize a cache. The caller must allocate and initialize */
26 /* the first chunk. */
27 void
gx_bits_cache_init(gx_bits_cache * bc,gx_bits_cache_chunk * bck)28 gx_bits_cache_init(gx_bits_cache * bc, gx_bits_cache_chunk * bck)
29 {
30 bck->next = bck;
31 bc->chunks = bck;
32 bc->cnext = 0;
33 bc->bsize = 0;
34 bc->csize = 0;
35 }
36
37 /* ------ Chunks ------ */
38
39 /* Initialize a chunk. The caller must allocate it and its data. */
40 void
gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck,byte * data,uint size)41 gx_bits_cache_chunk_init(gx_bits_cache_chunk * bck, byte * data, uint size)
42 {
43 bck->next = 0;
44 bck->data = data;
45 bck->size = size;
46 bck->allocated = 0;
47 if (data != 0) {
48 gx_cached_bits_head *cbh = (gx_cached_bits_head *) data;
49
50 cbh->size = size;
51 cb_head_set_free(cbh);
52 }
53 }
54
55 /* ------ Individual entries ------ */
56
57 /* Attempt to allocate an entry. If successful, set *pcbh and return 0. */
58 /* If there isn't enough room, set *pcbh to an entry requiring freeing, */
59 /* or to 0 if we are at the end of the chunk, and return -1. */
60 int
gx_bits_cache_alloc(gx_bits_cache * bc,ulong lsize,gx_cached_bits_head ** pcbh)61 gx_bits_cache_alloc(gx_bits_cache * bc, ulong lsize, gx_cached_bits_head ** pcbh)
62 {
63 #define ssize ((uint)lsize)
64 ulong lsize1 = lsize + sizeof(gx_cached_bits_head);
65
66 #define ssize1 ((uint)lsize1)
67 uint cnext = bc->cnext;
68 gx_bits_cache_chunk *bck = bc->chunks;
69 uint left = bck->size - cnext;
70 gx_cached_bits_head *cbh;
71 gx_cached_bits_head *cbh_next;
72 uint fsize = 0;
73
74 if (lsize1 > bck->size - cnext && lsize != left) { /* Not enough room to allocate in this chunk. */
75 *pcbh = 0;
76 return -1;
77 }
78 /* Look for and/or free enough space. */
79 cbh = cbh_next = (gx_cached_bits_head *) (bck->data + cnext);
80 while (fsize < ssize1 && fsize != ssize) {
81 if (!cb_head_is_free(cbh_next)) { /* Ask the caller to free the entry. */
82 if (fsize)
83 cbh->size = fsize;
84 *pcbh = cbh_next;
85 return -1;
86 }
87 fsize += cbh_next->size;
88 if_debug2('K', "[K]merging free bits 0x%lx(%u)\n",
89 (ulong) cbh_next, cbh_next->size);
90 cbh_next = (gx_cached_bits_head *) ((byte *) cbh + fsize);
91 }
92 if (fsize > ssize) { /* fsize >= ssize1 */
93 cbh_next = (gx_cached_bits_head *) ((byte *) cbh + ssize);
94 cbh_next->size = fsize - ssize;
95 cb_head_set_free(cbh_next);
96 if_debug2('K', "[K]shortening bits 0x%lx by %u (initial)\n",
97 (ulong) cbh, fsize - ssize);
98 }
99 gs_alloc_fill(cbh, gs_alloc_fill_block, ssize);
100 cbh->size = ssize;
101 bc->bsize += ssize;
102 bc->csize++;
103 bc->cnext += ssize;
104 bck->allocated += ssize;
105 *pcbh = cbh;
106 return 0;
107 #undef ssize
108 #undef ssize1
109 }
110
111 /* Shorten an entry by a given amount. */
112 void
gx_bits_cache_shorten(gx_bits_cache * bc,gx_cached_bits_head * cbh,uint diff,gx_bits_cache_chunk * bck)113 gx_bits_cache_shorten(gx_bits_cache * bc, gx_cached_bits_head * cbh,
114 uint diff, gx_bits_cache_chunk * bck)
115 {
116 gx_cached_bits_head *next;
117
118 if ((byte *) cbh + cbh->size == bck->data + bc->cnext &&
119 bck == bc->chunks
120 )
121 bc->cnext -= diff;
122 bc->bsize -= diff;
123 bck->allocated -= diff;
124 cbh->size -= diff;
125 next = (gx_cached_bits_head *) ((byte *) cbh + cbh->size);
126 cb_head_set_free(next);
127 next->size = diff;
128 }
129
130 /* Free an entry. The caller is responsible for removing the entry */
131 /* from any other structures (like a hash table). */
132 void
gx_bits_cache_free(gx_bits_cache * bc,gx_cached_bits_head * cbh,gx_bits_cache_chunk * bck)133 gx_bits_cache_free(gx_bits_cache * bc, gx_cached_bits_head * cbh,
134 gx_bits_cache_chunk * bck)
135 {
136 uint size = cbh->size;
137
138 bc->csize--;
139 bc->bsize -= size;
140 bck->allocated -= size;
141 gs_alloc_fill(cbh, gs_alloc_fill_deleted, size);
142 cbh->size = size; /* gs_alloc_fill may have overwritten */
143 cb_head_set_free(cbh);
144 }
145