diff options
Diffstat (limited to 'src/mongo/db/matcher/expression_leaf.cpp')
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 822 |
1 files changed, 416 insertions, 406 deletions
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index f0a91cffbbf..619fc64133d 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -41,52 +41,50 @@ namespace mongo { - Status LeafMatchExpression::initPath( StringData path ) { - _path = path; - return _elementPath.init( _path ); - } +Status LeafMatchExpression::initPath(StringData path) { + _path = path; + return _elementPath.init(_path); +} - bool LeafMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const { - MatchableDocument::IteratorHolder cursor( doc, &_elementPath ); - while ( cursor->more() ) { - ElementIterator::Context e = cursor->next(); - if ( !matchesSingleElement( e.element() ) ) - continue; - if ( details && details->needRecord() && !e.arrayOffset().eoo() ) { - details->setElemMatchKey( e.arrayOffset().fieldName() ); - } - return true; +bool LeafMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const { + MatchableDocument::IteratorHolder cursor(doc, &_elementPath); + while (cursor->more()) { + ElementIterator::Context e = cursor->next(); + if (!matchesSingleElement(e.element())) + continue; + if (details && details->needRecord() && !e.arrayOffset().eoo()) { + details->setElemMatchKey(e.arrayOffset().fieldName()); } - return false; + return true; } + return false; +} - // ------------- +// ------------- - bool ComparisonMatchExpression::equivalent( const MatchExpression* other ) const { - if ( other->matchType() != matchType() ) - return false; - const ComparisonMatchExpression* realOther = - static_cast<const ComparisonMatchExpression*>( other ); +bool ComparisonMatchExpression::equivalent(const MatchExpression* other) const { + if (other->matchType() != matchType()) + return false; + const ComparisonMatchExpression* realOther = + static_cast<const ComparisonMatchExpression*>(other); - return - path() == realOther->path() && - _rhs.valuesEqual( realOther->_rhs ); - } + return path() == realOther->path() && _rhs.valuesEqual(realOther->_rhs); +} - Status ComparisonMatchExpression::init( StringData path, const BSONElement& rhs ) { - _rhs = rhs; +Status ComparisonMatchExpression::init(StringData path, const BSONElement& rhs) { + _rhs = rhs; - if ( rhs.eoo() ) { - return Status( ErrorCodes::BadValue, "need a real operand" ); - } + if (rhs.eoo()) { + return Status(ErrorCodes::BadValue, "need a real operand"); + } - if ( rhs.type() == Undefined ) { - return Status( ErrorCodes::BadValue, "cannot compare to undefined" ); - } + if (rhs.type() == Undefined) { + return Status(ErrorCodes::BadValue, "cannot compare to undefined"); + } - switch ( matchType() ) { + switch (matchType()) { case LT: case LTE: case EQ: @@ -94,36 +92,36 @@ namespace mongo { case GTE: break; default: - return Status( ErrorCodes::BadValue, "bad match type for ComparisonMatchExpression" ); - } - - return initPath( path ); + return Status(ErrorCodes::BadValue, "bad match type for ComparisonMatchExpression"); } + return initPath(path); +} - bool ComparisonMatchExpression::matchesSingleElement( const BSONElement& e ) const { - //log() << "\t ComparisonMatchExpression e: " << e << " _rhs: " << _rhs << "\n" - //<< toString() << std::endl; - if ( e.canonicalType() != _rhs.canonicalType() ) { - // some special cases - // jstNULL and undefined are treated the same - if ( e.canonicalType() + _rhs.canonicalType() == 5 ) { - return matchType() == EQ || matchType() == LTE || matchType() == GTE; - } +bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e) const { + // log() << "\t ComparisonMatchExpression e: " << e << " _rhs: " << _rhs << "\n" + //<< toString() << std::endl; - if ( _rhs.type() == MaxKey || _rhs.type() == MinKey ) { - return matchType() != EQ; - } + if (e.canonicalType() != _rhs.canonicalType()) { + // some special cases + // jstNULL and undefined are treated the same + if (e.canonicalType() + _rhs.canonicalType() == 5) { + return matchType() == EQ || matchType() == LTE || matchType() == GTE; + } - return false; + if (_rhs.type() == MaxKey || _rhs.type() == MinKey) { + return matchType() != EQ; } - // Special case handling for NaN. NaN is equal to NaN but - // otherwise always compares to false. - if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) { - bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble()); - switch ( matchType() ) { + return false; + } + + // Special case handling for NaN. NaN is equal to NaN but + // otherwise always compares to false. + if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) { + bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble()); + switch (matchType()) { case LT: return false; case LTE: @@ -137,15 +135,15 @@ namespace mongo { default: // This is a comparison match expression, so it must be either // a $lt, $lte, $gt, $gte, or equality expression. - fassertFailed( 17448 ); - } + fassertFailed(17448); } + } - int x = compareElementValues( e, _rhs ); + int x = compareElementValues(e, _rhs); - //log() << "\t\t" << x << endl; + // log() << "\t\t" << x << endl; - switch ( matchType() ) { + switch (matchType()) { case LT: return x < 0; case LTE: @@ -159,450 +157,462 @@ namespace mongo { default: // This is a comparison match expression, so it must be either // a $lt, $lte, $gt, $gte, or equality expression. - fassertFailed( 16828 ); - } + fassertFailed(16828); } +} - void ComparisonMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << path() << " "; - switch ( matchType() ) { - case LT: debug << "$lt"; break; - case LTE: debug << "$lte"; break; - case EQ: debug << "=="; break; - case GT: debug << "$gt"; break; - case GTE: debug << "$gte"; break; - default: debug << " UNKNOWN - should be impossible"; break; - } - debug << " " << _rhs.toString( false ); - - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); - } - - debug << "\n"; +void ComparisonMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << path() << " "; + switch (matchType()) { + case LT: + debug << "$lt"; + break; + case LTE: + debug << "$lte"; + break; + case EQ: + debug << "=="; + break; + case GT: + debug << "$gt"; + break; + case GTE: + debug << "$gte"; + break; + default: + debug << " UNKNOWN - should be impossible"; + break; } + debug << " " << _rhs.toString(false); - void ComparisonMatchExpression::toBSON(BSONObjBuilder* out) const { - string opString = ""; - switch ( matchType() ) { - case LT: opString = "$lt"; break; - case LTE: opString = "$lte"; break; - case EQ: opString = "$eq"; break; - case GT: opString = "$gt"; break; - case GTE: opString = "$gte"; break; - default: opString = " UNKNOWN - should be impossible"; break; - } - - out->append(path(), BSON(opString << _rhs)); + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } - // --------------- - - // TODO: move - inline pcrecpp::RE_Options flags2options(const char* flags) { - pcrecpp::RE_Options options; - options.set_utf8(true); - while ( flags && *flags ) { - if ( *flags == 'i' ) - options.set_caseless(true); - else if ( *flags == 'm' ) - options.set_multiline(true); - else if ( *flags == 'x' ) - options.set_extended(true); - else if ( *flags == 's' ) - options.set_dotall(true); - flags++; - } - return options; + debug << "\n"; +} + +void ComparisonMatchExpression::toBSON(BSONObjBuilder* out) const { + string opString = ""; + switch (matchType()) { + case LT: + opString = "$lt"; + break; + case LTE: + opString = "$lte"; + break; + case EQ: + opString = "$eq"; + break; + case GT: + opString = "$gt"; + break; + case GTE: + opString = "$gte"; + break; + default: + opString = " UNKNOWN - should be impossible"; + break; } - RegexMatchExpression::RegexMatchExpression() - : LeafMatchExpression( REGEX ) {} + out->append(path(), BSON(opString << _rhs)); +} - RegexMatchExpression::~RegexMatchExpression() {} +// --------------- + +// TODO: move +inline pcrecpp::RE_Options flags2options(const char* flags) { + pcrecpp::RE_Options options; + options.set_utf8(true); + while (flags && *flags) { + if (*flags == 'i') + options.set_caseless(true); + else if (*flags == 'm') + options.set_multiline(true); + else if (*flags == 'x') + options.set_extended(true); + else if (*flags == 's') + options.set_dotall(true); + flags++; + } + return options; +} - bool RegexMatchExpression::equivalent( const MatchExpression* other ) const { - if ( matchType() != other->matchType() ) - return false; +RegexMatchExpression::RegexMatchExpression() : LeafMatchExpression(REGEX) {} - const RegexMatchExpression* realOther = static_cast<const RegexMatchExpression*>( other ); - return - path() == realOther->path() && - _regex == realOther->_regex - && _flags == realOther->_flags; - } +RegexMatchExpression::~RegexMatchExpression() {} +bool RegexMatchExpression::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) + return false; - Status RegexMatchExpression::init( StringData path, const BSONElement& e ) { - if ( e.type() != RegEx ) - return Status( ErrorCodes::BadValue, "regex not a regex" ); - return init( path, e.regex(), e.regexFlags() ); - } + const RegexMatchExpression* realOther = static_cast<const RegexMatchExpression*>(other); + return path() == realOther->path() && _regex == realOther->_regex && + _flags == realOther->_flags; +} - Status RegexMatchExpression::init( StringData path, StringData regex, StringData options ) { - if ( regex.size() > MaxPatternSize ) { - return Status( ErrorCodes::BadValue, "Regular expression is too long" ); - } +Status RegexMatchExpression::init(StringData path, const BSONElement& e) { + if (e.type() != RegEx) + return Status(ErrorCodes::BadValue, "regex not a regex"); + return init(path, e.regex(), e.regexFlags()); +} - _regex = regex.toString(); - _flags = options.toString(); - _re.reset( new pcrecpp::RE( _regex.c_str(), flags2options( _flags.c_str() ) ) ); - return initPath( path ); +Status RegexMatchExpression::init(StringData path, StringData regex, StringData options) { + if (regex.size() > MaxPatternSize) { + return Status(ErrorCodes::BadValue, "Regular expression is too long"); } - bool RegexMatchExpression::matchesSingleElement( const BSONElement& e ) const { - //log() << "RegexMatchExpression::matchesSingleElement _regex: " << _regex << " e: " << e << std::endl; - switch (e.type()) { + _regex = regex.toString(); + _flags = options.toString(); + _re.reset(new pcrecpp::RE(_regex.c_str(), flags2options(_flags.c_str()))); + + return initPath(path); +} + +bool RegexMatchExpression::matchesSingleElement(const BSONElement& e) const { + // log() << "RegexMatchExpression::matchesSingleElement _regex: " << _regex << " e: " << e << std::endl; + switch (e.type()) { case String: case Symbol: // TODO - //if (rm._prefix.empty()) - return _re->PartialMatch(e.valuestr()); - //else - //return !strncmp(e.valuestr(), rm._prefix.c_str(), rm._prefix.size()); + // if (rm._prefix.empty()) + return _re->PartialMatch(e.valuestr()); + // else + // return !strncmp(e.valuestr(), rm._prefix.c_str(), rm._prefix.size()); case RegEx: return _regex == e.regex() && _flags == e.regexFlags(); default: return false; - } } +} - void RegexMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << path() << " regex /" << _regex << "/" << _flags; +void RegexMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << path() << " regex /" << _regex << "/" << _flags; - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); - } - debug << "\n"; + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } + debug << "\n"; +} - void RegexMatchExpression::toBSON(BSONObjBuilder* out) const { - out->appendRegex(path(), _regex, _flags); - } +void RegexMatchExpression::toBSON(BSONObjBuilder* out) const { + out->appendRegex(path(), _regex, _flags); +} - void RegexMatchExpression::shortDebugString( StringBuilder& debug ) const { - debug << "/" << _regex << "/" << _flags; - } +void RegexMatchExpression::shortDebugString(StringBuilder& debug) const { + debug << "/" << _regex << "/" << _flags; +} - // --------- +// --------- - Status ModMatchExpression::init( StringData path, int divisor, int remainder ) { - if ( divisor == 0 ) - return Status( ErrorCodes::BadValue, "divisor cannot be 0" ); - _divisor = divisor; - _remainder = remainder; - return initPath( path ); - } +Status ModMatchExpression::init(StringData path, int divisor, int remainder) { + if (divisor == 0) + return Status(ErrorCodes::BadValue, "divisor cannot be 0"); + _divisor = divisor; + _remainder = remainder; + return initPath(path); +} - bool ModMatchExpression::matchesSingleElement( const BSONElement& e ) const { - if ( !e.isNumber() ) - return false; - return e.numberLong() % _divisor == _remainder; - } +bool ModMatchExpression::matchesSingleElement(const BSONElement& e) const { + if (!e.isNumber()) + return false; + return e.numberLong() % _divisor == _remainder; +} - void ModMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << path() << " mod " << _divisor << " % x == " << _remainder; - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); - } - debug << "\n"; +void ModMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << path() << " mod " << _divisor << " % x == " << _remainder; + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } + debug << "\n"; +} - void ModMatchExpression::toBSON(BSONObjBuilder* out) const { - out->append(path(), BSON("$mod" << BSON_ARRAY(_divisor << _remainder))); - } +void ModMatchExpression::toBSON(BSONObjBuilder* out) const { + out->append(path(), BSON("$mod" << BSON_ARRAY(_divisor << _remainder))); +} - bool ModMatchExpression::equivalent( const MatchExpression* other ) const { - if ( matchType() != other->matchType() ) - return false; +bool ModMatchExpression::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) + return false; - const ModMatchExpression* realOther = static_cast<const ModMatchExpression*>( other ); - return - path() == realOther->path() && - _divisor == realOther->_divisor && - _remainder == realOther->_remainder; - } + const ModMatchExpression* realOther = static_cast<const ModMatchExpression*>(other); + return path() == realOther->path() && _divisor == realOther->_divisor && + _remainder == realOther->_remainder; +} - // ------------------ +// ------------------ - Status ExistsMatchExpression::init( StringData path ) { - return initPath( path ); - } +Status ExistsMatchExpression::init(StringData path) { + return initPath(path); +} - bool ExistsMatchExpression::matchesSingleElement( const BSONElement& e ) const { - return !e.eoo(); - } +bool ExistsMatchExpression::matchesSingleElement(const BSONElement& e) const { + return !e.eoo(); +} - void ExistsMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << path() << " exists"; - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); - } - debug << "\n"; +void ExistsMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << path() << " exists"; + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } + debug << "\n"; +} - void ExistsMatchExpression::toBSON(BSONObjBuilder* out) const { - out->append(path(), BSON("$exists" << true)); - } +void ExistsMatchExpression::toBSON(BSONObjBuilder* out) const { + out->append(path(), BSON("$exists" << true)); +} - bool ExistsMatchExpression::equivalent( const MatchExpression* other ) const { - if ( matchType() != other->matchType() ) - return false; +bool ExistsMatchExpression::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) + return false; - const ExistsMatchExpression* realOther = static_cast<const ExistsMatchExpression*>( other ); - return path() == realOther->path(); - } + const ExistsMatchExpression* realOther = static_cast<const ExistsMatchExpression*>(other); + return path() == realOther->path(); +} - // ---- +// ---- - Status TypeMatchExpression::init( StringData path, int type ) { - _path = path; - _type = type; - return _elementPath.init( _path ); - } +Status TypeMatchExpression::init(StringData path, int type) { + _path = path; + _type = type; + return _elementPath.init(_path); +} - bool TypeMatchExpression::matchesSingleElement( const BSONElement& e ) const { - return e.type() == _type; - } +bool TypeMatchExpression::matchesSingleElement(const BSONElement& e) const { + return e.type() == _type; +} - bool TypeMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const { - MatchableDocument::IteratorHolder cursor( doc, &_elementPath ); - while ( cursor->more() ) { - ElementIterator::Context e = cursor->next(); - - // In the case where _elementPath is referring to an array, - // $type should match elements of that array only. - // outerArray() helps to identify elements of the array - // and the containing array itself. - // This matters when we are looking for {$type: Array}. - // Example (_elementPath refers to field 'a' and _type is Array): - // a : [ // outer array. should not match - // 123, // inner array - // [ 456 ], // inner array. should match - // ... - // ] - if ( _type == mongo::Array && e.outerArray() ) { - continue; - } - - if ( !matchesSingleElement( e.element() ) ) { - continue; - } - - if ( details && details->needRecord() && !e.arrayOffset().eoo() ) { - details->setElemMatchKey( e.arrayOffset().fieldName() ); - } - return true; +bool TypeMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const { + MatchableDocument::IteratorHolder cursor(doc, &_elementPath); + while (cursor->more()) { + ElementIterator::Context e = cursor->next(); + + // In the case where _elementPath is referring to an array, + // $type should match elements of that array only. + // outerArray() helps to identify elements of the array + // and the containing array itself. + // This matters when we are looking for {$type: Array}. + // Example (_elementPath refers to field 'a' and _type is Array): + // a : [ // outer array. should not match + // 123, // inner array + // [ 456 ], // inner array. should match + // ... + // ] + if (_type == mongo::Array && e.outerArray()) { + continue; } - return false; - } - void TypeMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << _path << " type: " << _type; - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); + if (!matchesSingleElement(e.element())) { + continue; } - debug << "\n"; - } - void TypeMatchExpression::toBSON(BSONObjBuilder* out) const { - out->append(path(), BSON("$type" << _type)); + if (details && details->needRecord() && !e.arrayOffset().eoo()) { + details->setElemMatchKey(e.arrayOffset().fieldName()); + } + return true; } + return false; +} - bool TypeMatchExpression::equivalent( const MatchExpression* other ) const { - if ( matchType() != other->matchType() ) - return false; - - const TypeMatchExpression* realOther = static_cast<const TypeMatchExpression*>( other ); - return _path == realOther->_path && _type == realOther->_type; +void TypeMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << _path << " type: " << _type; + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } + debug << "\n"; +} +void TypeMatchExpression::toBSON(BSONObjBuilder* out) const { + out->append(path(), BSON("$type" << _type)); +} - // -------- +bool TypeMatchExpression::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) + return false; - ArrayFilterEntries::ArrayFilterEntries(){ - _hasNull = false; - _hasEmptyArray = false; - } + const TypeMatchExpression* realOther = static_cast<const TypeMatchExpression*>(other); + return _path == realOther->_path && _type == realOther->_type; +} - ArrayFilterEntries::~ArrayFilterEntries() { - for ( unsigned i = 0; i < _regexes.size(); i++ ) - delete _regexes[i]; - _regexes.clear(); - } - Status ArrayFilterEntries::addEquality( const BSONElement& e ) { - if ( e.type() == RegEx ) - return Status( ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be a regex" ); +// -------- - if ( e.type() == Undefined ) { - return Status( ErrorCodes::BadValue, - "ArrayFilterEntries equality cannot be undefined" ); - } +ArrayFilterEntries::ArrayFilterEntries() { + _hasNull = false; + _hasEmptyArray = false; +} - if ( e.type() == jstNULL ) { - _hasNull = true; - } +ArrayFilterEntries::~ArrayFilterEntries() { + for (unsigned i = 0; i < _regexes.size(); i++) + delete _regexes[i]; + _regexes.clear(); +} - if ( e.type() == Array && e.Obj().isEmpty() ) - _hasEmptyArray = true; +Status ArrayFilterEntries::addEquality(const BSONElement& e) { + if (e.type() == RegEx) + return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be a regex"); - _equalities.insert( e ); - return Status::OK(); + if (e.type() == Undefined) { + return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be undefined"); } - Status ArrayFilterEntries::addRegex( RegexMatchExpression* expr ) { - _regexes.push_back( expr ); - return Status::OK(); + if (e.type() == jstNULL) { + _hasNull = true; } - bool ArrayFilterEntries::equivalent( const ArrayFilterEntries& other ) const { - if ( _hasNull != other._hasNull ) - return false; + if (e.type() == Array && e.Obj().isEmpty()) + _hasEmptyArray = true; - if ( _regexes.size() != other._regexes.size() ) + _equalities.insert(e); + return Status::OK(); +} + +Status ArrayFilterEntries::addRegex(RegexMatchExpression* expr) { + _regexes.push_back(expr); + return Status::OK(); +} + +bool ArrayFilterEntries::equivalent(const ArrayFilterEntries& other) const { + if (_hasNull != other._hasNull) + return false; + + if (_regexes.size() != other._regexes.size()) + return false; + for (unsigned i = 0; i < _regexes.size(); i++) + if (!_regexes[i]->equivalent(other._regexes[i])) return false; - for ( unsigned i = 0; i < _regexes.size(); i++ ) - if ( !_regexes[i]->equivalent( other._regexes[i] ) ) - return false; - return _equalities == other._equalities; - } + return _equalities == other._equalities; +} - void ArrayFilterEntries::copyTo( ArrayFilterEntries& toFillIn ) const { - toFillIn._hasNull = _hasNull; - toFillIn._hasEmptyArray = _hasEmptyArray; - toFillIn._equalities = _equalities; - for ( unsigned i = 0; i < _regexes.size(); i++ ) - toFillIn._regexes.push_back( static_cast<RegexMatchExpression*>(_regexes[i]->shallowClone()) ); - } +void ArrayFilterEntries::copyTo(ArrayFilterEntries& toFillIn) const { + toFillIn._hasNull = _hasNull; + toFillIn._hasEmptyArray = _hasEmptyArray; + toFillIn._equalities = _equalities; + for (unsigned i = 0; i < _regexes.size(); i++) + toFillIn._regexes.push_back( + static_cast<RegexMatchExpression*>(_regexes[i]->shallowClone())); +} - void ArrayFilterEntries::debugString( StringBuilder& debug ) const { - debug << "[ "; - for (BSONElementSet::const_iterator it = _equalities.begin(); - it != _equalities.end(); ++it) { - debug << it->toString( false ) << " "; - } - for (size_t i = 0; i < _regexes.size(); ++i) { - _regexes[i]->shortDebugString( debug ); - debug << " "; - } - debug << "]"; +void ArrayFilterEntries::debugString(StringBuilder& debug) const { + debug << "[ "; + for (BSONElementSet::const_iterator it = _equalities.begin(); it != _equalities.end(); ++it) { + debug << it->toString(false) << " "; } - - void ArrayFilterEntries::toBSON(BSONArrayBuilder* out) const { - for (BSONElementSet::const_iterator it = _equalities.begin(); - it != _equalities.end(); ++it) { - out->append(*it); - } - for (size_t i = 0; i < _regexes.size(); ++i) { - BSONObjBuilder regexBob; - _regexes[i]->toBSON(®exBob); - out->append(regexBob.obj().firstElement()); - } - out->doneFast(); + for (size_t i = 0; i < _regexes.size(); ++i) { + _regexes[i]->shortDebugString(debug); + debug << " "; } + debug << "]"; +} - // ----------- - - Status InMatchExpression::init( StringData path ) { - return initPath( path ); +void ArrayFilterEntries::toBSON(BSONArrayBuilder* out) const { + for (BSONElementSet::const_iterator it = _equalities.begin(); it != _equalities.end(); ++it) { + out->append(*it); } + for (size_t i = 0; i < _regexes.size(); ++i) { + BSONObjBuilder regexBob; + _regexes[i]->toBSON(®exBob); + out->append(regexBob.obj().firstElement()); + } + out->doneFast(); +} - bool InMatchExpression::_matchesRealElement( const BSONElement& e ) const { - if ( _arrayEntries.contains( e ) ) - return true; +// ----------- - for ( unsigned i = 0; i < _arrayEntries.numRegexes(); i++ ) { - if ( _arrayEntries.regex(i)->matchesSingleElement( e ) ) - return true; - } +Status InMatchExpression::init(StringData path) { + return initPath(path); +} - return false; - } +bool InMatchExpression::_matchesRealElement(const BSONElement& e) const { + if (_arrayEntries.contains(e)) + return true; - bool InMatchExpression::matchesSingleElement( const BSONElement& e ) const { - if ( _arrayEntries.hasNull() && e.eoo() ) + for (unsigned i = 0; i < _arrayEntries.numRegexes(); i++) { + if (_arrayEntries.regex(i)->matchesSingleElement(e)) return true; + } - if ( _matchesRealElement( e ) ) - return true; + return false; +} - /* - if ( e.type() == Array ) { - BSONObjIterator i( e.Obj() ); - while ( i.more() ) { - BSONElement sub = i.next(); - if ( _matchesRealElement( sub ) ) - return true; - } - } - */ +bool InMatchExpression::matchesSingleElement(const BSONElement& e) const { + if (_arrayEntries.hasNull() && e.eoo()) + return true; - return false; - } + if (_matchesRealElement(e)) + return true; - void InMatchExpression::debugString( StringBuilder& debug, int level ) const { - _debugAddSpace( debug, level ); - debug << path() << " $in "; - _arrayEntries.debugString(debug); - MatchExpression::TagData* td = getTag(); - if (NULL != td) { - debug << " "; - td->debugString(&debug); + /* + if ( e.type() == Array ) { + BSONObjIterator i( e.Obj() ); + while ( i.more() ) { + BSONElement sub = i.next(); + if ( _matchesRealElement( sub ) ) + return true; } - debug << "\n"; - } - - void InMatchExpression::toBSON(BSONObjBuilder* out) const { - BSONObjBuilder inBob(out->subobjStart(path())); - BSONArrayBuilder arrBob(inBob.subarrayStart("$in")); - _arrayEntries.toBSON(&arrBob); - inBob.doneFast(); } + */ - bool InMatchExpression::equivalent( const MatchExpression* other ) const { - if ( matchType() != other->matchType() ) - return false; - const InMatchExpression* realOther = static_cast<const InMatchExpression*>( other ); - return - path() == realOther->path() && - _arrayEntries.equivalent( realOther->_arrayEntries ); - } + return false; +} - LeafMatchExpression* InMatchExpression::shallowClone() const { - InMatchExpression* next = new InMatchExpression(); - copyTo( next ); - if ( getTag() ) { - next->setTag(getTag()->clone()); - } - return next; +void InMatchExpression::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << path() << " $in "; + _arrayEntries.debugString(debug); + MatchExpression::TagData* td = getTag(); + if (NULL != td) { + debug << " "; + td->debugString(&debug); } + debug << "\n"; +} - void InMatchExpression::copyTo( InMatchExpression* toFillIn ) const { - toFillIn->init( path() ); - _arrayEntries.copyTo( toFillIn->_arrayEntries ); - } +void InMatchExpression::toBSON(BSONObjBuilder* out) const { + BSONObjBuilder inBob(out->subobjStart(path())); + BSONArrayBuilder arrBob(inBob.subarrayStart("$in")); + _arrayEntries.toBSON(&arrBob); + inBob.doneFast(); +} +bool InMatchExpression::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) + return false; + const InMatchExpression* realOther = static_cast<const InMatchExpression*>(other); + return path() == realOther->path() && _arrayEntries.equivalent(realOther->_arrayEntries); } +LeafMatchExpression* InMatchExpression::shallowClone() const { + InMatchExpression* next = new InMatchExpression(); + copyTo(next); + if (getTag()) { + next->setTag(getTag()->clone()); + } + return next; +} +void InMatchExpression::copyTo(InMatchExpression* toFillIn) const { + toFillIn->init(path()); + _arrayEntries.copyTo(toFillIn->_arrayEntries); +} +} |