userlibandfileserver/fileserver/fs_utils/bit_vector.cpp
changeset 36 538db54a451d
child 291 206a6eaaeb71
equal deleted inserted replaced
34:f497542af8e4 36:538db54a451d
       
     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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    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
       
    17 //
       
    18 //  This is the internal file and must not be exported.
       
    19 
       
    20 /**
       
    21     @file
       
    22     @internalTechnology
       
    23 */
       
    24 
       
    25 #include "bit_vector.h"
       
    26 
       
    27 
       
    28 //#######################################################################################################################################
       
    29 //#   RBitVector class implementation
       
    30 //#######################################################################################################################################
       
    31 
       
    32 const TUint32 K_FFFF = 0xFFFFFFFF; //-- all one bits, beware rigth shifts of signed integers!
       
    33 
       
    34 RBitVector::RBitVector()
       
    35           :iNumBits(0), ipData(NULL), iNumWords(0)
       
    36     {
       
    37     }
       
    38 
       
    39 
       
    40 RBitVector::~RBitVector()
       
    41     {
       
    42     Close();
       
    43     }
       
    44 
       
    45 /**
       
    46     Panics.
       
    47     @param aPanicCode   a panic code
       
    48 */
       
    49 void RBitVector::Panic(TPanicCode aPanicCode) const
       
    50     {
       
    51     _LIT(KPanicCat,"RBitVector");
       
    52     User::Panic(KPanicCat, aPanicCode);
       
    53     }
       
    54 
       
    55 /** explicitly closes the object and deallocates memory */
       
    56 void RBitVector::Close()
       
    57     {
       
    58     iNumBits = 0;
       
    59     iNumWords =0;
       
    60     User::Free(ipData);
       
    61     ipData = NULL;
       
    62     }
       
    63 
       
    64 //-----------------------------------------------------------------------------
       
    65 
       
    66 /**
       
    67     Comparison perator.
       
    68     @param  aRhs a vector to compate with.
       
    69     @panic ESizeMismatch in the case of different vector sizes
       
    70 */
       
    71 TBool RBitVector::operator==(const RBitVector& aRhs) const
       
    72     {
       
    73     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
    74     __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
       
    75 
       
    76 
       
    77     if(!iNumBits)
       
    78         return ETrue; //-- comparing 0-lenght arrays
       
    79 
       
    80     if(this == &aRhs)
       
    81         {//-- comparing with itself, potential source of errors
       
    82         ASSERT(0);
       
    83         return ETrue; 
       
    84         }
       
    85     
       
    86     if(iNumWords >= 1)
       
    87         {
       
    88         const TUint32 cntBytes = (iNumBits >> 5) << 2; //-- bytes to compare
       
    89         if(memcompare((const TUint8*)ipData, cntBytes, (const TUint8*)aRhs.ipData, cntBytes))
       
    90             return EFalse;
       
    91         }
       
    92 
       
    93     const TUint32 bitsRest  = iNumBits & 0x1F;
       
    94     if(bitsRest)
       
    95         {
       
    96         const TUint32 mask = K_FFFF >> (32-bitsRest);
       
    97         return ( (ipData[iNumWords-1] & mask) == (aRhs.ipData[iNumWords-1] & mask) );
       
    98         }
       
    99     
       
   100     return ETrue;
       
   101     }
       
   102 
       
   103 TBool RBitVector::operator!=(const RBitVector& aRhs) const  
       
   104     {
       
   105     return ! ((*this) == aRhs);
       
   106     } 
       
   107 
       
   108 //-----------------------------------------------------------------------------
       
   109 
       
   110 /** The same as Create(), but leaves on error */
       
   111 void RBitVector::CreateL(TUint32 aNumBits)
       
   112     {
       
   113     User::LeaveIfError(Create(aNumBits));
       
   114     }
       
   115 
       
   116 
       
   117 /**
       
   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
       
   123 */
       
   124 TInt RBitVector::Create(TUint32 aNumBits)
       
   125     {
       
   126 
       
   127     if(ipData)
       
   128         return KErrInUse; //-- array is already in use. Close it first.
       
   129 
       
   130     if(!aNumBits)
       
   131         return KErrArgument;
       
   132 
       
   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);
       
   136 
       
   137     if(!ipData)
       
   138         return KErrNoMemory;
       
   139 
       
   140     iNumBits  = aNumBits;
       
   141     iNumWords = numWords;
       
   142 
       
   143     return KErrNone;
       
   144     }
       
   145 
       
   146 
       
   147 /**
       
   148     Fill a bit vector with a given bit value
       
   149     @param aVal a bit value
       
   150 */
       
   151 void RBitVector::Fill(TBool aVal)
       
   152     {
       
   153     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   154     memset(ipData, (aVal ? 0xFF : 0x00), iNumWords << 2);
       
   155     }
       
   156 
       
   157 /** Invert all bits in a bit vector */
       
   158 void RBitVector::Invert()
       
   159 {
       
   160     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   161     for(TUint32 i=0; i<iNumWords; ++i)
       
   162         ipData[i] ^= K_FFFF;
       
   163 }
       
   164 
       
   165 
       
   166 /**
       
   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
       
   170 */
       
   171 void RBitVector::And(const RBitVector& aRhs)
       
   172     {
       
   173     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   174     __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
       
   175     for(TUint32 i=0; i<iNumWords; ++i)
       
   176         {
       
   177         ipData[i] &= aRhs.ipData[i];
       
   178         }
       
   179     }
       
   180 
       
   181 /**
       
   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
       
   185 */
       
   186 void RBitVector::Or(const RBitVector& aRhs)
       
   187     {
       
   188     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   189     __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
       
   190     for(TUint32 i=0; i<iNumWords; ++i)
       
   191         {
       
   192         ipData[i] |= aRhs.ipData[i];
       
   193         }
       
   194     }
       
   195 
       
   196 /**
       
   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
       
   200 */
       
   201 void RBitVector::Xor(const RBitVector& aRhs)
       
   202     {
       
   203     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   204     __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
       
   205     for(TUint32 i=0; i<iNumWords; ++i)
       
   206         {
       
   207         ipData[i] ^= aRhs.ipData[i];
       
   208         }
       
   209     }
       
   210 
       
   211 //-----------------------------------------------------------------------------
       
   212 /**
       
   213     Fill a range from bit number "aIndexFrom" to "aIndexTo" inclusively with the value of aVal
       
   214     
       
   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)
       
   218 */
       
   219 void RBitVector::Fill(TUint32 aIndexFrom, TUint32 aIndexTo, TBool aVal)
       
   220     {
       
   221     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   222 
       
   223     //-- swap indexes if they are not in order
       
   224     if(aIndexFrom > aIndexTo)
       
   225         {
       
   226         const TUint32 tmp = aIndexFrom;
       
   227         aIndexFrom = aIndexTo;
       
   228         aIndexTo = tmp;
       
   229         }
       
   230 
       
   231     __ASSERT_ALWAYS((aIndexFrom < iNumBits) && (aIndexTo < iNumBits), Panic(EIndexOutOfRange));
       
   232 
       
   233     const TUint32 wordStart = WordNum(aIndexFrom);
       
   234     const TUint32 wordTo    = WordNum(aIndexTo);
       
   235 
       
   236     if(aVal)
       
   237         {//-- filling a range with '1'
       
   238         
       
   239         TUint32 shift = BitInWord(aIndexFrom);
       
   240         const TUint32 mask1 = (K_FFFF >> shift) << shift;
       
   241 
       
   242         TUint32 mask2 = K_FFFF;
       
   243         shift = 1+BitInWord(aIndexTo);
       
   244         if(shift < 32)
       
   245             {
       
   246             mask2 = ~((mask2 >> shift) << shift);
       
   247             }
       
   248 
       
   249         if(wordTo == wordStart)
       
   250             {//-- a special case, filling is in the same word
       
   251             ipData[wordStart] |= (mask1 & mask2);
       
   252             }
       
   253         else
       
   254             {
       
   255             ipData[wordStart] |= mask1; 
       
   256             ipData[wordTo]    |= mask2;
       
   257             
       
   258             const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled
       
   259 
       
   260             if(wholeWordsBetween)
       
   261                 memset(ipData+wordStart+1, 0xFF, wholeWordsBetween << 2);
       
   262                             
       
   263             }
       
   264         }
       
   265     else
       
   266         {//-- filling a range with '0'
       
   267         
       
   268         TUint32 shift = BitInWord(aIndexFrom);
       
   269         const TUint32 mask1 = ~((K_FFFF >> shift) << shift);
       
   270 
       
   271         TUint32 mask2 = 0;
       
   272         shift = 1+BitInWord(aIndexTo);
       
   273         if(shift < 32)
       
   274             {
       
   275             mask2 = ((K_FFFF >> shift) << shift);
       
   276             }
       
   277 
       
   278         if(wordTo == wordStart)
       
   279             {//-- a special case, filling is in the same word
       
   280             ipData[wordStart] &= (mask1 | mask2);
       
   281             }
       
   282         else
       
   283             {
       
   284             ipData[wordStart] &= mask1; 
       
   285             ipData[wordTo]    &= mask2;
       
   286             
       
   287             const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled
       
   288 
       
   289             if(wholeWordsBetween)
       
   290                 memset(ipData+wordStart+1, 0x00, wholeWordsBetween << 2);
       
   291                             
       
   292             }
       
   293         }
       
   294 
       
   295     }
       
   296 
       
   297 //-----------------------------------------------------------------------------
       
   298 
       
   299 /**
       
   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
       
   305 
       
   306     @return ETrue if the specified bit value is found; aStartPos gets updated.
       
   307             EFalse otherwise.
       
   308 
       
   309 */
       
   310 TBool RBitVector::Find(TUint32& aStartPos, TBool aBitVal, TFindDirection aDir) const
       
   311     {
       
   312     __ASSERT_ALWAYS(aStartPos < iNumBits, Panic(EIndexOutOfRange));
       
   313     ASSERT(iNumWords && ipData);
       
   314 
       
   315     switch(aDir)
       
   316         {
       
   317         case ERight:    //-- Search from the given position to the right
       
   318             return FindToRight(aStartPos, aBitVal);
       
   319 
       
   320         case ELeft:     //-- Search from the given position to the left (towards lower index)
       
   321             return FindToLeft(aStartPos, aBitVal);
       
   322 
       
   323         case ENearestL: //-- Search for the nearest value in both directions starting from left
       
   324             return FindNearest(aStartPos, aBitVal, ETrue);
       
   325 
       
   326         case ENearestR: //-- Search for the nearest value in both directions starting from right
       
   327             return FindNearest(aStartPos, aBitVal, EFalse);
       
   328 
       
   329         default:
       
   330             Panic(EWrondFindDirection);
       
   331             return EFalse;
       
   332 
       
   333         };
       
   334     
       
   335     }
       
   336 
       
   337 //-----------------------------------------------------------------------------
       
   338 /**
       
   339     Internal method to look for a given bit value in the right direction.
       
   340     see TBool RBitVector::Find(...)
       
   341 */
       
   342 TBool RBitVector::FindToRight(TUint32& aStartPos, TBool aBitVal) const
       
   343     {
       
   344     if(aStartPos >= iNumBits-1)
       
   345         return EFalse; //-- no way to the right
       
   346 
       
   347     const TUint32 startPos = aStartPos+1;
       
   348     const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
       
   349 
       
   350     TUint32 wordNum = WordNum(startPos);
       
   351     TUint32 val = ipData[wordNum] ^ fInvert;
       
   352 
       
   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);
       
   356         }
       
   357 
       
   358     const TUint32 shift = BitInWord(startPos);
       
   359     val = (val >> shift) << shift; //-- mask unused low bits
       
   360 
       
   361     if(val)
       
   362         {//-- there are '1' bits in the current word
       
   363         goto found;
       
   364         }
       
   365     else
       
   366         {//-- search in higher words
       
   367         wordNum++;
       
   368 
       
   369         while(iNumWords-wordNum > 1)
       
   370             {
       
   371             val = ipData[wordNum] ^ fInvert;
       
   372             if(val)
       
   373                 goto found;
       
   374 
       
   375             wordNum++;
       
   376             }
       
   377 
       
   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);
       
   382 
       
   383             if(val)
       
   384                 goto found;
       
   385             }
       
   386         }
       
   387 
       
   388     return EFalse; //-- haven't found anything
       
   389 
       
   390   found:
       
   391 
       
   392     val &= (~val+1); //-- select rightmost bit
       
   393     aStartPos = (wordNum << 5)+Log2(val);
       
   394     return ETrue;
       
   395     }
       
   396 
       
   397 
       
   398 //-----------------------------------------------------------------------------
       
   399 
       
   400 /**
       
   401     Internal method to look for a given bit value in the left direction.
       
   402     see TBool RBitVector::Find(...)
       
   403 */
       
   404 TBool RBitVector::FindToLeft(TUint32& aStartPos, TBool aBitVal) const
       
   405 {
       
   406     if(!aStartPos)
       
   407         return EFalse; //-- no way to the left
       
   408     
       
   409     const TUint32 startPos=aStartPos-1;
       
   410     const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
       
   411 
       
   412     TUint32 wordNum = WordNum(startPos);
       
   413     TUint32 val = ipData[wordNum] ^ fInvert;
       
   414 
       
   415     const TUint32 shift = 31-(BitInWord(startPos));
       
   416     val = (val << shift) >> shift; //-- mask unused high bits
       
   417 
       
   418     if(val)
       
   419     {//-- there are '1' bits in the current word
       
   420         goto found;
       
   421     }
       
   422     else
       
   423     {//-- search in the lower words
       
   424         while(wordNum)
       
   425         {
       
   426             wordNum--;
       
   427             val=ipData[wordNum] ^ fInvert;
       
   428             if(val)
       
   429                 goto found;
       
   430         }
       
   431     }
       
   432 
       
   433     return EFalse; //-- nothing found
       
   434 
       
   435  found:
       
   436     aStartPos = (wordNum << 5)+Log2(val);
       
   437     return ETrue;
       
   438 }
       
   439 
       
   440 //-----------------------------------------------------------------------------
       
   441 
       
   442 /**
       
   443     Internal method to look for a given bit value in the both directions.
       
   444     see TBool RBitVector::Find(...)
       
   445 */
       
   446 TBool RBitVector::FindNearest(TUint32& aStartPos, TBool aBitVal, TBool aToLeft) const
       
   447 {
       
   448     if(iNumBits < 2)
       
   449         return EFalse;
       
   450 
       
   451     if(aStartPos == 0)
       
   452         return FindToRight(aStartPos, aBitVal);
       
   453 
       
   454     if(aStartPos == iNumBits-1)
       
   455         return FindToLeft(aStartPos, aBitVal);
       
   456 
       
   457     
       
   458     const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
       
   459     
       
   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
       
   463     
       
   464     l_Idx = r_Idx = wordNum;
       
   465 
       
   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
       
   468 
       
   469     //-- look in the current word first
       
   470     TUint32 val = ipData[wordNum] ^ fInvert;
       
   471     
       
   472     if(noWayRight)
       
   473     {   //-- this is the last word in the array, mask unused high bits in the last word
       
   474         val = MaskLastWord(val);
       
   475     }
       
   476 
       
   477     const TUint32 bitPos = aStartPos & 0x1F;
       
   478     val &= ~(1<<bitPos); //-- mask the bit at current position
       
   479     
       
   480     if(val == 0)
       
   481     {//-- no '1' bits in the current word
       
   482         noWayLeft  = ItrLeft(l_Idx);
       
   483         noWayRight = ItrRight(r_Idx);
       
   484     }
       
   485     else if(bitPos == 0)
       
   486     {
       
   487         noWayLeft = ItrLeft(l_Idx); //-- move to the previous word
       
   488     }
       
   489     else if(bitPos == 31)
       
   490     {
       
   491         noWayRight = ItrRight(r_Idx); //-- move to the next word
       
   492     }
       
   493     else
       
   494     {//-- look in the current word, in both halves to the left and right from the start position
       
   495         
       
   496         const TUint32 shift1 = 32-bitPos;
       
   497         const TUint32 partLo = (val << shift1) >> shift1; //-- towards lower bits
       
   498 
       
   499         const TUint32 shift2 = bitPos+1;
       
   500         const TUint32 partHi = (val >> shift2) << shift2; //-- towards higher bits 
       
   501         
       
   502 
       
   503         if(partLo && !partHi) //-- only lower part has '1' bits   
       
   504         {
       
   505             aStartPos = (wordNum << 5)+Log2(partLo);
       
   506             return ETrue;
       
   507         }
       
   508         else if(!partLo && partHi) //-- only higher part has '1' bits
       
   509         {
       
   510             aStartPos = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
       
   511             return ETrue;
       
   512         }
       
   513         else if(partLo && partHi) //-- both parts contain '1' bits, select the nearest one
       
   514         {
       
   515             const TUint32 posL = (wordNum << 5)+Log2(partLo);
       
   516             const TUint32 posR = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
       
   517         
       
   518             ASSERT(aStartPos > posL);
       
   519             ASSERT(posR > aStartPos);
       
   520             const TUint32 distL = aStartPos-posL;
       
   521             const TUint32 distR = posR-aStartPos;
       
   522 
       
   523             if(distL < distR)
       
   524             {
       
   525                 aStartPos = posL;
       
   526                 return ETrue;
       
   527             }
       
   528             else if(distL > distR)
       
   529             {
       
   530                 aStartPos = posR;
       
   531                 return ETrue;
       
   532             }
       
   533             else
       
   534             {//-- distL == distR, take into account search priority
       
   535                 aStartPos = aToLeft ? posL : posR;
       
   536                 return ETrue;
       
   537             }
       
   538         }
       
   539         else //-- (!partLo && !partHi), nothing in the current word
       
   540         {
       
   541             ASSERT(0);
       
   542         }
       
   543 
       
   544     }// if(bitPos > 0 && bitPos < 31)
       
   545 
       
   546     //-- now we are processing separate words from both sides of the search position
       
   547     for(;;)
       
   548     { 
       
   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);
       
   554         }
       
   555 
       
   556         if(wL && !wR)
       
   557         {
       
   558             aStartPos = (l_Idx << 5)+Log2(wL);
       
   559             return ETrue;
       
   560         }
       
   561         else if(!wL && wR)
       
   562         {
       
   563             aStartPos = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
       
   564             return ETrue;
       
   565         }
       
   566         else if(wL && wR)
       
   567         {
       
   568             const TUint32 posL = (l_Idx << 5)+Log2(wL);
       
   569             const TUint32 posR = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
       
   570         
       
   571             ASSERT(aStartPos > posL);
       
   572             ASSERT(posR > aStartPos);
       
   573             const TUint32 distL = aStartPos-posL;
       
   574             const TUint32 distR = posR-aStartPos;
       
   575 
       
   576             if(distL < distR)
       
   577             {
       
   578                 aStartPos = posL;
       
   579                 return ETrue;
       
   580             }
       
   581             else if(distL > distR)
       
   582             {
       
   583                 aStartPos = posR;
       
   584                 return ETrue;
       
   585             }
       
   586             else
       
   587             {//-- distL == distR, take into account search priority
       
   588                 aStartPos = aToLeft ? posL : posR;
       
   589                 return ETrue;
       
   590             }
       
   591 
       
   592         }//else if(wL && wR)
       
   593 
       
   594 
       
   595         if(noWayLeft)
       
   596         {
       
   597             aStartPos = r_Idx << 5;
       
   598             return FindToRight(aStartPos, aBitVal);
       
   599         }
       
   600         else
       
   601         {
       
   602             noWayLeft  = ItrLeft(l_Idx);
       
   603         }
       
   604 
       
   605         if(noWayRight)
       
   606         {
       
   607             aStartPos = l_Idx << 5;
       
   608             return FindToLeft(aStartPos, aBitVal);
       
   609         }
       
   610         else
       
   611         {    
       
   612             noWayRight = ItrRight(r_Idx);
       
   613         }
       
   614 
       
   615    }//for(;;)
       
   616 
       
   617     //return EFalse;
       
   618 }
       
   619 
       
   620 //-----------------------------------------------------------------------------
       
   621 /**
       
   622     Find out if two vectors are different.
       
   623 
       
   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.
       
   627 */
       
   628 TBool RBitVector::Diff(const RBitVector& aRhs, TUint32& aDiffIndex) const
       
   629 {
       
   630     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   631     __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
       
   632     ASSERT(iNumWords > 0);
       
   633 
       
   634     TUint32 diffWord=0;
       
   635     TUint32 wordNum=0;
       
   636 
       
   637     //-- compare all but the last word in the array
       
   638     for(wordNum=0; wordNum < iNumWords-1; ++wordNum)
       
   639     {
       
   640         diffWord = ipData[wordNum] ^ aRhs.ipData[wordNum];
       
   641         if(diffWord)
       
   642             break;  //-- found difference
       
   643     }
       
   644 
       
   645     //-- process the last word in the array
       
   646     if(!diffWord)
       
   647     {
       
   648         diffWord = MaskLastWord(ipData[wordNum]) ^ MaskLastWord(aRhs.ipData[wordNum]);
       
   649     }
       
   650 
       
   651     if(!diffWord)
       
   652         return EFalse; //-- vectors are the same
       
   653 
       
   654     //-- calculate the position of the bit that different.
       
   655     diffWord &= (~diffWord+1); //-- select rightmost bit
       
   656     aDiffIndex = (wordNum << 5)+Log2(diffWord);
       
   657     
       
   658     return ETrue;
       
   659 }
       
   660 
       
   661 //-----------------------------------------------------------------------------
       
   662 
       
   663 /**
       
   664     Iterate to the left (towards lower index) in the array of words ipData
       
   665 
       
   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.
       
   668 */
       
   669 TBool RBitVector::ItrLeft(TUint32& aIdx) const
       
   670 {
       
   671     if(aIdx == 0)
       
   672         return ETrue;
       
   673     else
       
   674     {
       
   675         aIdx--;
       
   676         return EFalse;
       
   677     }
       
   678 }
       
   679 
       
   680 //-----------------------------------------------------------------------------
       
   681 
       
   682 /**
       
   683     Iterate to the right (towards higher index) in the array of words ipData
       
   684 
       
   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.
       
   687 */
       
   688 TBool RBitVector::ItrRight(TUint32& aIdx) const
       
   689 {
       
   690     if(aIdx < iNumWords-1)
       
   691     {
       
   692         aIdx++;
       
   693         return EFalse;
       
   694     }
       
   695     else
       
   696         return ETrue;
       
   697 }
       
   698 
       
   699 //-----------------------------------------------------------------------------
       
   700 
       
   701 /**
       
   702     Import data to the internal bit vector representation.
       
   703     Just replaces number of bytes from apData to the ipData.
       
   704 
       
   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.
       
   708 
       
   709 */
       
   710 void RBitVector::DoImportData(TUint32 aStartBit, TUint32 aNumBits, const TAny* apData)
       
   711 {
       
   712     ASSERT(aNumBits);
       
   713     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   714     
       
   715     //-- check parameters granularity. aStartBit must have 8-bit alignment
       
   716     __ASSERT_ALWAYS(!(aStartBit & 0x07), Panic(EDataAlignment));
       
   717 
       
   718 
       
   719     __ASSERT_ALWAYS(iNumWords && (aStartBit+aNumBits <= iNumBits), Panic(EIndexOutOfRange));
       
   720 
       
   721     const TUint     bitsTail = aNumBits & 0x07;
       
   722     const TUint32   nBytes = aNumBits >> 3;
       
   723  
       
   724     if(nBytes)
       
   725     {//-- copy full array of bytes
       
   726         const TUint32   startByte = aStartBit >> 3;
       
   727         Mem::Copy(((TUint8*)ipData) + startByte, apData, nBytes);
       
   728     }
       
   729 
       
   730     if(bitsTail)
       
   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;
       
   735 
       
   736         TUint8* pbData = (TUint8*)ipData + nBytes;
       
   737         *pbData &= andMask;
       
   738         *pbData |= orMask;
       
   739     }
       
   740 
       
   741 }
       
   742 
       
   743 //-----------------------------------------------------------------------------
       
   744 
       
   745 /**
       
   746     Export data from the internal bit vector buffer to the external one.
       
   747 
       
   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.
       
   753 
       
   754     @param aData     destination data descriptor   
       
   755 */
       
   756 void  RBitVector::DoExportData(TUint32 aStartBit, TUint32 aNumBits, TDes8& aData) const
       
   757 {
       
   758     ASSERT(aNumBits);
       
   759     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   760 
       
   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
       
   764 
       
   765     __ASSERT_ALWAYS(iNumWords && (aStartBit+aNumBits <= (iNumWords << (KBitsInByteLog2+sizeof(TUint32))) ), Panic(EIndexOutOfRange));
       
   766 
       
   767     const TUint32 nBytes = aNumBits >> 3;
       
   768     const TUint32 startByte = aStartBit >> 3;
       
   769     
       
   770     aData.SetLength(nBytes);
       
   771     aData.Copy(((const TUint8*)ipData) + startByte, nBytes);
       
   772 }
       
   773 
       
   774 //-----------------------------------------------------------------------------
       
   775 
       
   776 /**
       
   777     @return number of bits set to '1' in the vector
       
   778 */
       
   779 TUint32 RBitVector::Num1Bits() const
       
   780 {
       
   781     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   782     if(!iNumBits)
       
   783         return 0;
       
   784 
       
   785     TUint32 cntBits = 0;
       
   786 
       
   787     TUint32 wordNum;
       
   788     for(wordNum=0; wordNum < iNumWords-1; ++wordNum)
       
   789     {
       
   790         cntBits += Count1Bits(ipData[wordNum]);
       
   791     }
       
   792 
       
   793     //-- process the last word, it shall be masked
       
   794     cntBits += Count1Bits(MaskLastWord(ipData[wordNum]));
       
   795     
       
   796     return cntBits;
       
   797 }
       
   798 
       
   799 //-----------------------------------------------------------------------------
       
   800 /**
       
   801     @return number of bits set to '0' in the vector
       
   802 */
       
   803 TUint32 RBitVector::Num0Bits() const
       
   804 {
       
   805     return iNumBits - Num1Bits();
       
   806 }
       
   807 
       
   808 
       
   809 //-----------------------------------------------------------------------------
       
   810 /**
       
   811     Calculate number of '1' bits in the range from aIndexFrom to aIndexTo inclusively
       
   812 
       
   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
       
   816 */
       
   817 TUint32 RBitVector::Num1Bits(TUint32 aIndexFrom, TUint32 aIndexTo) const
       
   818 {
       
   819     __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
       
   820     __ASSERT_ALWAYS(aIndexTo < iNumBits && aIndexFrom <= aIndexTo, Panic(EIndexOutOfRange));
       
   821 
       
   822     const TUint32 wordFrom = WordNum(aIndexFrom); //?const
       
   823     const TUint32 wordTo   = WordNum(aIndexTo);
       
   824 
       
   825     if(wordFrom == wordTo)
       
   826     {//-- the same word
       
   827         TUint32 word = ipData[wordFrom];
       
   828 
       
   829         const TUint32 shMaskR = BitInWord(aIndexFrom);
       
   830         word >>= shMaskR; word <<= shMaskR; //-- zero low bits
       
   831 
       
   832         const TUint32 shMaskL = 31-BitInWord(aIndexTo);
       
   833         word <<= shMaskL;  //-- zero high bits
       
   834 
       
   835         return Count1Bits(word);
       
   836     } 
       
   837 
       
   838     TUint32 bitsCnt = 0;
       
   839     TUint32 wordsBetween = wordTo - wordFrom - 1;
       
   840 
       
   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);
       
   846 
       
   847     word = ipData[wordTo];
       
   848     const TUint32 shMaskL = 31-BitInWord(aIndexTo);
       
   849     word <<= shMaskL;  //-- zero high bits
       
   850     bitsCnt += Count1Bits(word);
       
   851 
       
   852     //-- count '1' bits in the words between terminal ones
       
   853     TUint32 wordIdx = wordFrom+1;
       
   854     while(wordsBetween--)
       
   855     {
       
   856         bitsCnt += Count1Bits(ipData[wordIdx]);
       
   857     }
       
   858     
       
   859 
       
   860     return bitsCnt;
       
   861 }
       
   862 
       
   863 
       
   864 
       
   865 
       
   866 
       
   867 
       
   868 
       
   869 
       
   870 
       
   871 
       
   872 
       
   873 
       
   874 
       
   875 
       
   876 
       
   877 
       
   878 
       
   879 
       
   880 
       
   881 
       
   882 
       
   883