my_bitmap.c 7.27 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14 15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 17 18

/*
  Handling of uchar arrays as large bitmaps.
19 20 21 22 23 24 25 26 27 28 29 30

  API limitations (or, rather asserted safety assumptions,
  to encourage correct programming)

    * the size of the used bitmap is less than ~(uint) 0
    * it's a multiple of 8 (for efficiency reasons)
    * when arguments are a bitmap and a bit number, the number
      must be within bitmap size
    * bitmap_set_prefix() is an exception - one can use ~0 to set all bits
    * when both arguments are bitmaps, they must be of the same size
    * bitmap_intersect() is an exception :)
      (for for Bitmap::intersect(ulonglong map2buff))
unknown's avatar
unknown committed
31 32

  TODO:
unknown's avatar
unknown committed
33
  Make assembler THREAD safe versions of these using test-and-set instructions
34 35 36 37
*/

#include "mysys_priv.h"
#include <my_bitmap.h>
unknown's avatar
unknown committed
38
#include <m_string.h>
39

40
static inline void bitmap_lock(MY_BITMAP* map)
unknown's avatar
unknown committed
41 42
{
#ifdef THREAD
43 44
  if (map->mutex)
    pthread_mutex_lock(map->mutex);
unknown's avatar
unknown committed
45 46 47
#endif
}

48
static inline void bitmap_unlock(MY_BITMAP* map)
unknown's avatar
unknown committed
49 50
{
#ifdef THREAD
51 52
  if (map->mutex)
    pthread_mutex_unlock(map->mutex);
unknown's avatar
unknown committed
53 54 55
#endif
}

56 57 58

my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
		    my_bool thread_safe)
unknown's avatar
unknown committed
59
{
60 61 62 63 64 65 66 67 68
  DBUG_ENTER("bitmap_init");

  DBUG_ASSERT((bitmap_size & 7) == 0);
  bitmap_size/=8;
  if (!(map->bitmap=buf) &&
      !(map->bitmap= (uchar*) my_malloc(bitmap_size +
					(thread_safe ?
					 sizeof(pthread_mutex_t) : 0),
					MYF(MY_WME | MY_ZEROFILL))))
unknown's avatar
unknown committed
69
    return 1;
70
  map->bitmap_size=bitmap_size;
unknown's avatar
unknown committed
71
#ifdef THREAD
72 73 74 75 76 77 78
  if (thread_safe)
  {
    map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size);
    pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
  }
  else
    map->mutex=0;
unknown's avatar
unknown committed
79
#endif
80
  DBUG_RETURN(0);
unknown's avatar
unknown committed
81 82
}

83

84
void bitmap_free(MY_BITMAP *map)
unknown's avatar
unknown committed
85
{
86
  DBUG_ENTER("bitmap_free");
unknown's avatar
unknown committed
87 88 89
  if (map->bitmap)
  {
#ifdef THREAD
90 91
    if (map->mutex)
      pthread_mutex_destroy(map->mutex);
unknown's avatar
unknown committed
92
#endif
93 94
    my_free((char*) map->bitmap, MYF(0));
    map->bitmap=0;
unknown's avatar
unknown committed
95
  }
96
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
97 98
}

99

100
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
unknown's avatar
unknown committed
101
{
102 103 104 105
  DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
  bitmap_lock(map);
  bitmap_fast_set_bit(map, bitmap_bit);
  bitmap_unlock(map);
unknown's avatar
unknown committed
106
}
107

unknown's avatar
unknown committed
108

109
uint bitmap_set_next(MY_BITMAP *map)
unknown's avatar
unknown committed
110
{
unknown's avatar
unknown committed
111
  uchar *bitmap=map->bitmap;
112
  uint bit_found = MY_BIT_NONE;
113
  uint bitmap_size=map->bitmap_size*8;
unknown's avatar
unknown committed
114
  uint i;
115

116
  DBUG_ASSERT(map->bitmap);
unknown's avatar
unknown committed
117
  bitmap_lock(map);
unknown's avatar
unknown committed
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
  for (i=0; i < bitmap_size ; i++, bitmap++)
  {
    if (*bitmap != 0xff)
    {						/* Found slot with free bit */
      uint b;
      for (b=0; ; b++)
      {
	if (!(*bitmap & (1 << b)))
	{
	  *bitmap |= 1<<b;
	  bit_found = (i*8)+b;
	  break;
	}
      }
      break;					/* Found bit */
    }
  }
unknown's avatar
unknown committed
135
  bitmap_unlock(map);
136
  return bit_found;
unknown's avatar
unknown committed
137 138
}

139

140
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
unknown's avatar
unknown committed
141
{
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
  DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
  bitmap_lock(map);
  bitmap_fast_clear_bit(map, bitmap_bit);
  bitmap_unlock(map);
}


