root/libutil/idset.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. idset_open
  2. idset_empty
  3. idset_add
  4. idset_contains
  5. idset_first
  6. idset_next
  7. idset_count
  8. idset_close

   1 /*
   2  * Copyright (c) 2005, 2006, 2007 Tama Communications Corporation
   3  *
   4  * This file is part of GNU GLOBAL.
   5  *
   6  * This program is free software: you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as published by
   8  * the Free Software Foundation, either version 3 of the License, or
   9  * (at your option) any later version.
  10  * 
  11  * This program is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  * 
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19 
  20 #ifdef HAVE_CONFIG_H
  21 #include <config.h>
  22 #endif
  23 #include <stdlib.h>
  24 #ifdef HAVE_LIMITS_H
  25 #include <limits.h>
  26 #endif
  27 #include "checkalloc.h"
  28 #include "die.h"
  29 #include "idset.h"
  30 
  31 #ifndef CHAR_BIT
  32 #define CHAR_BIT 8
  33 #endif
  34 #undef LONG_BIT
  35                                         /** maybe 32 or 64 */
  36 #define LONG_BIT        (sizeof(long) * CHAR_BIT)
  37 
  38 /**
  39  * @CODE{idset->min} is initialized to #END_OF_ID.
  40  * (You may use @CODE{idset->max} instead of @CODE{idset->min}.)
  41  */
  42 #define IS_EMPTY(idset)  ((idset)->min == END_OF_ID ? 1 : 0)
  43 
  44 /** @file
  45 Idset: usage and memory status
  46 
  47 @code
  48                                 idset->set
  49                                 []
  50 
  51 idset = idset_open(21)          000000000000000000000___________
  52                                  v
  53 idset_add(idset, 1)             010000000000000000000___________
  54                                   v
  55 idset_add(idset, 2)             011000000000000000000___________
  56                                                     v
  57 idset_add(idset, 20)            011000000000000000001___________
  58 
  59 idset_contains(idset, 2) == true
  60 idset_contains(idset, 3) == false
  61 
  62 idset_close(idset)              []
  63 @endcode
  64 
  65 Idset's index always start from 0 according to the custom of C language. <br>
  66 I you want to treat 1-20 then you @EMPH{must} invoke idset_open() with a argument 21.
  67 
  68 @code
  69         idset = idset_open(21);
  70         idset_add(idset, 0);            => OK
  71         idset_add(idset, 1);            => OK
  72                 ...
  73         idset_add(idset, 20);           => OK
  74         idset_add(idset, 21);           => ERROR (idset_add: id is out of range.)
  75 @endcode
  76 
  77 The range of value is from 0 to the maximum value expressible by unsigned integer - 1. <br>
  78 You should define index as an unsigned integer, and use #END_OF_ID like follows:
  79 
  80 @code
  81         unsigned int id;
  82         for (id = idset_first(set); id != END_OF_ID; id = idset_next(set))
  83                 -- processing about an id --
  84 @endcode
  85  */
  86 /**
  87  * bit mask table
  88  * Prepare all bit mask for performance.
  89  */
  90 static unsigned long *bit;
  91 
  92 /**
  93  * Allocate memory for new idset.
  94  */
  95 IDSET *
  96 idset_open(unsigned int size)
  97 {
  98         IDSET *idset = (IDSET *)check_malloc(sizeof(IDSET));
  99         int i;
 100 
 101         if (bit == NULL) {
 102                 bit = (unsigned long *)check_calloc(sizeof(unsigned long), LONG_BIT);
 103                 for (i = 0; i < LONG_BIT; i++)
 104                         bit[i] = 1UL << i;
 105         }
 106         idset->set = (unsigned long *)check_calloc(sizeof(unsigned long), (size + LONG_BIT - 1) / LONG_BIT);
 107         idset->size = size;
 108         /*
 109          * Initialize all id expressions using invalid value.
 110          * END_OF_ID means 'no value' or 'out of range'.
 111          */
 112         idset->min = idset->max = idset->lastid = END_OF_ID;
 113         return idset;
 114 }
 115 /**
 116  * Return true if @a idset is empty.
 117  *
 118  *      @param[in]      idset   idset structure
 119  *      @return         1: empty, 0: not empty
 120  */
 121 int
 122 idset_empty(IDSET *idset)
 123 {
 124         return IS_EMPTY(idset);
 125 }
 126 /**
 127  * Add @a id to the @a idset.
 128  *
 129  *      @param[in]      idset   idset structure
 130  *      @param[in]      id      id number
 131  */
 132 void
 133 idset_add(IDSET *idset, unsigned int id)
 134 {
 135         int empty = IS_EMPTY(idset);
 136 
 137         if (id >= idset->size)
 138                 die("idset_add: id is out of range.");
 139         idset->set[id / LONG_BIT] |= bit[id % LONG_BIT];
 140         if (empty)
 141                 idset->max = idset->min = id;
 142         else if (id > idset->max)
 143                 idset->max = id;
 144         else if (id < idset->min)
 145                 idset->min = id;
 146 }
 147 /**
 148  * Whether or not @a idset includes specified @a id.
 149  *
 150  *      @param[in]      idset   idset structure
 151  *      @param[in]      id      id number
 152  *      @return         true: contains, false: doesn't contain
 153  */
 154 int
 155 idset_contains(IDSET *idset, unsigned int id)
 156 {
 157         if (IS_EMPTY(idset))
 158                 return 0;
 159         if (id < idset->min || id > idset->max)
 160                 return 0;
 161         return (idset->set[id / LONG_BIT] & bit[id % LONG_BIT]) != 0;
 162 }
 163 /**
 164  * Get first id.
 165  *
 166  *      @param[in]      idset   idset structure
 167  *      @return              id (#END_OF_ID: end of id)
 168  *
 169  */
 170 unsigned int
 171 idset_first(IDSET *idset)
 172 {
 173         /* There is no need to check whether idset is empty
 174            because idset->min is initialized with END_OF_ID. */
 175         return idset->lastid = idset->min;
 176 }
 177 /**
 178  * Get next id.
 179  *
 180  *      @param[in]      idset   idset structure
 181  *      @return              id (#END_OF_ID: end of id)
 182  *
 183  */
 184 unsigned int
 185 idset_next(IDSET *idset)
 186 {
 187         unsigned int i, limit;
 188         int index0, index1;
 189 
 190         if (IS_EMPTY(idset))
 191                 return END_OF_ID;
 192         if (idset->lastid >= idset->max)
 193                 return END_OF_ID;
 194         limit = idset->max / LONG_BIT + 1;
 195         index0 = idset->lastid / LONG_BIT;
 196         index1 = idset->lastid % LONG_BIT;
 197         for (i = ++index1; i < LONG_BIT; i++)
 198                 if (bit[i] & idset->set[index0])
 199                         return idset->lastid = index0 * LONG_BIT + i;
 200         index0++;
 201         for (i = index0; i < limit && idset->set[i] == 0; i++)
 202                 ;
 203         if (i >= limit)
 204                 die("idset_next: internal error.");
 205         index0 = i;
 206         for (i = 0; i < LONG_BIT; i++)
 207                 if (bit[i] & idset->set[index0])
 208                         return idset->lastid = index0 * LONG_BIT + i;
 209         die("idset_next: internal error.");
 210 }
 211 /**
 212  * Return the number of bits.
 213  *
 214  *      @param[in]      idset   idset structure
 215  *      @return         number of bits
 216  */
 217 unsigned int
 218 idset_count(IDSET *idset)
 219 {
 220         unsigned int id, count = 0;
 221 
 222         for (id = idset_first(idset); id != END_OF_ID; id = idset_next(idset))
 223                 count++;
 224         return count;
 225 }
 226 /**
 227  * Free memory for the idset.
 228  */
 229 void
 230 idset_close(IDSET *idset)
 231 {
 232         free(idset->set);
 233         free(idset);
 234 }

/* [previous][next][first][last][top][bottom][index][help] */