Browse Source

2008-01-11 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Rewritten get*Missing*Index functions. Now no need to allocate 
memory
	each time these functions are called.
	* src/BitfieldMan.{h, cc}
	* test/BitfieldManTest.cc
	* src/array_fun.h
	* test/array_funTest.cc 

	Now BitfieldMan::countBlock() returns BitfieldMan::blocks.
	Added new BitfieldMan::countFilteredBlock() to get the number of 
blocks
	filtered. Removed unnecessary cast to int32_t.
	* src/BitfieldMan.{h, cc}
Tatsuhiro Tsujikawa 18 năm trước cách đây
mục cha
commit
83c82f3ec2
6 tập tin đã thay đổi với 603 bổ sung118 xóa
  1. 14 0
      ChangeLog
  2. 78 94
      src/BitfieldMan.cc
  3. 19 2
      src/BitfieldMan.h
  4. 198 0
      src/array_fun.h
  5. 227 22
      test/BitfieldManTest.cc
  6. 67 0
      test/array_funTest.cc

+ 14 - 0
ChangeLog

@@ -1,3 +1,17 @@
+2008-01-11  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Rewritten get*Missing*Index functions. Now no need to allocate memory
+	each time these functions are called.
+	* src/BitfieldMan.{h, cc}
+	* test/BitfieldManTest.cc
+	* src/array_fun.h
+	* test/array_funTest.cc 
+
+	Now BitfieldMan::countBlock() returns BitfieldMan::blocks.
+	Added new BitfieldMan::countFilteredBlock() to get the number of blocks
+	filtered. Removed unnecessary cast to int32_t.
+	* src/BitfieldMan.{h, cc}
+	
 2008-01-10  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Fixed the bug that EX_TOO_LONG_PAYLOAD exception is thrown if just

+ 78 - 94
src/BitfieldMan.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "BitfieldMan.h"
 #include "Util.h"
+#include "array_fun.h"
 #include <string.h>
 
 BitfieldMan::BitfieldMan(int32_t blockLength, int64_t totalLength)
@@ -131,8 +132,9 @@ int32_t BitfieldMan::getNthBitIndex(const unsigned char bitfield, int32_t nth) c
   return index;
 }
 
+template<typename Array>
 int32_t
