QueryRoutingTable.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Qt.h"
00024 #include "QueryRoutingTable.h"
00025 #include <math.h>
00026 #include "Imports.cpp"
00027
00028 using namespace Gnutella::PacketProcessing::QueryRouting;
00029
00030 namespace Gnutella {
00031 namespace PacketProcessing {
00032 namespace QueryRouting {
00033
00034 static const int A_INT=0x4F1BBCDC;
00035 static const quint8 EntryMask [8] = { 0x80, 0x40, 0x20, 0x10,
00036 0x08, 0x04, 0x02, 0x01};
00037 static const quint8 ValueShift [8] = { 7, 6, 5, 4, 3, 2, 1};
00038
00039 static bool isPowerOf2 (quint32 size)
00040 {
00041 if( size == 0 ) return false;
00042 return ( (size & size-1) == 0 );
00043 }
00044
00045 quint8 leftNibbleNonZero (quint8 ch)
00046 {
00047 return ch & 0xF0 != 0;
00048 }
00049
00050 quint8 rightNibbleNonZero (quint8 ch)
00051 {
00052 return ch & 0x0F != 0;
00053 }
00054
00055 quint8 checkTwoNibbles(quint8 ch)
00056 {
00057 quint8 changed = 0;
00058 changed |= leftNibbleNonZero (ch);
00059 changed <<= 1;
00060 changed |= rightNibbleNonZero (ch);
00061 return changed;
00062 }
00063
00064
00065
00066
00067
00068
00069 quint8 getBitsToOr (quint8 ch, quint8 entryBits)
00070 {
00071 Q_ASSERT (entryBits == 1 || entryBits == 4 || entryBits == 8);
00072 if (entryBits == 1)
00073 return ch;
00074 else if (entryBits == 4)
00075 return checkTwoNibbles (ch);
00076 else if (entryBits == 8)
00077 return ch != 0;
00078 return 0;
00079 }
00080
00081 }
00082 }
00083 }
00084
00085 QueryRoutingTable::QueryRoutingTable()
00086 : rawTable_(), size_ (0), sizeBits_ (0)
00087 {
00088 }
00089
00090 QueryRoutingTable::~QueryRoutingTable()
00091 {
00092 }
00093
00094 void QueryRoutingTable::reset (quint32 size)
00095 {
00096 Q_ASSERT (size >= 8 && isPowerOf2 (size));
00097
00098 if (size_ != size) {
00099 size_ = size;
00100 rawTable_ = QByteArray (size / 8, 0);
00101 double sizeAsDouble = size;
00102 sizeBits_ = static_cast <quint32> (log (sizeAsDouble) / log (2.0));
00103 } else {
00104 rawTable_.fill (0);
00105 }
00106 }
00107
00111
00112
00113
00114
00115
00116 void QueryRoutingTable::applyPatch (QByteArray &patchBuffer, quint8 entryBits)
00117 {
00118 Q_ASSERT (patchBuffer.size() == qint32 (size_ * entryBits / 8));
00119 Q_ASSERT (entryBits == 1 || entryBits == 4 || entryBits == 8);
00120
00121 int k = 0;
00122 for( int i = 0; i < rawTable_.size(); ++i ) {
00123 quint8 changed = 0;
00124 for (int j = 0; j < entryBits; ++j, ++k) {
00125 int numBits = 8/entryBits;
00126 changed <<= numBits;
00127 changed |= getBitsToOr (patchBuffer[k], entryBits);
00128 }
00129 rawTable_[i] = rawTable_[i] ^ changed;
00130 }
00131 }
00132
00136 QByteArray QueryRoutingTable::makePatchTo (const QueryRoutingTable &other,
00137 quint8 entryBits) const
00138 {
00139 Q_ASSERT (other.size_ == size_);
00140 Q_ASSERT (entryBits == 1 || entryBits == 4 || entryBits == 8);
00141
00142 QByteArray patchBuffer (size_ * entryBits / 8, 0);
00143
00144 const quint8 *oldTable = reinterpret_cast <const quint8 *>
00145 (rawTable_.data());
00146 const quint8 *oldTableEnd = oldTable + rawTable_.size();
00147 const quint8 *newTable = reinterpret_cast <const quint8 *>
00148 (other.rawTable_.data());
00149 quint8 *patch = reinterpret_cast <quint8 *> (patchBuffer.data());
00150 quint8 *patchEnd = patch + patchBuffer.size();
00151
00152 quint8 tmp, set, reset;
00153 quint8 setMask1, setMask2, resetMask1, resetMask2;
00154 quint8 *end;
00155 if (entryBits == 0x01) {
00156 while (oldTable != oldTableEnd)
00157 *patch++ = *oldTable++ ^ *newTable++;
00158 }
00159 if (entryBits == 0x04) {
00160 setMask1 = 0xF0;
00161 resetMask1 = 0x10;
00162 setMask2 = 0x0F;
00163 resetMask2 = 0x01;
00164 while (oldTable != oldTableEnd) {
00165 tmp = *oldTable ^ *newTable;
00166 set = tmp & *newTable++;
00167 reset = tmp & *oldTable++;
00168 for (end = patch + 4; patch < end; patch++) {
00169 *patch |= (set & 0x80) ? setMask1 : 0x00;
00170 *patch |= (reset & 0x80) ? resetMask1 :0x00;
00171 *patch |= (set & 0x40) ? setMask2 : 0x00;
00172 *patch |= (reset & 0x40) ? resetMask2 :0x00;
00173 set <<= 2; reset <<= 2;
00174 }
00175 }
00176 }
00177 if (entryBits == 0x08) {
00178 setMask1 = 0xFF;
00179 resetMask1 = 0x01;
00180 while (oldTable != oldTableEnd) {
00181 tmp = *oldTable ^ *newTable;
00182 set = tmp & *newTable++;
00183 reset = tmp & *oldTable++;
00184 for (end = patch + 8; patch < end; patch++) {
00185 *patch |= (set & 0x80) ? setMask1 : 0x00;
00186 *patch |= (reset & 0x80) ? resetMask1 :0x00;
00187 set <<= 1; reset <<= 1;
00188 }
00189 }
00190 }
00191 Q_ASSERT (patch == patchEnd);
00192 return patchBuffer;
00193 }
00194
00195 void QueryRoutingTable::scaledCopy (const QueryRoutingTable &other)
00196 {
00197 Q_ASSERT (size_ > 1 && other.size_ > 1);
00198
00199
00200
00201 quint8 *p1 = reinterpret_cast <quint8 *> (rawTable_.data());
00202 const quint8 *e1 = p1 + rawTable_.size();
00203 quint8 ei1 = 0;
00204 quint32 ec1 = (size_ > other.size_) ? (size_ / other.size_) : (1);
00205
00206 const quint8 *p2 = reinterpret_cast <const quint8 *>
00207 (other.rawTable_.data());
00208 const quint8 *e2 = p2 + other.rawTable_.size();
00209 quint8 ei2 = 0;
00210 quint32 ec2 = (other.size_ > size_) ? (other.size_ / size_) : (1);
00211
00212 quint32 i;
00213 quint8 mv;
00214 while (p1 < e1 && p2 < e2) {
00215
00216 for (mv = 0, i = 0; i < ec2; i++) {
00217 mv |= (*p2 & EntryMask [ei2]) != 0;
00218 ++ei2 %= 8;
00219 if (ei2 == 0) p2++;
00220 }
00221
00222 for (i = 0; i < ec1; i++) {
00223 *p1 &= ~EntryMask [ei1];
00224 *p1 |= mv << ValueShift [ei1];
00225 ++ei1 %= 8;
00226 if (ei1 == 0) p1++;
00227 }
00228 }
00229
00230 Q_ASSERT (p1 == e1 && p2 == e2);
00231 }
00232
00233 void QueryRoutingTable::addTable (const QueryRoutingTable &other)
00234 {
00235 Q_ASSERT (size_ > 1 && other.size_ > 1);
00236
00237 quint8 *p1 = reinterpret_cast <quint8 *> (rawTable_.data());
00238 const quint8 *e1 = p1 + rawTable_.size();
00239 const quint8 *p2 = reinterpret_cast <const quint8 *>
00240 (other.rawTable_.data());
00241 const quint8 *e2 = p2 + other.rawTable_.size();
00242
00243 if (rawTable_.size() == other.rawTable_.size()) {
00244 while (p1 != e1)
00245 *p1++ |= *p2++;
00246 } else {
00247
00248
00249 quint8 ei1 = 0;
00250 quint32 ec1 = (size_ > other.size_) ? (size_ / other.size_) : (1);
00251 quint8 ei2 = 0;
00252 quint32 ec2 = (other.size_ > size_) ? (other.size_ / size_) : (1);
00253
00254 quint32 i;
00255 quint8 mv;
00256 while (p1 < e1 && p2 < e2) {
00257
00258 for (mv = 0, i = 0; i < ec2; i++) {
00259 mv |= (*p2 & EntryMask [ei2]) != 0;
00260 ++ei2 %= 8;
00261 if (ei2 == 0) p2++;
00262 }
00263
00264 for (i = 0; i < ec1; i++) {
00265 *p1 |= mv << ValueShift [ei1];
00266 ++ei1 %= 8;
00267 if (ei1 == 0) p1++;
00268 }
00269 }
00270 }
00271
00272 Q_ASSERT (p1 == e1 && p2 == e2);
00273 }
00274
00275 bool QueryRoutingTable::isEntrySet (quint32 index) const
00276 {
00277 Q_ASSERT (index < size_);
00278
00279 quint32 byteIndex = index / 8;
00280 quint32 bitIndex = index % 8;
00281 quint8 byte = static_cast <quint8> (rawTable_.at (byteIndex));
00282
00283 return (byte & (0x80 >> bitIndex)) != 0;
00284 }
00285
00286 void QueryRoutingTable::setEntry (quint32 index)
00287 {
00288 Q_ASSERT (index < size_);
00289
00290 quint32 byteIndex = index / 8;
00291 quint32 bitIndex = index % 8;
00292 quint8 *byte = reinterpret_cast <quint8 *> (rawTable_.data()) + byteIndex;
00293
00294 *byte |= (0x80 >> bitIndex);
00295 }
00296
00297 void QueryRoutingTable::resetEntry (quint32 index)
00298 {
00299 Q_ASSERT (index < size_);
00300
00301 quint32 byteIndex = index / 8;
00302 quint32 bitIndex = index % 8;
00303 quint8 *byte = reinterpret_cast <quint8 *> (rawTable_.data()) + byteIndex;
00304
00305 *byte &= ~(0x80 >> bitIndex);
00306 }
00307
00308 bool QueryRoutingTable::hasString (QString x) const
00309 {
00310 Q_ASSERT (size_ > 0);
00311 quint32 index = hash (x,0,x.length(), sizeBits_);
00312 return isEntrySet (index);
00313 }
00314
00315 void QueryRoutingTable::add (QString x)
00316 {
00317 Q_ASSERT (size_ > 0);
00318 quint32 index = hash (x, 0, x.length(), sizeBits_);
00319 setEntry (index);
00320 }
00321
00322 void QueryRoutingTable::remove (QString x)
00323 {
00324 Q_ASSERT (size_ > 0);
00325 quint32 index = hash (x, 0, x.length(), sizeBits_);
00327 resetEntry (index);
00328 }
00329
00330 int QueryRoutingTable::hash(QString x, int start, int end, quint8 bits) const
00331 {
00332
00333
00334
00335
00336
00337
00338
00339
00340 int _xor=0;
00341 int j=0;
00342 for (int i=start; i<end; i++) {
00343
00344 int b = x.at(i).toLower().toAscii() & 0xFF;
00345 b=b<<(j*8);
00346 _xor=_xor^b;
00347 j=(j+1)%4;
00348 }
00349
00350 return hashFast(_xor, bits);
00351
00352 }
00353
00354 int QueryRoutingTable::hashFast(int x, quint8 bits) const
00355 {
00356
00357 quint64 prod = static_cast <quint64> (x) * static_cast <quint64> (A_INT);
00358 quint64 ret = prod << 32;
00359 ret = ret >> (32 + (32 - bits));
00360 return static_cast <int> (ret);
00361 }