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