-BitfieldMan::getMissingIndexRandomly(const unsigned char* bitfield,
+BitfieldMan::getMissingIndexRandomly(const Array& bitfield,
 				     int32_t bitfieldLength) const
 {
   /*
@@ -192,47 +194,35 @@ int32_t BitfieldMan::getMissingIndex(const unsigned char* peerBitfield, int32_t
   if(bitfieldLength != length) {
     return -1;
   }
-  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
-  for(int32_t i = 0; i < bitfieldLength; ++i) {
-    tempBitfield[i] = peerBitfield[i] & ~bitfield[i];
-    if(filterEnabled) {
-      tempBitfield[i] &= filterBitfield[i];
-    }
+  array_fun<unsigned char> bf = array_and(array_negate(bitfield), peerBitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
   }
-  int32_t index = getMissingIndexRandomly(tempBitfield, bitfieldLength);
-  delete [] tempBitfield;
-  return index;
+  return getMissingIndexRandomly(bf, bitfieldLength);
 }
 
 int32_t BitfieldMan::getMissingUnusedIndex(const unsigned char* peerBitfield, int32_t length) const {
   if(bitfieldLength != length) {
     return -1;
   }
-  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
-  for(int32_t i = 0; i < bitfieldLength; ++i) {
-    tempBitfield[i] = peerBitfield[i] & ~bitfield[i] & ~useBitfield[i];
-    if(filterEnabled) {
-      tempBitfield[i] &= filterBitfield[i];
-    }
+  array_fun<unsigned char> bf = array_and(array_and(array_negate(bitfield),
+						    array_negate(useBitfield)),
+					  peerBitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
   }
-  int32_t index = getMissingIndexRandomly(tempBitfield, bitfieldLength);
-  delete [] tempBitfield;
-  return index;
+  return getMissingIndexRandomly(bf, bitfieldLength);
 }
 
-int32_t BitfieldMan::getFirstMissingUnusedIndex(const unsigned char* peerBitfield, int32_t length) const {
-  if(bitfieldLength != length) {
-    return -1;
-  }
+template<typename Array>
+int32_t BitfieldMan::getFirstMissingIndex(const Array& bitfield, int32_t bitfieldLength) const
+{
   for(int32_t i = 0; i < bitfieldLength; ++i) {
-    unsigned char bit = peerBitfield[i] & ~bitfield[i] & ~useBitfield[i];
-    if(filterEnabled) {
-      bit &= filterBitfield[i];
-    }
-    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
-      unsigned char mask = 1 << bs;
-      if(bit & mask) {
-	return i*8+7-bs;
+    int32_t base = i*8;
+    for(int32_t bi = 0; bi < 8 && base+bi < blocks; ++bi) {
+      unsigned char mask = 128 >> bi;
+      if(bitfield[i] & mask) {
+	return base+bi;
       }
     }
   }
@@ -240,40 +230,38 @@ int32_t BitfieldMan::getFirstMissingUnusedIndex(const unsigned char* peerBitfiel
 }
 
 int32_t BitfieldMan::getFirstMissingUnusedIndex() const {
-  for(int32_t i = 0; i < bitfieldLength; ++i) {
-    unsigned char bit = ~bitfield[i] & ~useBitfield[i];
-    if(filterEnabled) {
-      bit &= filterBitfield[i];
-    }
-    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
-      unsigned char mask = 1 << bs;
-      if(bit & mask) {
-	return i*8+7-bs;
-      }
-    }
+  array_fun<unsigned char> bf = array_and(array_negate(bitfield),
+					  array_negate(useBitfield));
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
   }
-  return -1;
+  return getFirstMissingIndex(bf, bitfieldLength);
+}
+
+int32_t BitfieldMan::getFirstMissingIndex() const
+{
+  array_fun<unsigned char> bf = array_negate(bitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
+  }
+  return getFirstMissingIndex(bf, bitfieldLength);
 }
 
 int32_t BitfieldMan::getMissingIndex() const {
-  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
-  for(int32_t i = 0; i < bitfieldLength; ++i) {
-    tempBitfield[i] = ~bitfield[i];
-    if(filterEnabled) {
-      tempBitfield[i] &= filterBitfield[i];
-    }
+  array_fun<unsigned char> bf = array_negate(bitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
   }
-  int32_t index = getMissingIndexRandomly(tempBitfield, bitfieldLength);
-  delete [] tempBitfield;
-  return index;
+  return getMissingIndexRandomly(bf, bitfieldLength);
 }
 
 int32_t BitfieldMan::getMissingUnusedIndex() const {
-  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
-  memset(tempBitfield, 0xff, bitfieldLength);
-  int32_t index = getMissingUnusedIndex(tempBitfield, bitfieldLength);
-  delete [] tempBitfield;
-  return index;
+  array_fun<unsigned char> bf = array_and(array_negate(bitfield),
+					  array_negate(useBitfield));
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
+  }
+  return getMissingIndexRandomly(bf, bitfieldLength);
 }
 
 // [startIndex, endIndex)
@@ -298,8 +286,7 @@ public:
 };
 
 int32_t BitfieldMan::getStartIndex(int32_t index) const {
-  while(index < (int32_t)blocks &&
-	(isUseBitSet(index) || isBitSet(index))) {
+  while(index < blocks && (isUseBitSet(index) || isBitSet(index))) {
     index++;
   }
   if((int32_t)blocks <= index) {
@@ -310,8 +297,7 @@ int32_t BitfieldMan::getStartIndex(int32_t index) const {
 }
 
 int32_t BitfieldMan::getEndIndex(int32_t index) const {
-  while(index < (int32_t)blocks &&
-	(!isUseBitSet(index) && !isBitSet(index))) {
+  while(index < blocks && (!isUseBitSet(index) && !isBitSet(index))) {
     index++;
   }
   return index;
@@ -320,9 +306,8 @@ int32_t BitfieldMan::getEndIndex(int32_t index) const {
 int32_t BitfieldMan::getSparseMissingUnusedIndex() const {
   Range maxRange;
   int32_t index = 0;
-  int32_t blocks = countBlock();
   Range currentRange;
-  while(index < (int32_t)blocks) {
+  while(index < blocks) {
     currentRange.startIndex = getStartIndex(index);
     if(currentRange.startIndex == -1) {
       break;
@@ -346,41 +331,40 @@ int32_t BitfieldMan::getSparseMissingUnusedIndex() const {
   }
 }
 
-BlockIndexes BitfieldMan::getAllMissingIndexes() const {
+template<typename Array>
+BlockIndexes BitfieldMan::getAllMissingIndexes(const Array& bitfield, int32_t bitfieldLength) const
+{
   BlockIndexes missingIndexes;
   for(int32_t i = 0; i < bitfieldLength; ++i) {
-    unsigned char bit = ~bitfield[i];
-    if(filterEnabled) {
-      bit &= filterBitfield[i];
-    }
-    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
-      unsigned char mask = 1 << bs;
-      if(bit & mask) {
-	missingIndexes.push_back(i*8+7-bs);
+    int32_t base = i*8;
+    for(int32_t bi = 0; bi < 8 && base+bi < blocks; ++bi) {
+      unsigned char mask = 128 >> bi;
+      if(bitfield[i] & mask) {
+	missingIndexes.push_back(base+bi);
       }
     }
   }
   return missingIndexes;
 }
 
+BlockIndexes BitfieldMan::getAllMissingIndexes() const {
+  array_fun<unsigned char> bf = array_negate(bitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
+  }
+  return getAllMissingIndexes(bf, bitfieldLength);
+}
+
 BlockIndexes BitfieldMan::getAllMissingIndexes(const unsigned char* peerBitfield, int32_t peerBitfieldLength) const {
-  BlockIndexes missingIndexes;
   if(bitfieldLength != peerBitfieldLength) {
-    return missingIndexes;
+    return BlockIndexes();
   }
-  for(int32_t i = 0; i < bitfieldLength; ++i) {
-    unsigned char bit = peerBitfield[i] & ~bitfield[i];
-    if(filterEnabled) {
-      bit &= filterBitfield[i];
-    }
-    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
-      unsigned char mask = 1 << bs;
-      if(bit & mask) {
-	missingIndexes.push_back(i*8+7-bs);
-      }
-    }
+  array_fun<unsigned char> bf = array_and(array_negate(bitfield),
+					  peerBitfield);
+  if(filterEnabled) {
+    bf = array_and(bf, filterBitfield);
   }
-  return missingIndexes;
+  return getAllMissingIndexes(bf, bitfieldLength);
 }
 
 int32_t BitfieldMan::countMissingBlock() const {
@@ -402,12 +386,12 @@ int32_t BitfieldMan::countMissingBlockNow() const {
   }
 }
 
+int32_t BitfieldMan::countFilteredBlock() const {
+  return cachedNumFilteredBlock;
+}
+
 int32_t BitfieldMan::countBlock() const {
-  if(filterEnabled) {
-    return cachedNumFilteredBlock;
-  } else {
-    return blocks;
-  }
+  return blocks;
 }
 
 int32_t BitfieldMan::countFilteredBlockNow() const {
@@ -419,7 +403,7 @@ int32_t BitfieldMan::countFilteredBlockNow() const {
 }
 
 bool BitfieldMan::setBitInternal(unsigned char* bitfield, int32_t index, bool on) {
-  if((int32_t)blocks <= index) { return false; }
+  if(blocks <= index) { return false; }
   unsigned char mask = 128 >> index%8;
   if(on) {
     bitfield[index/8] |= mask;
@@ -479,7 +463,7 @@ bool BitfieldMan::isAllBitSet() const {
 }
 
 bool BitfieldMan::isBitSetInternal(const unsigned char* bitfield, int32_t index) const {
-  if(index < 0 || (int32_t)blocks <= index) { return false; }
+  if(index < 0 || blocks <= index) { return false; }
   unsigned char mask = 128 >> index%8;
   return (bitfield[index/8] & mask) != 0;
 }
@@ -535,7 +519,7 @@ void BitfieldMan::addFilter(int64_t offset, int64_t length) {
   }
   int32_t startBlock = offset/blockLength;
   int32_t endBlock = (offset+length-1)/blockLength;
-  for(int i = startBlock; i <= endBlock && i < (int32_t)blocks; i++) {
+  for(int i = startBlock; i <= endBlock && i < blocks; i++) {
     setFilterBit(i);
   }
   updateCache();

+ 19 - 2
src/BitfieldMan.h

@@ -63,6 +63,17 @@ private:
   int32_t countSetBit(const unsigned char* bitfield, int32_t len) const;
   int32_t getNthBitIndex(const unsigned char bit, int32_t nth) const;
   int32_t getMissingIndexRandomly(const unsigned char* bitfield, int32_t len) const;
+
+  template<typename Array>
+  int32_t
+  getMissingIndexRandomly(const Array& bitfield,
+			  int32_t bitfieldLength) const;
+  template<typename Array>
+  int32_t getFirstMissingIndex(const Array& bitfield, int32_t bitfieldLength) const;
+
+  template<typename Array>
+  BlockIndexes getAllMissingIndexes(const Array& bitfield, int32_t bitfieldLength) const;
+
   bool isBitSetInternal(const unsigned char* bitfield, int32_t index) const;
   bool setBitInternal(unsigned char* bitfield, int32_t index, bool on);
   bool setFilterBit(int32_t index);
@@ -112,9 +123,9 @@ public:
   }
 
   int32_t getBlockLength(int32_t index) const {
-    if(index == (int32_t)(blocks-1)) {
+    if(index == blocks-1) {
       return getLastBlockLength();
-    } else if(0 <= index && index < (int32_t)(blocks-1)) {
+    } else if(0 <= index && index < blocks-1) {
       return getBlockLength();
     } else {
       return 0;
@@ -143,6 +154,10 @@ public:
    * affected by filter
    */
   int32_t getFirstMissingUnusedIndex() const;
+  /**
+   * affected by filter
+   */
+  int32_t getFirstMissingIndex() const;
   /**
    * affected by filter
    */
@@ -194,6 +209,8 @@ public:
   /**
    * affected by filter
    */
+  int32_t countFilteredBlock() const;
+
   int32_t countBlock() const;
   /**
    * affected by filter

+ 198 - 0
src/array_fun.h

@@ -0,0 +1,198 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_ARRAY_FUN_H_
+#define _D_ARRAY_FUN_H_
+
+#include <functional>
+
+template<typename T>
+class bit_negate:public std::unary_function<T, T> {
+public:
+  T operator()(const T& t) const
+  {
+    return ~t;
+  }
+};
+
+template<typename T>
+class bit_and:public std::binary_function<T, T, T> {
+public:
+  T operator()(const T& t1, const T& t2) const
+  {
+    return t1&t2;
+  }
+};
+
+template<typename R>
+class array_function_base {
+public:
+  virtual ~array_function_base() {}
+
+  virtual R operator[](std::size_t index) const = 0;
+
+  virtual array_function_base* clone() const = 0;
+};
+
+template<typename A, typename F>
+class array_unary_function:public array_function_base<typename F::result_type> {
+private:
+  A _a;
+  F _f;
+public:
+  array_unary_function(A a, F f):_a(a), _f(f) {}
+
+  virtual typename F::result_type operator[](std::size_t index) const
+  {
+    return _f(_a[index]);
+  }
+
+  virtual array_function_base<typename F::result_type>* clone() const
+  {
+    return new array_unary_function(*this);
+  }
+};
+
+template<typename A, typename B, typename F>
+class array_binary_function:public array_function_base<typename F::result_type>{
+private:
+  A _a;
+  B _b;
+  F _f;
+public:
+  array_binary_function(A a, B b, F f):_a(a), _b(b), _f(f) {}
+
+  virtual typename F::result_type operator[](std::size_t index) const
+  {
+    return _f(_a[index], _b[index]);
+  }
+
+  virtual array_function_base<typename F::result_type>* clone() const
+  {
+    return new array_binary_function(*this);
+  }
+};
+
+template<typename R>
+class array_fun {
+private:
+  array_function_base<R>* _p;
+public:
+  template<typename A, typename F>
+  array_fun(A a, F f):_p(new array_unary_function<A, F>(a, f)) {}
+
+  template<typename A, typename B, typename F>
+  array_fun(A a, B b, F f):_p(new array_binary_function<A, B, F>(a, b, f)) {}
+
+  array_fun(const array_fun& af):_p(af._p->clone()) {}
+
+  ~array_fun()
+  {
+    delete _p;
+  }
+
+  array_fun& operator=(const array_fun& af)
+  {
+    if(this != &af) {
+      delete _p;
+      _p = af._p->clone();
+    }
+    return *this;
+  }
+
+  R operator[](std::size_t index) const
+  {
+    return (*_p)[index];
+  }
+
+  typedef R result_type;
+};
+
+template<typename R, typename A>
+array_fun<R>
+array_negate(A a)
+{
+  return array_fun<R>(a, bit_negate<R>());
+}
+
+template<typename T>
+array_fun<T>
+array_negate(T* a)
+{
+  return array_fun<T>(a, bit_negate<T>());
+}
+
+template<typename A>
+array_fun<typename A::result_type>
+array_negate(A a)
+{
+  return array_fun<typename A::result_type>(a, bit_negate<typename A::result_type>());
+}
+
+template<typename R, typename A, typename B>
+array_fun<R>
+array_and(A a, B b)
+{
+  return array_fun<R>(a, b, bit_and<R>());
+}
+
+template<typename T>
+array_fun<T>
+array_and(T* a, T* b)
+{
+  return array_fun<T>(a, b, bit_and<T>());
+}
+
+template<typename T>
+array_fun<typename T::result_type>
+array_and(T a, T b)
+{
+  return array_fun<typename T::result_type>(a, b, bit_and<typename T::result_type>());
+}
+
+template<typename A, typename B>
+array_fun<typename A::result_type>
+array_and(A a, B b)
+{
+  return array_fun<typename A::result_type>(a, b, bit_and<typename A::result_type>());
+}
+
+template<typename A, typename B>
+array_fun<typename B::result_type>
+array_and(A a, B b)
+{
+  return array_fun<typename B::result_type>(a, b, bit_and<typename B::result_type>());
+}
+
+#endif // _D_ARRAY_FUN_H_

+ 227 - 22
test/BitfieldManTest.cc

@@ -1,16 +1,13 @@
 #include "BitfieldMan.h"
 #include "FixedNumberRandomizer.h"
-#include "BitfieldManFactory.h"
-#include <string>
 #include <cppunit/extensions/HelperMacros.h>
 
-using namespace std;
-
 class BitfieldManTest:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(BitfieldManTest);
   CPPUNIT_TEST(testGetBlockSize);
   CPPUNIT_TEST(testGetFirstMissingUnusedIndex);
+  CPPUNIT_TEST(testGetFirstMissingIndex);
   CPPUNIT_TEST(testIsAllBitSet);
   CPPUNIT_TEST(testFilter);
   CPPUNIT_TEST(testGetMissingIndex);
@@ -19,6 +16,12 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testIsBitSetOffsetRange);
   CPPUNIT_TEST(testGetMissingUnusedLength);
   CPPUNIT_TEST(testSetBitRange);
+  CPPUNIT_TEST(testGetAllMissingIndexes);
+  CPPUNIT_TEST(testGetAllMissingIndexes_noarg);
+  CPPUNIT_TEST(testGetMissingUnusedIndex);
+  CPPUNIT_TEST(testGetMissingIndex_noarg);
+  CPPUNIT_TEST(testGetMissingUnusedIndex_noarg);
+  CPPUNIT_TEST(testCountFilteredBlock);
   CPPUNIT_TEST_SUITE_END();
 private:
   RandomizerHandle fixedNumberRandomizer;
@@ -35,14 +38,22 @@ public:
 
   void testGetBlockSize();
   void testGetFirstMissingUnusedIndex();
+  void testGetFirstMissingIndex();
+  void testGetMissingIndex();
+  void testGetMissingIndex_noarg();
+  void testGetMissingUnusedIndex();
+  void testGetMissingUnusedIndex_noarg();
+  void testGetAllMissingIndexes();
+  void testGetAllMissingIndexes_noarg();
+
   void testIsAllBitSet();
   void testFilter();
-  void testGetMissingIndex();
   void testGetSparceMissingUnusedIndex();
   void testGetSparceMissingUnusedIndex_setBit();
   void testIsBitSetOffsetRange();
   void testGetMissingUnusedLength();
   void testSetBitRange();
+  void testCountFilteredBlock();
 };
 
 
@@ -58,27 +69,116 @@ void BitfieldManTest::testGetBlockSize() {
   CPPUNIT_ASSERT_EQUAL((int32_t)0, bt2.getBlockLength(11));
 }
 
-void BitfieldManTest::testGetFirstMissingUnusedIndex() {
-  BitfieldMan bt1(1024, 1024*10);
-  unsigned char bitfield[2];
-  memset(bitfield, 0xff, sizeof(bitfield));
+void BitfieldManTest::testGetFirstMissingUnusedIndex()
+{
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getFirstMissingUnusedIndex());
+    bt1.setUseBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingUnusedIndex());
+    bt1.unsetUseBit(0);
+    bt1.setBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingUnusedIndex());
+    bt1.setAllBit();
+    CPPUNIT_ASSERT_EQUAL(-1, bt1.getFirstMissingUnusedIndex());
+  }
+  {
+    BitfieldMan bt1(1024, 1024*10);
+
+    bt1.addFilter(1024, 1024*10);
+    bt1.enableFilter();
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingUnusedIndex());
+    bt1.setUseBit(1);
+    CPPUNIT_ASSERT_EQUAL(2, bt1.getFirstMissingUnusedIndex());
+    bt1.setBit(2);
+    CPPUNIT_ASSERT_EQUAL(3, bt1.getFirstMissingUnusedIndex());
+  }
+}
 
-  CPPUNIT_ASSERT_EQUAL((int32_t)0, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
-  CPPUNIT_ASSERT(bt1.setUseBit(0));
-  CPPUNIT_ASSERT_EQUAL((int32_t)1, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
-  CPPUNIT_ASSERT(bt1.unsetUseBit(0));
-  CPPUNIT_ASSERT_EQUAL((int32_t)0, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
-  CPPUNIT_ASSERT(bt1.setBit(0));
-  CPPUNIT_ASSERT_EQUAL((int32_t)1, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+void BitfieldManTest::testGetFirstMissingIndex()
+{
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getFirstMissingIndex());
+    bt1.setUseBit(0);
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getFirstMissingIndex());
+    bt1.unsetUseBit(0);
+    bt1.setBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingIndex());
+    bt1.setAllBit();
+    CPPUNIT_ASSERT_EQUAL(-1, bt1.getFirstMissingIndex());
+  }
+  {
+    BitfieldMan bt1(1024, 1024*10);
+
+    bt1.addFilter(1024, 1024*10);
+    bt1.enableFilter();
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingIndex());
+    bt1.setUseBit(1);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingIndex());
+    bt1.setBit(1);
+    CPPUNIT_ASSERT_EQUAL(2, bt1.getFirstMissingIndex());
+  }
+}
 
-  for(int i = 0; i < 8; i++) {
-    CPPUNIT_ASSERT(bt1.setBit(i));
+void BitfieldManTest::testGetMissingUnusedIndex_noarg()
+{
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    bt1.setRandomizer(fixedNumberRandomizer);
+    
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingUnusedIndex());
+    bt1.setUseBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingUnusedIndex());
+    bt1.unsetUseBit(0);
+    bt1.setBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingUnusedIndex());
+    bt1.setAllBit();
+    CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingUnusedIndex());
   }
-  CPPUNIT_ASSERT_EQUAL((int32_t)8, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    bt1.setRandomizer(fixedNumberRandomizer);
+
+    bt1.addFilter(1024, 1024*10);
+    bt1.enableFilter();
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingUnusedIndex());
+    bt1.setUseBit(1);
+    CPPUNIT_ASSERT_EQUAL(2, bt1.getMissingUnusedIndex());
+    bt1.setBit(2);
+    CPPUNIT_ASSERT_EQUAL(3, bt1.getMissingUnusedIndex());
+  }
+}
 
-  CPPUNIT_ASSERT_EQUAL((int32_t)8, bt1.getFirstMissingUnusedIndex());
-  CPPUNIT_ASSERT(bt1.setUseBit(8));
-  CPPUNIT_ASSERT_EQUAL((int32_t)9, bt1.getFirstMissingUnusedIndex());
+void BitfieldManTest::testGetMissingIndex_noarg()
+{
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    bt1.setRandomizer(fixedNumberRandomizer);
+
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingIndex());
+    bt1.setUseBit(0);
+    CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingIndex());
+    bt1.unsetUseBit(0);
+    bt1.setBit(0);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingIndex());
+    bt1.setAllBit();
+    CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingIndex());
+  }
+  {
+    BitfieldMan bt1(1024, 1024*10);
+    bt1.setRandomizer(fixedNumberRandomizer);
+
+    bt1.addFilter(1024, 1024*10);
+    bt1.enableFilter();
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingIndex());
+    bt1.setUseBit(1);
+    CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingIndex());
+    bt1.setBit(1);
+    CPPUNIT_ASSERT_EQUAL(2, bt1.getMissingIndex());
+  }
 }
 
 void BitfieldManTest::testIsAllBitSet() {
@@ -178,6 +278,11 @@ void BitfieldManTest::testGetMissingIndex() {
   };
   CPPUNIT_ASSERT_EQUAL((int32_t)0, bt1.getMissingIndex(bitArray, 32));
 
+  bt1.addFilter(1024, 1024*256);
+  bt1.enableFilter();
+  CPPUNIT_ASSERT_EQUAL((int32_t)1, bt1.getMissingIndex(bitArray, 32));
+  bt1.disableFilter();
+
   unsigned char bitArray2[] = {
     0x0f, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff,
@@ -354,3 +459,103 @@ void BitfieldManTest::testSetBitRange()
   }
   CPPUNIT_ASSERT_EQUAL(int64_t(5*blockLength), bf.getCompletedLength());
 }
+
+void BitfieldManTest::testGetAllMissingIndexes_noarg()
+{
+  int32_t blockLength = 16*1024;
+  int64_t totalLength = 1024*1024;
+  BitfieldMan bf(blockLength, totalLength);
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, bf.getAllMissingIndexes().size());
+  for(int32_t i = 0; i < 63; ++i) {
+    bf.setBit(i);
+  }
+  CPPUNIT_ASSERT_EQUAL((size_t)1, bf.getAllMissingIndexes().size());
+  CPPUNIT_ASSERT_EQUAL(63, bf.getAllMissingIndexes().front());
+}
+
+void BitfieldManTest::testGetAllMissingIndexes()
+{
+  int32_t blockLength = 16*1024;
+  int64_t totalLength = 1024*1024;
+  BitfieldMan bf(blockLength, totalLength);
+  BitfieldMan peerBf(blockLength, totalLength);
+  peerBf.setAllBit();
+
+  CPPUNIT_ASSERT_EQUAL((size_t)64, bf.getAllMissingIndexes(peerBf.getBitfield(),
+							   peerBf.getBitfieldLength()).size());
+  for(int32_t i = 0; i < 62; ++i) {
+    bf.setBit(i);
+  }
+  peerBf.unsetBit(62);
+
+  {
+    Integers indexes = bf.getAllMissingIndexes(peerBf.getBitfield(),
+					       peerBf.getBitfieldLength());
+    
+    CPPUNIT_ASSERT_EQUAL((size_t)1, indexes.size());
+    CPPUNIT_ASSERT_EQUAL(63, indexes.front());
+  }
+}
+
+void BitfieldManTest::testGetMissingUnusedIndex()
+{
+  BitfieldMan bt1(1024, 1024*256);
+  bt1.setRandomizer(fixedNumberRandomizer);
+
+  unsigned char bitArray[] = {
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+  };
+  CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingUnusedIndex(bitArray, 32));
+  
+  bt1.addFilter(1024, 1024*256);
+  bt1.enableFilter();
+  CPPUNIT_ASSERT_EQUAL(1, bt1.getMissingUnusedIndex(bitArray, 32));
+  bt1.setUseBit(1);
+  CPPUNIT_ASSERT_EQUAL(2, bt1.getMissingUnusedIndex(bitArray, 32));
+  bt1.disableFilter();
+
+  bt1.setBit(0);
+  CPPUNIT_ASSERT_EQUAL(2, bt1.getMissingUnusedIndex(bitArray, 32));
+
+  bt1.setAllBit();
+  CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingUnusedIndex(bitArray, 32));
+  
+  bt1.clearAllBit();
+  bt1.setAllUseBit();
+  CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingUnusedIndex(bitArray, 32));
+
+  unsigned char bitArray4[] = {
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+  };
+
+  CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingUnusedIndex(bitArray4, 32));
+}
+
+void BitfieldManTest::testCountFilteredBlock()
+{
+  BitfieldMan bt(1024, 1024*256);
+  CPPUNIT_ASSERT_EQUAL(256, bt.countBlock());
+  CPPUNIT_ASSERT_EQUAL(0, bt.countFilteredBlock());
+  bt.addFilter(1024, 1024*256);
+  bt.enableFilter();
+  CPPUNIT_ASSERT_EQUAL(256, bt.countBlock());
+  CPPUNIT_ASSERT_EQUAL(255, bt.countFilteredBlock());
+  bt.disableFilter();
+  CPPUNIT_ASSERT_EQUAL(256, bt.countBlock());
+  CPPUNIT_ASSERT_EQUAL(0, bt.countFilteredBlock());
+}

+ 67 - 0
test/array_funTest.cc

@@ -0,0 +1,67 @@
+#include "array_fun.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class array_funTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(array_funTest);
+  CPPUNIT_TEST(testBit_negate);
+  CPPUNIT_TEST(testBit_and);
+  CPPUNIT_TEST(testArray_negate);
+  CPPUNIT_TEST(testArray_and);
+  CPPUNIT_TEST_SUITE_END();
+public:
+  void testBit_negate();
+  void testBit_and();
+  void testArray_negate();
+  void testArray_and();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(array_funTest);
+
+void array_funTest::testBit_negate()
+{
+  unsigned char b = 0xaa;
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x55, bit_negate<unsigned char>()(b));
+}
+
+void array_funTest::testBit_and()
+{
+  unsigned char b = 0xaa;
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x0a, bit_and<unsigned char>()(b, 0x0a));
+}
+
+void array_funTest::testArray_negate()
+{
+  unsigned char a[] = { 0xaa, 0x55 };
+  array_fun<unsigned char> f = array_negate((unsigned char*)a);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x55, f[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0xaa, f[1]);
+
+  array_fun<unsigned char> ff = array_negate(f);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0xaa, ff[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x55, ff[1]);
+}
+
+void array_funTest::testArray_and()
+{
+  unsigned char a1[] = { 0xaa, 0x55 };
+  unsigned char a2[] = { 0x1a, 0x25 };
+  array_fun<unsigned char> f = array_and((unsigned char*)a1, (unsigned char*)a2);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x0a, f[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x05, f[1]);
+
+  array_fun<unsigned char> f2 = array_and((unsigned char*)a1, array_negate(a2));
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0xa0, f2[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x50, f2[1]);
+
+  array_fun<unsigned char> f3 = array_and(array_negate(a2), (unsigned char*)a1);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0xa0, f3[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x50, f3[1]);
+
+  array_fun<unsigned char> f4 = array_and(array_negate(a1), array_negate(a2));
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x45, f4[0]);
+  CPPUNIT_ASSERT_EQUAL((unsigned char)0x8a, f4[1]);
+}