bool KeyV1::woEqual(const KeyV1& right) const { const unsigned char *l = _keyData; const unsigned char *r = right._keyData; if( (*l|*r) == IsBSON ) { return toBson().equal(right.toBson()); } while( 1 ) { char lval = *l; char rval = *r; if( (lval&(cCANONTYPEMASK|cHASMORE)) != (rval&(cCANONTYPEMASK|cHASMORE)) ) return false; l++; r++; switch( lval&cCANONTYPEMASK ) { case coid: if( *((unsigned*) l) != *((unsigned*) r) ) return false; l += 4; r += 4; case cdate: case cdouble: if( *((unsigned long long *) l) != *((unsigned long long *) r) ) return false; l += 8; r += 8; break; case cstring: { unsigned sz = ((unsigned) *l) + 1; if( memcmp(l, r, sz) ) // first byte checked is the length byte return false; l += sz; r += sz; break; } case cbindata: { int len = binDataCodeToLength(*l) + 1; if( memcmp(l, r, len) ) return false; l += len; r += len; break; } case cminkey: case cnull: case cfalse: case ctrue: case cmaxkey: break; default: assert(false); } if( (lval&cHASMORE) == 0 ) break; } return true; }
inline unsigned sizeOfElement(const unsigned char* p) { unsigned type = *p & cCANONTYPEMASK; unsigned sz = sizes[type]; if (sz == 0) { if (type == cstring) { sz = ((unsigned)p[1]) + 2; } else { verify(type == cbindata); sz = binDataCodeToLength(p[1]) + 2; } } return sz; }
bool KeyV1::woEqual(const KeyV1& right) const { const unsigned char *l = _keyData; const unsigned char *r = right._keyData; if( (*l|*r) == IsBSON ) { return toBson().equal(right.toBson()); } while( 1 ) { char lval = *l; char rval = *r; if( (lval&(cCANONTYPEMASK|cHASMORE)) != (rval&(cCANONTYPEMASK|cHASMORE)) ) return false; l++; r++; switch( lval&cCANONTYPEMASK ) { case coid: if( *((unsigned*) l) != *((unsigned*) r) ) return false; l += 4; r += 4; case cdate: if( *((unsigned long long *) l) != *((unsigned long long *) r) ) return false; l += 8; r += 8; break; case cdouble: if( (reinterpret_cast< const PackedDouble* > (l))->d != (reinterpret_cast< const PackedDouble* >(r))->d ) return false; l += 8; r += 8; break; case cstring: { if( *l != *r ) return false; // not same length unsigned sz = ((unsigned) *l) + 1; if( memcmp(l, r, sz) ) return false; l += sz; r += sz; break; } case cbindata: { if( *l != *r ) return false; // len or subtype mismatch int len = binDataCodeToLength(*l) + 1; if( memcmp(l, r, len) ) return false; l += len; r += len; break; } case cminkey: case cnull: case cfalse: case ctrue: case cmaxkey: break; default: verify(false); } if( (lval&cHASMORE) == 0 ) break; } return true; }
static int compare(const unsigned char *&l, const unsigned char *&r) { int lt = (*l & cCANONTYPEMASK); int rt = (*r & cCANONTYPEMASK); int x = lt - rt; if( x ) return x; l++; r++; // same type switch( lt ) { case cdouble: { double L = (reinterpret_cast< const PackedDouble* >(l))->d; double R = (reinterpret_cast< const PackedDouble* >(r))->d; if( L < R ) return -1; if( L != R ) return 1; l += 8; r += 8; break; } case cstring: { int lsz = *l; int rsz = *r; int common = min(lsz, rsz); l++; r++; // skip the size byte // use memcmp as we (will) allow zeros in UTF8 strings int res = memcmp(l, r, common); if( res ) return res; // longer string is the greater one int diff = lsz-rsz; if( diff ) return diff; l += lsz; r += lsz; break; } case cbindata: { int L = *l; int R = *r; int llen = binDataCodeToLength(L); int diff = L-R; // checks length and subtype simultaneously if( diff ) { // unfortunately nibbles are backwards to do subtype and len in one check (could bit swap...) int rlen = binDataCodeToLength(R); if( llen != rlen ) return llen - rlen; return diff; } // same length, same type l++; r++; int res = memcmp(l, r, llen); if( res ) return res; l += llen; r += llen; break; } case cdate: { long long L = *((long long *) l); long long R = *((long long *) r); if( L < R ) return -1; if( L > R ) return 1; l += 8; r += 8; break; } case coid: { int res = memcmp(l, r, sizeof(OID)); if( res ) return res; l += 12; r += 12; break; } default: // all the others are a match -- e.g. null == null ; } return 0; }
BSONObj KeyV1::toBson() const { verify( _keyData != 0 ); if( !isCompactFormat() ) return bson(); BSONObjBuilder b(512); const unsigned char *p = _keyData; while( 1 ) { unsigned bits = *p++; switch( bits & 0x3f ) { case cminkey: b.appendMinKey(""); break; case cnull: b.appendNull(""); break; case cfalse: b.appendBool("", false); break; case ctrue: b.appendBool("", true); break; case cmaxkey: b.appendMaxKey(""); break; case cstring: { unsigned sz = *p++; // we build the element ourself as we have to null terminate it BufBuilder &bb = b.bb(); bb.appendNum((char) String); bb.appendUChar(0); // fieldname "" bb.appendNum(sz+1); bb.appendBuf(p, sz); bb.appendUChar(0); // null char at end of string p += sz; break; } case coid: b.appendOID("", (OID *) p); p += sizeof(OID); break; case cbindata: { int len = binDataCodeToLength(*p); int subtype = (*p) & BinDataTypeMask; if( subtype & 0x8 ) { subtype = (subtype & 0x7) | 0x80; } b.appendBinData("", len, (BinDataType) subtype, ++p); p += len; break; } case cdate: b.appendDate("", (Date_t&) *p); p += 8; break; case cdouble: b.append("", (double&) *p); p += sizeof(double); break; case cint: b.append("", static_cast< int >((reinterpret_cast< const PackedDouble& >(*p)).d)); p += sizeof(double); break; case clong: b.append("", static_cast< long long>((reinterpret_cast< const PackedDouble& >(*p)).d)); p += sizeof(double); break; default: verify(false); } if( (bits & cHASMORE) == 0 ) break; } return b.obj(); }
static int compare(const unsigned char *&l, const unsigned char *&r) { int lt_real = (*l & cFULLTYPEMASK); int rt_real = (*r & cFULLTYPEMASK); int lt = (lt_real & cCANONTYPEMASK); int rt = (rt_real & cCANONTYPEMASK); int x = lt - rt; if( x ) return x; l++; r++; // same type switch( lt ) { case cdouble: { if (unlikely(lt_real == cint64 && rt_real == cint64)) { long long L = *reinterpret_cast<const long long *>(l); long long R = *reinterpret_cast<const long long *>(r); if (L < R) { return -1; } if (L != R) { return 1; } } else { // We only pack numbers as cint64 if they are larger than the largest thing // we would store as a double. However, user inputted doubles can be larger // than 2^52 and just be packed as doubles because they came that way, so we // need to actually do the comparison, not just take the one that's packed // as an int to be greater or lesser. double L = (unlikely(lt_real == cint64) ? double(*reinterpret_cast<const long long *>(l)) : (reinterpret_cast<const PackedDouble *>(l))->d); double R = (unlikely(rt_real == cint64) ? double(*reinterpret_cast<const long long *>(r)) : (reinterpret_cast<const PackedDouble *>(r))->d); if (L < R) { return -1; } if (L != R) { return 1; } } l += 8; r += 8; break; } case cstring: { int lsz = *l; int rsz = *r; int common = min(lsz, rsz); l++; r++; // skip the size byte // use memcmp as we (will) allow zeros in UTF8 strings int res = memcmp(l, r, common); if( res ) return res; // longer string is the greater one int diff = lsz-rsz; if( diff ) return diff; l += lsz; r += lsz; break; } case cbindata: { int L = *l; int R = *r; int llen = binDataCodeToLength(L); int diff = L-R; // checks length and subtype simultaneously if( diff ) { // unfortunately nibbles are backwards to do subtype and len in one check (could bit swap...) int rlen = binDataCodeToLength(R); if( llen != rlen ) return llen - rlen; return diff; } // same length, same type l++; r++; int res = memcmp(l, r, llen); if( res ) return res; l += llen; r += llen; break; } case cdate: { long long L = *((long long *) l); long long R = *((long long *) r); if( L < R ) return -1; if( L > R ) return 1; l += 8; r += 8; break; } case coid: { int res = memcmp(l, r, sizeof(OID)); if( res ) return res; l += 12; r += 12; break; } default: // all the others are a match -- e.g. null == null ; } return 0; }
static int compare(const unsigned char *&l, const unsigned char *&r) { int lt = (*l & cCANONTYPEMASK); int rt = (*r & cCANONTYPEMASK); int x = lt - rt; if( x ) return x; l++; r++; // same type switch( lt ) { case cdouble: { double L = *((double *) l); double R = *((double *) r); if( L < R ) return -1; if( L > R ) return 1; l += 8; r += 8; break; } case cstring: { int lsz = *l; int rsz = *r; int common = min(lsz, rsz); l++; r++; // skip the size byte // use memcmp as we (will) allow zeros in UTF8 strings int res = memcmp(l, r, common); if( res ) return res; // longer string is the greater one int diff = lsz-rsz; if( diff ) return diff; l += lsz; r += lsz; break; } case coid: { int res = memcmp(l, r, sizeof(OID)); if( res ) return res; l += 12; r += 12; break; } case cbindata: { int L = *l; int R = *r; int diff = L-R; // checks length and subtype simultaneously if( diff ) return diff; // same length, same type l++; r++; int len = binDataCodeToLength(L); int res = memcmp(l, r, len); if( res ) return res; l += len; r += len; break; } case cdate: { long long L = *((long long *) l); long long R = *((long long *) r); if( L < R ) return -1; if( L > R ) return 1; l += 8; r += 8; break; } default: // all the others are a match -- e.g. null == null ; } return 0; }