MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_bitmap.c
1 /*
2  Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
3 
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.
7 
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.
12 
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
16 
17 /*
18  Handling of uchar arrays as large bitmaps.
19 
20  API limitations (or, rather asserted safety assumptions,
21  to encourage correct programming)
22 
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_*
26 
27  TODO:
28  Make assembler THREAD safe versions of these using test-and-set instructions
29 
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
33  Kindahl.
34 */
35 
36 #include "mysys_priv.h"
37 #include <my_bitmap.h>
38 #include <m_string.h>
39 #include <my_bit.h>
40 
41 void create_last_word_mask(MY_BITMAP *map)
42 {
43  /* Get the number of used bits (1..8) in the last byte */
44  unsigned int const used= 1U + ((map->n_bits-1U) & 0x7U);
45 
46  /*
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.
49  */
50  unsigned char const mask= (~((1 << used) - 1)) & 255;
51 
52  /*
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.
57  */
58  unsigned char *ptr= (unsigned char*)&map->last_word_mask;
59 
60  map->last_word_ptr= map->bitmap + no_words_in_map(map)-1;
61  switch (no_bytes_in_map(map) & 3) {
62  case 1:
63  map->last_word_mask= ~0U;
64  ptr[0]= mask;
65  return;
66  case 2:
67  map->last_word_mask= ~0U;
68  ptr[0]= 0;
69  ptr[1]= mask;
70  return;
71  case 3:
72  map->last_word_mask= 0U;
73  ptr[2]= mask;
74  ptr[3]= 0xFFU;
75  return;
76  case 0:
77  map->last_word_mask= 0U;
78  ptr[3]= mask;
79  return;
80  }
81 }
82 
83 
84 static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused)))
85 {
86  if (map->mutex)
87  mysql_mutex_lock(map->mutex);
88 }
89 
90 
91 static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused)))
92 {
93  if (map->mutex)
94  mysql_mutex_unlock(map->mutex);
95 }
96 
97 
98 static inline uint get_first_set(uint32 value, uint word_pos)
99 {
100  uchar *byte_ptr= (uchar*)&value;
101  uchar byte_value;
102  uint byte_pos, bit_pos;
103 
104  for (byte_pos=0; byte_pos < 4; byte_pos++, byte_ptr++)
105  {
106  byte_value= *byte_ptr;
107  if (byte_value)
108  {
109  for (bit_pos=0; ; bit_pos++)
110  if (byte_value & (1 << bit_pos))
111  return (word_pos*32) + (byte_pos*8) + bit_pos;
112  }
113  }
114  return MY_BIT_NONE;
115 }
116 
117 
118 static inline uint get_first_not_set(uint32 value, uint word_pos)
119 {
120  uchar *byte_ptr= (uchar*)&value;
121  uchar byte_value;
122  uint byte_pos, bit_pos;
123 
124  for (byte_pos=0; byte_pos < 4; byte_pos++, byte_ptr++)
125  {
126  byte_value= *byte_ptr;
127  if (byte_value != 0xFF)
128  {
129  for (bit_pos=0; ; bit_pos++)
130  if (!(byte_value & (1 << bit_pos)))
131  return (word_pos*32) + (byte_pos*8) + bit_pos;
132  }
133  }
134  return MY_BIT_NONE;
135 }
136 
137 
138 my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits,
139  my_bool thread_safe __attribute__((unused)))
140 {
141  DBUG_ENTER("bitmap_init");
142  if (!buf)
143  {
144  uint size_in_bytes= bitmap_buffer_size(n_bits);
145  uint extra= 0;
146 
147  if (thread_safe)
148  {
149  size_in_bytes= ALIGN_SIZE(size_in_bytes);
150  extra= sizeof(mysql_mutex_t);
151  }
152  map->mutex= 0;
153 
154  if (!(buf= (my_bitmap_map*) my_malloc(size_in_bytes+extra, MYF(MY_WME))))
155  DBUG_RETURN(1);
156 
157  if (thread_safe)
158  {
159  map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes);
160  mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST);
161  }
162 
163  }
164 
165  else
166  {
167  DBUG_ASSERT(thread_safe == 0);
168  map->mutex= NULL;
169  }
170 
171 
172  map->bitmap= buf;
173  map->n_bits= n_bits;
174  create_last_word_mask(map);
175  bitmap_clear_all(map);
176  DBUG_RETURN(0);
177 }
178 
179 
180 void bitmap_free(MY_BITMAP *map)
181 {
182  DBUG_ENTER("bitmap_free");
183  if (map->bitmap)
184  {
185  if (map->mutex)
186  mysql_mutex_destroy(map->mutex);
187 
188  my_free(map->bitmap);
189  map->bitmap=0;
190  }
191  DBUG_VOID_RETURN;
192 }
193 
194 
195 /*
196  test if bit already set and set it if it was not (thread unsafe method)
197 
198  SYNOPSIS
199  bitmap_fast_test_and_set()
200  MAP bit map struct
201  BIT bit number
202 
203  RETURN
204  0 bit was not set
205  !=0 bit was set
206 */
207 
208 my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
209 {
210  uchar *value= ((uchar*) map->bitmap) + (bitmap_bit / 8);
211  uchar bit= 1 << ((bitmap_bit) & 7);
212  uchar res= (*value) & bit;
213  *value|= bit;
214  return res;
215 }
216 
217 
218 /*
219  test if bit already set and set it if it was not (thread safe method)
220 
221  SYNOPSIS
222  bitmap_fast_test_and_set()
223  map bit map struct
224  bitmap_bit bit number
225 
226  RETURN
227  0 bit was not set
228  !=0 bit was set
229 */
230 
231 my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
232 {
233  my_bool res;
234  DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
235  bitmap_lock(map);
236  res= bitmap_fast_test_and_set(map, bitmap_bit);
237  bitmap_unlock(map);
238  return res;
239 }
240 
241 /*
242  test if bit already set and clear it if it was set(thread unsafe method)
243 
244  SYNOPSIS
245  bitmap_fast_test_and_set()
246  MAP bit map struct
247  BIT bit number
248 
249  RETURN
250  0 bit was not set
251  !=0 bit was set
252 */
253 
254 my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
255 {
256  uchar *byte= (uchar*) map->bitmap + (bitmap_bit / 8);
257  uchar bit= 1 << ((bitmap_bit) & 7);
258  uchar res= (*byte) & bit;
259  *byte&= ~bit;
260  return res;
261 }
262 
263 
264 my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
265 {
266  my_bool res;
267  DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
268  bitmap_lock(map);
269  res= bitmap_fast_test_and_clear(map, bitmap_bit);
270  bitmap_unlock(map);
271  return res;
272 }
273 
274 
275 uint bitmap_set_next(MY_BITMAP *map)
276 {
277  uint bit_found;
278  DBUG_ASSERT(map->bitmap);
279  if ((bit_found= bitmap_get_first(map)) != MY_BIT_NONE)
280  bitmap_set_bit(map, bit_found);
281  return bit_found;
282 }
283 
284 
285 void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
286 {
287  uint prefix_bytes, prefix_bits, d;
288  uchar *m= (uchar *)map->bitmap;
289 
290  DBUG_ASSERT(map->bitmap &&
291  (prefix_size <= map->n_bits || prefix_size == (uint) ~0));
292  set_if_smaller(prefix_size, map->n_bits);
293  if ((prefix_bytes= prefix_size / 8))
294  memset(m, 0xff, prefix_bytes);
295  m+= prefix_bytes;
296  if ((prefix_bits= prefix_size & 7))
297  *(m++)= (1 << prefix_bits)-1;
298  if ((d= no_bytes_in_map(map)-prefix_bytes))
299  memset(m, 0, d);
300 }
301 
302 
303 my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
304 {
305  uint prefix_bits= prefix_size % 32;
306  my_bitmap_map *word_ptr= map->bitmap, last_word;
307  my_bitmap_map *end_prefix= word_ptr + prefix_size / 32;
308  DBUG_ASSERT(word_ptr && prefix_size <= map->n_bits);
309 
310  /* 1: Words that should be filled with 1 */
311  for (; word_ptr < end_prefix; word_ptr++)
312  if (*word_ptr != 0xFFFFFFFF)
313  return FALSE;
314 
315  last_word= *map->last_word_ptr & ~map->last_word_mask;
316 
317  /* 2: Word which contains the end of the prefix (if any) */
318  if (prefix_bits)
319  {
320  if (word_ptr == map->last_word_ptr)
321  return uint4korr((uchar*)&last_word) == (uint32)((1 << prefix_bits) - 1);
322  else if (uint4korr((uchar*)word_ptr) != (uint32)((1 << prefix_bits) - 1))
323  return FALSE;
324  word_ptr++;
325  }
326 
327  /* 3: Words that should be filled with 0 */
328  for (; word_ptr < map->last_word_ptr; word_ptr++)
329  if (*word_ptr != 0)
330  return FALSE;
331 
332  /*
333  We can end up here in two situations:
334  1) We went through the whole bitmap in step 1. This will happen if the
335  whole bitmap is filled with 1 and prefix_size is a multiple of 32
336  (i.e. the prefix does not end in the middle of a word).
337  In this case word_ptr will be larger than map->last_word_ptr.
338  2) We have gone through steps 1-3 and just need to check that also
339  the last word is 0.
340  */
341  return word_ptr > map->last_word_ptr || last_word == 0;
342 }
343 
344 
345 my_bool bitmap_is_set_all(const MY_BITMAP *map)
346 {
347  my_bitmap_map *data_ptr= map->bitmap;
348  my_bitmap_map *end= map->last_word_ptr;
349 
350  for (; data_ptr < end; data_ptr++)
351  if (*data_ptr != 0xFFFFFFFF)
352  return FALSE;
353  if ((*map->last_word_ptr | map->last_word_mask) != 0xFFFFFFFF)
354  return FALSE;
355  return TRUE;
356 }
357 
358 
359 my_bool bitmap_is_clear_all(const MY_BITMAP *map)
360 {
361  my_bitmap_map *data_ptr= map->bitmap;
362  my_bitmap_map *end= map->last_word_ptr;
363 
364  for (; data_ptr < end; data_ptr++)
365  if (*data_ptr)
366  return FALSE;
367  if (*map->last_word_ptr & ~map->last_word_mask)
368  return FALSE;
369  return TRUE;
370 }
371 
372 /* Return TRUE if map1 is a subset of map2 */
373 
374 my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
375 {
376  my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
377 
378  DBUG_ASSERT(map1->bitmap && map2->bitmap &&
379  map1->n_bits==map2->n_bits);
380 
381  end= map1->last_word_ptr;
382  for (; m1 < end; m1++, m2++)
383  if (*m1 & ~(*m2))
384  return FALSE;
385 
386  if ((*map1->last_word_ptr & ~map1->last_word_mask) &
387  ~(*map2->last_word_ptr & ~map2->last_word_mask))
388  return FALSE;
389  return TRUE;
390 }
391 
392 /* True if bitmaps has any common bits */
393 
394 my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
395 {
396  my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end;
397 
398  DBUG_ASSERT(map1->bitmap && map2->bitmap &&
399  map1->n_bits==map2->n_bits);
400 
401  end= map1->last_word_ptr;
402  for (; m1 < end; m1++, m2++)
403  if (*m1 & *m2)
404  return TRUE;
405 
406  if ((*map1->last_word_ptr & ~map1->last_word_mask) &
407  (*map2->last_word_ptr & ~map2->last_word_mask))
408  return TRUE;
409  return FALSE;
410 }
411 
412 
413 void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
414 {
415  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
416  uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
417 
418  DBUG_ASSERT(map->bitmap && map2->bitmap);
419 
420  end= to + MY_MIN(len, len2);
421  for (; to < end; to++, from++)
422  *to &= *from;
423 
424  if (len >= len2)
425  map->bitmap[len2 - 1] &= ~map2->last_word_mask;
426 
427  if (len2 < len)
428  {
429  end+=len-len2;
430  for (; to < end; to++)
431  *to= 0;
432  }
433 }
434 
435 
436 /*
437  Set/clear all bits above a bit.
438 
439  SYNOPSIS
440  bitmap_set_above()
441  map RETURN The bitmap to change.
442  from_byte The bitmap buffer byte offset to start with.
443  use_bit The bit value (1/0) to use for all upper bits.
444 
445  NOTE
446  You can only set/clear full bytes.
447  The function is meant for the situation that you copy a smaller bitmap
448  to a bigger bitmap. Bitmap lengths are always multiple of eigth (the
449  size of a byte). Using 'from_byte' saves multiplication and division
450  by eight during parameter passing.
451 
452  RETURN
453  void
454 */
455 
456 void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit)
457 {
458  uchar use_byte= use_bit ? 0xff : 0;
459  uchar *to= (uchar *)map->bitmap + from_byte;
460  uchar *end= (uchar *)map->bitmap + (map->n_bits+7)/8;
461 
462  for (; to < end; to++)
463  *to= use_byte;
464 }
465 
466 
467 void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
468 {
469  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
470  DBUG_ASSERT(map->bitmap && map2->bitmap &&
471  map->n_bits==map2->n_bits);
472  end= map->last_word_ptr;
473 
474  for (; to <= end; to++, from++)
475  *to &= ~(*from);
476 }
477 
478 
479 void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
480 {
481  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
482  DBUG_ASSERT(map->bitmap && map2->bitmap &&
483  map->n_bits==map2->n_bits);
484  end= map->last_word_ptr;
485 
486  for (; to <= end; to++, from++)
487  *to |= *from;
488 }
489 
490 
491 void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
492 {
493  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
494  DBUG_ASSERT(map->bitmap && map2->bitmap &&
495  map->n_bits==map2->n_bits);
496  end= map->last_word_ptr;
497 
498  for (; to <= end; to++, from++)
499  *to ^= *from;
500 }
501 
502 
503 void bitmap_invert(MY_BITMAP *map)
504 {
505  my_bitmap_map *to= map->bitmap, *end;
506  DBUG_ASSERT(map->bitmap);
507  end= map->last_word_ptr;
508 
509  for (; to <= end; to++)
510  *to ^= 0xFFFFFFFF;
511 }
512 
513 
514 uint bitmap_bits_set(const MY_BITMAP *map)
515 {
516  my_bitmap_map *data_ptr= map->bitmap;
517  my_bitmap_map *end= map->last_word_ptr;
518  uint res= 0;
519  DBUG_ASSERT(map->bitmap);
520 
521  for (; data_ptr < end; data_ptr++)
522  res+= my_count_bits_uint32(*data_ptr);
523 
524  /*Reset last bits to zero*/
525  res+= my_count_bits_uint32(*map->last_word_ptr & ~map->last_word_mask);
526  return res;
527 }
528 
529 
530 void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
531 {
532  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
533  DBUG_ASSERT(map->bitmap && map2->bitmap &&
534  map->n_bits==map2->n_bits);
535  end= map->last_word_ptr;
536 
537  for (; to <= end; to++, from++)
538  *to = *from;
539 }
540 
541 
542 uint bitmap_get_first_set(const MY_BITMAP *map)
543 {
544  uint word_pos;
545  my_bitmap_map *data_ptr, *end= map->last_word_ptr;
546 
547  DBUG_ASSERT(map->bitmap);
548  data_ptr= map->bitmap;
549 
550  for (word_pos=0; data_ptr < end; data_ptr++, word_pos++)
551  if (*data_ptr)
552  return get_first_set(*data_ptr, word_pos);
553 
554  return get_first_set(*map->last_word_ptr & ~map->last_word_mask, word_pos);
555 }
556 
557 
567 uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit)
568 {
569  uint word_pos, byte_to_mask, i;
570  my_bitmap_map first_word;
571  unsigned char *ptr= (unsigned char*) &first_word;
572  my_bitmap_map *data_ptr, *end= map->last_word_ptr;
573 
574  DBUG_ASSERT(map->bitmap);
575 
576  /* Look for the next bit */
577  bitmap_bit++;
578  if (bitmap_bit >= map->n_bits)
579  return MY_BIT_NONE;
580  word_pos= bitmap_bit / 32;
581  data_ptr= map->bitmap + word_pos;
582  first_word= *data_ptr;
583 
584  /* Mask out previous bits */
585  byte_to_mask= (bitmap_bit % 32) / 8;
586  for (i= 0; i < byte_to_mask; i++)
587  ptr[i]= 0;
588  ptr[byte_to_mask]&= 0xFFU << (bitmap_bit & 7);
589 
590  if (data_ptr == end)
591  return get_first_set(first_word & ~map->last_word_mask, word_pos);
592 
593  if (first_word)
594  return get_first_set(first_word, word_pos);
595 
596  for (data_ptr++, word_pos++; data_ptr < end; data_ptr++, word_pos++)
597  if (*data_ptr)
598  return get_first_set(*data_ptr, word_pos);
599 
600  return get_first_set(*end & ~map->last_word_mask, word_pos);
601 }
602 
603 
604 uint bitmap_get_first(const MY_BITMAP *map)
605 {
606  uint word_pos;
607  my_bitmap_map *data_ptr, *end= map->last_word_ptr;
608 
609  DBUG_ASSERT(map->bitmap);
610  data_ptr= map->bitmap;
611 
612  for (word_pos=0; data_ptr < end; data_ptr++, word_pos++)
613  if (*data_ptr != 0xFFFFFFFF)
614  return get_first_not_set(*data_ptr, word_pos);
615 
616  return get_first_not_set(*map->last_word_ptr | map->last_word_mask, word_pos);
617 }
618 
619 
620 uint bitmap_lock_set_next(MY_BITMAP *map)
621 {
622  uint bit_found;
623  bitmap_lock(map);
624  bit_found= bitmap_set_next(map);
625  bitmap_unlock(map);
626  return bit_found;
627 }
628 
629 
630 void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit)
631 {
632  bitmap_lock(map);
633  DBUG_ASSERT(map->bitmap && bitmap_bit < map->n_bits);
634  bitmap_clear_bit(map, bitmap_bit);
635  bitmap_unlock(map);
636 }