mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			709 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			709 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
   Copyright (c) 2001, 2011, Oracle and/or its affiliates.
 | 
						|
   Copyright (C) 2009- 2011 Monty Program 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; version 2 of the License.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335
 | 
						|
   USA
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
  Handling of my_bitmap_map (ulonglong) arrays as large bitmaps.
 | 
						|
 | 
						|
  API limitations (or, rather asserted safety assumptions,
 | 
						|
  to encourage correct programming)
 | 
						|
 | 
						|
    * the internal storage is a set of 64 bit words
 | 
						|
    * the number of bits specified in creation can be any number > 0
 | 
						|
 | 
						|
  Implementation notes:
 | 
						|
    * MY_BITMAP includes a pointer, last_word_ptr, to the last word.
 | 
						|
     The implication is that if one copies bitmaps to another memory
 | 
						|
     location, one has to call create_last_bit_mask() on the bitmap to
 | 
						|
     fix the internal pointer.
 | 
						|
   * The not used part of a the last word should always be 0.
 | 
						|
     This avoids special handling of the last bitmap in several cases.
 | 
						|
     This is checked for most calls to bitmap functions.
 | 
						|
 | 
						|
  TODO:
 | 
						|
  Make assembler thread safe versions of these using test-and-set instructions
 | 
						|
 | 
						|
  Original version created by Sergei Golubchik 2001 - 2004.
 | 
						|
  New version written and test program added and some changes to the interface
 | 
						|
  was made by Mikael Ronstrom 2005, with assistance of Tomas Ulin and Mats
 | 
						|
  Kindahl.
 | 
						|
  Updated to 64 bits and use my_find_first_bit() to speed up
 | 
						|
  bitmap_get_next_set() by Monty in 2024
 | 
						|
*/
 | 
						|
 | 
						|
#include "mysys_priv.h"
 | 
						|
#include <my_bitmap.h>
 | 
						|
#include <m_string.h>
 | 
						|
#include <my_bit.h>
 | 
						|
#include <my_byteorder.h>
 | 
						|
 | 
						|
 | 
						|
/* Defines to check bitmaps */
 | 
						|
 | 
						|
#define DBUG_ASSERT_BITMAP(M) \
 | 
						|
  DBUG_ASSERT((M)->bitmap); \
 | 
						|
  DBUG_ASSERT((M)->n_bits > 0); \
 | 
						|
  DBUG_ASSERT((M)->last_word_ptr == (M)->bitmap + no_words_in_map(M)-1); \
 | 
						|
  DBUG_ASSERT((*(M)->last_word_ptr & (M)->last_bit_mask) == 0);
 | 
						|
 | 
						|
#define DBUG_ASSERT_BITMAP_AND_BIT(M,B) \
 | 
						|
  DBUG_ASSERT_BITMAP(M); \
 | 
						|
  DBUG_ASSERT((B) < (M)->n_bits);
 | 
						|
 | 
						|
#define DBUG_ASSERT_DIFFERENT_BITMAPS(M,N) \
 | 
						|
  DBUG_ASSERT_BITMAP(M); \
 | 
						|
  DBUG_ASSERT_BITMAP(N);
 | 
						|
 | 
						|
#define DBUG_ASSERT_IDENTICAL_BITMAPS(M,N) \
 | 
						|
  DBUG_ASSERT_BITMAP(M); \
 | 
						|
  DBUG_ASSERT_BITMAP(N); \
 | 
						|
  DBUG_ASSERT((M)->n_bits == (N)->n_bits);
 | 
						|
 | 
						|
