2
Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; version 2 of the License.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
Handling of uchar arrays as large bitmaps.
20
API limitations (or, rather asserted safety assumptions,
21
to encourage correct programming)
23
* the internal size is a set of 32 bit words
24
* the number of bits specified in creation can be any number > 0
25
* there are THREAD safe versions of most calls called bitmap_lock_*
28
Make assembler THREAD safe versions of these using test-and-set instructions
30
Original version created by Sergei Golubchik 2001 - 2004.
31
New version written and test program added and some changes to the interface
32
was made by Mikael Ronstrƶm 2005, with assistance of Tomas Ulin and Mats
36
#include "mysys_priv.h"
37
#include <my_bitmap.h>
41
void create_last_word_mask(MY_BITMAP *map)
43
/* Get the number of used bits (1..8) in the last byte */
44
unsigned int const used= 1U + ((map->n_bits-1U) & 0x7U);
47
Create a mask with the upper 'unused' bits set and the lower 'used'
48
bits clear. The bits within each byte is stored in big-endian order.
50
unsigned char const mask= (~((1 << used) - 1)) & 255;
53
The first bytes are to be set to zero since they represent real bits
54
in the bitvector. The last bytes are set to 0xFF since they represent
55
bytes not used by the bitvector. Finally the last byte contains bits
56
as set by the mask above.
58
unsigned char *ptr= (unsigned char*)&map->last_word_mask;
60
map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
61
switch (no_bytes_in_map(map) & 3) {
63
map->last_word_mask= ~0U;
67
map->last_word_mask= ~0U;
72
map->last_word_mask= 0U;
77
map->last_word_mask= 0U;
84
static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused)))
87
mysql_mutex_lock(map->mutex);
91
static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
94
mysql_mutex_unlock(map->mutex);
98
static inline uint get_first_set(uint32 value, uint word_pos)
100
uchar *byte_ptr= (uchar*)&value;
102
uint byte_pos, bit_pos;
104
for (byte_pos=0; byte_pos < 4; byte_pos++, byte_ptr++)
106
byte_value= *byte_ptr;
109
for (bit_pos=0; ; bit_pos++)
110
if (byte_value & (1 << bit_pos))
111
return (word_pos*32) + (byte_pos*8) + bit_pos;
118
static inline uint get_first_not_set(uint32 value, uint word_pos)
120
uchar *byte_ptr= (uchar*)&value;
122
uint byte_pos, bit_pos;
124
for (byte_pos=0; byte_pos < 4; byte_pos++, byte_ptr++)
126
byte_value= *byte_ptr;
127
if (byte_value != 0xFF)
129
for (bit_pos=0; ; bit_pos++)
130
if (!(byte_value & (1 << bit_pos)))
131
return (word_pos*32) + (byte_pos*8) + bit_pos;
138
my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
139
my_bool thread_safe __attribute__((unused)))
141
DBUG_ENTER("bitmap_init");
144
uint size_in_bytes= bitmap_buffer_size(n_bits);
149
size_in_bytes= ALIGN_SIZE(size_in_bytes);
150
extra= sizeof(mysql_mutex_t);
154
if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
159
map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes);
160
mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST);
167
DBUG_ASSERT(thread_safe == 0);
173
create_last_word_mask(map);
174
bitmap_clear_all(map);
179
void bitmap_free(MY_BITMAP *map)
181
DBUG_ENTER("bitmap_free");
185
mysql_mutex_destroy(map->mutex);
187
my_free(map->bitmap);
195
test if bit already set and set it if it was not (thread unsafe method)
198
bitmap_fast_test_and_set()
207
my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
209
uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
210
uchar bit= 1 << ((bitmap_bit) & 7);
211
uchar res= (*value) & bit;
218
test if bit already set and set it if it was not (thread safe method)
221
bitmap_fast_test_and_set()
223
bitmap_bit bit number
230
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
233
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
235
res= bitmap_fast_test_and_set(map, bitmap_bit);
241
test if bit already set and clear it if it was set(thread unsafe method)
244
bitmap_fast_test_and_set()
253
my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
255
uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
256
uchar bit= 1 << ((bitmap_bit) & 7);
257
uchar res= (*byte) & bit;
263
my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
266
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
268
res= bitmap_fast_test_and_clear(map, bitmap_bit);
274
uint bitmap_set_next(MY_BITMAP *map)
277
DBUG_ASSERT(map->bitmap);
278
if ((bit_found= bitmap_get_first(map)) != MY_BIT_NONE)
279
bitmap_set_bit(map, bit_found);
284
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
286
uint prefix_bytes, prefix_bits, d;
287
uchar *m= (uchar *)map->bitmap;
289
DBUG_ASSERT(map->bitmap &&
290
(prefix_size <= map->n_bits || prefix_size == (uint) ~0));
291
set_if_smaller(prefix_size, map->n_bits);
292
if ((prefix_bytes= prefix_size / 8))
293
memset(m, 0xff, prefix_bytes);
295
if ((prefix_bits= prefix_size & 7))
296
*(m++)= (1 << prefix_bits)-1;
297
if ((d= no_bytes_in_map(map)-prefix_bytes))
302
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
304
uint prefix_bits= prefix_size % 32;
305
my_bitmap_map *word_ptr= map->bitmap, last_word;
306
my_bitmap_map *end_prefix= word_ptr + prefix_size / 32;
307
DBUG_ASSERT(word_ptr && prefix_size <= map->n_bits);
309
/* 1: Words that should be filled with 1 */
310
for (; word_ptr < end_prefix; word_ptr++)
311
if (*word_ptr != 0xFFFFFFFF)
314
last_word= *map->last_word_ptr & ~map->last_word_mask;
316
/* 2: Word which contains the end of the prefix (if any) */
319
if (word_ptr == map->last_word_ptr)
320
return uint4korr((uchar*)&last_word) == (uint32)((1 << prefix_bits) - 1);
321
else if (uint4korr((uchar*)word_ptr) != (uint32)((1 << prefix_bits) - 1))
326
/* 3: Words that should be filled with 0 */
327
for (; word_ptr < map->last_word_ptr; word_ptr++)
332
We can end up here in two situations:
333
1) We went through the whole bitmap in step 1. This will happen if the
334
whole bitmap is filled with 1 and prefix_size is a multiple of 32
335
(i.e. the prefix does not end in the middle of a word).
336
In this case word_ptr will be larger than map->last_word_ptr.
337
2) We have gone through steps 1-3 and just need to check that also
340
return word_ptr > map->last_word_ptr || last_word == 0;
344
my_bool bitmap_is_set_all(const MY_BITMAP *map)
346
my_bitmap_map *data_ptr= map->bitmap;
347
my_bitmap_map *end= map->last_word_ptr;
349
for (; data_ptr < end; data_ptr++)
350
if (*data_ptr != 0xFFFFFFFF)
352
if ((*map->last_word_ptr | map->last_word_mask) != 0xFFFFFFFF)
358
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
360
my_bitmap_map *data_ptr= map->bitmap;
361
my_bitmap_map *end= map->last_word_ptr;
363
for (; data_ptr < end; data_ptr++)
366
if (*map->last_word_ptr & ~map->last_word_mask)
371
/* Return TRUE if map1 is a subset of map2 */
373
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
375
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
377
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
378
map1->n_bits==map2->n_bits);
380
end= map1->last_word_ptr;
381
for (; m1 < end; m1++, m2++)
385
if ((*map1->last_word_ptr & ~map1->last_word_mask) &
386
~(*map2->last_word_ptr & ~map2->last_word_mask))
391
/* True if bitmaps has any common bits */
393
my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
395
my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
397
DBUG_ASSERT(map1->bitmap && map2->bitmap &&
398
map1->n_bits==map2->n_bits);
400
end= map1->last_word_ptr;
401
for (; m1 < end; m1++, m2++)
405
if ((*map1->last_word_ptr & ~map1->last_word_mask) &
406
(*map2->last_word_ptr & ~map2->last_word_mask))
412
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
414
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
415
uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
417
DBUG_ASSERT(map->bitmap && map2->bitmap);
419
end= to+min(len,len2);
420
for (; to < end; to++, from++)
424
map->bitmap[len2 - 1] &= ~map2->last_word_mask;
429
for (; to < end; to++)
436
Set/clear all bits above a bit.
440
map RETURN The bitmap to change.
441
from_byte The bitmap buffer byte offset to start with.
442
use_bit The bit value (1/0) to use for all upper bits.
445
You can only set/clear full bytes.
446
The function is meant for the situation that you copy a smaller bitmap
447
to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
448
size of a byte). Using 'from_byte' saves multiplication and division
449
by eight during parameter passing.
455
void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
457
uchar use_byte= use_bit ? 0xff : 0;
458
uchar *to= (uchar *)map->bitmap + from_byte;
459
uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
461
for (; to < end; to++)
466
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
468
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
469
DBUG_ASSERT(map->bitmap && map2->bitmap &&
470
map->n_bits==map2->n_bits);
471
end= map->last_word_ptr;
473
for (; to <= end; to++, from++)
478
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
480
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
481
DBUG_ASSERT(map->bitmap && map2->bitmap &&
482
map->n_bits==map2->n_bits);
483
end= map->last_word_ptr;
485
for (; to <= end; to++, from++)
490
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
492
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
493
DBUG_ASSERT(map->bitmap && map2->bitmap &&
494
map->n_bits==map2->n_bits);
495
end= map->last_word_ptr;
497
for (; to <= end; to++, from++)
502
void bitmap_invert(MY_BITMAP *map)
504
my_bitmap_map *to= map->bitmap, *end;
505
DBUG_ASSERT(map->bitmap);
506
end= map->last_word_ptr;
508
for (; to <= end; to++)
513
uint bitmap_bits_set(const MY_BITMAP *map)
515
my_bitmap_map *data_ptr= map->bitmap;
516
my_bitmap_map *end= map->last_word_ptr;
518
DBUG_ASSERT(map->bitmap);
520
for (; data_ptr < end; data_ptr++)
521
res+= my_count_bits_uint32(*data_ptr);
523
/*Reset last bits to zero*/
524
res+= my_count_bits_uint32(*map->last_word_ptr & ~map->last_word_mask);
529
void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
531
my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
532
DBUG_ASSERT(map->bitmap && map2->bitmap &&
533
map->n_bits==map2->n_bits);
534
end= map->last_word_ptr;
536
for (; to <= end; to++, from++)
541
uint bitmap_get_first_set(const MY_BITMAP *map)
544
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
546
DBUG_ASSERT(map->bitmap);
547
data_ptr= map->bitmap;
549
for (word_pos=0; data_ptr < end; data_ptr++, word_pos++)
551
return get_first_set(*data_ptr, word_pos);
553
return get_first_set(*map->last_word_ptr & ~map->last_word_mask, word_pos);
557
uint bitmap_get_first(const MY_BITMAP *map)
560
my_bitmap_map *data_ptr, *end= map->last_word_ptr;
562
DBUG_ASSERT(map->bitmap);
563
data_ptr= map->bitmap;
565
for (word_pos=0; data_ptr < end; data_ptr++, word_pos++)
566
if (*data_ptr != 0xFFFFFFFF)
567
return get_first_not_set(*data_ptr, word_pos);
569
return get_first_not_set(*map->last_word_ptr | map->last_word_mask, word_pos);
573
uint bitmap_lock_set_next(MY_BITMAP *map)
577
bit_found= bitmap_set_next(map);
583
void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
586
DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
587
bitmap_clear_bit(map, bitmap_bit);