void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
  uint prefix_bytes, prefix_bits;

  DBUG_ASSERT(map->bitmap &&
	      (prefix_size <= map->bitmap_size*8 || prefix_size == (uint) ~0));
  bitmap_lock(map);
  set_if_smaller(prefix_size, map->bitmap_size*8);
  if ((prefix_bytes= prefix_size / 8))
    memset(map->bitmap, 0xff, prefix_bytes);
  if ((prefix_bits= prefix_size & 7))
    map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1;
  if (prefix_bytes < map->bitmap_size)
    bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes);
  bitmap_unlock(map);
}


void bitmap_clear_all(MY_BITMAP *map)
{
  bitmap_set_prefix(map, 0);
}


void bitmap_set_all(MY_BITMAP *map)
{
  bitmap_set_prefix(map, ~0);
}


my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
{
  uint prefix_bits= prefix_size & 7, res= 0;
  uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8,
        *end= map->bitmap+map->bitmap_size;

  DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8);

  bitmap_lock((MY_BITMAP *)map);
  while (m < end_prefix)
    if (*m++ != 0xff)
      goto ret;

  if (prefix_bits && *m++ != (1 << prefix_bits)-1)
    goto ret;

  while (m < end)
    if (*m++ != 0)
      goto ret;

  res=1;
ret:
  bitmap_unlock((MY_BITMAP *)map);
  return res;
}


my_bool bitmap_is_clear_all(const MY_BITMAP *map)
{
  return bitmap_is_prefix(map, 0);
}

my_bool bitmap_is_set_all(const MY_BITMAP *map)
{
  return bitmap_is_prefix(map, map->bitmap_size*8);
}


my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit)
{
  DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8);
  return bitmap_fast_is_set(map, bitmap_bit);
}


my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
{
  uint res=0;
  uchar *m1=map1->bitmap, *m2=map2->bitmap, *end;

  DBUG_ASSERT(map1->bitmap && map2->bitmap &&
              map1->bitmap_size==map2->bitmap_size);
  bitmap_lock((MY_BITMAP *)map1);
  bitmap_lock((MY_BITMAP *)map2);

  end= m1+map1->bitmap_size;

  while (m1 < end)
unknown's avatar
unknown committed
237
  {
238 239
    if ((*m1++) & ~(*m2++))
      goto ret;
unknown's avatar
unknown committed
240
  }
241 242 243 244 245 246

  res=1;
ret:
  bitmap_unlock((MY_BITMAP *)map2);
  bitmap_unlock((MY_BITMAP *)map1);
  return res;
unknown's avatar
unknown committed
247
}
248

unknown's avatar
unknown committed
249

250
my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2)
unknown's avatar
unknown committed
251
{
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
  uint res;

  DBUG_ASSERT(map1->bitmap && map2->bitmap &&
              map1->bitmap_size==map2->bitmap_size);
  bitmap_lock((MY_BITMAP *)map1);
  bitmap_lock((MY_BITMAP *)map2);

  res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0;

  bitmap_unlock((MY_BITMAP *)map2);
  bitmap_unlock((MY_BITMAP *)map1);
  return res;
}


void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
{
  uchar *to=map->bitmap, *from=map2->bitmap, *end;
  uint len=map->bitmap_size, len2=map2->bitmap_size;

  DBUG_ASSERT(map->bitmap && map2->bitmap);
unknown's avatar
unknown committed
273
  bitmap_lock(map);
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
  bitmap_lock((MY_BITMAP *)map2);

  end= to+min(len,len2);

  while (to < end)
    *to++ &= *from++;

  if (len2 < len)
  {
    end+=len-len2;
    while (to < end)
      *to++=0;
  }

  bitmap_unlock((MY_BITMAP *)map2);
unknown's avatar
unknown committed
289 290 291
  bitmap_unlock(map);
}

292 293

void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
unknown's avatar
unknown committed
294
{
295 296 297 298 299 300 301 302 303 304 305 306 307 308
  uchar *to=map->bitmap, *from=map2->bitmap, *end;

  DBUG_ASSERT(map->bitmap && map2->bitmap &&
              map->bitmap_size==map2->bitmap_size);
  bitmap_lock(map);
  bitmap_lock((MY_BITMAP *)map2);

  end= to+map->bitmap_size;

  while (to < end)
    *to++ &= ~(*from++);

  bitmap_unlock((MY_BITMAP *)map2);
  bitmap_unlock(map);
unknown's avatar
unknown committed
309 310
}

311 312

void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
unknown's avatar
unknown committed
313
{
314 315 316 317
  uchar *to=map->bitmap, *from=map2->bitmap, *end;

  DBUG_ASSERT(map->bitmap && map2->bitmap &&
              map->bitmap_size==map2->bitmap_size);
unknown's avatar
unknown committed
318
  bitmap_lock(map);
319 320 321 322 323 324 325 326
  bitmap_lock((MY_BITMAP *)map2);

  end= to+map->bitmap_size;

  while (to < end)
    *to++ |= *from++;

  bitmap_unlock((MY_BITMAP *)map2);
unknown's avatar
unknown committed
327 328
  bitmap_unlock(map);
}
329