628 lines
23 KiB
C++
628 lines
23 KiB
C++
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* $Id: CMStateSet.hpp 901107 2010-01-20 08:45:02Z borisk $
|
|
*/
|
|
|
|
#if !defined(XERCESC_INCLUDE_GUARD_CMSTATESET_HPP)
|
|
#define XERCESC_INCLUDE_GUARD_CMSTATESET_HPP
|
|
|
|
// DESCRIPTION:
|
|
//
|
|
// This class is a specialized bitset class for the content model code of
|
|
// the validator. It assumes that its never called with two objects of
|
|
// different bit counts, and that bit sets smaller than a threshold are far
|
|
// and away the most common. So it can be a lot more optimized than a general
|
|
// purpose utility bitset class
|
|
//
|
|
|
|
#include <xercesc/util/ArrayIndexOutOfBoundsException.hpp>
|
|
#include <xercesc/util/RuntimeException.hpp>
|
|
#include <xercesc/util/PlatformUtils.hpp>
|
|
#include <xercesc/framework/MemoryManager.hpp>
|
|
#include <string.h>
|
|
|
|
#if XERCES_HAVE_EMMINTRIN_H
|
|
# include <emmintrin.h>
|
|
#endif
|
|
|
|
XERCES_CPP_NAMESPACE_BEGIN
|
|
|
|
class CMStateSetEnumerator;
|
|
|
|
// This value must be 4 in order to use the SSE2 instruction set
|
|
#define CMSTATE_CACHED_INT32_SIZE 4
|
|
|
|
// This value must be a multiple of 128 in order to use the SSE2 instruction set
|
|
#define CMSTATE_BITFIELD_CHUNK 1024
|
|
#define CMSTATE_BITFIELD_INT32_SIZE (1024 / 32)
|
|
|
|
struct CMDynamicBuffer
|
|
{
|
|
// fArraySize
|
|
// This indicates the number of elements of the fBitArray vector
|
|
//
|
|
// fBitArray
|
|
// A vector of arrays of XMLInt32; each array is allocated on demand
|
|
// if a bit needs to be set in that range
|
|
//
|
|
// fMemoryManager
|
|
// The memory manager used to allocate and deallocate memory
|
|
//
|
|
XMLSize_t fArraySize;
|
|
XMLInt32** fBitArray;
|
|
MemoryManager* fMemoryManager;
|
|
};
|
|
|
|
class CMStateSet : public XMemory
|
|
{
|
|
public :
|
|
// -----------------------------------------------------------------------
|
|
// Constructors and Destructor
|
|
// -----------------------------------------------------------------------
|
|
CMStateSet( const XMLSize_t bitCount
|
|
, MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager) :
|
|
|
|
fBitCount(bitCount)
|
|
, fDynamicBuffer(0)
|
|
{
|
|
//
|
|
// See if we need to allocate the byte array or whether we can live
|
|
// within the cached bit high performance scheme.
|
|
//
|
|
if (fBitCount > (CMSTATE_CACHED_INT32_SIZE * 32))
|
|
{
|
|
fDynamicBuffer = (CMDynamicBuffer*)manager->allocate(sizeof(CMDynamicBuffer));
|
|
fDynamicBuffer->fMemoryManager = manager;
|
|
// allocate an array of vectors, each one containing CMSTATE_BITFIELD_CHUNK bits
|
|
fDynamicBuffer->fArraySize = fBitCount / CMSTATE_BITFIELD_CHUNK;
|
|
if (fBitCount % CMSTATE_BITFIELD_CHUNK)
|
|
fDynamicBuffer->fArraySize++;
|
|
fDynamicBuffer->fBitArray = (XMLInt32**) fDynamicBuffer->fMemoryManager->allocate(fDynamicBuffer->fArraySize*sizeof(XMLInt32*));
|
|
for(XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
fDynamicBuffer->fBitArray[index]=NULL;
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
fBits[index] = 0;
|
|
}
|
|
}
|
|
|
|
CMStateSet(const CMStateSet& toCopy) :
|
|
XMemory(toCopy)
|
|
, fBitCount(toCopy.fBitCount)
|
|
, fDynamicBuffer(0)
|
|
{
|
|
//
|
|
// See if we need to allocate the byte array or whether we can live
|
|
// within the cahced bit high performance scheme.
|
|
//
|
|
if (fBitCount > (CMSTATE_CACHED_INT32_SIZE * 32))
|
|
{
|
|
fDynamicBuffer = (CMDynamicBuffer*) toCopy.fDynamicBuffer->fMemoryManager->allocate(sizeof(CMDynamicBuffer));
|
|
fDynamicBuffer->fMemoryManager = toCopy.fDynamicBuffer->fMemoryManager;
|
|
fDynamicBuffer->fArraySize = fBitCount / CMSTATE_BITFIELD_CHUNK;
|
|
if (fBitCount % CMSTATE_BITFIELD_CHUNK)
|
|
fDynamicBuffer->fArraySize++;
|
|
fDynamicBuffer->fBitArray = (XMLInt32**) fDynamicBuffer->fMemoryManager->allocate(fDynamicBuffer->fArraySize*sizeof(XMLInt32*));
|
|
for(XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
if(toCopy.fDynamicBuffer->fBitArray[index]!=NULL)
|
|
{
|
|
allocateChunk(index);
|
|
memcpy((void *) fDynamicBuffer->fBitArray[index],
|
|
(const void *) toCopy.fDynamicBuffer->fBitArray[index],
|
|
CMSTATE_BITFIELD_INT32_SIZE * sizeof(XMLInt32));
|
|
}
|
|
else
|
|
fDynamicBuffer->fBitArray[index]=NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy((void *) fBits,
|
|
(const void *) toCopy.fBits,
|
|
CMSTATE_CACHED_INT32_SIZE * sizeof(XMLInt32));
|
|
}
|
|
}
|
|
|
|
~CMStateSet()
|
|
{
|
|
if(fDynamicBuffer)
|
|
{
|
|
for(XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
if(fDynamicBuffer->fBitArray[index]!=NULL)
|
|
deallocateChunk(index);
|
|
fDynamicBuffer->fMemoryManager->deallocate(fDynamicBuffer->fBitArray);
|
|
fDynamicBuffer->fMemoryManager->deallocate(fDynamicBuffer);
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Set manipulation methods
|
|
// -----------------------------------------------------------------------
|
|
void operator|=(const CMStateSet& setToOr)
|
|
{
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
#ifdef XERCES_HAVE_SSE2_INTRINSIC
|
|
if(XMLPlatformUtils::fgSSE2ok)
|
|
{
|
|
__m128i xmm1 = _mm_loadu_si128((__m128i*)fBits);
|
|
__m128i xmm2 = _mm_loadu_si128((__m128i*)setToOr.fBits);
|
|
__m128i xmm3 = _mm_or_si128(xmm1, xmm2); // OR 4 32-bit words
|
|
_mm_storeu_si128((__m128i*)fBits, xmm3);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
if(setToOr.fBits[index])
|
|
{
|
|
if(fBits[index])
|
|
fBits[index] |= setToOr.fBits[index];
|
|
else
|
|
fBits[index] = setToOr.fBits[index];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
XMLInt32 *& other = setToOr.fDynamicBuffer->fBitArray[index];
|
|
if(other!=NULL)
|
|
{
|
|
// if we haven't allocated the subvector yet, allocate it and copy
|
|
if(fDynamicBuffer->fBitArray[index]==NULL)
|
|
{
|
|
allocateChunk(index);
|
|
memcpy((void *) fDynamicBuffer->fBitArray[index],
|
|
(const void *) other,
|
|
CMSTATE_BITFIELD_INT32_SIZE * sizeof(XMLInt32));
|
|
}
|
|
else
|
|
{
|
|
// otherwise, merge them
|
|
XMLInt32*& mine = fDynamicBuffer->fBitArray[index];
|
|
#ifdef XERCES_HAVE_SSE2_INTRINSIC
|
|
if(XMLPlatformUtils::fgSSE2ok)
|
|
{
|
|
for(XMLSize_t subIndex = 0; subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex+=4)
|
|
{
|
|
__m128i xmm1 = _mm_load_si128((__m128i*)&other[subIndex]);
|
|
__m128i xmm2 = _mm_load_si128((__m128i*)&mine[subIndex]);
|
|
__m128i xmm3 = _mm_or_si128(xmm1, xmm2); // OR 4 32-bit words
|
|
_mm_store_si128((__m128i*)&mine[subIndex], xmm3);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
for(XMLSize_t subIndex = 0; subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
if(setToOr.fDynamicBuffer->fBitArray[index][subIndex])
|
|
{
|
|
if(fDynamicBuffer->fBitArray[index][subIndex])
|
|
fDynamicBuffer->fBitArray[index][subIndex] |= setToOr.fDynamicBuffer->fBitArray[index][subIndex];
|
|
else
|
|
fDynamicBuffer->fBitArray[index][subIndex] = setToOr.fDynamicBuffer->fBitArray[index][subIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool operator==(const CMStateSet& setToCompare) const
|
|
{
|
|
if (fBitCount != setToCompare.fBitCount)
|
|
return false;
|
|
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
{
|
|
if (fBits[index] != setToCompare.fBits[index])
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
XMLInt32 *& other = setToCompare.fDynamicBuffer->fBitArray[index],
|
|
*& mine = fDynamicBuffer->fBitArray[index];
|
|
if(mine==NULL && other==NULL)
|
|
continue;
|
|
else if(mine==NULL || other==NULL) // the other should have been empty too
|
|
return false;
|
|
else
|
|
{
|
|
for(XMLSize_t subIndex = 0; subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
if(mine[subIndex]!=other[subIndex])
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
CMStateSet& operator=(const CMStateSet& srcSet)
|
|
{
|
|
if (this == &srcSet)
|
|
return *this;
|
|
|
|
// They have to be the same size
|
|
if (fBitCount != srcSet.fBitCount)
|
|
{
|
|
if(fDynamicBuffer)
|
|
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Bitset_NotEqualSize, fDynamicBuffer->fMemoryManager);
|
|
else
|
|
ThrowXML(RuntimeException, XMLExcepts::Bitset_NotEqualSize);
|
|
}
|
|
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
fBits[index] = srcSet.fBits[index];
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
if(srcSet.fDynamicBuffer->fBitArray[index]==NULL)
|
|
{
|
|
// delete this subentry
|
|
if(fDynamicBuffer->fBitArray[index]!=NULL)
|
|
deallocateChunk(index);
|
|
}
|
|
else
|
|
{
|
|
// if we haven't allocated the subvector yet, allocate it and copy
|
|
if(fDynamicBuffer->fBitArray[index]==NULL)
|
|
allocateChunk(index);
|
|
memcpy((void *) fDynamicBuffer->fBitArray[index],
|
|
(const void *) srcSet.fDynamicBuffer->fBitArray[index],
|
|
CMSTATE_BITFIELD_INT32_SIZE * sizeof(XMLInt32));
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
XMLSize_t getBitCountInRange(XMLSize_t start, XMLSize_t end) const
|
|
{
|
|
XMLSize_t count = 0;
|
|
end /= 32;
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
if(end > CMSTATE_CACHED_INT32_SIZE)
|
|
end = CMSTATE_CACHED_INT32_SIZE;
|
|
for (XMLSize_t index = start / 32; index < end; index++)
|
|
{
|
|
if (fBits[index] != 0)
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
const XMLInt32 mask = 1UL << i;
|
|
if(fBits[index] & mask)
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(end > fDynamicBuffer->fArraySize)
|
|
end = fDynamicBuffer->fArraySize;
|
|
for (XMLSize_t index = start / 32; index < end; index++)
|
|
{
|
|
if(fDynamicBuffer->fBitArray[index]==NULL)
|
|
continue;
|
|
for(XMLSize_t subIndex=0;subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
{
|
|
if (fDynamicBuffer->fBitArray[index][subIndex] != 0)
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
const XMLInt32 mask = 1UL << i;
|
|
if(fDynamicBuffer->fBitArray[index][subIndex] & mask)
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
bool getBit(const XMLSize_t bitToGet) const
|
|
{
|
|
if (bitToGet >= fBitCount)
|
|
{
|
|
if(fDynamicBuffer)
|
|
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Bitset_BadIndex, fDynamicBuffer->fMemoryManager);
|
|
else
|
|
ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::Bitset_BadIndex);
|
|
}
|
|
|
|
// And access the right bit and byte
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
const XMLInt32 mask = 1UL << (bitToGet % 32);
|
|
const XMLSize_t byteOfs = bitToGet / 32;
|
|
return (fBits[byteOfs]!=0 && (fBits[byteOfs] & mask) != 0);
|
|
}
|
|
else
|
|
{
|
|
const XMLSize_t vectorOfs = bitToGet / CMSTATE_BITFIELD_CHUNK;
|
|
if(fDynamicBuffer->fBitArray[vectorOfs]==NULL)
|
|
return false;
|
|
const XMLInt32 mask = 1UL << (bitToGet % 32);
|
|
const XMLSize_t byteOfs = (bitToGet % CMSTATE_BITFIELD_CHUNK) / 32;
|
|
return (fDynamicBuffer->fBitArray[vectorOfs][byteOfs]!=0 && (fDynamicBuffer->fBitArray[vectorOfs][byteOfs] & mask) != 0);
|
|
}
|
|
}
|
|
|
|
bool isEmpty() const
|
|
{
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
{
|
|
if (fBits[index] != 0)
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
if(fDynamicBuffer->fBitArray[index]==NULL)
|
|
continue;
|
|
for(XMLSize_t subIndex=0;subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
{
|
|
if (fDynamicBuffer->fBitArray[index][subIndex] != 0)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void setBit(const XMLSize_t bitToSet)
|
|
{
|
|
if (bitToSet >= fBitCount)
|
|
{
|
|
if(fDynamicBuffer)
|
|
ThrowXMLwithMemMgr(ArrayIndexOutOfBoundsException, XMLExcepts::Bitset_BadIndex, fDynamicBuffer->fMemoryManager);
|
|
else
|
|
ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::Bitset_BadIndex);
|
|
}
|
|
|
|
const XMLInt32 mask = 1UL << (bitToSet % 32);
|
|
|
|
// And access the right bit and byte
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
const XMLSize_t byteOfs = bitToSet / 32;
|
|
fBits[byteOfs] &= ~mask;
|
|
fBits[byteOfs] |= mask;
|
|
}
|
|
else
|
|
{
|
|
const XMLSize_t vectorOfs = bitToSet / CMSTATE_BITFIELD_CHUNK;
|
|
if(fDynamicBuffer->fBitArray[vectorOfs]==NULL)
|
|
{
|
|
allocateChunk(vectorOfs);
|
|
for(XMLSize_t index=0;index < CMSTATE_BITFIELD_INT32_SIZE; index++)
|
|
fDynamicBuffer->fBitArray[vectorOfs][index]=0;
|
|
}
|
|
const XMLSize_t byteOfs = (bitToSet % CMSTATE_BITFIELD_CHUNK) / 32;
|
|
fDynamicBuffer->fBitArray[vectorOfs][byteOfs] &= ~mask;
|
|
fDynamicBuffer->fBitArray[vectorOfs][byteOfs] |= mask;
|
|
}
|
|
}
|
|
|
|
void zeroBits()
|
|
{
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
for (XMLSize_t index = 0; index < CMSTATE_CACHED_INT32_SIZE; index++)
|
|
fBits[index] = 0;
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
|
|
// delete this subentry
|
|
if(fDynamicBuffer->fBitArray[index]!=NULL)
|
|
deallocateChunk(index);
|
|
}
|
|
}
|
|
|
|
XMLSize_t hashCode() const
|
|
{
|
|
XMLSize_t hash = 0;
|
|
if(fDynamicBuffer==0)
|
|
{
|
|
for (XMLSize_t index = 0; index<CMSTATE_CACHED_INT32_SIZE; index++)
|
|
hash = fBits[index] + hash * 31;
|
|
}
|
|
else
|
|
{
|
|
for (XMLSize_t index = 0; index<fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
if(fDynamicBuffer->fBitArray[index]==NULL)
|
|
// simulates the iteration on the missing bits
|
|
for(XMLSize_t subIndex=0;subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
hash *= 31;
|
|
else
|
|
for(XMLSize_t subIndex=0;subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
hash = fDynamicBuffer->fBitArray[index][subIndex] + hash * 31;
|
|
}
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
private :
|
|
// -----------------------------------------------------------------------
|
|
// Unimplemented constructors and operators
|
|
// -----------------------------------------------------------------------
|
|
CMStateSet();
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Helpers
|
|
// -----------------------------------------------------------------------
|
|
void allocateChunk(const XMLSize_t index)
|
|
{
|
|
#ifdef XERCES_HAVE_SSE2_INTRINSIC
|
|
if(XMLPlatformUtils::fgSSE2ok)
|
|
fDynamicBuffer->fBitArray[index]=(XMLInt32*)_mm_malloc(CMSTATE_BITFIELD_INT32_SIZE * sizeof(XMLInt32), 16);
|
|
else
|
|
#endif
|
|
fDynamicBuffer->fBitArray[index]=(XMLInt32*)fDynamicBuffer->fMemoryManager->allocate(CMSTATE_BITFIELD_INT32_SIZE * sizeof(XMLInt32));
|
|
}
|
|
|
|
void deallocateChunk(const XMLSize_t index)
|
|
{
|
|
#ifdef XERCES_HAVE_SSE2_INTRINSIC
|
|
if(XMLPlatformUtils::fgSSE2ok)
|
|
_mm_free(fDynamicBuffer->fBitArray[index]);
|
|
else
|
|
#endif
|
|
fDynamicBuffer->fMemoryManager->deallocate(fDynamicBuffer->fBitArray[index]);
|
|
fDynamicBuffer->fBitArray[index]=NULL;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// Private data members
|
|
//
|
|
// fBitCount
|
|
// The count of bits that the outside world wants to support,
|
|
// so its the max bit index plus one.
|
|
//
|
|
// fBits
|
|
// When the bit count is less than a threshold (very common), these hold the bits.
|
|
// Otherwise, the fDynamicBuffer member holds htem.
|
|
//
|
|
// fDynamicBuffer
|
|
// If the bit count is greater than the threshold, then we allocate this structure to
|
|
// store the bits, the length, and the memory manager to allocate/deallocate
|
|
// the memory
|
|
//
|
|
// -----------------------------------------------------------------------
|
|
XMLSize_t fBitCount;
|
|
XMLInt32 fBits[CMSTATE_CACHED_INT32_SIZE];
|
|
CMDynamicBuffer* fDynamicBuffer;
|
|
|
|
friend class CMStateSetEnumerator;
|
|
};
|
|
|
|
class CMStateSetEnumerator : public XMemory
|
|
{
|
|
public:
|
|
CMStateSetEnumerator(const CMStateSet* toEnum, XMLSize_t start = 0) :
|
|
fToEnum(toEnum),
|
|
fIndexCount((XMLSize_t)-1),
|
|
fLastValue(0)
|
|
{
|
|
// if a starting bit is specified, place fIndexCount at the beginning of the previous 32 bit area
|
|
// so the findNext moves to the one where 'start' is located
|
|
if(start > 32)
|
|
fIndexCount = (start/32 - 1) * 32;
|
|
findNext();
|
|
// if we found data, and fIndexCount is still pointing to the area where 'start' is located, erase the bits before 'start'
|
|
if(hasMoreElements() && fIndexCount < start)
|
|
{
|
|
for(XMLSize_t i=0;i< (start - fIndexCount);i++)
|
|
{
|
|
XMLInt32 mask=1UL << i;
|
|
if(fLastValue & mask)
|
|
fLastValue &= ~mask;
|
|
}
|
|
// in case the 32 bit area contained only bits before 'start', advance
|
|
if(fLastValue==0)
|
|
findNext();
|
|
}
|
|
}
|
|
|
|
bool hasMoreElements()
|
|
{
|
|
return fLastValue!=0;
|
|
}
|
|
|
|
unsigned int nextElement()
|
|
{
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
XMLInt32 mask=1UL << i;
|
|
if(fLastValue & mask)
|
|
{
|
|
fLastValue &= ~mask;
|
|
unsigned int retVal=(unsigned int)fIndexCount+i;
|
|
if(fLastValue==0)
|
|
findNext();
|
|
return retVal;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
void findNext()
|
|
{
|
|
if(fToEnum->fDynamicBuffer==0)
|
|
{
|
|
XMLSize_t nOffset=((fIndexCount==(XMLSize_t)-1)?0:(fIndexCount/32)+1);
|
|
for(XMLSize_t index=nOffset;index<CMSTATE_CACHED_INT32_SIZE;index++)
|
|
{
|
|
if(fToEnum->fBits[index]!=0)
|
|
{
|
|
fIndexCount=index*32;
|
|
fLastValue=fToEnum->fBits[index];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XMLSize_t nOffset=((fIndexCount==(XMLSize_t)-1)?0:(fIndexCount/CMSTATE_BITFIELD_CHUNK));
|
|
XMLSize_t nSubOffset=((fIndexCount==(XMLSize_t)-1)?0:((fIndexCount % CMSTATE_BITFIELD_CHUNK) /32)+1);
|
|
for (XMLSize_t index = nOffset; index<fToEnum->fDynamicBuffer->fArraySize; index++)
|
|
{
|
|
if(fToEnum->fDynamicBuffer->fBitArray[index]!=NULL)
|
|
{
|
|
for(XMLSize_t subIndex=nSubOffset;subIndex < CMSTATE_BITFIELD_INT32_SIZE; subIndex++)
|
|
if(fToEnum->fDynamicBuffer->fBitArray[index][subIndex]!=0)
|
|
{
|
|
fIndexCount=index*CMSTATE_BITFIELD_CHUNK + subIndex*32;
|
|
fLastValue=fToEnum->fDynamicBuffer->fBitArray[index][subIndex];
|
|
return;
|
|
}
|
|
}
|
|
nSubOffset = 0; // next chunks will be processed from the beginning
|
|
}
|
|
}
|
|
}
|
|
|
|
const CMStateSet* fToEnum;
|
|
XMLSize_t fIndexCount;
|
|
XMLInt32 fLastValue;
|
|
};
|
|
|
|
XERCES_CPP_NAMESPACE_END
|
|
|
|
#endif
|