.del-bitvector.h~781aeab4a8d8c6da:

  Delete: sql/bitvector.h
.del-bitvector.cc~604d2cbc5915345:
  Delete: sql/bitvector.cc
parent 27b48cba
/* -*- Mode: C++ -*-
Copyright (C) 2005 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,
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include <bitvector.h>
void bitvector::create_last_word_mask()
{
/* Get the number of used bits (1..8) in the last byte */
unsigned int const used= 1U + ((size()-1U) & 0x7U);
/*
* Create a mask with the upper 'unused' bits set and the lower 'used'
* bits clear. The bits within each byte is stored in big-endian order.
*/
unsigned char const mask= (~((1 << used) - 1)) & 255;
unsigned int byte_no= ((bytes()-1)) & ~3U;
last_word_ptr= (uint32*)&m_data[byte_no];
/*
The first bytes are to be set to zero since they represent real bits
in the bitvector. The last bytes are set to 0xFF since they represent
bytes not used by the bitvector. Finally the last byte contains bits
as set by the mask above.
*/
unsigned char *ptr= (unsigned char*)&last_word_mask;
switch (bytes()&3)
{
case 1:
last_word_mask= ~0U;
ptr[0]= mask;
return;
case 2:
last_word_mask= ~0U;
ptr[0]= 0;
ptr[1]= mask;
return;
case 3:
last_word_mask= 0U;
ptr[2]= mask;
ptr[3]= 0xFFU;
return;
case 0:
last_word_mask= 0U;
ptr[3]= mask;
return;
}
}
int bitvector::init(size_t size)
{
DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND);
DBUG_ASSERT(size > 0);
m_size= size;
m_data= (uchar*)sql_alloc(byte_size_word_aligned(size));
if (m_data)
{
create_last_word_mask();
clear_all();
return FALSE;
}
return TRUE;
}
uint bitvector::no_bits_set()
{
uint no_bytes= bytes(), res=0, i;
uchar *ptr= m_data;
*last_word_ptr^=last_word_mask; //Reset last bits to zero
for (i=0; i< no_bytes; i++, ptr++)
res+=my_count_bits_ushort(*ptr);
*last_word_ptr^=last_word_mask; //Set last bits to one again
return res;
}
uint bitvector::get_first_bit_set()
{
uchar *byte_ptr;
uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k;
for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++)
{
if (*data_ptr)
{
byte_ptr= (uchar*)data_ptr;
for (j=0; j < 4; j++, byte_ptr++)
{
if (*byte_ptr)
{
for (k=0; k < 8; k++)
{
if (*byte_ptr & (1 << k))
{
bit_found= (i << 5) + (j << 3) + k;
if (bit_found == m_size)
return MYSQL_NO_BIT_FOUND;
else
return bit_found;
}
}
DBUG_ASSERT(1);
}
}
DBUG_ASSERT(1);
}
}
return MYSQL_NO_BIT_FOUND;
}
uint bitvector::get_first_bit_clear()
{
uchar *byte_ptr;
uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k;
for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++)
{
if (*data_ptr != 0xFFFFFFFF)
{
byte_ptr= (uchar*)data_ptr;
for (j=0; j < 4; j++, byte_ptr++)
{
if (*byte_ptr != 0xFF)
{
for (k=0; k < 8; k++)
{
if (!(*byte_ptr & (1 << k)))
{
bit_found= (i << 5) + (j << 3) + k;
if (bit_found == m_size)
return MYSQL_NO_BIT_FOUND;
else
return bit_found;
}
}
DBUG_ASSERT(1);
}
}
DBUG_ASSERT(1);
}
}
return MYSQL_NO_BIT_FOUND;
}
#ifdef TEST_BITVECTOR
uint get_rand_bit(uint bitsize)
{
return (rand() % bitsize);
}
bool test_set_get_clear_bit(bitvector *bv, uint bitsize)
{
uint i, test_bit;
uint no_loops= bitsize > 128 ? 128 : bitsize;
for (i=0; i < no_loops; i++)
{
test_bit= get_rand_bit(bitsize);
bv->set_bit(test_bit);
if (!bv->get_bit(test_bit))
goto error1;
bv->clear_bit(test_bit);
if (bv->get_bit(test_bit))
goto error2;
}
return FALSE;
error1:
printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize);
return TRUE;
error2:
printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize);
return TRUE;
}
bool test_flip_bit(bitvector *bv, uint bitsize)
{
uint i, test_bit;
uint no_loops= bitsize > 128 ? 128 : bitsize;
for (i=0; i < no_loops; i++)
{
test_bit= get_rand_bit(bitsize);
bv->flip_bit(test_bit);
if (!bv->get_bit(test_bit))
goto error1;
bv->flip_bit(test_bit);
if (bv->get_bit(test_bit))
goto error2;
}
return FALSE;
error1:
printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize);
return TRUE;
error2:
printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize);
return TRUE;
}
bool test_operators(bitvector *bv, uint bitsize)
{
return FALSE;
}
bool test_get_all_bits(bitvector *bv, uint bitsize)
{
uint i;
bv->set_all();
if (!bv->get_all_bits_set())
goto error1;
bv->clear_all();
if (!bv->get_all_bits_clear())
goto error2;
for (i=0; i<bitsize;i++)
bv->set_bit(i);
if (!bv->get_all_bits_set())
goto error3;
for (i=0; i<bitsize;i++)
bv->clear_bit(i);
if (!bv->get_all_bits_clear())
goto error4;
return FALSE;
error1:
printf("Error in set_all, bitsize = %u", bitsize);
return TRUE;
error2:
printf("Error in clear_all, bitsize = %u", bitsize);
return TRUE;
error3:
printf("Error in bitwise set all, bitsize = %u", bitsize);
return TRUE;
error4:
printf("Error in bitwise clear all, bitsize = %u", bitsize);
return TRUE;
}
bool test_compare_operators(bitvector *bv, uint bitsize)
{
return FALSE;
}
bool test_count_bits_set(bitvector *bv, uint bitsize)
{
uint i, bit_count=0, test_bit;
uint no_loops= bitsize > 128 ? 128 : bitsize;
for (i=0; i < no_loops; i++)
{
test_bit=get_rand_bit(bitsize);
if (!bv->get_bit(test_bit))
{
bv->set_bit(test_bit);
bit_count++;
}
}
if (bit_count==0 && bitsize > 0)
goto error1;
if (bv->no_bits_set() != bit_count)
goto error2;
return FALSE;
error1:
printf("No bits set bitsize = %u", bitsize);
return TRUE;
error2:
printf("Wrong count of bits set, bitsize = %u", bitsize);
return TRUE;
}
bool test_get_first_bit(bitvector *bv, uint bitsize)
{
return FALSE;
}
bool test_get_next_bit(bitvector *bv, uint bitsize)
{
return FALSE;
}
bool do_test(uint bitsize)
{
bitvector *bv;
bv = new bitvector;
bv->init(bitsize);
if (test_set_get_clear_bit(bv,bitsize))
goto error;
bv->clear_all();
if (test_flip_bit(bv,bitsize))
goto error;
bv->clear_all();
if (test_operators(bv,bitsize))
goto error;
bv->clear_all();
if (test_get_all_bits(bv, bitsize))
goto error;
bv->clear_all();
if (test_compare_operators(bv,bitsize))
goto error;
bv->clear_all();
if (test_count_bits_set(bv,bitsize))
goto error;
bv->clear_all();
if (test_get_first_bit(bv,bitsize))
goto error;
bv->clear_all();
if (test_get_next_bit(bv,bitsize))
goto error;
delete bv;
return FALSE;
error:
delete bv;
printf("\n");
return TRUE;
}
int main()
{
int i;
for (i= 1; i < 4096; i++)
if (do_test(i))
return -1;
printf("OK\n");
return 0;
}
/*
Compile by using the below on a compiled clone
g++ -DHAVE_CONFIG_H -I. -I. -I.. -I../include -I../regex -I. -I../include
-g -fno-omit-frame-pointer -fno-common -felide-constructors -fno-exceptions
-fno-rtti -fno-implicit-templates -fno-exceptions -fno-rtti
-DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL -DHAVE_DARWIN_THREADS
-D_P1003_1B_VISIBLE -DTEST_BITVECTOR -DSIGNAL_WITH_VIO_CLOSE
-DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -o bitvector.o
-c bitvector.cc
g++ -o bitvector bitvector.o -L../mysys -lmysys -L../dbug -L../strings
-lmystrings -ldbug
*/
#endif
/* -*- Mode: C++ -*-
Copyright (C) 2005 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,
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef BITVECTOR_H
#define BITVECTOR_H
#include <my_global.h>
#include <my_sys.h>
#include <cstring>
#include <climits>
/* Some compile-time checks to ensure the integrity of the implementation. */
#if CHAR_BIT != 8
# error "This implementation is designed for 8-bit bytes!"
#endif
#ifndef __cplusplus
# error "This is not a C header file, it's a C++ header file"
#endif
namespace
{
/* Defining my own swap, since we cannot use std::swap() */
template <class T>
inline void my_swap(T& x, T& y)
{
T t(x); x= y; y= t;
}
}
/*
A run-time sized bitvector for storing bits.
CAVEAT
This class is not designed to be inherited from, please don't do that.
Right now, the vector cannot change size. It's only used as a replacement
for using an array of bytes and a counter. If you want to change the size
of the vector, construct a new bitvector and assign it to the vector,
e.g.:
bitvector new_bv(new_size);
old_bv= new_bv;
An alternative is to use the swap member function to replace the instance:
bitvector new_bv(new_size);
old_bv.swap(new_bv);
The latter may be more efficient on compilers that are not so good at
inlining code.
*/
/* Number returned when no bit found */
#define MYSQL_NO_BIT_FOUND 1 << 20
class bitvector :public Sql_alloc
{
private:
/* Compute the number of bytes required to store 'bits' bits in an array. */
static inline size_t byte_size(size_t bits)
{
uint const byte_bits = sizeof(byte) * CHAR_BIT;
return (bits + (byte_bits-1)) / byte_bits;
}
static inline size_t byte_size_word_aligned(size_t bits)
{
return ((bits + 31) >> 5) << 2;
}
void create_last_word_mask();
inline void tidy_last_word()
{
*last_word_ptr|= last_word_mask;
}
public:
bitvector()
: m_size(0), m_data(0)
{
}
explicit bitvector(size_t size, bool value= false)
: m_size(size),
m_data((uchar*)sql_alloc(byte_size_word_aligned(size)))
{
DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND);
create_last_word_mask();
if (value)
set_all();
else
clear_all();
}
/* Constructor to create a bitvector from data. Observe that 'size' is the
* number of *bits* in the bitvector.
*/
explicit bitvector(byte const* data, size_t size)
: m_size(size),
m_data((uchar*)sql_alloc(byte_size_word_aligned(size)))
{
DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND);
create_last_word_mask();
memcpy(m_data, data, byte_size(size));
tidy_last_word();
}
bitvector(bitvector const& other)
: m_size(other.size()),
m_data((uchar*)sql_alloc(other.bytes()))
{
DBUG_ASSERT(m_size < MYSQL_NO_BIT_FOUND);
create_last_word_mask();
memcpy(m_data, other.data(), other.bytes());
tidy_last_word();
}
~bitvector() {}
/*
Allocate memory to the bitvector and create last word mask
and clear all bits in the bitvector.
*/
int init(size_t size);
/* Get number of bits set in the bitvector */
uint no_bits_set();
/* Get first bit set/clear in bitvector */
uint get_first_bit_set();
uint get_first_bit_clear();
/* Swap the guts of this instance with another instance. */
void swap(bitvector& other)
{
my_swap(m_size, other.m_size);
my_swap(m_data, other.m_data);
}
bitvector &operator=(const bitvector &rhs)
{
DBUG_ASSERT(rhs.size() == size());
memcpy(m_data, rhs.data(), byte_size_word_aligned(m_size));
return *this;
}
bool get_all_bits_set()
{
uint32 *data_ptr= (uint32*)&m_data[0];
for (; data_ptr <= last_word_ptr; data_ptr++)
if (*data_ptr != 0xFFFFFFFF)
return FALSE;
return TRUE;
}
bool get_all_bits_clear()
{
uint32 *data_ptr= (uint32*)m_data;
if (*last_word_ptr != last_word_mask)
return FALSE;
for (; data_ptr < last_word_ptr; data_ptr++)
if (*data_ptr)
return FALSE;
return TRUE;
}
/* A pointer to the bytes representing the bits */
uchar const *data() const { return m_data; }
/* The size of the data in *bytes* */
size_t bytes() const { return byte_size(m_size); }
/* The number of bits in the bit vector */
size_t size() const { return m_size; }
/* Set all bits in the vector */
void set_all()
{
memset(m_data, 255, byte_size_word_aligned(m_size));
}
/* Set a bit to a value */
void set_bit(size_t pos)
{
DBUG_ASSERT(pos < m_size);
m_data[pos>>3]|= (uchar)(1 << (pos & 0x7U));
}
/* Reset (clear) all bits in the vector */
void clear_all()
{
memset(m_data, 0, bytes());
tidy_last_word();
}
/* Reset one bit in the vector */
void clear_bit(size_t pos)
{
DBUG_ASSERT(pos < m_size);
m_data[pos>>3]&= ~(uchar)(1 << (pos & 0x7U));
}
void flip_bit(size_t pos)
{
DBUG_ASSERT(pos < m_size);
m_data[pos>>3]^= (uchar)(1 << (pos & 0x7U));
}
bool get_bit(size_t pos) const
{
DBUG_ASSERT(pos < m_size);
/*
!! provides the most effective implementation of conversion to
bool
*/
uchar *byte_word= m_data + (pos >> 3);
uchar mask= 1 << (pos & 0x7U);
bool ret_value= !!(*byte_word & mask);
return ret_value;
};
bool operator==(bitvector const& rhs) const
{
if (size() != rhs.size())
return false;
/* This works since I have ensured that the last byte of the array
* contain sensible data.
*/
if (memcmp(data(), rhs.data(), bytes()) != 0)
return false;
return true;
}
bool operator!=(bitvector const& rhs) const
{
return !(*this == rhs);
}
bitvector &operator&=(bitvector const& rhs)
{
DBUG_ASSERT(size() == rhs.size());
uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data();
uint32 *last_ptr= last_word_ptr;
for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++)
*data_ptr&=*rhs_data_ptr;
return *this;
}
bitvector &operator|=(bitvector const& rhs)
{
DBUG_ASSERT(size() == rhs.size());
uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data();
uint32 *last_ptr= last_word_ptr;
for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++)
*data_ptr|=*rhs_data_ptr;
return *this;
}
bitvector &operator^=(bitvector const& rhs)
{
DBUG_ASSERT(size() == rhs.size());
uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data();
uint32 *last_ptr= last_word_ptr;
for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++)
*data_ptr^=*rhs_data_ptr;
tidy_last_word();
return *this;
}
bitvector &operator~()
{
uint32 *data_ptr= (uint32*)data();
uint32 *last_ptr= last_word_ptr;
for (; data_ptr <= last_ptr; data_ptr++)
*data_ptr^=0xFFFFFFFF;
tidy_last_word();
return *this;
}
private:
size_t m_size;
uint32 last_word_mask;
uchar *m_data;
uint32 *last_word_ptr;
};
#endif /* BITVECTOR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment