int KeyV1::woCompare(const KeyV1& right, const Ordering &order) const { const unsigned char *l = _keyData; const unsigned char *r = right._keyData; if( (*l|*r) == IsBSON ) // only can do this if cNOTUSED maintained return compareHybrid(right, order); unsigned mask = 1; while( 1 ) { char lval = *l; char rval = *r; { int x = compare(l, r); // updates l and r pointers if( x ) { if( order.descending(mask) ) x = -x; return x; } } { int x = ((int)(lval & cHASMORE)) - ((int)(rval & cHASMORE)); if( x ) return x; if( (lval & cHASMORE) == 0 ) break; } mask <<= 1; } return 0; }
int BSONObj::woCompare(const BSONObj& r, const Ordering &o, bool considerFieldName) const { if ( isEmpty() ) return r.isEmpty() ? 0 : -1; if ( r.isEmpty() ) return 1; BSONObjIterator i(*this); BSONObjIterator j(r); unsigned mask = 1; while ( 1 ) { // so far, equal... BSONElement l = i.next(); BSONElement r = j.next(); if ( l.eoo() ) return r.eoo() ? 0 : -1; if ( r.eoo() ) return 1; int x; { x = l.woCompare( r, considerFieldName ); if( o.descending(mask) ) x = -x; } if ( x != 0 ) return x; mask <<= 1; } return -1; }
// pre signed dates & such int oldCompare(const BSONObj& l,const BSONObj& r, const Ordering &o) { BSONObjIterator i(l); BSONObjIterator j(r); unsigned mask = 1; while ( 1 ) { // so far, equal... BSONElement l = i.next(); BSONElement r = j.next(); if ( l.eoo() ) return r.eoo() ? 0 : -1; if ( r.eoo() ) return 1; int x; { x = oldElemCompare(l, r); if( o.descending(mask) ) x = -x; } if ( x != 0 ) return x; mask <<= 1; } return -1; }
void testPermutation(const std::vector<BSONObj>& elementsOrig, const std::vector<BSONObj>& orderings, bool debug) { // Since KeyStrings are compared using memcmp we can assume it provides a total ordering such // that there won't be cases where (a < b && b < c && !(a < c)). This test still needs to ensure // that it provides the *correct* total ordering. for (size_t k = 0; k < orderings.size(); k++) { BSONObj orderObj = orderings[k]; Ordering ordering = Ordering::make(orderObj); if (debug) log() << "ordering: " << orderObj; std::vector<BSONObj> elements = elementsOrig; std::stable_sort(elements.begin(), elements.end(), BSONObjCmp(orderObj)); for (size_t i = 0; i < elements.size(); i++) { const BSONObj& o1 = elements[i]; if (debug) log() << "\to1: " << o1; ROUNDTRIP_ORDER(o1, ordering); KeyString k1(o1, ordering); KeyString l1(BSON("l" << o1.firstElement()), ordering); // kLess KeyString g1(BSON("g" << o1.firstElement()), ordering); // kGreater ASSERT_LT(l1, k1); ASSERT_GT(g1, k1); if (i + 1 < elements.size()) { const BSONObj& o2 = elements[i + 1]; if (debug) log() << "\t\t o2: " << o2; KeyString k2(o2, ordering); KeyString g2(BSON("g" << o2.firstElement()), ordering); KeyString l2(BSON("l" << o2.firstElement()), ordering); int bsonCmp = o1.woCompare(o2, ordering); invariant(bsonCmp <= 0); // We should be sorted... if (bsonCmp == 0) { ASSERT_EQ(k1, k2); } else { ASSERT_LT(k1, k2); } // Test the query encodings using kLess and kGreater int firstElementComp = o1.firstElement().woCompare(o2.firstElement()); if (ordering.descending(1)) firstElementComp = -firstElementComp; invariant(firstElementComp <= 0); if (firstElementComp == 0) { // If they share a first element then l1/g1 should equal l2/g2 and l1 should be // less than both and g1 should be greater than both. ASSERT_EQ(l1, l2); ASSERT_EQ(g1, g2); ASSERT_LT(l1, k2); ASSERT_GT(g1, k2); } else { // k1 is less than k2. Less(k2) and Greater(k1) should be between them. ASSERT_LT(g1, k2); ASSERT_GT(l2, k1); } } } } }