14a49301eSmrg/**************************************************************************
2361fc4cbSmaya *
34a49301eSmrg * Copyright 2009 VMware, Inc.
44a49301eSmrg * All Rights Reserved.
5361fc4cbSmaya *
64a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
74a49301eSmrg * copy of this software and associated documentation files (the
84a49301eSmrg * "Software"), to deal in the Software without restriction, including
94a49301eSmrg * without limitation the rights to use, copy, modify, merge, publish,
104a49301eSmrg * distribute, sub license, and/or sell copies of the Software, and to
114a49301eSmrg * permit persons to whom the Software is furnished to do so, subject to
124a49301eSmrg * the following conditions:
13361fc4cbSmaya *
144a49301eSmrg * The above copyright notice and this permission notice (including the
154a49301eSmrg * next paragraph) shall be included in all copies or substantial portions
164a49301eSmrg * of the Software.
17361fc4cbSmaya *
184a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204a49301eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
214a49301eSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
224a49301eSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
234a49301eSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
244a49301eSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25361fc4cbSmaya *
264a49301eSmrg **************************************************************************/
274a49301eSmrg
284a49301eSmrg/**
294a49301eSmrg * @file
304a49301eSmrg * Generic bitmask implementation.
31361fc4cbSmaya *
324a49301eSmrg * @author Jose Fonseca <jfonseca@vmware.com>
334a49301eSmrg */
344a49301eSmrg
354a49301eSmrg
364a49301eSmrg#include "pipe/p_compiler.h"
374a49301eSmrg#include "util/u_debug.h"
384a49301eSmrg
394a49301eSmrg#include "util/u_memory.h"
404a49301eSmrg#include "util/u_bitmask.h"
414a49301eSmrg
424a49301eSmrg
43361fc4cbSmayatypedef uint32_t util_bitmask_word;
444a49301eSmrg
454a49301eSmrg
464a49301eSmrg#define UTIL_BITMASK_INITIAL_WORDS 16
474a49301eSmrg#define UTIL_BITMASK_BITS_PER_BYTE 8
484a49301eSmrg#define UTIL_BITMASK_BITS_PER_WORD (sizeof(util_bitmask_word) * UTIL_BITMASK_BITS_PER_BYTE)
494a49301eSmrg
504a49301eSmrg
514a49301eSmrgstruct util_bitmask
524a49301eSmrg{
534a49301eSmrg   util_bitmask_word *words;
54361fc4cbSmaya
554a49301eSmrg   /** Number of bits we can currently hold */
564a49301eSmrg   unsigned size;
57361fc4cbSmaya
584a49301eSmrg   /** Number of consecutive bits set at the start of the bitmask */
594a49301eSmrg   unsigned filled;
604a49301eSmrg};
614a49301eSmrg
624a49301eSmrg
634a49301eSmrgstruct util_bitmask *
644a49301eSmrgutil_bitmask_create(void)
654a49301eSmrg{
664a49301eSmrg   struct util_bitmask *bm;
67361fc4cbSmaya
684a49301eSmrg   bm = MALLOC_STRUCT(util_bitmask);
6901e04c3fSmrg   if (!bm)
704a49301eSmrg      return NULL;
71361fc4cbSmaya
72361fc4cbSmaya   bm->words = (util_bitmask_word *)
73361fc4cbSmaya      CALLOC(UTIL_BITMASK_INITIAL_WORDS, sizeof(util_bitmask_word));
74361fc4cbSmaya   if (!bm->words) {
754a49301eSmrg      FREE(bm);
764a49301eSmrg      return NULL;
774a49301eSmrg   }
78361fc4cbSmaya
794a49301eSmrg   bm->size = UTIL_BITMASK_INITIAL_WORDS * UTIL_BITMASK_BITS_PER_WORD;
804a49301eSmrg   bm->filled = 0;
81361fc4cbSmaya
824a49301eSmrg   return bm;
834a49301eSmrg}
844a49301eSmrg
854a49301eSmrg
864a49301eSmrg/**
87361fc4cbSmaya * Resize the bitmask if necessary
884a49301eSmrg */
8901e04c3fSmrgstatic inline boolean
904a49301eSmrgutil_bitmask_resize(struct util_bitmask *bm,
914a49301eSmrg                    unsigned minimum_index)
924a49301eSmrg{
93361fc4cbSmaya   const unsigned minimum_size = minimum_index + 1;
944a49301eSmrg   unsigned new_size;
954a49301eSmrg   util_bitmask_word *new_words;
964a49301eSmrg
974a49301eSmrg   /* Check integer overflow */
98361fc4cbSmaya   if (!minimum_size)
994a49301eSmrg      return FALSE;
100361fc4cbSmaya
101361fc4cbSmaya   if (bm->size >= minimum_size)
1024a49301eSmrg      return TRUE;
1034a49301eSmrg
1044a49301eSmrg   assert(bm->size % UTIL_BITMASK_BITS_PER_WORD == 0);
1054a49301eSmrg   new_size = bm->size;
106361fc4cbSmaya   while (new_size < minimum_size) {
1074a49301eSmrg      new_size *= 2;
1084a49301eSmrg      /* Check integer overflow */
109361fc4cbSmaya      if (new_size < bm->size)
1104a49301eSmrg         return FALSE;
1114a49301eSmrg   }
1124a49301eSmrg   assert(new_size);
1134a49301eSmrg   assert(new_size % UTIL_BITMASK_BITS_PER_WORD == 0);
114361fc4cbSmaya
115361fc4cbSmaya   new_words = (util_bitmask_word *)
116361fc4cbSmaya      REALLOC((void *)bm->words,
117361fc4cbSmaya              bm->size / UTIL_BITMASK_BITS_PER_BYTE,
118361fc4cbSmaya              new_size / UTIL_BITMASK_BITS_PER_BYTE);
11901e04c3fSmrg   if (!new_words)
1204a49301eSmrg      return FALSE;
121361fc4cbSmaya
122361fc4cbSmaya   memset(new_words + bm->size/UTIL_BITMASK_BITS_PER_WORD,
123361fc4cbSmaya          0,
1244a49301eSmrg          (new_size - bm->size)/UTIL_BITMASK_BITS_PER_BYTE);
125361fc4cbSmaya
1264a49301eSmrg   bm->size = new_size;
1274a49301eSmrg   bm->words = new_words;
128361fc4cbSmaya
1294a49301eSmrg   return TRUE;
1304a49301eSmrg}
1314a49301eSmrg
1324a49301eSmrg
1334a49301eSmrg/**
134361fc4cbSmaya * Check if we can increment the filled counter.
1354a49301eSmrg */
13601e04c3fSmrgstatic inline void
1374a49301eSmrgutil_bitmask_filled_set(struct util_bitmask *bm,
1384a49301eSmrg                        unsigned index)
1394a49301eSmrg{
1404a49301eSmrg   assert(bm->filled <= bm->size);
1414a49301eSmrg   assert(index < bm->size);
142361fc4cbSmaya
143361fc4cbSmaya   if (index == bm->filled) {
1444a49301eSmrg      ++bm->filled;
1454a49301eSmrg      assert(bm->filled <= bm->size);
1464a49301eSmrg   }
1474a49301eSmrg}
1484a49301eSmrg
149361fc4cbSmaya
150361fc4cbSmaya/**
151361fc4cbSmaya * Check if we need to decrement the filled counter.
152361fc4cbSmaya */
15301e04c3fSmrgstatic inline void
1544a49301eSmrgutil_bitmask_filled_unset(struct util_bitmask *bm,
1554a49301eSmrg                          unsigned index)
1564a49301eSmrg{
1574a49301eSmrg   assert(bm->filled <= bm->size);
1584a49301eSmrg   assert(index < bm->size);
159361fc4cbSmaya
160361fc4cbSmaya   if (index < bm->filled)
1614a49301eSmrg      bm->filled = index;
1624a49301eSmrg}
1634a49301eSmrg
1644a49301eSmrg
1654a49301eSmrgunsigned
1664a49301eSmrgutil_bitmask_add(struct util_bitmask *bm)
1674a49301eSmrg{
1684a49301eSmrg   unsigned word;
1694a49301eSmrg   unsigned bit;
1704a49301eSmrg   util_bitmask_word mask;
171361fc4cbSmaya
1724a49301eSmrg   assert(bm);
1734a49301eSmrg
174361fc4cbSmaya   /* linear search for an empty index, starting at filled position */
1754a49301eSmrg   word = bm->filled / UTIL_BITMASK_BITS_PER_WORD;
1764a49301eSmrg   bit  = bm->filled % UTIL_BITMASK_BITS_PER_WORD;
1774a49301eSmrg   mask = 1 << bit;
178361fc4cbSmaya   while (word < bm->size / UTIL_BITMASK_BITS_PER_WORD) {
179361fc4cbSmaya      while (bit < UTIL_BITMASK_BITS_PER_WORD) {
180361fc4cbSmaya         if (!(bm->words[word] & mask))
1814a49301eSmrg            goto found;
1824a49301eSmrg         ++bm->filled;
1834a49301eSmrg         ++bit;
1844a49301eSmrg         mask <<= 1;
1854a49301eSmrg      }
1864a49301eSmrg      ++word;
1874a49301eSmrg      bit = 0;
1884a49301eSmrg      mask = 1;
1894a49301eSmrg   }
1904a49301eSmrgfound:
1914a49301eSmrg
1924a49301eSmrg   /* grow the bitmask if necessary */
193361fc4cbSmaya   if (!util_bitmask_resize(bm, bm->filled))
1944a49301eSmrg      return UTIL_BITMASK_INVALID_INDEX;
1954a49301eSmrg
1964a49301eSmrg   assert(!(bm->words[word] & mask));
1974a49301eSmrg   bm->words[word] |= mask;
1984a49301eSmrg
1994a49301eSmrg   return bm->filled++;
2004a49301eSmrg}
2014a49301eSmrg
2024a49301eSmrg
2034a49301eSmrgunsigned
204361fc4cbSmayautil_bitmask_set(struct util_bitmask *bm,
2054a49301eSmrg                 unsigned index)
2064a49301eSmrg{
2074a49301eSmrg   unsigned word;
2084a49301eSmrg   unsigned bit;
2094a49301eSmrg   util_bitmask_word mask;
210361fc4cbSmaya
2114a49301eSmrg   assert(bm);
212361fc4cbSmaya
2134a49301eSmrg   /* grow the bitmask if necessary */
214361fc4cbSmaya   if (!util_bitmask_resize(bm, index))
2154a49301eSmrg      return UTIL_BITMASK_INVALID_INDEX;
2164a49301eSmrg
2174a49301eSmrg   word = index / UTIL_BITMASK_BITS_PER_WORD;
2184a49301eSmrg   bit  = index % UTIL_BITMASK_BITS_PER_WORD;
2194a49301eSmrg   mask = 1 << bit;
2204a49301eSmrg
2214a49301eSmrg   bm->words[word] |= mask;
2224a49301eSmrg
2234a49301eSmrg   util_bitmask_filled_set(bm, index);
224361fc4cbSmaya
2254a49301eSmrg   return index;
2264a49301eSmrg}
2274a49301eSmrg
2284a49301eSmrg
2294a49301eSmrgvoid
230361fc4cbSmayautil_bitmask_clear(struct util_bitmask *bm,
2314a49301eSmrg                   unsigned index)
2324a49301eSmrg{
2334a49301eSmrg   unsigned word;
2344a49301eSmrg   unsigned bit;
2354a49301eSmrg   util_bitmask_word mask;
236361fc4cbSmaya
2374a49301eSmrg   assert(bm);
238361fc4cbSmaya
239361fc4cbSmaya   if (index >= bm->size)
2404a49301eSmrg      return;
2414a49301eSmrg
2424a49301eSmrg   word = index / UTIL_BITMASK_BITS_PER_WORD;
2434a49301eSmrg   bit  = index % UTIL_BITMASK_BITS_PER_WORD;
2444a49301eSmrg   mask = 1 << bit;
2454a49301eSmrg
2464a49301eSmrg   bm->words[word] &= ~mask;
247361fc4cbSmaya
2484a49301eSmrg   util_bitmask_filled_unset(bm, index);
2494a49301eSmrg}
2504a49301eSmrg
2514a49301eSmrg
2524a49301eSmrgboolean
253361fc4cbSmayautil_bitmask_get(struct util_bitmask *bm,
2544a49301eSmrg                 unsigned index)
2554a49301eSmrg{
256361fc4cbSmaya   const unsigned word = index / UTIL_BITMASK_BITS_PER_WORD;
257361fc4cbSmaya   const unsigned bit  = index % UTIL_BITMASK_BITS_PER_WORD;
258361fc4cbSmaya   const util_bitmask_word mask = 1 << bit;
259361fc4cbSmaya
2604a49301eSmrg   assert(bm);
261361fc4cbSmaya
262361fc4cbSmaya   if (index < bm->filled) {
2634a49301eSmrg      assert(bm->words[word] & mask);
2644a49301eSmrg      return TRUE;
2654a49301eSmrg   }
2664a49301eSmrg
267361fc4cbSmaya   if (index >= bm->size)
2684a49301eSmrg      return FALSE;
2694a49301eSmrg
270361fc4cbSmaya   if (bm->words[word] & mask) {
2714a49301eSmrg      util_bitmask_filled_set(bm, index);
2724a49301eSmrg      return TRUE;
2734a49301eSmrg   }
2744a49301eSmrg   else
2754a49301eSmrg      return FALSE;
2764a49301eSmrg}
2774a49301eSmrg
2784a49301eSmrg
2794a49301eSmrgunsigned
280361fc4cbSmayautil_bitmask_get_next_index(struct util_bitmask *bm,
2814a49301eSmrg                            unsigned index)
2824a49301eSmrg{
2834a49301eSmrg   unsigned word = index / UTIL_BITMASK_BITS_PER_WORD;
2844a49301eSmrg   unsigned bit  = index % UTIL_BITMASK_BITS_PER_WORD;
2854a49301eSmrg   util_bitmask_word mask = 1 << bit;
2864a49301eSmrg
287361fc4cbSmaya   if (index < bm->filled) {
2884a49301eSmrg      assert(bm->words[word] & mask);
2894a49301eSmrg      return index;
2904a49301eSmrg   }
2914a49301eSmrg
292361fc4cbSmaya   if (index >= bm->size) {
2934a49301eSmrg      return UTIL_BITMASK_INVALID_INDEX;
2944a49301eSmrg   }
2954a49301eSmrg
2964a49301eSmrg   /* Do a linear search */
297361fc4cbSmaya   while (word < bm->size / UTIL_BITMASK_BITS_PER_WORD) {
298361fc4cbSmaya      while (bit < UTIL_BITMASK_BITS_PER_WORD) {
299361fc4cbSmaya         if (bm->words[word] & mask) {
300361fc4cbSmaya            if (index == bm->filled) {
3014a49301eSmrg               ++bm->filled;
3024a49301eSmrg               assert(bm->filled <= bm->size);
3034a49301eSmrg            }
3044a49301eSmrg            return index;
3054a49301eSmrg         }
3064a49301eSmrg         ++index;
3074a49301eSmrg         ++bit;
3084a49301eSmrg         mask <<= 1;
3094a49301eSmrg      }
3104a49301eSmrg      ++word;
3114a49301eSmrg      bit = 0;
3124a49301eSmrg      mask = 1;
3134a49301eSmrg   }
314361fc4cbSmaya
3154a49301eSmrg   return UTIL_BITMASK_INVALID_INDEX;
3164a49301eSmrg}
3174a49301eSmrg
3184a49301eSmrg
3194a49301eSmrgunsigned
3204a49301eSmrgutil_bitmask_get_first_index(struct util_bitmask *bm)
3214a49301eSmrg{
3224a49301eSmrg   return util_bitmask_get_next_index(bm, 0);
3234a49301eSmrg}
3244a49301eSmrg
3254a49301eSmrg
3264a49301eSmrgvoid
3274a49301eSmrgutil_bitmask_destroy(struct util_bitmask *bm)
3284a49301eSmrg{
32901e04c3fSmrg   if (bm) {
33001e04c3fSmrg      FREE(bm->words);
33101e04c3fSmrg      FREE(bm);
33201e04c3fSmrg   }
3334a49301eSmrg}
334