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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 Handling of uchar arrays as large bitmaps.
21 API limitations (or, rather asserted safety assumptions,
22 to encourage correct programming)
24 * the internal size is a set of 32 bit words
25 * the number of bits specified in creation can be any number > 0
26 * there are THREAD safe versions of most calls called bitmap_lock_*
27 many of those are not used and not compiled normally but the code
28 already exist for them in an #ifdef:ed part. These can only be used
29 if THREAD was specified in bitmap_init
32 Make assembler THREAD safe versions of these using test-and-set instructions
34 Original version created by Sergei Golubchik 2001 - 2004.
35 New version written and test program added and some changes to the interface
36 was made by Mikael Ronström 2005, with assistance of Tomas Ulin and Mats
40 #include "mysys_priv.h"
41 #include <my_bitmap.h>
45 void create_last_word_mask(MY_BITMAP
*map
)
47 /* Get the number of used bits (1..8) in the last byte */
48 unsigned int const used
= 1U + ((map
->n_bits
-1U) & 0x7U
);
51 Create a mask with the upper 'unused' bits set and the lower 'used'
52 bits clear. The bits within each byte is stored in big-endian order.
54 unsigned char const mask
= (~((1 << used
) - 1)) & 255;
57 The first bytes are to be set to zero since they represent real bits
58 in the bitvector. The last bytes are set to 0xFF since they represent
59 bytes not used by the bitvector. Finally the last byte contains bits
60 as set by the mask above.
62 unsigned char *ptr
= (unsigned char*)&map
->last_word_mask
;
64 map
->last_word_ptr
= map
->bitmap
+ no_words_in_map(map
)-1;
65 switch (no_bytes_in_map(map
) & 3) {
67 map
->last_word_mask
= ~0U;
71 map
->last_word_mask
= ~0U;
76 map
->last_word_mask
= 0U;
81 map
->last_word_mask
= 0U;
88 static inline void bitmap_lock(MY_BITMAP
*map
__attribute__((unused
)))
92 pthread_mutex_lock(map
->mutex
);
97 static inline void bitmap_unlock(MY_BITMAP
*map
__attribute__((unused
)))
101 pthread_mutex_unlock(map
->mutex
);
106 static inline uint
get_first_set(uint32 value
, uint word_pos
)
108 uchar
*byte_ptr
= (uchar
*)&value
;
110 uint byte_pos
, bit_pos
;
112 for (byte_pos
=0; byte_pos
< 4; byte_pos
++, byte_ptr
++)
114 byte_value
= *byte_ptr
;
117 for (bit_pos
=0; ; bit_pos
++)
118 if (byte_value
& (1 << bit_pos
))
119 return (word_pos
*32) + (byte_pos
*8) + bit_pos
;
126 static inline uint
get_first_not_set(uint32 value
, uint word_pos
)
128 uchar
*byte_ptr
= (uchar
*)&value
;
130 uint byte_pos
, bit_pos
;
132 for (byte_pos
=0; byte_pos
< 4; byte_pos
++, byte_ptr
++)
134 byte_value
= *byte_ptr
;
135 if (byte_value
!= 0xFF)
137 for (bit_pos
=0; ; bit_pos
++)
138 if (!(byte_value
& (1 << bit_pos
)))
139 return (word_pos
*32) + (byte_pos
*8) + bit_pos
;
146 my_bool
bitmap_init(MY_BITMAP
*map
, my_bitmap_map
*buf
, uint n_bits
,
147 my_bool thread_safe
__attribute__((unused
)))
149 DBUG_ENTER("bitmap_init");
152 uint size_in_bytes
= bitmap_buffer_size(n_bits
);
157 size_in_bytes
= ALIGN_SIZE(size_in_bytes
);
158 extra
= sizeof(pthread_mutex_t
);
162 if (!(buf
= (my_bitmap_map
*) my_malloc(size_in_bytes
+extra
, MYF(MY_WME
))))
167 map
->mutex
= (pthread_mutex_t
*) ((char*) buf
+ size_in_bytes
);
168 pthread_mutex_init(map
->mutex
, MY_MUTEX_INIT_FAST
);
175 DBUG_ASSERT(thread_safe
== 0);
181 create_last_word_mask(map
);
182 bitmap_clear_all(map
);
187 void bitmap_free(MY_BITMAP
*map
)
189 DBUG_ENTER("bitmap_free");
194 pthread_mutex_destroy(map
->mutex
);
196 my_free((char*) map
->bitmap
, MYF(0));
204 test if bit already set and set it if it was not (thread unsafe method)
207 bitmap_fast_test_and_set()
216 my_bool
bitmap_fast_test_and_set(MY_BITMAP
*map
, uint bitmap_bit
)
218 uchar
*value
= ((uchar
*) map
->bitmap
) + (bitmap_bit
/ 8);
219 uchar bit
= 1 << ((bitmap_bit
) & 7);
220 uchar res
= (*value
) & bit
;
227 test if bit already set and set it if it was not (thread safe method)
230 bitmap_fast_test_and_set()
232 bitmap_bit bit number
239 my_bool
bitmap_test_and_set(MY_BITMAP
*map
, uint bitmap_bit
)
242 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
244 res
= bitmap_fast_test_and_set(map
, bitmap_bit
);
250 test if bit already set and clear it if it was set(thread unsafe method)
253 bitmap_fast_test_and_set()
262 my_bool
bitmap_fast_test_and_clear(MY_BITMAP
*map
, uint bitmap_bit
)
264 uchar
*byte
= (uchar
*) map
->bitmap
+ (bitmap_bit
/ 8);
265 uchar bit
= 1 << ((bitmap_bit
) & 7);
266 uchar res
= (*byte
) & bit
;
272 my_bool
bitmap_test_and_clear(MY_BITMAP
*map
, uint bitmap_bit
)
275 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
277 res
= bitmap_fast_test_and_clear(map
, bitmap_bit
);
283 uint
bitmap_set_next(MY_BITMAP
*map
)
286 DBUG_ASSERT(map
->bitmap
);
287 if ((bit_found
= bitmap_get_first(map
)) != MY_BIT_NONE
)
288 bitmap_set_bit(map
, bit_found
);
293 void bitmap_set_prefix(MY_BITMAP
*map
, uint prefix_size
)
295 uint prefix_bytes
, prefix_bits
, d
;
296 uchar
*m
= (uchar
*)map
->bitmap
;
298 DBUG_ASSERT(map
->bitmap
&&
299 (prefix_size
<= map
->n_bits
|| prefix_size
== (uint
) ~0));
300 set_if_smaller(prefix_size
, map
->n_bits
);
301 if ((prefix_bytes
= prefix_size
/ 8))
302 memset(m
, 0xff, prefix_bytes
);
304 if ((prefix_bits
= prefix_size
& 7))
305 *(m
++)= (1 << prefix_bits
)-1;
306 if ((d
= no_bytes_in_map(map
)-prefix_bytes
))
311 my_bool
bitmap_is_prefix(const MY_BITMAP
*map
, uint prefix_size
)
313 uint prefix_bits
= prefix_size
% 32;
314 my_bitmap_map
*word_ptr
= map
->bitmap
, last_word
;
315 my_bitmap_map
*end_prefix
= word_ptr
+ prefix_size
/ 32;
316 DBUG_ASSERT(word_ptr
&& prefix_size
<= map
->n_bits
);
318 /* 1: Words that should be filled with 1 */
319 for (; word_ptr
< end_prefix
; word_ptr
++)
320 if (*word_ptr
!= 0xFFFFFFFF)
323 last_word
= *map
->last_word_ptr
& ~map
->last_word_mask
;
325 /* 2: Word which contains the end of the prefix (if any) */
328 if (word_ptr
== map
->last_word_ptr
)
329 return uint4korr((uchar
*)&last_word
) == (uint32
)((1 << prefix_bits
) - 1);
330 else if (uint4korr((uchar
*)word_ptr
) != (uint32
)((1 << prefix_bits
) - 1))
335 /* 3: Words that should be filled with 0 */
336 for (; word_ptr
< map
->last_word_ptr
; word_ptr
++)
341 We can end up here in two situations:
342 1) We went through the whole bitmap in step 1. This will happen if the
343 whole bitmap is filled with 1 and prefix_size is a multiple of 32
344 (i.e. the prefix does not end in the middle of a word).
345 In this case word_ptr will be larger than map->last_word_ptr.
346 2) We have gone through steps 1-3 and just need to check that also
349 return word_ptr
> map
->last_word_ptr
|| last_word
== 0;
353 my_bool
bitmap_is_set_all(const MY_BITMAP
*map
)
355 my_bitmap_map
*data_ptr
= map
->bitmap
;
356 my_bitmap_map
*end
= map
->last_word_ptr
;
358 for (; data_ptr
< end
; data_ptr
++)
359 if (*data_ptr
!= 0xFFFFFFFF)
361 if ((*map
->last_word_ptr
| map
->last_word_mask
) != 0xFFFFFFFF)
367 my_bool
bitmap_is_clear_all(const MY_BITMAP
*map
)
369 my_bitmap_map
*data_ptr
= map
->bitmap
;
370 my_bitmap_map
*end
= map
->last_word_ptr
;
372 for (; data_ptr
< end
; data_ptr
++)
375 if (*map
->last_word_ptr
& ~map
->last_word_mask
)
380 /* Return TRUE if map1 is a subset of map2 */
382 my_bool
bitmap_is_subset(const MY_BITMAP
*map1
, const MY_BITMAP
*map2
)
384 my_bitmap_map
*m1
= map1
->bitmap
, *m2
= map2
->bitmap
, *end
;
386 DBUG_ASSERT(map1
->bitmap
&& map2
->bitmap
&&
387 map1
->n_bits
==map2
->n_bits
);
389 end
= map1
->last_word_ptr
;
390 for (; m1
< end
; m1
++, m2
++)
394 if ((*map1
->last_word_ptr
& ~map1
->last_word_mask
) &
395 ~(*map2
->last_word_ptr
& ~map2
->last_word_mask
))
400 /* True if bitmaps has any common bits */
402 my_bool
bitmap_is_overlapping(const MY_BITMAP
*map1
, const MY_BITMAP
*map2
)
404 my_bitmap_map
*m1
= map1
->bitmap
, *m2
= map2
->bitmap
, *end
;
406 DBUG_ASSERT(map1
->bitmap
&& map2
->bitmap
&&
407 map1
->n_bits
==map2
->n_bits
);
409 end
= map1
->last_word_ptr
;
410 for (; m1
< end
; m1
++, m2
++)
414 if ((*map1
->last_word_ptr
& ~map1
->last_word_mask
) &
415 (*map2
->last_word_ptr
& ~map2
->last_word_mask
))
421 void bitmap_intersect(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
423 my_bitmap_map
*to
= map
->bitmap
, *from
= map2
->bitmap
, *end
;
424 uint len
= no_words_in_map(map
), len2
= no_words_in_map(map2
);
426 DBUG_ASSERT(map
->bitmap
&& map2
->bitmap
);
428 end
= to
+min(len
,len2
);
429 for (; to
< end
; to
++, from
++)
433 map
->bitmap
[len2
- 1] &= ~map2
->last_word_mask
;
438 for (; to
< end
; to
++)
445 Set/clear all bits above a bit.
449 map RETURN The bitmap to change.
450 from_byte The bitmap buffer byte offset to start with.
451 use_bit The bit value (1/0) to use for all upper bits.
454 You can only set/clear full bytes.
455 The function is meant for the situation that you copy a smaller bitmap
456 to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
457 size of a byte). Using 'from_byte' saves multiplication and division
458 by eight during parameter passing.
464 void bitmap_set_above(MY_BITMAP
*map
, uint from_byte
, uint use_bit
)
466 uchar use_byte
= use_bit
? 0xff : 0;
467 uchar
*to
= (uchar
*)map
->bitmap
+ from_byte
;
468 uchar
*end
= (uchar
*)map
->bitmap
+ (map
->n_bits
+7)/8;
470 for (; to
< end
; to
++)
475 void bitmap_subtract(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
477 my_bitmap_map
*to
= map
->bitmap
, *from
= map2
->bitmap
, *end
;
478 DBUG_ASSERT(map
->bitmap
&& map2
->bitmap
&&
479 map
->n_bits
==map2
->n_bits
);
480 end
= map
->last_word_ptr
;
482 for (; to
<= end
; to
++, from
++)
487 void bitmap_union(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
489 my_bitmap_map
*to
= map
->bitmap
, *from
= map2
->bitmap
, *end
;
490 DBUG_ASSERT(map
->bitmap
&& map2
->bitmap
&&
491 map
->n_bits
==map2
->n_bits
);
492 end
= map
->last_word_ptr
;
494 for (; to
<= end
; to
++, from
++)
499 void bitmap_xor(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
501 my_bitmap_map
*to
= map
->bitmap
, *from
= map2
->bitmap
, *end
;
502 DBUG_ASSERT(map
->bitmap
&& map2
->bitmap
&&
503 map
->n_bits
==map2
->n_bits
);
504 end
= map
->last_word_ptr
;
506 for (; to
<= end
; to
++, from
++)
511 void bitmap_invert(MY_BITMAP
*map
)
513 my_bitmap_map
*to
= map
->bitmap
, *end
;
514 DBUG_ASSERT(map
->bitmap
);
515 end
= map
->last_word_ptr
;
517 for (; to
<= end
; to
++)
522 uint
bitmap_bits_set(const MY_BITMAP
*map
)
524 my_bitmap_map
*data_ptr
= map
->bitmap
;
525 my_bitmap_map
*end
= map
->last_word_ptr
;
527 DBUG_ASSERT(map
->bitmap
);
529 for (; data_ptr
< end
; data_ptr
++)
530 res
+= my_count_bits_uint32(*data_ptr
);
532 /*Reset last bits to zero*/
533 res
+= my_count_bits_uint32(*map
->last_word_ptr
& ~map
->last_word_mask
);
538 void bitmap_copy(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
540 my_bitmap_map
*to
= map
->bitmap
, *from
= map2
->bitmap
, *end
;
541 DBUG_ASSERT(map
->bitmap
&& map2
->bitmap
&&
542 map
->n_bits
==map2
->n_bits
);
543 end
= map
->last_word_ptr
;
545 for (; to
<= end
; to
++, from
++)
550 uint
bitmap_get_first_set(const MY_BITMAP
*map
)
553 my_bitmap_map
*data_ptr
, *end
= map
->last_word_ptr
;
555 DBUG_ASSERT(map
->bitmap
);
556 data_ptr
= map
->bitmap
;
558 for (word_pos
=0; data_ptr
< end
; data_ptr
++, word_pos
++)
560 return get_first_set(*data_ptr
, word_pos
);
562 return get_first_set(*map
->last_word_ptr
& ~map
->last_word_mask
, word_pos
);
566 uint
bitmap_get_first(const MY_BITMAP
*map
)
569 my_bitmap_map
*data_ptr
, *end
= map
->last_word_ptr
;
571 DBUG_ASSERT(map
->bitmap
);
572 data_ptr
= map
->bitmap
;
574 for (word_pos
=0; data_ptr
< end
; data_ptr
++, word_pos
++)
575 if (*data_ptr
!= 0xFFFFFFFF)
576 return get_first_not_set(*data_ptr
, word_pos
);
578 return get_first_not_set(*map
->last_word_ptr
| map
->last_word_mask
, word_pos
);
582 uint
bitmap_lock_set_next(MY_BITMAP
*map
)
586 bit_found
= bitmap_set_next(map
);
592 void bitmap_lock_clear_bit(MY_BITMAP
*map
, uint bitmap_bit
)
595 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
596 bitmap_clear_bit(map
, bitmap_bit
);
602 my_bool
bitmap_lock_is_prefix(const MY_BITMAP
*map
, uint prefix_size
)
605 bitmap_lock((MY_BITMAP
*)map
);
606 res
= bitmap_is_prefix(map
, prefix_size
);
607 bitmap_unlock((MY_BITMAP
*)map
);
612 void bitmap_lock_set_all(MY_BITMAP
*map
)
620 void bitmap_lock_clear_all(MY_BITMAP
*map
)
623 bitmap_clear_all(map
);
628 void bitmap_lock_set_prefix(MY_BITMAP
*map
, uint prefix_size
)
631 bitmap_set_prefix(map
, prefix_size
);
636 my_bool
bitmap_lock_is_clear_all(const MY_BITMAP
*map
)
639 bitmap_lock((MY_BITMAP
*)map
);
640 res
= bitmap_is_clear_all(map
);
641 bitmap_unlock((MY_BITMAP
*)map
);
646 my_bool
bitmap_lock_is_set_all(const MY_BITMAP
*map
)
649 bitmap_lock((MY_BITMAP
*)map
);
650 res
= bitmap_is_set_all(map
);
651 bitmap_unlock((MY_BITMAP
*)map
);
656 my_bool
bitmap_lock_is_set(const MY_BITMAP
*map
, uint bitmap_bit
)
659 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
660 bitmap_lock((MY_BITMAP
*)map
);
661 res
= bitmap_is_set(map
, bitmap_bit
);
662 bitmap_unlock((MY_BITMAP
*)map
);
667 my_bool
bitmap_lock_is_subset(const MY_BITMAP
*map1
, const MY_BITMAP
*map2
)
670 bitmap_lock((MY_BITMAP
*)map1
);
671 bitmap_lock((MY_BITMAP
*)map2
);
672 res
= bitmap_is_subset(map1
, map2
);
673 bitmap_unlock((MY_BITMAP
*)map2
);
674 bitmap_unlock((MY_BITMAP
*)map1
);
679 my_bool
bitmap_lock_cmp(const MY_BITMAP
*map1
, const MY_BITMAP
*map2
)
683 DBUG_ASSERT(map1
->bitmap
&& map2
->bitmap
&&
684 map1
->n_bits
==map2
->n_bits
);
685 bitmap_lock((MY_BITMAP
*)map1
);
686 bitmap_lock((MY_BITMAP
*)map2
);
687 res
= bitmap_cmp(map1
, map2
);
688 bitmap_unlock((MY_BITMAP
*)map2
);
689 bitmap_unlock((MY_BITMAP
*)map1
);
694 void bitmap_lock_intersect(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
697 bitmap_lock((MY_BITMAP
*)map2
);
698 bitmap_intersect(map
, map2
);
699 bitmap_unlock((MY_BITMAP
*)map2
);
704 void bitmap_lock_subtract(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
707 bitmap_lock((MY_BITMAP
*)map2
);
708 bitmap_subtract(map
, map2
);
709 bitmap_unlock((MY_BITMAP
*)map2
);
714 void bitmap_lock_union(MY_BITMAP
*map
, const MY_BITMAP
*map2
)
717 bitmap_lock((MY_BITMAP
*)map2
);
718 bitmap_union(map
, map2
);
719 bitmap_unlock((MY_BITMAP
*)map2
);
729 Number of set bits in the bitmap.
731 uint
bitmap_lock_bits_set(const MY_BITMAP
*map
)
734 bitmap_lock((MY_BITMAP
*)map
);
735 DBUG_ASSERT(map
->bitmap
);
736 res
= bitmap_bits_set(map
);
737 bitmap_unlock((MY_BITMAP
*)map
);
747 Number of first unset bit in the bitmap or MY_BIT_NONE if all bits are set.
749 uint
bitmap_lock_get_first(const MY_BITMAP
*map
)
752 bitmap_lock((MY_BITMAP
*)map
);
753 res
= bitmap_get_first(map
);
754 bitmap_unlock((MY_BITMAP
*)map
);
759 uint
bitmap_lock_get_first_set(const MY_BITMAP
*map
)
762 bitmap_lock((MY_BITMAP
*)map
);
763 res
= bitmap_get_first_set(map
);
764 bitmap_unlock((MY_BITMAP
*)map
);
769 void bitmap_lock_set_bit(MY_BITMAP
*map
, uint bitmap_bit
)
771 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
773 bitmap_set_bit(map
, bitmap_bit
);
778 void bitmap_lock_flip_bit(MY_BITMAP
*map
, uint bitmap_bit
)
780 DBUG_ASSERT(map
->bitmap
&& bitmap_bit
< map
->n_bits
);
782 bitmap_flip_bit(map
, bitmap_bit
);