/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: sfx2_bitset.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif
#ifdef _MSC_VER
#pragma hdrstop
#endif

#include "bitset.hxx"

#include <string.h>		// memset(), memcpy()
#include <limits.h>		// USHRT_MAX
namespace binfilter {

//====================================================================
// add nOffset to each bit-value in the set

/*N*/ BitSet BitSet::operator<<( USHORT nOffset ) const
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	// create a work-copy, return it if nothing to shift
/*N*/ 	BitSet aSet(*this);
/*N*/ 	if ( nOffset == 0 )
/*N*/ 		return aSet;
/*N*/ 
/*N*/ 	// compute the shiftment in long-words and bits
/*N*/ 	USHORT nBlockDiff = nOffset / 32;
/*N*/ 	ULONG nBitValDiff = nOffset % 32;
/*N*/ 
/*N*/ 	// compute the new number of bits
/*N*/ 	for ( USHORT nBlock = 0; nBlock < nBlockDiff; ++nBlock )
/*?*/ 		aSet.nCount -= CountBits( *(aSet.pBitmap+nBlock) );
/*N*/ 	aSet.nCount -= CountBits( *(aSet.pBitmap+nBlockDiff) >> (32-nBitValDiff) );
/*N*/ 
/*N*/ 	// shift complete long-words
/*N*/ 	USHORT nTarget, nSource;
/*N*/ 	for ( nTarget = 0, nSource = nBlockDiff;
/*N*/ 		  (nSource+1) < aSet.nBlocks;
/*N*/ 		  ++nTarget, ++nSource )
/*N*/ 		*(aSet.pBitmap+nTarget) =
/*N*/ 			( *(aSet.pBitmap+nSource) << nBitValDiff ) |
/*N*/ 			( *(aSet.pBitmap+nSource+1) >> (32-nBitValDiff) );
/*N*/ 
/*N*/ 	// shift the remainder (if in total minor 32 bits, only this)
/*N*/ 	*(aSet.pBitmap+nTarget) = *(aSet.pBitmap+nSource) << nBitValDiff;
/*N*/ 
/*N*/ 	// determine the last used block
/*N*/ 	while ( *(aSet.pBitmap+nTarget) == 0 )
/*N*/ 		--nTarget;
/*N*/ 
/*N*/ 	// shorten the block-array
/*N*/ 	if ( nTarget < aSet.nBlocks )
/*N*/ 	{
/*N*/ 		ULONG* pNewMap = new ULONG[nTarget];
/*N*/ 		memcpy( pNewMap, aSet.pBitmap, 4 * nTarget );
/*N*/         delete [] aSet.pBitmap;
/*N*/ 		aSet.pBitmap = pNewMap;
/*N*/ 		aSet.nBlocks = nTarget;
/*N*/ 	}
/*N*/ 
/*N*/ 	return aSet;
/*N*/ }

//--------------------------------------------------------------------

// substracts nOffset from each bit-value in the set


//--------------------------------------------------------------------

// internal code for operator= and copy-ctor

/*N*/ void BitSet::CopyFrom( const BitSet& rSet )
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	nCount = rSet.nCount;
/*N*/ 	nBlocks = rSet.nBlocks;
/*N*/ 	if ( rSet.nBlocks )
/*N*/ 	{
/*N*/ 		DBG_MEMTEST();
/*N*/ 		pBitmap = new ULONG[nBlocks];
/*N*/ 		memcpy( pBitmap, rSet.pBitmap, 4 * nBlocks );
/*N*/ 	}
/*N*/ 	else
/*N*/ 		pBitmap = 0;
/*N*/ }

//--------------------------------------------------------------------

// creates an empty bitset

/*N*/ BitSet::BitSet()
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	nCount = 0;
/*N*/ 	nBlocks = 0;
/*N*/ 	pBitmap = 0;
/*N*/ }

//--------------------------------------------------------------------

// creates a copy of bitset rOrig

/*N*/ BitSet::BitSet( const BitSet& rOrig )
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	CopyFrom(rOrig);
/*N*/ }

//--------------------------------------------------------------------

// creates a bitset from an array


//--------------------------------------------------------------------

// frees the storage

/*N*/ BitSet::~BitSet()
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/     delete [] pBitmap;
/*N*/ }

//--------------------------------------------------------------------

// creates a bitmap with all bits in rRange set


//--------------------------------------------------------------------

