1848b8605Smrg/**************************************************************************
2b8e80941Smrg *
3848b8605Smrg * Copyright 2009 VMware, Inc.
4848b8605Smrg * All Rights Reserved.
5b8e80941Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13b8e80941Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17b8e80941Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25b8e80941Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg/**
29848b8605Smrg * @file
30848b8605Smrg * Generic bitmask implementation.
31b8e80941Smrg *
32848b8605Smrg * @author Jose Fonseca <jfonseca@vmware.com>
33848b8605Smrg */
34848b8605Smrg
35848b8605Smrg
36848b8605Smrg#include "pipe/p_compiler.h"
37848b8605Smrg#include "util/u_debug.h"
38848b8605Smrg
39848b8605Smrg#include "util/u_memory.h"
40848b8605Smrg#include "util/u_bitmask.h"
41848b8605Smrg
42848b8605Smrg
43b8e80941Smrgtypedef uint32_t util_bitmask_word;
44848b8605Smrg
45848b8605Smrg
46848b8605Smrg#define UTIL_BITMASK_INITIAL_WORDS 16
47848b8605Smrg#define UTIL_BITMASK_BITS_PER_BYTE 8
48848b8605Smrg#define UTIL_BITMASK_BITS_PER_WORD (sizeof(util_bitmask_word) * UTIL_BITMASK_BITS_PER_BYTE)
49848b8605Smrg
50848b8605Smrg
51848b8605Smrgstruct util_bitmask
52848b8605Smrg{
53848b8605Smrg   util_bitmask_word *words;
54b8e80941Smrg
55848b8605Smrg   /** Number of bits we can currently hold */
56848b8605Smrg   unsigned size;
57b8e80941Smrg
58848b8605Smrg   /** Number of consecutive bits set at the start of the bitmask */
59848b8605Smrg   unsigned filled;
60848b8605Smrg};
61848b8605Smrg
62848b8605Smrg
63848b8605Smrgstruct util_bitmask *
64848b8605Smrgutil_bitmask_create(void)
65848b8605Smrg{
66848b8605Smrg   struct util_bitmask *bm;
67b8e80941Smrg
68848b8605Smrg   bm = MALLOC_STRUCT(util_bitmask);
69b8e80941Smrg   if (!bm)
70848b8605Smrg      return NULL;
71b8e80941Smrg
72b8e80941Smrg   bm->words = (util_bitmask_word *)
73b8e80941Smrg      CALLOC(UTIL_BITMASK_INITIAL_WORDS, sizeof(util_bitmask_word));
74b8e80941Smrg   if (!bm->words) {
75848b8605Smrg      FREE(bm);
76848b8605Smrg      return NULL;
77848b8605Smrg   }
78b8e80941Smrg
79848b8605Smrg   bm->size = UTIL_BITMASK_INITIAL_WORDS * UTIL_BITMASK_BITS_PER_WORD;
80848b8605Smrg   bm->filled = 0;
81b8e80941Smrg
82848b8605Smrg   return bm;
83848b8605Smrg}
84848b8605Smrg
85848b8605Smrg
86848b8605Smrg/**
87b8e80941Smrg * Resize the bitmask if necessary
88848b8605Smrg */
89b8e80941Smrgstatic inline boolean
90848b8605Smrgutil_bitmask_resize(struct util_bitmask *bm,
91848b8605Smrg                    unsigned minimum_index)
92848b8605Smrg{
93b8e80941Smrg   const unsigned minimum_size = minimum_index + 1;
94848b8605Smrg   unsigned new_size;
95848b8605Smrg   util_bitmask_word *new_words;
96848b8605Smrg
97848b8605Smrg   /* Check integer overflow */
98b8e80941Smrg   if (!minimum_size)
99848b8605Smrg      return FALSE;
100b8e80941Smrg
101b8e80941Smrg   if (bm->size >= minimum_size)
102848b8605Smrg      return TRUE;
103848b8605Smrg
104848b8605Smrg   assert(bm->size % UTIL_BITMASK_BITS_PER_WORD == 0);
105848b8605Smrg   new_size = bm->size;
106b8e80941Smrg   while (new_size < minimum_size) {
107848b8605Smrg      new_size *= 2;
108848b8605Smrg      /* Check integer overflow */
109b8e80941Smrg      if (new_size < bm->size)
110848b8605Smrg         return FALSE;
111848b8605Smrg   }
112848b8605Smrg   assert(new_size);
113848b8605Smrg   assert(new_size % UTIL_BITMASK_BITS_PER_WORD == 0);
114b8e80941Smrg
115b8e80941Smrg   new_words = (util_bitmask_word *)
116b8e80941Smrg      REALLOC((void *)bm->words,
117b8e80941Smrg              bm->size / UTIL_BITMASK_BITS_PER_BYTE,
118b8e80941Smrg              new_size / UTIL_BITMASK_BITS_PER_BYTE);
119b8e80941Smrg   if (!new_words)
120848b8605Smrg      return FALSE;
121b8e80941Smrg
122b8e80941Smrg   memset(new_words + bm->size/UTIL_BITMASK_BITS_PER_WORD,
123b8e80941Smrg          0,
124848b8605Smrg          (new_size - bm->size)/UTIL_BITMASK_BITS_PER_BYTE);
125b8e80941Smrg
126848b8605Smrg   bm->size = new_size;
127848b8605Smrg   bm->words = new_words;
128b8e80941Smrg
129848b8605Smrg   return TRUE;
130848b8605Smrg}
131848b8605Smrg
132848b8605Smrg
133848b8605Smrg/**
134b8e80941Smrg * Check if we can increment the filled counter.
135848b8605Smrg */
136b8e80941Smrgstatic inline void
137848b8605Smrgutil_bitmask_filled_set(struct util_bitmask *bm,
138848b8605Smrg                        unsigned index)
139848b8605Smrg{
140848b8605Smrg   assert(bm->filled <= bm->size);
141848b8605Smrg   assert(index < bm->size);
142b8e80941Smrg
143b8e80941Smrg   if (index == bm->filled) {
144848b8605Smrg      ++bm->filled;
145848b8605Smrg      assert(bm->filled <= bm->size);
146848b8605Smrg   }
147848b8605Smrg}
148848b8605Smrg
149b8e80941Smrg
150b8e80941Smrg/**
151b8e80941Smrg * Check if we need to decrement the filled counter.
152b8e80941Smrg */
153b8e80941Smrgstatic inline void
154848b8605Smrgutil_bitmask_filled_unset(struct util_bitmask *bm,
155848b8605Smrg                          unsigned index)
156848b8605Smrg{
157848b8605Smrg   assert(bm->filled <= bm->size);
158848b8605Smrg   assert(index < bm->size);
159b8e80941Smrg
160b8e80941Smrg   if (index < bm->filled)
161848b8605Smrg      bm->filled = index;
162848b8605Smrg}
163848b8605Smrg
164848b8605Smrg
165848b8605Smrgunsigned
166848b8605Smrgutil_bitmask_add(struct util_bitmask *bm)
167848b8605Smrg{
168848b8605Smrg   unsigned word;
169848b8605Smrg   unsigned bit;
170848b8605Smrg   util_bitmask_word mask;
171b8e80941Smrg
172848b8605Smrg   assert(bm);
173848b8605Smrg
174b8e80941Smrg   /* linear search for an empty index, starting at filled position */
175848b8605Smrg   word = bm->filled / UTIL_BITMASK_BITS_PER_WORD;
176848b8605Smrg   bit  = bm->filled % UTIL_BITMASK_BITS_PER_WORD;
177848b8605Smrg   mask = 1 << bit;
178b8e80941Smrg   while (word < bm->size / UTIL_BITMASK_BITS_PER_WORD) {
179b8e80941Smrg      while (bit < UTIL_BITMASK_BITS_PER_WORD) {
180b8e80941Smrg         if (!(bm->words[word] & mask))
181848b8605Smrg            goto found;
182848b8605Smrg         ++bm->filled;
183848b8605Smrg         ++bit;
184848b8605Smrg         mask <<= 1;
185848b8605Smrg      }
186848b8605Smrg      ++word;
187848b8605Smrg      bit = 0;
188848b8605Smrg      mask = 1;
189848b8605Smrg   }
190848b8605Smrgfound:
191848b8605Smrg
192848b8605Smrg   /* grow the bitmask if necessary */
193b8e80941Smrg   if (!util_bitmask_resize(bm, bm->filled))
194848b8605Smrg      return UTIL_BITMASK_INVALID_INDEX;
195848b8605Smrg
196848b8605Smrg   assert(!(bm->words[word] & mask));
197848b8605Smrg   bm->words[word] |= mask;
198848b8605Smrg
199848b8605Smrg   return bm->filled++;
200848b8605Smrg}
201848b8605Smrg
202848b8605Smrg
203848b8605Smrgunsigned
204b8e80941Smrgutil_bitmask_set(struct util_bitmask *bm,
205848b8605Smrg                 unsigned index)
206848b8605Smrg{
207848b8605Smrg   unsigned word;
208848b8605Smrg   unsigned bit;
209848b8605Smrg   util_bitmask_word mask;
210b8e80941Smrg
211848b8605Smrg   assert(bm);
212b8e80941Smrg
213848b8605Smrg   /* grow the bitmask if necessary */
214b8e80941Smrg   if (!util_bitmask_resize(bm, index))
215848b8605Smrg      return UTIL_BITMASK_INVALID_INDEX;
216848b8605Smrg
217848b8605Smrg   word = index / UTIL_BITMASK_BITS_PER_WORD;
218848b8605Smrg   bit  = index % UTIL_BITMASK_BITS_PER_WORD;
219848b8605Smrg   mask = 1 << bit;
220848b8605Smrg
221848b8605Smrg   bm->words[word] |= mask;
222848b8605Smrg
223848b8605Smrg   util_bitmask_filled_set(bm, index);
224b8e80941Smrg
225848b8605Smrg   return index;
226848b8605Smrg}
227848b8605Smrg
228848b8605Smrg
229848b8605Smrgvoid
230b8e80941Smrgutil_bitmask_clear(struct util_bitmask *bm,
231848b8605Smrg                   unsigned index)
232848b8605Smrg{
233848b8605Smrg   unsigned word;
234848b8605Smrg   unsigned bit;
235848b8605Smrg   util_bitmask_word mask;
236b8e80941Smrg
237848b8605Smrg   assert(bm);
238b8e80941Smrg
239b8e80941Smrg   if (index >= bm->size)
240848b8605Smrg      return;
241848b8605Smrg
242848b8605Smrg   word = index / UTIL_BITMASK_BITS_PER_WORD;
243848b8605Smrg   bit  = index % UTIL_BITMASK_BITS_PER_WORD;
244848b8605Smrg   mask = 1 << bit;
245848b8605Smrg
246848b8605Smrg   bm->words[word] &= ~mask;
247b8e80941Smrg
248848b8605Smrg   util_bitmask_filled_unset(bm, index);
249848b8605Smrg}
250848b8605Smrg
251848b8605Smrg
252848b8605Smrgboolean
253b8e80941Smrgutil_bitmask_get(struct util_bitmask *bm,
254848b8605Smrg                 unsigned index)
255848b8605Smrg{
256b8e80941Smrg   const unsigned word = index / UTIL_BITMASK_BITS_PER_WORD;
257b8e80941Smrg   const unsigned bit  = index % UTIL_BITMASK_BITS_PER_WORD;
258b8e80941Smrg   const util_bitmask_word mask = 1 << bit;
259b8e80941Smrg
260848b8605Smrg   assert(bm);
261b8e80941Smrg
262b8e80941Smrg   if (index < bm->filled) {
263848b8605Smrg      assert(bm->words[word] & mask);
264848b8605Smrg      return TRUE;
265848b8605Smrg   }
266848b8605Smrg
267b8e80941Smrg   if (index >= bm->size)
268848b8605Smrg      return FALSE;
269848b8605Smrg
270b8e80941Smrg   if (bm->words[word] & mask) {
271848b8605Smrg      util_bitmask_filled_set(bm, index);
272848b8605Smrg      return TRUE;
273848b8605Smrg   }
274848b8605Smrg   else
275848b8605Smrg      return FALSE;
276848b8605Smrg}
277848b8605Smrg
278848b8605Smrg
279848b8605Smrgunsigned
280b8e80941Smrgutil_bitmask_get_next_index(struct util_bitmask *bm,
281848b8605Smrg                            unsigned index)
282848b8605Smrg{
283848b8605Smrg   unsigned word = index / UTIL_BITMASK_BITS_PER_WORD;
284848b8605Smrg   unsigned bit  = index % UTIL_BITMASK_BITS_PER_WORD;
285848b8605Smrg   util_bitmask_word mask = 1 << bit;
286848b8605Smrg
287b8e80941Smrg   if (index < bm->filled) {
288848b8605Smrg      assert(bm->words[word] & mask);
289848b8605Smrg      return index;
290848b8605Smrg   }
291848b8605Smrg
292b8e80941Smrg   if (index >= bm->size) {
293848b8605Smrg      return UTIL_BITMASK_INVALID_INDEX;
294848b8605Smrg   }
295848b8605Smrg
296848b8605Smrg   /* Do a linear search */
297b8e80941Smrg   while (word < bm->size / UTIL_BITMASK_BITS_PER_WORD) {
298b8e80941Smrg      while (bit < UTIL_BITMASK_BITS_PER_WORD) {
299b8e80941Smrg         if (bm->words[word] & mask) {
300b8e80941Smrg            if (index == bm->filled) {
301848b8605Smrg               ++bm->filled;
302848b8605Smrg               assert(bm->filled <= bm->size);
303848b8605Smrg            }
304848b8605Smrg            return index;
305848b8605Smrg         }
306848b8605Smrg         ++index;
307848b8605Smrg         ++bit;
308848b8605Smrg         mask <<= 1;
309848b8605Smrg      }
310848b8605Smrg      ++word;
311848b8605Smrg      bit = 0;
312848b8605Smrg      mask = 1;
313848b8605Smrg   }
314b8e80941Smrg
315848b8605Smrg   return UTIL_BITMASK_INVALID_INDEX;
316848b8605Smrg}
317848b8605Smrg
318848b8605Smrg
319848b8605Smrgunsigned
320848b8605Smrgutil_bitmask_get_first_index(struct util_bitmask *bm)
321848b8605Smrg{
322848b8605Smrg   return util_bitmask_get_next_index(bm, 0);
323848b8605Smrg}
324848b8605Smrg
325848b8605Smrg
326848b8605Smrgvoid
327848b8605Smrgutil_bitmask_destroy(struct util_bitmask *bm)
328848b8605Smrg{
329b8e80941Smrg   if (bm) {
330b8e80941Smrg      FREE(bm->words);
331b8e80941Smrg      FREE(bm);
332b8e80941Smrg   }
333848b8605Smrg}
334