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