// assignment from another bitset


//--------------------------------------------------------------------

// assignment from a single bit


//--------------------------------------------------------------------

// creates the asymetric difference with another bitset

/*N*/ BitSet& BitSet::operator-=(USHORT nBit)
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	USHORT nBlock = nBit / 32;
/*N*/ 	ULONG nBitVal = 1L << (nBit % 32);
/*N*/ 
/*N*/ 	if ( nBlock >= nBlocks )
/*N*/ 	  return *this;
/*N*/ 
/*N*/ 	if ( (*(pBitmap+nBlock) & nBitVal) )
/*N*/ 	{
/*N*/ 		*(pBitmap+nBlock) &= ~nBitVal;
/*N*/ 		--nCount;
/*N*/ 	}
/*N*/ 
/*N*/ 	return *this;
/*N*/ }

//--------------------------------------------------------------------

// unites with the bits of rSet

/*N*/ BitSet& BitSet::operator|=( const BitSet& rSet )
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	USHORT nMax = Min(nBlocks, rSet.nBlocks);
/*N*/ 
/*N*/ 	// expand the bitmap
/*N*/ 	if ( nBlocks < rSet.nBlocks )
/*N*/ 	{
/*N*/ 		ULONG *pNewMap = new ULONG[rSet.nBlocks];
/*N*/ 		memset( pNewMap + nBlocks, 0, 4 * (rSet.nBlocks - nBlocks) );
/*N*/ 
/*N*/ 		if ( pBitmap )
/*N*/ 		{
/*?*/ 			memcpy( pNewMap, pBitmap, 4 * nBlocks );
/*?*/             delete [] pBitmap;
/*N*/ 		}
/*N*/ 		pBitmap = pNewMap;
/*N*/ 		nBlocks = rSet.nBlocks;
/*N*/ 	}
/*N*/ 
/*N*/ 	// add the bits blocks by block
/*N*/ 	for ( USHORT nBlock = 0; nBlock < nMax; ++nBlock )
/*N*/ 	{
/*N*/ 		// compute numberof additional bits
/*?*/ 		ULONG nDiff = ~*(pBitmap+nBlock) & *(rSet.pBitmap+nBlock);
/*?*/ 		nCount += CountBits(nDiff);
/*?*/ 
/*?*/ 		*(pBitmap+nBlock) |= *(rSet.pBitmap+nBlock);
/*N*/ 	}
/*N*/ 
/*N*/ 	return *this;
/*N*/ }

//--------------------------------------------------------------------

// unites with a single bit

/*N*/ BitSet& BitSet::operator|=( USHORT nBit )
/*N*/ {
/*N*/ 	DBG_MEMTEST();
/*N*/ 	USHORT nBlock = nBit / 32;
/*N*/ 	ULONG nBitVal = 1L << (nBit % 32);
/*N*/ 
/*N*/ 	if ( nBlock >= nBlocks )
/*N*/ 	{
/*N*/ 		ULONG *pNewMap = new ULONG[nBlock+1];
/*N*/ 		memset( pNewMap + nBlocks, 0, 4 * (nBlock - nBlocks + 1) );
/*N*/ 
/*N*/ 		if ( pBitmap )
/*N*/ 		{
/*N*/ 			memcpy( pNewMap, pBitmap, 4 * nBlocks );
/*N*/             delete [] pBitmap;
/*N*/ 		}
/*N*/ 		pBitmap = pNewMap;
/*N*/ 		nBlocks = nBlock+1;
/*N*/ 	}
/*N*/ 
/*N*/ 	if ( (*(pBitmap+nBlock) & nBitVal) == 0 )
/*N*/ 	{
/*N*/ 		*(pBitmap+nBlock) |= nBitVal;
/*N*/ 		++nCount;
/*N*/ 	}
/*N*/ 
/*N*/ 	return *this;
/*N*/ }

// counts the number of 1-bits in the parameter

/*N*/ USHORT BitSet::CountBits( ULONG nBits )
/*N*/ {
/*N*/ 	USHORT nCount = 0;
/*N*/ 	int nBit = 32;
/*N*/ 	while ( nBit-- && nBits )
/*?*/ 	{   if ( ( (long)nBits ) < 0 )
/*?*/ 			++nCount;
/*?*/ 		nBits = nBits << 1;
/*N*/ 	}
/*N*/ 	return nCount;
/*N*/ }

}