/*
 | 
						|
  Create a mask for the usable bits on the LAST my_bitmap_map position for
 | 
						|
  a bitmap with 'bits' number of bits.
 | 
						|
 | 
						|
  The lowest 'bits' bits are set to zero and the rest bits are set to 1.
 | 
						|
  For (bits & 63) == 0 , 0 is returned as in this case all bits in the
 | 
						|
  my_bitmap_position are significant. (This example assumes the
 | 
						|
  storage is ulonglong).
 | 
						|
 | 
						|
  For 'bits & 63' it will return values from the series
 | 
						|
  0, 0xfffffffffffffffe,.... 0x8000000000000000
 | 
						|
*/
 | 
						|
 | 
						|
static inline my_bitmap_map last_bit_mask(uint bits)
 | 
						|
{
 | 
						|
  uint bits_in_last_map= (bits & (my_bitmap_map_bits-1));
 | 
						|
  return bits_in_last_map ? ~((1ULL << bits_in_last_map)-1) : 0ULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Get a mask of the bits that are to be considered as 'on' at location
 | 
						|
  starting with 'bits'.
 | 
						|
  This function has _inv in its name as its usage is the inverse compared
 | 
						|
  to last_bit_mask().
 | 
						|
 | 
						|
  For (bits & 63) it will return values from the series
 | 
						|
  0xffffffffffffffff, 0xfffffffffffffffe,.... 0x8000000000000000
 | 
						|
*/
 | 
						|
 | 
						|
static inline my_bitmap_map first_bit_mask_inv(uint bits)
 | 
						|
{
 | 
						|
  uint bits_in_last_map= (bits & (my_bitmap_map_bits-1));
 | 
						|
  return ~((1ULL << bits_in_last_map)-1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Update the bitmap's last_word_ptr and last_bit_mask
 | 
						|
  Also ensure that the last world is all zero to make it
 | 
						|
  easy to find the next set bit.
 | 
						|
 | 
						|
  Note that if n_bits is 0, then last_word_ptr will point to
 | 
						|
  bitmap (safely). The bitmap will not be usable for almost any operation.
 | 
						|
*/
 | 
						|
 | 
						|
void create_last_bit_mask(MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map mask= last_bit_mask(map->n_bits);
 | 
						|
  map->last_bit_mask= mask;
 | 
						|
  map->last_word_ptr= map->bitmap + MY_MAX(no_words_in_map(map),1) -1;
 | 
						|
  if (map->n_bits > 0)
 | 
						|
  {
 | 
						|
    *map->last_word_ptr&= ~mask;           /* Set not used bits to 0 */
 | 
						|
    DBUG_ASSERT_BITMAP(map);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Initialize a bitmap object. All bits will be set to zero
 | 
						|
*/
 | 
						|
 | 
						|
my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits)
 | 
						|
{
 | 
						|
  DBUG_ENTER("my_bitmap_init");
 | 
						|
 | 
						|
  if (!buf)
 | 
						|
  {
 | 
						|
    uint size_in_bytes= bitmap_buffer_size(n_bits);
 | 
						|
    if (!(buf= (my_bitmap_map*) my_malloc(key_memory_MY_BITMAP_bitmap,
 | 
						|
                                          size_in_bytes, MYF(MY_WME))))
 | 
						|
    {
 | 
						|
      map->bitmap= 0;
 | 
						|
      DBUG_RETURN(1);
 | 
						|
    }
 | 
						|
    map->bitmap_allocated= 1;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    map->bitmap_allocated= 0;
 | 
						|
 | 
						|
  map->bitmap= buf;
 | 
						|
  map->n_bits= n_bits;
 | 
						|
  create_last_bit_mask(map);
 | 
						|
  bitmap_clear_all(map);
 | 
						|
  DBUG_RETURN(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void my_bitmap_free(MY_BITMAP *map)
 | 
						|
{
 | 
						|
  DBUG_ENTER("my_bitmap_free");
 | 
						|
  if (map->bitmap)
 | 
						|
  {
 | 
						|
    if (map->bitmap_allocated)
 | 
						|
      my_free(map->bitmap);
 | 
						|
    map->bitmap=0;
 | 
						|
  }
 | 
						|
  DBUG_VOID_RETURN;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  test if bit already set and set it if it was not (thread unsafe method)
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    bitmap_fast_test_and_set()
 | 
						|
    MAP   bit map struct
 | 
						|
    BIT   bit number
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0    bit was not set
 | 
						|
    !=0  bit was set
 | 
						|
*/
 | 
						|
 | 
						|
my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit)
 | 
						|
{
 | 
						|
  my_bitmap_map *value, bit, res;
 | 
						|
  DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
 | 
						|
 | 
						|
  value= map->bitmap + (bitmap_bit/my_bitmap_map_bits);
 | 
						|
  bit= 1ULL << (bitmap_bit & (my_bitmap_map_bits-1));
 | 
						|
  res= *value & bit;
 | 
						|
  *value|= bit;
 | 
						|
  return MY_TEST(res);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  test if bit already set and set it if it was not (thread safe method)
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    bitmap_fast_test_and_set()
 | 
						|
    map          bit map struct
 | 
						|
    bitmap_bit   bit number
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0    bit was not set
 | 
						|
    !=0  bit was set
 | 
						|
*/
 | 
						|
 | 
						|
my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit)
 | 
						|
{
 | 
						|
  DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
 | 
						|
  return bitmap_fast_test_and_set(map, bitmap_bit);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  test if bit already set and clear it if it was set(thread unsafe method)
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    bitmap_fast_test_and_set()
 | 
						|
    MAP   bit map struct
 | 
						|
    BIT   bit number
 | 
						|
 | 
						|
  RETURN
 | 
						|
    0    bit was not set
 | 
						|
    !=0  bit was set
 | 
						|
*/
 | 
						|
 | 
						|
my_bool bitmap_fast_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
 | 
						|
{
 | 
						|
  my_bitmap_map *value, bit, res;
 | 
						|
  DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
 | 
						|
 | 
						|
  value= map->bitmap + (bitmap_bit/my_bitmap_map_bits);
 | 
						|
  bit= 1ULL << (bitmap_bit & (my_bitmap_map_bits-1));
 | 
						|
  res= *value & bit;
 | 
						|
  *value&= ~bit;
 | 
						|
  return MY_TEST(res);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my_bool bitmap_test_and_clear(MY_BITMAP *map, uint bitmap_bit)
 | 
						|
{
 | 
						|
  DBUG_ASSERT_BITMAP_AND_BIT(map, bitmap_bit);
 | 
						|
  return bitmap_fast_test_and_clear(map, bitmap_bit);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
uint bitmap_set_next(MY_BITMAP *map)
 | 
						|
{
 | 
						|
  uint bit_found;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
  if ((bit_found= bitmap_get_first_clear(map)) != MY_BIT_NONE)
 | 
						|
    bitmap_set_bit(map, bit_found);
 | 
						|
  return bit_found;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Set the specified number of bits in the bitmap buffer.
 | 
						|
 | 
						|
  @param map         [IN]       Bitmap
 | 
						|
  @param prefix_size [IN]       Number of bits to be set or (uint) ~0 for all
 | 
						|
*/
 | 
						|
 | 
						|
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
 | 
						|
{
 | 
						|
  uint prefix, prefix_bits;
 | 
						|
  my_bitmap_map *value= map->bitmap;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
  DBUG_ASSERT(prefix_size <= map->n_bits || prefix_size == (uint) ~0);
 | 
						|
  set_if_smaller(prefix_size, map->n_bits);
 | 
						|
 | 
						|
  if ((prefix= prefix_size / my_bitmap_map_bits))
 | 
						|
  {
 | 
						|
    my_bitmap_map *end= value+prefix;
 | 
						|
    do
 | 
						|
    {
 | 
						|
      *value++= ~(my_bitmap_map) 0;
 | 
						|
    } while (value < end);
 | 
						|
  }
 | 
						|
  if ((prefix_bits= prefix_size & (my_bitmap_map_bits-1)))
 | 
						|
    *value++= (1ULL << prefix_bits)-1;
 | 
						|
  while (value <= map->last_word_ptr)
 | 
						|
    *value++= 0;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
   Check if bitmap is a bitmap of prefix bits set in the beginning
 | 
						|
 | 
						|
   @param map          bitmap
 | 
						|
   @param prefix_size  number of bits that should be set. 0 is allowed.
 | 
						|
 | 
						|
   @return 1           Yes, prefix bits where set or prefix_size == 0.
 | 
						|
   @return 0           No
 | 
						|
*/
 | 
						|
 | 
						|
my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size)
 | 
						|
{
 | 
						|
  my_bitmap_map *value= map->bitmap;
 | 
						|
  my_bitmap_map *end=  value+ (prefix_size/my_bitmap_map_bits);
 | 
						|
  uint prefix_bits;
 | 
						|
 | 
						|
  /* Empty prefix is always true */
 | 
						|
  if (!prefix_size)
 | 
						|
    return 1;
 | 
						|
 | 
						|
  DBUG_ASSERT_BITMAP_AND_BIT(map, prefix_size-1);
 | 
						|
 | 
						|
  while (value < end)
 | 
						|
    if (*value++ != ~(my_bitmap_map) 0)
 | 
						|
      return 0;
 | 
						|
 | 
						|
  if ((prefix_bits= prefix_size & (my_bitmap_map_bits-1)))
 | 
						|
  {
 | 
						|
    if (*value++ != (1ULL << prefix_bits)-1)
 | 
						|
      return 0;
 | 
						|
  }
 | 
						|
  end= map->last_word_ptr;
 | 
						|
  while (value <= end)
 | 
						|
    if (*value++ != 0)
 | 
						|
      return 0;
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my_bool bitmap_is_set_all(const MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *data_ptr= map->bitmap;
 | 
						|
  my_bitmap_map *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  for (; data_ptr < end; data_ptr++)
 | 
						|
    if (*data_ptr != ~(my_bitmap_map)0)
 | 
						|
      return FALSE;
 | 
						|
  return (*data_ptr | map->last_bit_mask) == ~(my_bitmap_map)0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
my_bool bitmap_is_clear_all(const MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *data_ptr= map->bitmap;
 | 
						|
  my_bitmap_map *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  for (; data_ptr <= end; data_ptr++)
 | 
						|
    if (*data_ptr)
 | 
						|
      return FALSE;
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Return TRUE if map1 is a subset of map2 */
 | 
						|
 | 
						|
my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
 | 
						|
 | 
						|
  while (m1 <= end)
 | 
						|
  {
 | 
						|
    if ((*m1++) & ~(*m2++))
 | 
						|
      return 0;
 | 
						|
  }
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* True if bitmaps has any common bits */
 | 
						|
 | 
						|
my_bool bitmap_is_overlapping(const MY_BITMAP *map1, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
 | 
						|
 | 
						|
  while (m1 <= end)
 | 
						|
  {
 | 
						|
    if ((*m1++) & (*m2++))
 | 
						|
      return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Create intersection of two bitmaps
 | 
						|
 | 
						|
  @param map    map1. Result is stored here
 | 
						|
  @param map2   map2
 | 
						|
*/
 | 
						|
 | 
						|
void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
 | 
						|
  uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
 | 
						|
  DBUG_ASSERT_DIFFERENT_BITMAPS(map,map2);
 | 
						|
 | 
						|
  end= to+MY_MIN(len,len2);
 | 
						|
  while (to < end)
 | 
						|
    *to++ &= *from++;
 | 
						|
 | 
						|
  if (len2 <= len)
 | 
						|
  {
 | 
						|
    to[-1]&= ~map2->last_bit_mask; /* Clear last not relevant bits */
 | 
						|
    end+= len-len2;
 | 
						|
    while (to < end)
 | 
						|
      *to++= 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Check if there is some bit index between start_bit and end_bit, such that
 | 
						|
  this is at least on bit that set for all bitmaps in bitmap_list.
 | 
						|
 | 
						|
  SYNOPSIS
 | 
						|
    bitmap_exists_intersection()
 | 
						|
    bitmpap_array [in]  a set of MY_BITMAPs
 | 
						|
    bitmap_count  [in]  number of elements in bitmap_array
 | 
						|
    start_bit     [in]  beginning (inclusive) of the range of bits to search
 | 
						|
    end_bit       [in]  end (inclusive) of the range of bits to search, must be
 | 
						|
                        no bigger than the bits of the shortest bitmap.
 | 
						|
 | 
						|
  RETURN
 | 
						|
    TRUE  if an intersecion exists
 | 
						|
    FALSE no intersection
 | 
						|
*/
 | 
						|
 | 
						|
my_bool bitmap_exists_intersection(MY_BITMAP **bitmap_array,
 | 
						|
                                   uint bitmap_count,
 | 
						|
                                   uint start_bit, uint end_bit)
 | 
						|
{
 | 
						|
  uint i, j, start_idx, end_idx;
 | 
						|
  my_bitmap_map cur_res, first_map;
 | 
						|
 | 
						|
  DBUG_ASSERT(bitmap_count);
 | 
						|
  DBUG_ASSERT(end_bit >= start_bit);
 | 
						|
  for (j= 0; j < bitmap_count; j++)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT_BITMAP_AND_BIT(bitmap_array[j], end_bit);
 | 
						|
  }
 | 
						|
 | 
						|
  start_idx= start_bit/8/sizeof(my_bitmap_map);
 | 
						|
  end_idx= end_bit/8/sizeof(my_bitmap_map);
 | 
						|
 | 
						|
  first_map= first_bit_mask_inv(start_bit);
 | 
						|
  cur_res= first_map;
 | 
						|
  for (i= start_idx; i < end_idx; i++)
 | 
						|
  {
 | 
						|
    for (j= 0; cur_res && j < bitmap_count; j++)
 | 
						|
      cur_res &= bitmap_array[j]->bitmap[i];
 | 
						|
    if (cur_res)
 | 
						|
      return TRUE;
 | 
						|
    cur_res= ~(my_bitmap_map) 0;
 | 
						|
  }
 | 
						|
  cur_res= ~last_bit_mask(end_bit+1);
 | 
						|
  if (start_idx == end_idx)
 | 
						|
    cur_res&= first_map;
 | 
						|
  for (j= 0; cur_res && j < bitmap_count; j++)
 | 
						|
    cur_res &= bitmap_array[j]->bitmap[end_idx];
 | 
						|
  return cur_res != 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* True if union of bitmaps have all bits set */
 | 
						|
 | 
						|
my_bool bitmap_union_is_set_all(const MY_BITMAP *map1, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *m1= map1->bitmap, *m2= map2->bitmap, *end= map1->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map1,map2);
 | 
						|
 | 
						|
  while ( m1 < end)
 | 
						|
    if ((*m1++ | *m2++) != ~(my_bitmap_map)0)
 | 
						|
      return FALSE;
 | 
						|
  /* here both maps have the same number of bits - see assert above */
 | 
						|
  return ((*m1 | *m2 | map1->last_bit_mask) != ~(my_bitmap_map)0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
 | 
						|
 | 
						|
  while (to <= end)
 | 
						|
    *to++ &= ~(*from++);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
 | 
						|
 | 
						|
  while (to <= end)
 | 
						|
    *to++ |= *from++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_IDENTICAL_BITMAPS(map,map2);
 | 
						|
 | 
						|
  while (to <= end)
 | 
						|
    *to++ ^= *from++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void bitmap_invert(MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  while (to < end)
 | 
						|
    *to++ ^= ~(my_bitmap_map)0;
 | 
						|
 | 
						|
  *to ^= (~(my_bitmap_map)0 & ~map->last_bit_mask);
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
uint bitmap_bits_set(const MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *data_ptr= map->bitmap;
 | 
						|
  my_bitmap_map *end= map->last_word_ptr;
 | 
						|
  uint res= 0;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  for (; data_ptr <= end; data_ptr++)
 | 
						|
    res+= my_count_bits(*data_ptr);
 | 
						|
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Copy bitmaps (if source bigger tail is left unchanged)
 | 
						|
 | 
						|
  @param map    to-bitmap
 | 
						|
  @param map2   from-bitmap
 | 
						|
 | 
						|
  @notes
 | 
						|
  Code will work even of the bitmaps are of different size.
 | 
						|
  In this case, only up to to->n_bits will be copied.
 | 
						|
*/
 | 
						|
 | 
						|
void bitmap_copy(MY_BITMAP *map, const MY_BITMAP *map2)
 | 
						|
{
 | 
						|
  my_bitmap_map *to= map->bitmap, *from= map2->bitmap, *end;
 | 
						|
  uint len= no_words_in_map(map), len2 = no_words_in_map(map2);
 | 
						|
  DBUG_ASSERT_DIFFERENT_BITMAPS(map, map2);
 | 
						|
 | 
						|
  end= to + MY_MIN(len, len2 - 1);
 | 
						|
  while (to < end)
 | 
						|
    *to++ = *from++;
 | 
						|
 | 
						|
  if (len2 <= len)
 | 
						|
    *to= (*from & ~map2->last_bit_mask) | (*to & map2->last_bit_mask);
 | 
						|
  *(map->last_word_ptr)&= ~map->last_bit_mask;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  Find first set bit in the bitmap
 | 
						|
*/
 | 
						|
 | 
						|
uint bitmap_get_first_set(const MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *data_ptr= map->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  for (uint i=0; data_ptr <= end; data_ptr++, i++)
 | 
						|
    if (*data_ptr)
 | 
						|
      return my_find_first_bit(*data_ptr) + i * sizeof(my_bitmap_map)*8;
 | 
						|
  return MY_BIT_NONE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the next set bit.
 | 
						|
 | 
						|
  @param  map         Bitmap
 | 
						|
  @param  bitmap_bit  Bit to start search from
 | 
						|
 | 
						|
  @return Index to first bit set after bitmap_bit
 | 
						|
*/
 | 
						|
 | 
						|
uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit)
 | 
						|
{
 | 
						|
  uint word_pos;
 | 
						|
  my_bitmap_map first_word, *data_ptr, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  /* Look for the next bit */
 | 
						|
  bitmap_bit++;
 | 
						|
  if (bitmap_bit >= map->n_bits)
 | 
						|
    return MY_BIT_NONE;
 | 
						|
 | 
						|
  word_pos= bitmap_bit / 64;
 | 
						|
  data_ptr= map->bitmap + word_pos;
 | 
						|
 | 
						|
  first_word= *data_ptr & first_bit_mask_inv(bitmap_bit);
 | 
						|
 | 
						|
  if (first_word)
 | 
						|
  {
 | 
						|
    /* Optimize common case when most bits are set */
 | 
						|
    if (first_word & (1ULL << ((bitmap_bit & (my_bitmap_map_bits-1)))))
 | 
						|
      return bitmap_bit;
 | 
						|
    return my_find_first_bit(first_word) + (bitmap_bit & ~(my_bitmap_map_bits-1));
 | 
						|
  }
 | 
						|
 | 
						|
  for (data_ptr++; data_ptr <= end; data_ptr++)
 | 
						|
  {
 | 
						|
    bitmap_bit+= 64;
 | 
						|
    if (*data_ptr)
 | 
						|
      return my_find_first_bit(*data_ptr) + (bitmap_bit & ~(my_bitmap_map_bits-1));
 | 
						|
  }
 | 
						|
  return MY_BIT_NONE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Get first clear bit */
 | 
						|
 | 
						|
uint bitmap_get_first_clear(const MY_BITMAP *map)
 | 
						|
{
 | 
						|
  uint i;
 | 
						|
  my_bitmap_map *data_ptr= map->bitmap, *end= map->last_word_ptr;
 | 
						|
  DBUG_ASSERT_BITMAP(map);
 | 
						|
 | 
						|
  for (i= 0; data_ptr < end; data_ptr++, i++)
 | 
						|
    if (*data_ptr != ~(my_bitmap_map)0)
 | 
						|
      goto found;
 | 
						|
  if ((*data_ptr | map->last_bit_mask) == ~(my_bitmap_map)0)
 | 
						|
    return MY_BIT_NONE;
 | 
						|
found:
 | 
						|
  /* find first zero bit by reverting all bits and find first bit */
 | 
						|
  return my_find_first_bit(~*data_ptr) + i * sizeof(my_bitmap_map)*8;
 | 
						|
}
 | 
						|
/*
 | 
						|
  Functions to export/import bitmaps to an architecture independent format
 | 
						|
  (low_byte_first)
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef WORDS_BIGENDIAN
 | 
						|
/* Big endian machines, like powerpc or s390x */
 | 
						|
 | 
						|
void bitmap_export(uchar *to, MY_BITMAP *map)
 | 
						|
{
 | 
						|
  my_bitmap_map *value;
 | 
						|
  uint length;
 | 
						|
  uchar buff[my_bitmap_map_bytes];
 | 
						|
 | 
						|
  for (value= map->bitmap ; value < map->last_word_ptr ; value++)
 | 
						|
  {
 | 
						|
    int8store(to, *value);
 | 
						|
    to+= 8;
 | 
						|
  }
 | 
						|
  int8store(buff, *value);
 | 
						|
 | 
						|
  /* We want length & 7 to return a serie 8,2,3,4,5,6,7, 8,2,3,... */
 | 
						|
  length= 1+ ((no_bytes_in_export_map(map) + 7) & 7);
 | 
						|
  memcpy(to, buff, length);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void bitmap_import(MY_BITMAP *map, uchar *from)
 | 
						|
{
 | 
						|
  my_bitmap_map *value;
 | 
						|
  uint length;
 | 
						|
  uchar buff[my_bitmap_map_bytes];
 | 
						|
 | 
						|
  for (value= map->bitmap ; value < map->last_word_ptr ; value++)
 | 
						|
  {
 | 
						|
    *value= uint8korr(from);
 | 
						|
    from+= 8;
 | 
						|
  }
 | 
						|
  bzero(buff, sizeof(buff));
 | 
						|
 | 
						|
  /* We want length & 7 to return a serie 8,2,3,4,5,6,7, 8,2,3,... */
 | 
						|
  length= 1+ ((no_bytes_in_export_map(map) + 7) & 7);
 | 
						|
  memcpy(buff, from, length);
 | 
						|
  *value= uint8korr(buff) & ~map->last_bit_mask;
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
/* Little endian machines, like intel and amd */
 | 
						|
 | 
						|
void bitmap_export(uchar *to, MY_BITMAP *map)
 | 
						|
{
 | 
						|
  memcpy(to, (uchar*) map->bitmap, no_bytes_in_export_map(map));
 | 
						|
}
 | 
						|
 | 
						|
void bitmap_import(MY_BITMAP *map, uchar *from)
 | 
						|
{
 | 
						|
  memcpy((uchar*) map->bitmap, from, no_bytes_in_export_map(map));
 | 
						|
  *map->last_word_ptr&= ~map->last_bit_mask;
 | 
						|
}
 | 
						|
#endif /* WORDS_BIGENDIAN */
 |