// path.h
/**
* Copyright (C) 2013 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/base/status.h"
#include "mongo/base/string_data.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/db/field_ref.h"
namespace mongo {
class ElementPath {
public:
Status init( StringData path );
void setTraverseNonleafArrays( bool b ) { _shouldTraverseNonleafArrays = b; }
void setTraverseLeafArray( bool b ) { _shouldTraverseLeafArray = b; }
const FieldRef& fieldRef() const { return _fieldRef; }
bool shouldTraverseNonleafArrays() const { return _shouldTraverseNonleafArrays; }
bool shouldTraverseLeafArray() const { return _shouldTraverseLeafArray; }
private:
FieldRef _fieldRef;
bool _shouldTraverseNonleafArrays;
bool _shouldTraverseLeafArray;
};
class ElementIterator {
public:
class Context {
public:
void reset();
void reset( BSONElement element, BSONElement arrayOffset, bool outerArray );
void setArrayOffset( BSONElement e ) { _arrayOffset = e; }
BSONElement element() const { return _element; }
BSONElement arrayOffset() const { return _arrayOffset; }
bool outerArray() const { return _outerArray; }
private:
BSONElement _element;
BSONElement _arrayOffset;
bool _outerArray;
};
virtual ~ElementIterator();
virtual bool more() = 0;
virtual Context next() = 0;
};
// ---------------------------------------------------------------
class SingleElementElementIterator : public ElementIterator {
public:
explicit SingleElementElementIterator( BSONElement e )
: _seen( false ) {
_element.reset( e, BSONElement(), false );
}
virtual ~SingleElementElementIterator(){}
virtual bool more() { return !_seen; }
virtual Context next() { _seen = true; return _element; }
private:
bool _seen;
ElementIterator::Context _element;
};
class SimpleArrayElementIterator : public ElementIterator {
public:
SimpleArrayElementIterator( const BSONElement& theArray, bool returnArrayLast );
virtual bool more();
virtual Context next();
private:
BSONElement _theArray;
bool _returnArrayLast;
BSONObjIterator _iterator;
};
class BSONElementIterator : public ElementIterator {
public:
BSONElementIterator();
BSONElementIterator( const ElementPath* path, const BSONObj& context );
virtual ~BSONElementIterator();
void reset( const ElementPath* path, const BSONObj& context );
bool more();
Context next();
private:
/**
* Helper for more(). Recurs on _subCursor (which traverses the remainder of a path through
* subdocuments of an array).
*/
bool subCursorHasMore();
const ElementPath* _path;
BSONObj _context;
enum State { BEGIN, IN_ARRAY, DONE } _state;
Context _next;
struct ArrayIterationState {
void reset( const FieldRef& ref, int start );
void startIterator( BSONElement theArray );
bool more();
BSONElement next();
bool isArrayOffsetMatch( StringData fieldName ) const;
bool nextEntireRest() const { return nextPieceOfPath.size() == restOfPath.size(); }
std::string restOfPath;
bool hasMore;
StringData nextPieceOfPath;
bool nextPieceOfPathIsNumber;
BSONElement _theArray;
BSONElement _current;
std::unique_ptr _iterator;
};
ArrayIterationState _arrayIterationState;
std::unique_ptr _subCursor;
std::unique_ptr _subCursorPath;
};
}