Update contrib.
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
15 // Collection of common constants, utility functions, etc. for the file server and file systems.
16 // Definitions here must be filesystem-agnostic, i.e. generic enougs to be used by every file system
18 // This is the internal file and must not be exported.
25 #include "bit_vector.h"
28 //#######################################################################################################################################
29 //# RBitVector class implementation
30 //#######################################################################################################################################
32 const TUint32 K_FFFF = 0xFFFFFFFF; //-- all one bits, beware rigth shifts of signed integers!
34 RBitVector::RBitVector()
35 :iNumBits(0), ipData(NULL), iNumWords(0)
40 RBitVector::~RBitVector()
47 @param aPanicCode a panic code
49 void RBitVector::Panic(TPanicCode aPanicCode) const
51 _LIT(KPanicCat,"RBitVector");
52 User::Panic(KPanicCat, aPanicCode);
55 /** explicitly closes the object and deallocates memory */
56 void RBitVector::Close()
64 //-----------------------------------------------------------------------------
68 @param aRhs a vector to compate with.
69 @panic ESizeMismatch in the case of different vector sizes
71 TBool RBitVector::operator==(const RBitVector& aRhs) const
73 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
74 __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
78 return ETrue; //-- comparing 0-lenght arrays
81 {//-- comparing with itself, potential source of errors
88 const TUint32 cntBytes = (iNumBits >> 5) << 2; //-- bytes to compare
89 if(memcompare((const TUint8*)ipData, cntBytes, (const TUint8*)aRhs.ipData, cntBytes))
93 const TUint32 bitsRest = iNumBits & 0x1F;
96 const TUint32 mask = K_FFFF >> (32-bitsRest);
97 return ( (ipData[iNumWords-1] & mask) == (aRhs.ipData[iNumWords-1] & mask) );
103 TBool RBitVector::operator!=(const RBitVector& aRhs) const
105 return ! ((*this) == aRhs);
108 //-----------------------------------------------------------------------------
110 /** The same as Create(), but leaves on error */
111 void RBitVector::CreateL(TUint32 aNumBits)
113 User::LeaveIfError(Create(aNumBits));
118 Create the vector with the size of aNumBits bits.
119 @return system-wide error codes:
120 KErrNoMemory unable to allocate sufficient amount of memory for the array
121 KErrInUse an attempt to call Create() for non-empty vector. Close it first.
122 KErrArgument invalid aNumBits value == 0
124 TInt RBitVector::Create(TUint32 aNumBits)
128 return KErrInUse; //-- array is already in use. Close it first.
133 //-- memory is allocated by word (32 bit) quiantities
134 const TUint32 numWords = (aNumBits >> 5) + ((aNumBits & 0x1F) > 0 ? 1:0);
135 ipData = (TUint32*)User::AllocZ(numWords << 2);
141 iNumWords = numWords;
148 Fill a bit vector with a given bit value
149 @param aVal a bit value
151 void RBitVector::Fill(TBool aVal)
153 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
154 memset(ipData, (aVal ? 0xFF : 0x00), iNumWords << 2);
157 /** Invert all bits in a bit vector */
158 void RBitVector::Invert()
160 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
161 for(TUint32 i=0; i<iNumWords; ++i)
167 Perform "And" operation between 2 vectors. They shall be the same size.
168 @param aRhs a vector from the right hand side
169 @panic ESizeMismatch in the case of different vector sizes
171 void RBitVector::And(const RBitVector& aRhs)
173 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
174 __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
175 for(TUint32 i=0; i<iNumWords; ++i)
177 ipData[i] &= aRhs.ipData[i];
182 Perform "Or" operation between 2 vectors. They shall be the same size.
183 @param aRhs a vector from the right hand side
184 @panic ESizeMismatch in the case of different vector sizes
186 void RBitVector::Or(const RBitVector& aRhs)
188 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
189 __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
190 for(TUint32 i=0; i<iNumWords; ++i)
192 ipData[i] |= aRhs.ipData[i];
197 Perform "Xor" operation between 2 vectors. They shall be the same size.
198 @param aRhs a vector from the right hand side
199 @panic ESizeMismatch in the case of different vector sizes
201 void RBitVector::Xor(const RBitVector& aRhs)
203 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
204 __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
205 for(TUint32 i=0; i<iNumWords; ++i)
207 ipData[i] ^= aRhs.ipData[i];
211 //-----------------------------------------------------------------------------
213 Fill a range from bit number "aIndexFrom" to "aIndexTo" inclusively with the value of aVal
215 @param aIndexFrom start bit number (inclusive)
216 @param aIndexTo end bit number (inclusive)
217 @param aVal the value to be used to fill the range (0s or 1s)
219 void RBitVector::Fill(TUint32 aIndexFrom, TUint32 aIndexTo, TBool aVal)
221 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
223 //-- swap indexes if they are not in order
224 if(aIndexFrom > aIndexTo)
226 const TUint32 tmp = aIndexFrom;
227 aIndexFrom = aIndexTo;
231 __ASSERT_ALWAYS((aIndexFrom < iNumBits) && (aIndexTo < iNumBits), Panic(EIndexOutOfRange));
233 const TUint32 wordStart = WordNum(aIndexFrom);
234 const TUint32 wordTo = WordNum(aIndexTo);
237 {//-- filling a range with '1'
239 TUint32 shift = BitInWord(aIndexFrom);
240 const TUint32 mask1 = (K_FFFF >> shift) << shift;
242 TUint32 mask2 = K_FFFF;
243 shift = 1+BitInWord(aIndexTo);
246 mask2 = ~((mask2 >> shift) << shift);
249 if(wordTo == wordStart)
250 {//-- a special case, filling is in the same word
251 ipData[wordStart] |= (mask1 & mask2);
255 ipData[wordStart] |= mask1;
256 ipData[wordTo] |= mask2;
258 const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled
260 if(wholeWordsBetween)
261 memset(ipData+wordStart+1, 0xFF, wholeWordsBetween << 2);
266 {//-- filling a range with '0'
268 TUint32 shift = BitInWord(aIndexFrom);
269 const TUint32 mask1 = ~((K_FFFF >> shift) << shift);
272 shift = 1+BitInWord(aIndexTo);
275 mask2 = ((K_FFFF >> shift) << shift);
278 if(wordTo == wordStart)
279 {//-- a special case, filling is in the same word
280 ipData[wordStart] &= (mask1 | mask2);
284 ipData[wordStart] &= mask1;
285 ipData[wordTo] &= mask2;
287 const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled
289 if(wholeWordsBetween)
290 memset(ipData+wordStart+1, 0x00, wholeWordsBetween << 2);
297 //-----------------------------------------------------------------------------
300 Search for a specified bit value ('0' or '1') in the vector from the given position.
301 @param aStartPos zero-based index; from this position the search will start. This position isn't included to the search.
302 On return may contain a new position if the specified bit is found in specified direction.
303 @param aBitVal zero or non-zero bit to search.
304 @param aDir Specifies the search direction
306 @return ETrue if the specified bit value is found; aStartPos gets updated.
310 TBool RBitVector::Find(TUint32& aStartPos, TBool aBitVal, TFindDirection aDir) const
312 __ASSERT_ALWAYS(aStartPos < iNumBits, Panic(EIndexOutOfRange));
313 ASSERT(iNumWords && ipData);
317 case ERight: //-- Search from the given position to the right
318 return FindToRight(aStartPos, aBitVal);
320 case ELeft: //-- Search from the given position to the left (towards lower index)
321 return FindToLeft(aStartPos, aBitVal);
323 case ENearestL: //-- Search for the nearest value in both directions starting from left
324 return FindNearest(aStartPos, aBitVal, ETrue);
326 case ENearestR: //-- Search for the nearest value in both directions starting from right
327 return FindNearest(aStartPos, aBitVal, EFalse);
330 Panic(EWrondFindDirection);
337 //-----------------------------------------------------------------------------
339 Internal method to look for a given bit value in the right direction.
340 see TBool RBitVector::Find(...)
342 TBool RBitVector::FindToRight(TUint32& aStartPos, TBool aBitVal) const
344 if(aStartPos >= iNumBits-1)
345 return EFalse; //-- no way to the right
347 const TUint32 startPos = aStartPos+1;
348 const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
350 TUint32 wordNum = WordNum(startPos);
351 TUint32 val = ipData[wordNum] ^ fInvert;
353 if(wordNum == iNumWords-1)
354 {//-- process the last word in the array, some higher bits might not belong to the bit vector
355 val = MaskLastWord(val);
358 const TUint32 shift = BitInWord(startPos);
359 val = (val >> shift) << shift; //-- mask unused low bits
362 {//-- there are '1' bits in the current word
366 {//-- search in higher words
369 while(iNumWords-wordNum > 1)
371 val = ipData[wordNum] ^ fInvert;
378 if(wordNum == iNumWords-1)
379 {//-- process the last word in the array, some higher bith might not belong to the bit vector
380 val = ipData[wordNum] ^ fInvert;
381 val = MaskLastWord(val);
388 return EFalse; //-- haven't found anything
392 val &= (~val+1); //-- select rightmost bit
393 aStartPos = (wordNum << 5)+Log2(val);
398 //-----------------------------------------------------------------------------
401 Internal method to look for a given bit value in the left direction.
402 see TBool RBitVector::Find(...)
404 TBool RBitVector::FindToLeft(TUint32& aStartPos, TBool aBitVal) const
407 return EFalse; //-- no way to the left
409 const TUint32 startPos=aStartPos-1;
410 const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
412 TUint32 wordNum = WordNum(startPos);
413 TUint32 val = ipData[wordNum] ^ fInvert;
415 const TUint32 shift = 31-(BitInWord(startPos));
416 val = (val << shift) >> shift; //-- mask unused high bits
419 {//-- there are '1' bits in the current word
423 {//-- search in the lower words
427 val=ipData[wordNum] ^ fInvert;
433 return EFalse; //-- nothing found
436 aStartPos = (wordNum << 5)+Log2(val);
440 //-----------------------------------------------------------------------------
443 Internal method to look for a given bit value in the both directions.
444 see TBool RBitVector::Find(...)
446 TBool RBitVector::FindNearest(TUint32& aStartPos, TBool aBitVal, TBool aToLeft) const
452 return FindToRight(aStartPos, aBitVal);
454 if(aStartPos == iNumBits-1)
455 return FindToLeft(aStartPos, aBitVal);
458 const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
460 TUint32 wordNum = WordNum(aStartPos);
461 TUint32 l_Idx; //-- index of the word to the left
462 TUint32 r_Idx; //-- index of the word to the right
464 l_Idx = r_Idx = wordNum;
466 TBool noWayLeft = (wordNum == 0); //-- if we are in the first word
467 TBool noWayRight = (wordNum == iNumWords-1); //-- if we are in the last word
469 //-- look in the current word first
470 TUint32 val = ipData[wordNum] ^ fInvert;
473 { //-- this is the last word in the array, mask unused high bits in the last word
474 val = MaskLastWord(val);
477 const TUint32 bitPos = aStartPos & 0x1F;
478 val &= ~(1<<bitPos); //-- mask the bit at current position
481 {//-- no '1' bits in the current word
482 noWayLeft = ItrLeft(l_Idx);
483 noWayRight = ItrRight(r_Idx);
487 noWayLeft = ItrLeft(l_Idx); //-- move to the previous word
489 else if(bitPos == 31)
491 noWayRight = ItrRight(r_Idx); //-- move to the next word
494 {//-- look in the current word, in both halves to the left and right from the start position
496 const TUint32 shift1 = 32-bitPos;
497 const TUint32 partLo = (val << shift1) >> shift1; //-- towards lower bits
499 const TUint32 shift2 = bitPos+1;
500 const TUint32 partHi = (val >> shift2) << shift2; //-- towards higher bits
503 if(partLo && !partHi) //-- only lower part has '1' bits
505 aStartPos = (wordNum << 5)+Log2(partLo);
508 else if(!partLo && partHi) //-- only higher part has '1' bits
510 aStartPos = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
513 else if(partLo && partHi) //-- both parts contain '1' bits, select the nearest one
515 const TUint32 posL = (wordNum << 5)+Log2(partLo);
516 const TUint32 posR = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
518 ASSERT(aStartPos > posL);
519 ASSERT(posR > aStartPos);
520 const TUint32 distL = aStartPos-posL;
521 const TUint32 distR = posR-aStartPos;
528 else if(distL > distR)
534 {//-- distL == distR, take into account search priority
535 aStartPos = aToLeft ? posL : posR;
539 else //-- (!partLo && !partHi), nothing in the current word
544 }// if(bitPos > 0 && bitPos < 31)
546 //-- now we are processing separate words from both sides of the search position
549 TUint32 wL = ipData[l_Idx] ^ fInvert;
550 TUint32 wR = ipData[r_Idx] ^ fInvert;
551 if(r_Idx == iNumWords-1)
552 { //-- this is the last word in the array, mask unused high bits in the last word
553 wR = MaskLastWord(wR);
558 aStartPos = (l_Idx << 5)+Log2(wL);
563 aStartPos = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
568 const TUint32 posL = (l_Idx << 5)+Log2(wL);
569 const TUint32 posR = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
571 ASSERT(aStartPos > posL);
572 ASSERT(posR > aStartPos);
573 const TUint32 distL = aStartPos-posL;
574 const TUint32 distR = posR-aStartPos;
581 else if(distL > distR)
587 {//-- distL == distR, take into account search priority
588 aStartPos = aToLeft ? posL : posR;
597 aStartPos = r_Idx << 5;
598 return FindToRight(aStartPos, aBitVal);
602 noWayLeft = ItrLeft(l_Idx);
607 aStartPos = l_Idx << 5;
608 return FindToLeft(aStartPos, aBitVal);
612 noWayRight = ItrRight(r_Idx);
620 //-----------------------------------------------------------------------------
622 Find out if two vectors are different.
624 @param aRhs vector to compare with
625 @param aDiffIndex if there is a differene, here will be the number of the first different bit
626 @return ETrue if vectors differ, EFalse, if they are identical.
628 TBool RBitVector::Diff(const RBitVector& aRhs, TUint32& aDiffIndex) const
630 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
631 __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
632 ASSERT(iNumWords > 0);
637 //-- compare all but the last word in the array
638 for(wordNum=0; wordNum < iNumWords-1; ++wordNum)
640 diffWord = ipData[wordNum] ^ aRhs.ipData[wordNum];
642 break; //-- found difference
645 //-- process the last word in the array
648 diffWord = MaskLastWord(ipData[wordNum]) ^ MaskLastWord(aRhs.ipData[wordNum]);
652 return EFalse; //-- vectors are the same
654 //-- calculate the position of the bit that different.
655 diffWord &= (~diffWord+1); //-- select rightmost bit
656 aDiffIndex = (wordNum << 5)+Log2(diffWord);
661 //-----------------------------------------------------------------------------
664 Iterate to the left (towards lower index) in the array of words ipData
666 @param aIdx index within ipData array to be decremented; if it's possible to move left, it will be decreased
667 @return ETrue if there is no way left i.e. aIdx is 0. EFalse otherwise and aIdx decreased.
669 TBool RBitVector::ItrLeft(TUint32& aIdx) const
680 //-----------------------------------------------------------------------------
683 Iterate to the right (towards higher index) in the array of words ipData
685 @param aIdx index within ipData array to be incremented; if it's possible to move right, it will be increased
686 @return ETrue if there is no way right i.e. aIdx corresponds to the last word. EFalse otherwise and aIdx increased.
688 TBool RBitVector::ItrRight(TUint32& aIdx) const
690 if(aIdx < iNumWords-1)
699 //-----------------------------------------------------------------------------
702 Import data to the internal bit vector representation.
703 Just replaces number of bytes from apData to the ipData.
705 @param aStartBit starting bit number. Must have 8-bit alignment.
706 @param aNumBits number of bits to import; granularity: 1 bit, i.e. it can be 177, for example.
707 @param apData pointer to the data (bitstream) to import.
710 void RBitVector::DoImportData(TUint32 aStartBit, TUint32 aNumBits, const TAny* apData)
713 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
715 //-- check parameters granularity. aStartBit must have 8-bit alignment
716 __ASSERT_ALWAYS(!(aStartBit & 0x07), Panic(EDataAlignment));
719 __ASSERT_ALWAYS(iNumWords && (aStartBit+aNumBits <= iNumBits), Panic(EIndexOutOfRange));
721 const TUint bitsTail = aNumBits & 0x07;
722 const TUint32 nBytes = aNumBits >> 3;
725 {//-- copy full array of bytes
726 const TUint32 startByte = aStartBit >> 3;
727 Mem::Copy(((TUint8*)ipData) + startByte, apData, nBytes);
731 {//-- we need to copy trailing bits from the input data to the corresponding byte of the internal array
732 const TUint8 mask = (TUint8)(0xFF >> (8-bitsTail));
733 const TUint8 orMask = (TUint8)( *((const TUint8*)apData + nBytes) & mask);
734 const TUint8 andMask= (TUint8)~mask;
736 TUint8* pbData = (TUint8*)ipData + nBytes;
743 //-----------------------------------------------------------------------------
746 Export data from the internal bit vector buffer to the external one.
748 @param aStartBit starting bit number. Must have 8-bit alignment.
749 @param aNumBits number of bits to export, must comprise the whole byte, i.e. be multiple of 8.
750 The client is responsible for masking extra bits it doesn't need.
751 Another implication: e.g. if the bitvector consists of 3 bits, this value must be 8.
752 The value of bits 3-7 in the aData[0] will be undefined.
754 @param aData destination data descriptor
756 void RBitVector::DoExportData(TUint32 aStartBit, TUint32 aNumBits, TDes8& aData) const
759 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
761 //-- check parameters granularity.
762 __ASSERT_ALWAYS(!(aStartBit & 0x07), Panic(EDataAlignment)); //-- aStartBit must have 8-bit alignment
763 __ASSERT_ALWAYS(!(aNumBits & 0x07), Panic(EDataAlignment)); //-- number of bits shall comprise a byte
765 __ASSERT_ALWAYS(iNumWords && (aStartBit+aNumBits <= (iNumWords << (KBitsInByteLog2+sizeof(TUint32))) ), Panic(EIndexOutOfRange));
767 const TUint32 nBytes = aNumBits >> 3;
768 const TUint32 startByte = aStartBit >> 3;
770 aData.SetLength(nBytes);
771 aData.Copy(((const TUint8*)ipData) + startByte, nBytes);
774 //-----------------------------------------------------------------------------
777 @return number of bits set to '1' in the vector
779 TUint32 RBitVector::Num1Bits() const
781 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
788 for(wordNum=0; wordNum < iNumWords-1; ++wordNum)
790 cntBits += Count1Bits(ipData[wordNum]);
793 //-- process the last word, it shall be masked
794 cntBits += Count1Bits(MaskLastWord(ipData[wordNum]));
799 //-----------------------------------------------------------------------------
801 @return number of bits set to '0' in the vector
803 TUint32 RBitVector::Num0Bits() const
805 return iNumBits - Num1Bits();
809 //-----------------------------------------------------------------------------
811 Calculate number of '1' bits in the range from aIndexFrom to aIndexTo inclusively
813 @param aIndexFrom starting index; bit[aIndexFrom] is included to the search
814 @param aIndexTo ending index; bit[aIndexTo] is included to the search
815 @return number of bits set to '1' in the slice
817 TUint32 RBitVector::Num1Bits(TUint32 aIndexFrom, TUint32 aIndexTo) const
819 __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
820 __ASSERT_ALWAYS(aIndexTo < iNumBits && aIndexFrom <= aIndexTo, Panic(EIndexOutOfRange));
822 const TUint32 wordFrom = WordNum(aIndexFrom); //?const
823 const TUint32 wordTo = WordNum(aIndexTo);
825 if(wordFrom == wordTo)
827 TUint32 word = ipData[wordFrom];
829 const TUint32 shMaskR = BitInWord(aIndexFrom);
830 word >>= shMaskR; word <<= shMaskR; //-- zero low bits
832 const TUint32 shMaskL = 31-BitInWord(aIndexTo);
833 word <<= shMaskL; //-- zero high bits
835 return Count1Bits(word);
839 TUint32 wordsBetween = wordTo - wordFrom - 1;
841 //-- count '1' bits in the termial words
842 TUint32 word = ipData[wordFrom];
843 const TUint32 shMaskR = BitInWord(aIndexFrom);
844 word >>= shMaskR; //-- zero low bits
845 bitsCnt += Count1Bits(word);
847 word = ipData[wordTo];
848 const TUint32 shMaskL = 31-BitInWord(aIndexTo);
849 word <<= shMaskL; //-- zero high bits
850 bitsCnt += Count1Bits(word);
852 //-- count '1' bits in the words between terminal ones
853 TUint32 wordIdx = wordFrom+1;
854 while(wordsBetween--)
856 bitsCnt += Count1Bits(ipData[wordIdx]);