bitvector.cpp

Go to the documentation of this file.
00001 /*
00002 This program is distributed under the terms of the 'MIT license'. The text
00003 of this licence follows...
00004 
00005 Copyright (c) 2007-2009 J.D.Medhurst (a.k.a. Tixy)
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00022 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00023 THE SOFTWARE.
00024 */
00025 
00032 #include "common.h"
00033 #include "bitvector.h"
00034 
00035 
00036 void BitVectorPointer::Reset()
00037     {
00038     unsigned* bits = Bits;
00039     unsigned* bitsEnd = Bits+((Size+BitVectorIndexMask)>>BitVectorIndexShift);
00040     unsigned zero = 0;
00041     while(bits<bitsEnd)
00042         *bits++ = zero;
00043     }
00044 
00045 
00046 int BitVectorPointer::Test(unsigned index)
00047     {
00048     ASSERT_DEBUG(index<Size);
00049     return (Bits[index>>BitVectorIndexShift]>>(index&BitVectorIndexMask))&1;
00050     }
00051 
00052 
00053 void BitVectorPointer::Set(unsigned index)
00054     {
00055     ASSERT_DEBUG(index<Size);
00056     Bits[index>>BitVectorIndexShift] |= 1<<(index&BitVectorIndexMask);
00057     }
00058 
00059 
00060 void BitVectorPointer::Clear(unsigned index)
00061     {
00062     ASSERT_DEBUG(index<Size);
00063     Bits[index>>BitVectorIndexShift] &= ~(1<<(index&BitVectorIndexMask));
00064     }
00065 
00066 
00067 #if defined(__GNUC__) && defined(_ARM) // ARM assembler versions...
00068 
00069 
00070 #if defined(DEBUG) && !defined(LOCAL_ASSERTFAILED_DEFINED)
00071 
00072 #define LOCAL_ASSERTFAILED_DEFINED
00073 
00074 static int AssertFailed(int line)
00075     {
00076     return AssertFailed(__FILE__,line);
00077     }
00078 
00079 #endif
00080 
00081 
00082 __attribute__((naked)) int BitVectorPointer::TestSet(unsigned /*index*/, size_t /*count*/)
00083     {
00084 #ifdef DEBUG
00085     asm("ldr    r3, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Size)));
00086     asm("add    r12, r1, r2");
00087     asm("cmp    r1, r3");
00088     asm("ldrhs  r0, =%a0"       : : "i" (__LINE__));
00089     asm("bhs    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index>=Size
00090     asm("cmp    r12, r1");
00091     asm("ldrls  r0, =%a0"       : : "i" (__LINE__));
00092     asm("bls    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count<=index
00093     asm("cmp    r12, r3");
00094     asm("ldrhi  r0, =%a0"       : : "i" (__LINE__));
00095     asm("bhi    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count>Size
00096 #endif
00097     // set r3 = ptr, r2 = startMask ...
00098     asm("ldr    r12, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Bits)));
00099     asm("mov    r0, r1, lsr #5");
00100     asm("add    r3, r12, r0, lsl #2");
00101     asm("and    r0, r1, #31");
00102     asm("add    r1, r1, r2");
00103     asm("sub    r1, r1, #1");
00104     asm("mvn    r2, #0");
00105     asm("mvn    r2, r2, lsl r0");
00106     // set r1 = end, r12 = endMask ...
00107     asm("mvn    r0, r1");
00108     asm("and    r0, r0, #31");
00109     asm("mov    r1, r1, lsr #5");
00110     asm("add    r1, r12, r1, lsl #2");
00111     asm("mvn    r12, #0");
00112     asm("mvn    r12, r12, lsr r0");
00113     // do first word...
00114     asm("cmp    r3, r1");
00115     asm("ldr    r0, [r3], #4");
00116     asm("orreq  r2, r2, r12");
00117     asm("orr    r0, r0, r2");
00118     asm("beq    9f");
00119     // do middle words...
00120     asm("cmp    r3, r1");
00121     asm("0:");
00122     asm("ldrlo  r2, [r3], #4");
00123     asm("andlo  r0, r0, r2");
00124     asm("cmplo  r3, r1");
00125     asm("blo    0b");
00126     // do last word...
00127     asm("ldr    r2, [r3]");
00128     asm("orr    r2, r2, r12");
00129     asm("and    r0, r0, r2");
00130     asm("9:");
00131     asm("cmp    r0, #0xffffffff"); // don't use "cmn r0,#0" here because GCC produces the wrong op-code for that!
00132     asm("moveq  r0, #1");
00133     asm("movne  r0, #0");
00134     asm("mov    pc, lr");
00135     dummy_return(int);
00136     }
00137 
00138 
00139 __attribute__((naked)) int BitVectorPointer::TestClear(unsigned /*index*/, size_t /*count*/)
00140     {
00141 #ifdef DEBUG
00142     asm("ldr    r3, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Size)));
00143     asm("add    r12, r1, r2");
00144     asm("cmp    r1, r3");
00145     asm("ldrhs  r0, =%a0"       : : "i" (__LINE__));
00146     asm("bhs    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index>=Size
00147     asm("cmp    r12, r1");
00148     asm("ldrlo  r0, =%a0"       : : "i" (__LINE__));
00149     asm("bls    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count<=index
00150     asm("cmp    r12, r3");
00151     asm("ldrhi  r0, =%a0"       : : "i" (__LINE__));
00152     asm("bhi    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count>Size
00153 #endif
00154     // set r3 = ptr, r2 = startMask ...
00155     asm("ldr    r12, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Bits)));
00156     asm("mov    r0, r1, lsr #5");
00157     asm("add    r3, r12, r0, lsl #2");
00158     asm("and    r0, r1, #31");
00159     asm("add    r1, r1, r2");
00160     asm("sub    r1, r1, #1");
00161     asm("mvn    r2, #0");
00162     asm("mov    r2, r2, lsl r0");
00163     // set r1 = end, r12 = endMask ...
00164     asm("mvn    r0, r1");
00165     asm("and    r0, r0, #31");
00166     asm("mov    r1, r1, lsr #5");
00167     asm("add    r1, r12, r1, lsl #2");
00168     asm("mvn    r12, #0");
00169     asm("mov    r12, r12, lsr r0");
00170     // do first word...
00171     asm("cmp    r3, r1");
00172     asm("ldr    r0, [r3], #4");
00173     asm("andeq  r2, r2, r12");
00174     asm("and    r0, r0, r2");
00175     asm("beq    9f");
00176     // do middle words...
00177     asm("cmp    r3, r1");
00178     asm("0:");
00179     asm("ldrlo  r2, [r3], #4");
00180     asm("orrlo  r0, r0, r2");
00181     asm("cmplo  r3, r1");
00182     asm("blo    0b");
00183     // do last word...
00184     asm("ldr    r2, [r3]");
00185     asm("and    r2, r2, r12");
00186     asm("orr    r0, r0, r2");
00187     asm("9:");
00188     asm("cmp    r0, #0");
00189     asm("moveq  r0, #1");
00190     asm("movne  r0, #0");
00191     asm("mov    pc, lr");
00192     dummy_return(int);
00193     }
00194 
00195 
00196 __attribute__((naked)) void BitVectorPointer::Set(unsigned /*index*/, size_t /*count*/)
00197     {
00198 #ifdef DEBUG
00199     asm("ldr    r3, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Size)));
00200     asm("add    r12, r1, r2");
00201     asm("cmp    r1, r3");
00202     asm("ldrhs  r0, =%a0"       : : "i" (__LINE__));
00203     asm("bhs    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index>=Size
00204     asm("cmp    r12, r1");
00205     asm("ldrlo  r0, =%a0"       : : "i" (__LINE__));
00206     asm("blo    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count<index
00207     asm("cmp    r12, r3");
00208     asm("ldrhi  r0, =%a0"       : : "i" (__LINE__));
00209     asm("bhi    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count>Size
00210 #endif
00211     asm("cmp    r2, #0");
00212     asm("moveq  pc, lr");
00213     // set r3 = ptr, r2 = startMask ...
00214     asm("ldr    r12, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Bits)));
00215     asm("mov    r0, r1, lsr #5");
00216     asm("add    r3, r12, r0, lsl #2");
00217     asm("and    r0, r1, #31");
00218     asm("add    r1, r1, r2");
00219     asm("sub    r1, r1, #1");
00220     asm("mvn    r2, #0");
00221     asm("mov    r2, r2, lsl r0");
00222     // set r1 = end, r12 = endMask ...
00223     asm("mvn    r0, r1");
00224     asm("and    r0, r0, #31");
00225     asm("mov    r1, r1, lsr #5");
00226     asm("add    r1, r12, r1, lsl #2");
00227     asm("mvn    r12, #0");
00228     asm("mov    r12, r12, lsr r0");
00229     // do first word...
00230     asm("ldr    r0, [r3]");
00231     asm("cmp    r3, r1");
00232     asm("andeq  r2, r2, r12");
00233     asm("orr    r0, r0, r2");
00234     asm("str    r0, [r3], #4");
00235     asm("moveq  pc, lr");
00236     // do middle words...
00237     asm("mvn    r0, #0");
00238     asm("cmp    r3, r1");
00239     asm("0:");
00240     asm("strlo  r0, [r3], #4");
00241     asm("cmplo  r3, r1");
00242     asm("blo    0b");
00243     // do last word...
00244     asm("ldr    r0, [r3]");
00245     asm("orr    r0, r0, r12");
00246     asm("str    r0, [r3]");
00247     asm("mov    pc, lr");
00248     }
00249 
00250 
00251 __attribute__((naked)) void BitVectorPointer::Clear(unsigned /*index*/, size_t /*count*/)
00252     {
00253 #ifdef DEBUG
00254     asm("ldr    r3, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Size)));
00255     asm("add    r12, r1, r2");
00256     asm("cmp    r1, r3");
00257     asm("ldrhs  r0, =%a0"       : : "i" (__LINE__));
00258     asm("bhs    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index>=Size
00259     asm("cmp    r12, r1");
00260     asm("ldrlo  r0, =%a0"       : : "i" (__LINE__));
00261     asm("blo    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count<index
00262     asm("cmp    r12, r3");
00263     asm("ldrhi  r0, =%a0"       : : "i" (__LINE__));
00264     asm("bhi    %a0"            : : "i" ((int(*)(int))AssertFailed)); // index+count>Size
00265 #endif
00266     asm("cmp    r2, #0");
00267     asm("moveq  pc, lr");
00268     // r3 = ptr, r2 = startMask
00269     asm("ldr    r12, [r0, #%a0]" : : "i" (offsetof(BitVectorPointer,Bits)));
00270     asm("mov    r0, r1, lsr #5");
00271     asm("add    r3, r12, r0, lsl #2");
00272     asm("and    r0, r1, #31");
00273     asm("add    r1, r1, r2");
00274     asm("sub    r1, r1, #1");
00275     asm("mvn    r2, #0");
00276     asm("mov    r2, r2, lsl r0");
00277     // r1 = end, r12 = endMask
00278     asm("mvn    r0, r1");
00279     asm("and    r0, r0, #31");
00280     asm("mov    r1, r1, lsr #5");
00281     asm("add    r1, r12, r1, lsl #2");
00282     asm("mvn    r12, #0");
00283     asm("mov    r12, r12, lsr r0");
00284     // do first word...
00285     asm("ldr    r0, [r3]");
00286     asm("cmp    r3, r1");
00287     asm("andeq  r2, r2, r12");
00288     asm("bic    r0, r0, r2");
00289     asm("str    r0, [r3], #4");
00290     asm("moveq  pc, lr");
00291     // do middle words...
00292     asm("mov    r0, #0");
00293     asm("cmp    r3, r1");
00294     asm("0:");
00295     asm("strlo  r0, [r3], #4");
00296     asm("cmplo  r3, r1");
00297     asm("blo    0b");
00298     // do last word...
00299     asm("ldr    r0, [r3]");
00300     asm("bic    r0, r0, r12");
00301     asm("str    r0, [r3]");
00302     asm("mov    pc, lr");
00303     }
00304 
00305 
00306 #else // C++ versions...
00307 
00308 
00309 int BitVectorPointer::TestSet(unsigned index, size_t count)
00310     {
00311     ASSERT_DEBUG(index<Size);
00312     ASSERT_DEBUG(index+count>index);
00313     ASSERT_DEBUG(index+count<=Size);
00314 
00315     unsigned* ptr = Bits+(index>>BitVectorIndexShift);
00316     unsigned startMask = ~((~0u)<<(index&BitVectorIndexMask));
00317     index = index+count-1;
00318     unsigned* end = Bits+(index>>BitVectorIndexShift);
00319     unsigned endMask = ~((~0u)>>((~index)&BitVectorIndexMask));
00320 
00321     // startMask and endMask contain bitmasks for the first and last
00322     // entries in the Bits array which we will use. They have set (1)
00323     // bits for each bit in these entries which lie outside the range
00324     // we are testing, so ORing with these will set the bits we
00325     // aren't interested in.
00326 
00327     unsigned result; // all bits will be set to one if test is true
00328     if(ptr==end)
00329         {
00330         startMask |= endMask;
00331         result = *ptr|startMask;
00332         }
00333     else
00334         {
00335         result = *ptr++|startMask;
00336         while(ptr<end)
00337             result &= *ptr++;
00338         result &= *ptr|endMask;
00339         }
00340     return result==~0u;
00341     }
00342 
00343 
00344 int BitVectorPointer::TestClear(unsigned index, size_t count)
00345     {
00346     ASSERT_DEBUG(index<Size);
00347     ASSERT_DEBUG(index+count>index);
00348     ASSERT_DEBUG(index+count<=Size);
00349 
00350     unsigned* ptr = Bits+(index>>BitVectorIndexShift);
00351     unsigned startMask = (~0u)<<(index&BitVectorIndexMask);
00352     index = index+count-1;
00353     unsigned* end = Bits+(index>>BitVectorIndexShift);
00354     unsigned endMask = (~0u)>>((~index)&BitVectorIndexMask);
00355 
00356     // startMask and endMask contain bitmasks for the first and last
00357     // entries in the Bits array which we will use. They have set (1)
00358     // bits for each bit in these entries which lie inside the range
00359     // we are testing, so ANDing with these will clear the bits we
00360     // aren't interested in.
00361 
00362     unsigned result; // all bits will be set to zero if test is true
00363 
00364     if(ptr==end)
00365         result = *ptr&startMask&endMask;
00366     else
00367         {
00368         result = *ptr++&startMask;
00369         while(ptr<end)
00370             result |= *ptr++;
00371         result |= *ptr&endMask;
00372         }
00373     return result==0;
00374     }
00375 
00376 
00377 void BitVectorPointer::Set(unsigned index, size_t count)
00378     {
00379     ASSERT_DEBUG(index<Size);
00380     ASSERT_DEBUG(index+count>=index);
00381     ASSERT_DEBUG(index+count<=Size);
00382 
00383     if(!count)
00384         return;
00385 
00386     unsigned* ptr = Bits+(index>>BitVectorIndexShift);
00387     unsigned startMask = (~0u)<<(index&BitVectorIndexMask);
00388     index = index+count-1;
00389     unsigned* end = Bits+(index>>BitVectorIndexShift);
00390     unsigned endMask = (~0u)>>((~index)&BitVectorIndexMask);
00391 
00392     // startMask and endMask contain bitmasks for the first and last
00393     // entries in the Bits array which we will use. They have set (1)
00394     // bits for each bit in these entries which lie inside the range
00395     // we are testing, so ORing with these will set the bits we want to.
00396 
00397     if(ptr==end)
00398         {
00399         startMask &= endMask;
00400         *ptr |= startMask;
00401         }
00402     else
00403         {
00404         *ptr++ |= startMask;
00405         while(ptr<end)
00406             *ptr++ = ~0u;
00407         *ptr |= endMask;
00408         }
00409     }
00410 
00411 
00412 void BitVectorPointer::Clear(unsigned index, size_t count)
00413     {
00414     ASSERT_DEBUG(index<Size);
00415     ASSERT_DEBUG(index+count>=index);
00416     ASSERT_DEBUG(index+count<=Size);
00417 
00418     if(!count)
00419         return;
00420 
00421     unsigned* ptr = Bits+(index>>BitVectorIndexShift);
00422     unsigned startMask = (~0u)<<(index&BitVectorIndexMask);
00423     index = index+count-1;
00424     unsigned* end = Bits+(index>>BitVectorIndexShift);
00425     unsigned endMask = (~0u)>>((~index)&BitVectorIndexMask);
00426 
00427     // startMask and endMask contain bitmasks for the first and last
00428     // entries in the Bits array which we will use. They have set (1)
00429     // bits for each bit in these entries which lie inside the range
00430     // we are testing, so ANDing with the inverse of these will clear
00431     // the bits we want to.
00432 
00433     if(ptr==end)
00434         {
00435         startMask &= endMask;
00436         *ptr &= ~startMask;
00437         }
00438     else
00439         {
00440         *ptr++ &= ~startMask;
00441         while(ptr<end)
00442             *ptr++ = 0;
00443         *ptr &= ~endMask;
00444         }
00445     }
00446 
00447 #endif
00448 
00449 
00450 int BitVectorPointer::Find(size_t count, unsigned state)
00451     {
00452     if(count>Size || !count)
00453         return -1;
00454 
00455     unsigned* ptr = Bits;
00456     unsigned* end = ptr+((Size+BitVectorIndexMask)>>BitVectorIndexShift);
00457     unsigned bits;
00458     unsigned mask = 0;
00459     unsigned found = 0;
00460     if(state)
00461         state = ~0u;
00462 
00463 _next_word:
00464     if(ptr>=end)
00465         goto _not_found;
00466     bits = state^*ptr++;
00467     mask = 1;
00468     if(bits&mask)
00469         {
00470 _skip_set:
00471         found = 0;
00472         if(bits+mask<mask)
00473             goto _next_word; // rest of bits are all set
00474         do
00475             mask<<=1;
00476         while(bits&mask);
00477         }
00478     bits = ~bits;
00479     do
00480         {
00481         ++found;
00482         mask<<=1;
00483         }
00484     while(bits&mask);
00485     if(found>=count)
00486         goto _found;
00487     if(!mask)
00488         goto _next_word;
00489     bits = ~bits;
00490     goto _skip_set;
00491 
00492 _found:
00493     {
00494     unsigned index = (ptr-Bits)<<BitVectorIndexShift;
00495     if(mask)
00496         do --index; while(mask<<=1);
00497     return index-found;
00498     }
00499 
00500 _not_found:
00501     return -1;
00502     }
00503 

Generated by  doxygen 1.6.1