diff options
Diffstat (limited to 'src/mongo/db/matcher/path.cpp')
-rw-r--r-- | src/mongo/db/matcher/path.cpp | 431 |
1 files changed, 208 insertions, 223 deletions
diff --git a/src/mongo/db/matcher/path.cpp b/src/mongo/db/matcher/path.cpp index 80fdd3e8ec8..3dd9374faa7 100644 --- a/src/mongo/db/matcher/path.cpp +++ b/src/mongo/db/matcher/path.cpp @@ -35,295 +35,280 @@ namespace mongo { - Status ElementPath::init( StringData path ) { - _shouldTraverseNonleafArrays = true; - _shouldTraverseLeafArray = true; - _fieldRef.parse( path ); - return Status::OK(); - } - - // ----- +Status ElementPath::init(StringData path) { + _shouldTraverseNonleafArrays = true; + _shouldTraverseLeafArray = true; + _fieldRef.parse(path); + return Status::OK(); +} - ElementIterator::~ElementIterator(){ - } +// ----- - void ElementIterator::Context::reset() { - _element = BSONElement(); - } +ElementIterator::~ElementIterator() {} - void ElementIterator::Context::reset( BSONElement element, - BSONElement arrayOffset, - bool outerArray ) { - _element = element; - _arrayOffset = arrayOffset; - _outerArray = outerArray; - } +void ElementIterator::Context::reset() { + _element = BSONElement(); +} +void ElementIterator::Context::reset(BSONElement element, + BSONElement arrayOffset, + bool outerArray) { + _element = element; + _arrayOffset = arrayOffset; + _outerArray = outerArray; +} - // ------ - SimpleArrayElementIterator::SimpleArrayElementIterator( const BSONElement& theArray, bool returnArrayLast ) - : _theArray( theArray ), _returnArrayLast( returnArrayLast ), _iterator( theArray.Obj() ) { +// ------ - } +SimpleArrayElementIterator::SimpleArrayElementIterator(const BSONElement& theArray, + bool returnArrayLast) + : _theArray(theArray), _returnArrayLast(returnArrayLast), _iterator(theArray.Obj()) {} - bool SimpleArrayElementIterator::more() { - return _iterator.more() || _returnArrayLast; - } +bool SimpleArrayElementIterator::more() { + return _iterator.more() || _returnArrayLast; +} - ElementIterator::Context SimpleArrayElementIterator::next() { - if ( _iterator.more() ) { - Context e; - e.reset( _iterator.next(), BSONElement(), false ); - return e; - } - _returnArrayLast = false; +ElementIterator::Context SimpleArrayElementIterator::next() { + if (_iterator.more()) { Context e; - e.reset( _theArray, BSONElement(), true ); + e.reset(_iterator.next(), BSONElement(), false); return e; } + _returnArrayLast = false; + Context e; + e.reset(_theArray, BSONElement(), true); + return e; +} +// ------ +BSONElementIterator::BSONElementIterator() { + _path = NULL; +} - // ------ - BSONElementIterator::BSONElementIterator() { - _path = NULL; - } - - BSONElementIterator::BSONElementIterator( const ElementPath* path, const BSONObj& context ) - : _path( path ), _context( context ) { - _state = BEGIN; - //log() << "path: " << path.fieldRef().dottedField() << " context: " << context << endl; - } +BSONElementIterator::BSONElementIterator(const ElementPath* path, const BSONObj& context) + : _path(path), _context(context) { + _state = BEGIN; + // log() << "path: " << path.fieldRef().dottedField() << " context: " << context << endl; +} - BSONElementIterator::~BSONElementIterator() { - } +BSONElementIterator::~BSONElementIterator() {} - void BSONElementIterator::reset( const ElementPath* path, const BSONObj& context ) { - _path = path; - _context = context; - _state = BEGIN; - _next.reset(); +void BSONElementIterator::reset(const ElementPath* path, const BSONObj& context) { + _path = path; + _context = context; + _state = BEGIN; + _next.reset(); - _subCursor.reset(); - _subCursorPath.reset(); - } + _subCursor.reset(); + _subCursorPath.reset(); +} - void BSONElementIterator::ArrayIterationState::reset( const FieldRef& ref, int start ) { - restOfPath = ref.dottedField( start ).toString(); - hasMore = restOfPath.size() > 0; - if ( hasMore ) { - nextPieceOfPath = ref.getPart( start ); - nextPieceOfPathIsNumber = isAllDigits( nextPieceOfPath ); - } - else { - nextPieceOfPathIsNumber = false; - } +void BSONElementIterator::ArrayIterationState::reset(const FieldRef& ref, int start) { + restOfPath = ref.dottedField(start).toString(); + hasMore = restOfPath.size() > 0; + if (hasMore) { + nextPieceOfPath = ref.getPart(start); + nextPieceOfPathIsNumber = isAllDigits(nextPieceOfPath); + } else { + nextPieceOfPathIsNumber = false; } +} - bool BSONElementIterator::ArrayIterationState::isArrayOffsetMatch( StringData fieldName ) const { - if ( !nextPieceOfPathIsNumber ) - return false; - return nextPieceOfPath == fieldName; - } +bool BSONElementIterator::ArrayIterationState::isArrayOffsetMatch(StringData fieldName) const { + if (!nextPieceOfPathIsNumber) + return false; + return nextPieceOfPath == fieldName; +} - void BSONElementIterator::ArrayIterationState::startIterator( BSONElement e ) { - _theArray = e; - _iterator.reset( new BSONObjIterator( _theArray.Obj() ) ); - } +void BSONElementIterator::ArrayIterationState::startIterator(BSONElement e) { + _theArray = e; + _iterator.reset(new BSONObjIterator(_theArray.Obj())); +} - bool BSONElementIterator::ArrayIterationState::more() { - return _iterator && _iterator->more(); - } +bool BSONElementIterator::ArrayIterationState::more() { + return _iterator && _iterator->more(); +} - BSONElement BSONElementIterator::ArrayIterationState::next() { - _current = _iterator->next(); - return _current; - } +BSONElement BSONElementIterator::ArrayIterationState::next() { + _current = _iterator->next(); + return _current; +} - bool BSONElementIterator::subCursorHasMore() { - // While we still are still finding arrays along the path, keep traversing deeper. - while ( _subCursor ) { +bool BSONElementIterator::subCursorHasMore() { + // While we still are still finding arrays along the path, keep traversing deeper. + while (_subCursor) { + if (_subCursor->more()) { + return true; + } + _subCursor.reset(); - if ( _subCursor->more() ) { + // If the subcursor doesn't have more, see if the current element is an array offset + // match (see comment in BSONElementIterator::more() for an example). If it is indeed + // an array offset match, create a new subcursor and examine it. + if (_arrayIterationState.isArrayOffsetMatch(_arrayIterationState._current.fieldName())) { + if (_arrayIterationState.nextEntireRest()) { + // Our path terminates at the array offset. _next should point at the current + // array element. + _next.reset(_arrayIterationState._current, _arrayIterationState._current, true); + _arrayIterationState._current = BSONElement(); return true; } - _subCursor.reset(); - - // If the subcursor doesn't have more, see if the current element is an array offset - // match (see comment in BSONElementIterator::more() for an example). If it is indeed - // an array offset match, create a new subcursor and examine it. - if ( _arrayIterationState.isArrayOffsetMatch( _arrayIterationState._current.fieldName() ) ) { - if ( _arrayIterationState.nextEntireRest() ) { - // Our path terminates at the array offset. _next should point at the current - // array element. - _next.reset( _arrayIterationState._current, - _arrayIterationState._current, - true ); - _arrayIterationState._current = BSONElement(); - return true; - } - _subCursorPath.reset( new ElementPath() ); - _subCursorPath->init( _arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1 ) ); - _subCursorPath->setTraverseLeafArray( _path->shouldTraverseLeafArray() ); + _subCursorPath.reset(new ElementPath()); + _subCursorPath->init(_arrayIterationState.restOfPath.substr( + _arrayIterationState.nextPieceOfPath.size() + 1)); + _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); - // If we're here, we must be able to traverse nonleaf arrays. - dassert(_path->shouldTraverseNonleafArrays()); - dassert(_subCursorPath->shouldTraverseNonleafArrays()); - - _subCursor.reset( new BSONElementIterator( _subCursorPath.get(), - _arrayIterationState._current.Obj() ) ); - _arrayIterationState._current = BSONElement(); - } + // If we're here, we must be able to traverse nonleaf arrays. + dassert(_path->shouldTraverseNonleafArrays()); + dassert(_subCursorPath->shouldTraverseNonleafArrays()); + _subCursor.reset( + new BSONElementIterator(_subCursorPath.get(), _arrayIterationState._current.Obj())); + _arrayIterationState._current = BSONElement(); } + } + return false; +} + +bool BSONElementIterator::more() { + if (subCursorHasMore()) { + return true; + } + + if (!_next.element().eoo()) { + return true; + } + + if (_state == DONE) { return false; } - bool BSONElementIterator::more() { - if ( subCursorHasMore() ) { - return true; - } + if (_state == BEGIN) { + size_t idxPath = 0; + BSONElement e = getFieldDottedOrArray(_context, _path->fieldRef(), &idxPath); - if ( !_next.element().eoo() ) { + if (e.type() != Array) { + _next.reset(e, BSONElement(), false); + _state = DONE; return true; } - if ( _state == DONE ){ + // It's an array. + + _arrayIterationState.reset(_path->fieldRef(), idxPath + 1); + + if (_arrayIterationState.hasMore && !_path->shouldTraverseNonleafArrays()) { + // Don't allow traversing the array. + _state = DONE; return false; + } else if (!_arrayIterationState.hasMore && !_path->shouldTraverseLeafArray()) { + // Return the leaf array. + _next.reset(e, BSONElement(), true); + _state = DONE; + return true; } - if ( _state == BEGIN ) { - size_t idxPath = 0; - BSONElement e = getFieldDottedOrArray( _context, _path->fieldRef(), &idxPath ); - - if ( e.type() != Array ) { - _next.reset( e, BSONElement(), false ); - _state = DONE; - return true; - } + _arrayIterationState.startIterator(e); + _state = IN_ARRAY; - // It's an array. + invariant(_next.element().eoo()); + } - _arrayIterationState.reset( _path->fieldRef(), idxPath + 1 ); + if (_state == IN_ARRAY) { + // We're traversing an array. Look at each array element. - if (_arrayIterationState.hasMore && !_path->shouldTraverseNonleafArrays()) { - // Don't allow traversing the array. - _state = DONE; - return false; - } - else if (!_arrayIterationState.hasMore && !_path->shouldTraverseLeafArray()) { - // Return the leaf array. - _next.reset(e, BSONElement(), true); - _state = DONE; + while (_arrayIterationState.more()) { + BSONElement eltInArray = _arrayIterationState.next(); + if (!_arrayIterationState.hasMore) { + // Our path terminates at this array. _next should point at the current array + // element. + _next.reset(eltInArray, eltInArray, false); return true; } - _arrayIterationState.startIterator( e ); - _state = IN_ARRAY; + // Our path does not terminate at this array; there's a subpath left over. Inspect + // the current array element to see if it could match the subpath. - invariant( _next.element().eoo() ); - } - - if ( _state == IN_ARRAY ) { - // We're traversing an array. Look at each array element. - - while ( _arrayIterationState.more() ) { + if (eltInArray.type() == Object) { + // The current array element is a subdocument. See if the subdocument generates + // any elements matching the remaining subpath. + _subCursorPath.reset(new ElementPath()); + _subCursorPath->init(_arrayIterationState.restOfPath); + _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); - BSONElement eltInArray = _arrayIterationState.next(); - if ( !_arrayIterationState.hasMore ) { - // Our path terminates at this array. _next should point at the current array - // element. - _next.reset( eltInArray, eltInArray, false ); + _subCursor.reset(new BSONElementIterator(_subCursorPath.get(), eltInArray.Obj())); + if (subCursorHasMore()) { return true; } - - // Our path does not terminate at this array; there's a subpath left over. Inspect - // the current array element to see if it could match the subpath. - - if ( eltInArray.type() == Object ) { - // The current array element is a subdocument. See if the subdocument generates - // any elements matching the remaining subpath. - _subCursorPath.reset( new ElementPath() ); - _subCursorPath->init( _arrayIterationState.restOfPath ); - _subCursorPath->setTraverseLeafArray( _path->shouldTraverseLeafArray() ); - - _subCursor.reset( new BSONElementIterator( _subCursorPath.get(), - eltInArray.Obj() ) ); - if ( subCursorHasMore() ) { - return true; - } + } else if (_arrayIterationState.isArrayOffsetMatch(eltInArray.fieldName())) { + // The path we're traversing has an array offset component, and the current + // array element corresponds to the offset we're looking for (for example: our + // path has a ".0" component, and we're looking at the first element of the + // array, so we should look inside this element). + + if (_arrayIterationState.nextEntireRest()) { + // Our path terminates at the array offset. _next should point at the + // current array element. + _next.reset(eltInArray, eltInArray, false); + return true; } - else if ( _arrayIterationState.isArrayOffsetMatch( eltInArray.fieldName() ) ) { - // The path we're traversing has an array offset component, and the current - // array element corresponds to the offset we're looking for (for example: our - // path has a ".0" component, and we're looking at the first element of the - // array, so we should look inside this element). - - if ( _arrayIterationState.nextEntireRest() ) { - // Our path terminates at the array offset. _next should point at the - // current array element. - _next.reset( eltInArray, eltInArray, false ); - return true; - } - invariant( eltInArray.type() != Object ); // Handled above. - if ( eltInArray.type() == Array ) { - // The current array element is itself an array. See if the nested array - // has any elements matching the remainihng. - _subCursorPath.reset( new ElementPath() ); - _subCursorPath->init( _arrayIterationState.restOfPath.substr( _arrayIterationState.nextPieceOfPath.size() + 1 ) ); - _subCursorPath->setTraverseLeafArray( _path->shouldTraverseLeafArray() ); - BSONElementIterator* real = - new BSONElementIterator( _subCursorPath.get(), - _arrayIterationState._current.Obj() ); - _subCursor.reset( real ); - real->_arrayIterationState.reset( _subCursorPath->fieldRef(), 0 ); - real->_arrayIterationState.startIterator( eltInArray ); - real->_state = IN_ARRAY; - _arrayIterationState._current = BSONElement(); - if ( subCursorHasMore() ) { - return true; - } + invariant(eltInArray.type() != Object); // Handled above. + if (eltInArray.type() == Array) { + // The current array element is itself an array. See if the nested array + // has any elements matching the remainihng. + _subCursorPath.reset(new ElementPath()); + _subCursorPath->init(_arrayIterationState.restOfPath.substr( + _arrayIterationState.nextPieceOfPath.size() + 1)); + _subCursorPath->setTraverseLeafArray(_path->shouldTraverseLeafArray()); + BSONElementIterator* real = new BSONElementIterator( + _subCursorPath.get(), _arrayIterationState._current.Obj()); + _subCursor.reset(real); + real->_arrayIterationState.reset(_subCursorPath->fieldRef(), 0); + real->_arrayIterationState.startIterator(eltInArray); + real->_state = IN_ARRAY; + _arrayIterationState._current = BSONElement(); + if (subCursorHasMore()) { + return true; } } - - } - - if ( _arrayIterationState.hasMore ) { - return false; } + } - _next.reset( _arrayIterationState._theArray, BSONElement(), true ); - _state = DONE; - return true; + if (_arrayIterationState.hasMore) { + return false; } - return false; + _next.reset(_arrayIterationState._theArray, BSONElement(), true); + _state = DONE; + return true; } - ElementIterator::Context BSONElementIterator::next() { - if ( _subCursor ) { - Context e = _subCursor->next(); - // Use our array offset if we have one, otherwise copy our subcursor's. This has the - // effect of preferring the outermost array offset, in the case where we are implicitly - // traversing nested arrays and have multiple candidate array offsets. For example, - // when we use the path "a.b" to generate elements from the document {a: [{b: [1, 2]}]}, - // the element with a value of 2 should be returned with an array offset of 0. - if ( !_arrayIterationState._current.eoo() ) { - e.setArrayOffset( _arrayIterationState._current ); - } - return e; + return false; +} + +ElementIterator::Context BSONElementIterator::next() { + if (_subCursor) { + Context e = _subCursor->next(); + // Use our array offset if we have one, otherwise copy our subcursor's. This has the + // effect of preferring the outermost array offset, in the case where we are implicitly + // traversing nested arrays and have multiple candidate array offsets. For example, + // when we use the path "a.b" to generate elements from the document {a: [{b: [1, 2]}]}, + // the element with a value of 2 should be returned with an array offset of 0. + if (!_arrayIterationState._current.eoo()) { + e.setArrayOffset(_arrayIterationState._current); } - Context x = _next; - _next.reset(); - return x; + return e; } - - + Context x = _next; + _next.reset(); + return x; +} } |