summaryrefslogtreecommitdiff
path: root/bson
diff options
context:
space:
mode:
Diffstat (limited to 'bson')
-rw-r--r--bson/bson-inl.h (renamed from bson/bsoninlines.h)187
-rw-r--r--bson/bson.h30
-rw-r--r--bson/bson_db.h28
-rw-r--r--bson/bsondemo/bsondemo.cpp26
-rw-r--r--bson/bsonelement.h662
-rw-r--r--bson/bsonmisc.h78
-rw-r--r--bson/bsonobj.h212
-rw-r--r--bson/bsonobjbuilder.h265
-rw-r--r--bson/bsonobjiterator.h70
-rw-r--r--bson/bsontypes.h112
-rw-r--r--bson/inline_decls.h2
-rw-r--r--bson/oid.cpp154
-rw-r--r--bson/oid.h95
-rw-r--r--bson/ordering.h10
-rw-r--r--bson/stringdata.h37
-rw-r--r--bson/util/atomic_int.h40
-rw-r--r--bson/util/builder.h149
-rw-r--r--bson/util/misc.h4
18 files changed, 1268 insertions, 893 deletions
diff --git a/bson/bsoninlines.h b/bson/bson-inl.h
index 0a2e59b..5b4c490 100644
--- a/bson/bsoninlines.h
+++ b/bson/bson-inl.h
@@ -24,13 +24,17 @@
namespace mongo {
- inline BSONObjIterator BSONObj::begin() {
+ inline BSONObjIterator BSONObj::begin() {
return BSONObjIterator(*this);
}
inline BSONObj BSONElement::embeddedObjectUserCheck() const {
- uassert( 10065 , "invalid parameter: expected an object", isABSONObj() );
- return BSONObj(value());
+ if ( isABSONObj() )
+ return BSONObj(value());
+ stringstream ss;
+ ss << "invalid parameter: expected an object (" << fieldName() << ")";
+ uasserted( 10065 , ss.str() );
+ return BSONObj(); // never reachable
}
inline BSONObj BSONElement::embeddedObject() const {
@@ -43,13 +47,34 @@ namespace mongo {
int strSizeWNull = *(int *)( value() + 4 );
return BSONObj( value() + 4 + 4 + strSizeWNull );
}
-
- inline BSONObj BSONObj::copy() const {
+
+ inline NOINLINE_DECL void BSONObj::_assertInvalid() const {
+ StringBuilder ss;
+ int os = objsize();
+ ss << "Invalid BSONObj size: " << os << " (0x" << toHex( &os, 4 ) << ')';
+ try {
+ BSONElement e = firstElement();
+ ss << " first element: " << e.toString();
+ }
+ catch ( ... ) { }
+ massert( 10334 , ss.str() , 0 );
+ }
+
+ /* the idea with NOINLINE_DECL here is to keep this from inlining in the
+ getOwned() method. the presumption being that is better.
+ */
+ inline NOINLINE_DECL BSONObj BSONObj::copy() const {
char *p = (char*) malloc(objsize());
memcpy(p, objdata(), objsize());
return BSONObj(p, true);
}
+ inline BSONObj BSONObj::getOwned() const {
+ if ( isOwned() )
+ return *this;
+ return copy();
+ }
+
// wrap this element up as a singleton object.
inline BSONObj BSONElement::wrap() const {
BSONObjBuilder b(size()+6);
@@ -63,7 +88,6 @@ namespace mongo {
return b.obj();
}
-
inline bool BSONObj::hasElement(const char *name) const {
if ( !isEmpty() ) {
BSONObjIterator it(*this);
@@ -97,14 +121,34 @@ namespace mongo {
return *this;
}
- inline bool BSONObj::isValid(){
+ /* add all the fields from the object specified to this object if they don't exist */
+ inline BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) {
+ set<string> have;
+ {
+ BSONObjIterator i = iterator();
+ while ( i.more() )
+ have.insert( i.next().fieldName() );
+ }
+
+ BSONObjIterator it(x);
+ while ( it.more() ) {
+ BSONElement e = it.next();
+ if ( have.count( e.fieldName() ) )
+ continue;
+ append(e);
+ }
+ return *this;
+ }
+
+
+ inline bool BSONObj::isValid() {
int x = objsize();
- return x > 0 && x <= 1024 * 1024 * 8;
+ return x > 0 && x <= BSONObjMaxInternalSize;
}
- inline bool BSONObj::getObjectID(BSONElement& e) const {
+ inline bool BSONObj::getObjectID(BSONElement& e) const {
BSONElement f = getField("_id");
- if( !f.eoo() ) {
+ if( !f.eoo() ) {
e = f;
return true;
}
@@ -115,21 +159,21 @@ namespace mongo {
_fieldName = 0;
_builder = builder;
}
-
- template<class T>
- inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) {
+
+ template<class T>
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) {
_builder->append(_fieldName, value);
_fieldName = 0;
return *_builder;
}
- inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSONElement& e ) {
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSONElement& e ) {
_builder->appendAs( e , _fieldName );
_fieldName = 0;
return *_builder;
}
- inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::Label &l ) {
+ inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::Label &l ) {
return Labeler( l, this );
}
@@ -139,29 +183,29 @@ namespace mongo {
}
_subobj.reset();
_fieldName = nextFieldName;
- }
+ }
inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() {
if ( !haveSubobj() )
_subobj.reset( new BSONObjBuilder() );
return _subobj.get();
}
-
+
template<class T> inline
BSONObjBuilder& Labeler::operator<<( T value ) {
s_->subobj()->append( l_.l_, value );
return *s_->_builder;
- }
+ }
inline
BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) {
s_->subobj()->appendAs( e, l_.l_ );
return *s_->_builder;
- }
+ }
// {a: {b:1}} -> {a.b:1}
void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base="");
- inline BSONObj nested2dotted(const BSONObj& obj){
+ inline BSONObj nested2dotted(const BSONObj& obj) {
BSONObjBuilder b;
nested2dotted(b, obj);
return b.obj();
@@ -169,7 +213,7 @@ namespace mongo {
// {a.b:1} -> {a: {b:1}}
void dotted2nested(BSONObjBuilder& b, const BSONObj& obj);
- inline BSONObj dotted2nested(const BSONObj& obj){
+ inline BSONObj dotted2nested(const BSONObj& obj) {
BSONObjBuilder b;
dotted2nested(b, obj);
return b.obj();
@@ -180,17 +224,25 @@ namespace mongo {
const char * e = _b.buf() + _b.len();
return BSONObjIterator( s , e );
}
-
+
+ inline bool BSONObjBuilder::hasField( const StringData& name ) const {
+ BSONObjIterator i = iterator();
+ while ( i.more() )
+ if ( strcmp( name.data() , i.next().fieldName() ) == 0 )
+ return true;
+ return false;
+ }
+
/* WARNING: nested/dotted conversions are not 100% reversible
* nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1}
* also, dotted2nested ignores order
*/
typedef map<string, BSONElement> BSONMap;
- inline BSONMap bson2map(const BSONObj& obj){
+ inline BSONMap bson2map(const BSONObj& obj) {
BSONMap m;
BSONObjIterator it(obj);
- while (it.more()){
+ while (it.more()) {
BSONElement e = it.next();
m[e.fieldName()] = e;
}
@@ -204,7 +256,7 @@ namespace mongo {
};
typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements;
- inline BSONSortedElements bson2set( const BSONObj& obj ){
+ inline BSONSortedElements bson2set( const BSONObj& obj ) {
BSONSortedElements s;
BSONObjIterator it(obj);
while ( it.more() )
@@ -219,7 +271,7 @@ namespace mongo {
return s.str();
}
inline void BSONObj::toString(StringBuilder& s, bool isArray, bool full ) const {
- if ( isEmpty() ){
+ if ( isEmpty() ) {
s << "{}";
return;
}
@@ -234,7 +286,7 @@ namespace mongo {
massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) );
int offset = (int) (e.rawdata() - this->objdata());
massert( 10330 , "Element extends past end of object",
- e.size() + offset <= this->objsize() );
+ e.size() + offset <= this->objsize() );
e.validate();
bool end = ( e.size() + offset == this->objsize() );
if ( e.eoo() ) {
@@ -254,17 +306,20 @@ namespace mongo {
inline void BSONElement::validate() const {
const BSONType t = type();
-
+
switch( t ) {
case DBRef:
case Code:
case Symbol:
case mongo::String: {
- int x = valuestrsize();
- if ( x > 0 && valuestr()[x-1] == 0 )
+ unsigned x = (unsigned) valuestrsize();
+ bool lenOk = x > 0 && x < (unsigned) BSONObjMaxInternalSize;
+ if( lenOk && valuestr()[x-1] == 0 )
return;
StringBuilder buf;
- buf << "Invalid dbref/code/string/symbol size: " << x << " strnlen:" << mongo::strnlen( valuestr() , x );
+ buf << "Invalid dbref/code/string/symbol size: " << x;
+ if( lenOk )
+ buf << " strnlen:" << mongo::strnlen( valuestr() , x );
msgasserted( 10321 , buf.str() );
break;
}
@@ -341,13 +396,19 @@ namespace mongo {
massert( 10317 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
x = valuestrsize() + 4 + 1/*subtype*/;
break;
- case RegEx:
- {
+ case RegEx: {
const char *p = value();
size_t len1 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen( p, remain );
//massert( 10318 , "Invalid regex string", len1 != -1 ); // ERH - 4/28/10 - don't think this does anything
p = p + len1 + 1;
- size_t len2 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen( p, remain - len1 - 1 );
+ size_t len2;
+ if( maxLen == -1 )
+ len2 = strlen( p );
+ else {
+ size_t x = remain - len1 - 1;
+ assert( x <= 0x7fffffff );
+ len2 = mongo::strnlen( p, (int) x );
+ }
//massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything
x = (int) (len1 + 1 + len2 + 1);
}
@@ -379,13 +440,12 @@ namespace mongo {
case mongo::Date:
s << "new Date(" << date() << ')';
break;
- case RegEx:
- {
- s << "/" << regex() << '/';
- const char *p = regexFlags();
- if ( p ) s << p;
- }
- break;
+ case RegEx: {
+ s << "/" << regex() << '/';
+ const char *p = regexFlags();
+ if ( p ) s << p;
+ }
+ break;
case NumberDouble:
s.appendDoubleNice( number() );
break;
@@ -418,13 +478,14 @@ namespace mongo {
break;
case CodeWScope:
s << "CodeWScope( "
- << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")";
+ << codeWScopeCode() << ", " << codeWScopeObject().toString(false, full) << ")";
break;
case Code:
if ( !full && valuestrsize() > 80 ) {
s.write(valuestr(), 70);
s << "...";
- } else {
+ }
+ else {
s.write(valuestr(), valuestrsize()-1);
}
break;
@@ -434,7 +495,8 @@ namespace mongo {
if ( !full && valuestrsize() > 80 ) {
s.write(valuestr(), 70);
s << "...\"";
- } else {
+ }
+ else {
s.write(valuestr(), valuestrsize()-1);
s << '"';
}
@@ -452,7 +514,7 @@ namespace mongo {
break;
case BinData:
s << "BinData";
- if (full){
+ if (full) {
int len;
const char* data = binDataClean(len);
s << '(' << binDataType() << ", " << toHex(data, len) << ')';
@@ -503,14 +565,17 @@ namespace mongo {
}
inline BSONObj::BSONObj() {
- /* LITTLE ENDIAN */
- static char p[] = { 5, 0, 0, 0, 0 };
+ /* little endian ordering here, but perhaps that is ok regardless as BSON is spec'd
+ to be little endian external to the system. (i.e. the rest of the implementation of bson,
+ not this part, fails to support big endian)
+ */
+ static char p[] = { /*size*/5, 0, 0, 0, /*eoo*/0 };
_objdata = p;
}
inline BSONObj BSONElement::Obj() const { return embeddedObjectUserCheck(); }
- inline BSONElement BSONElement::operator[] (const string& field) const {
+ inline BSONElement BSONElement::operator[] (const string& field) const {
BSONObj o = Obj();
return o[field];
}
@@ -521,14 +586,14 @@ namespace mongo {
v.push_back(i.next());
}
- inline void BSONObj::elems(list<BSONElement> &v) const {
+ inline void BSONObj::elems(list<BSONElement> &v) const {
BSONObjIterator i(*this);
while( i.more() )
v.push_back(i.next());
}
template <class T>
- void BSONObj::Vals(vector<T>& v) const {
+ void BSONObj::Vals(vector<T>& v) const {
BSONObjIterator i(*this);
while( i.more() ) {
T t;
@@ -537,7 +602,7 @@ namespace mongo {
}
}
template <class T>
- void BSONObj::Vals(list<T>& v) const {
+ void BSONObj::Vals(list<T>& v) const {
BSONObjIterator i(*this);
while( i.more() ) {
T t;
@@ -547,25 +612,27 @@ namespace mongo {
}
template <class T>
- void BSONObj::vals(vector<T>& v) const {
+ void BSONObj::vals(vector<T>& v) const {
BSONObjIterator i(*this);
while( i.more() ) {
try {
T t;
i.next().Val(t);
v.push_back(t);
- } catch(...) { }
+ }
+ catch(...) { }
}
}
template <class T>
- void BSONObj::vals(list<T>& v) const {
+ void BSONObj::vals(list<T>& v) const {
BSONObjIterator i(*this);
while( i.more() ) {
try {
T t;
i.next().Val(t);
v.push_back(t);
- } catch(...) { }
+ }
+ catch(...) { }
}
}
@@ -577,6 +644,16 @@ namespace mongo {
return s << e.toString();
}
+ inline StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ) {
+ o.toString( s );
+ return s;
+ }
+ inline StringBuilder& operator<<( StringBuilder &s, const BSONElement &e ) {
+ e.toString( s );
+ return s;
+ }
+
+
inline void BSONElement::Val(BSONObj& v) const { v = Obj(); }
template<typename T>
diff --git a/bson/bson.h b/bson/bson.h
index 3d92831..ba1b751 100644
--- a/bson/bson.h
+++ b/bson/bson.h
@@ -1,10 +1,10 @@
-/* NOTE: Standalone bson header for when not using MongoDB.
+/* NOTE: Standalone bson header for when not using MongoDB.
See also: bsondemo.
MongoDB includes ../db/jsobj.h instead. This file, however, pulls in much less code / dependencies.
*/
-/** @file bson.h
+/** @file bson.h
BSON classes
*/
@@ -25,7 +25,7 @@
*/
/**
- BSONObj and its helpers
+ bo and its helpers
"BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be
represented in JSON (plus a few extensions useful for databases & other languages).
@@ -47,15 +47,15 @@
#include <boost/utility.hpp>
#include "util/builder.h"
-namespace bson {
+namespace bson {
using std::string;
using std::stringstream;
- class assertion : public std::exception {
+ class assertion : public std::exception {
public:
assertion( unsigned u , const string& s )
- : id( u ) , msg( s ){
+ : id( u ) , msg( s ) {
mongo::StringBuilder ss;
ss << "BsonAssertion id: " << u << " " << s;
full = ss.str();
@@ -64,7 +64,7 @@ namespace bson {
virtual ~assertion() throw() {}
virtual const char* what() const throw() { return full.c_str(); }
-
+
unsigned id;
string msg;
string full;
@@ -72,9 +72,9 @@ namespace bson {
}
namespace mongo {
-#if !defined(assert)
+#if !defined(assert)
inline void assert(bool expr) {
- if(!expr) {
+ if(!expr) {
throw bson::assertion( 0 , "assertion failure in bson library" );
}
}
@@ -88,12 +88,12 @@ namespace mongo {
if( !expr )
uasserted( msgid , msg );
}
- inline void msgasserted(int msgid, const char *msg) {
+ inline void msgasserted(int msgid, const char *msg) {
throw bson::assertion( msgid , msg );
}
inline void msgasserted(int msgid, const std::string &msg) { msgasserted(msgid, msg.c_str()); }
- inline void massert(unsigned msgid, std::string msg, bool expr) {
- if(!expr) {
+ inline void massert(unsigned msgid, std::string msg, bool expr) {
+ if(!expr) {
std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl;
throw bson::assertion( msgid , msg );
}
@@ -108,15 +108,15 @@ namespace mongo {
#include "../bson/bsonmisc.h"
#include "../bson/bsonobjbuilder.h"
#include "../bson/bsonobjiterator.h"
-#include "../bson/bsoninlines.h"
+#include "../bson/bson-inl.h"
-namespace mongo {
+namespace mongo {
inline unsigned getRandomNumber() {
#if defined(_WIN32)
return rand();
#else
- return random();
+ return random();
#endif
}
diff --git a/bson/bson_db.h b/bson/bson_db.h
index 18cd59f..71f92aa 100644
--- a/bson/bson_db.h
+++ b/bson/bson_db.h
@@ -1,10 +1,10 @@
-/** @file bson_db.h
+/** @file bson_db.h
- This file contains the implementation of BSON-related methods that are required
+ This file contains the implementation of BSON-related methods that are required
by the MongoDB database server.
- Normally, for standalone BSON usage, you do not want this file - it will tend to
- pull in some other files from the MongoDB project. Thus, bson.h (the main file
+ Normally, for standalone BSON usage, you do not want this file - it will tend to
+ pull in some other files from the MongoDB project. Thus, bson.h (the main file
one would use) does not include this file.
*/
@@ -26,6 +26,7 @@
#pragma once
#include "../util/optime.h"
+#include "../util/time_support.h"
namespace mongo {
@@ -34,10 +35,10 @@ namespace mongo {
Append a timestamp element to the object being ebuilt.
@param time - in millis (but stored in seconds)
*/
- inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( const StringData& fieldName , unsigned long long time , unsigned int inc ){
+ inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( const StringData& fieldName , unsigned long long time , unsigned int inc ) {
OpTime t( (unsigned) (time / 1000) , inc );
appendTimestamp( fieldName , t.asDate() );
- return *this;
+ return *this;
}
inline OpTime BSONElement::_opTime() const {
@@ -47,7 +48,7 @@ namespace mongo {
}
inline string BSONElement::_asCode() const {
- switch( type() ){
+ switch( type() ) {
case mongo::String:
case Code:
return string(valuestr(), valuestrsize()-1);
@@ -60,11 +61,22 @@ namespace mongo {
return "";
}
- inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLabeler& id){
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLabeler& id) {
_builder->appendDate(_fieldName, jsTime());
_fieldName = 0;
return *_builder;
}
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MinKeyLabeler& id) {
+ _builder->appendMinKey(_fieldName);
+ _fieldName = 0;
+ return *_builder;
+ }
+
+ inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MaxKeyLabeler& id) {
+ _builder->appendMaxKey(_fieldName);
+ _fieldName = 0;
+ return *_builder;
+ }
}
diff --git a/bson/bsondemo/bsondemo.cpp b/bson/bsondemo/bsondemo.cpp
index b0da1b8..ec83f5e 100644
--- a/bson/bsondemo/bsondemo.cpp
+++ b/bson/bsondemo/bsondemo.cpp
@@ -1,4 +1,4 @@
-/** @file bsondemo.cpp
+/** @file bsondemo.cpp
Example of use of BSON from C++.
@@ -29,17 +29,16 @@
using namespace std;
using namespace bson;
-void iter(bo o) {
+void iter(bo o) {
/* iterator example */
cout << "\niter()\n";
- for( bo::iterator i(o); i.more(); ) {
+ for( bo::iterator i(o); i.more(); ) {
cout << ' ' << i.next().toString() << '\n';
}
}
-int main()
-{
- cout << "build bits: " << 8 * sizeof(char *) << '\n' << endl;
+int main() {
+ cout << "build bits: " << 8 * sizeof(char *) << '\n' << endl;
/* a bson object defaults on construction to { } */
bo empty;
@@ -47,7 +46,7 @@ int main()
/* make a simple { name : 'joe', age : 33.7 } object */
{
- bob b;
+ bob b;
b.append("name", "joe");
b.append("age", 33.7);
b.obj();
@@ -73,7 +72,7 @@ int main()
/* reach in and get subobj.z */
cout << "subobj.z: " << y.getFieldDotted("subobj.z").Number() << endl;
-
+
/* alternate syntax: */
cout << "subobj.z: " << y["subobj"]["z"].Number() << endl;
@@ -83,19 +82,19 @@ int main()
cout << v[0] << endl;
/* into an array */
- list<be> L;
+ list<be> L;
y.elems(L);
bo sub = y["subobj"].Obj();
- /* grab all the int's that were in subobj. if it had elements that were not ints, we throw an exception
- (capital V on Vals() means exception if wrong type found
+ /* grab all the int's that were in subobj. if it had elements that were not ints, we throw an exception
+ (capital V on Vals() means exception if wrong type found
*/
vector<int> myints;
sub.Vals(myints);
cout << "my ints: " << myints[0] << ' ' << myints[1] << endl;
- /* grab all the string values from x. if the field isn't of string type, just skip it --
+ /* grab all the string values from x. if the field isn't of string type, just skip it --
lowercase v on vals() indicates skip don't throw.
*/
vector<string> strs;
@@ -103,5 +102,6 @@ int main()
cout << strs.size() << " strings, first one: " << strs[0] << endl;
iter(y);
- return 0;
+ return 0;
}
+
diff --git a/bson/bsonelement.h b/bson/bsonelement.h
index 534c773..23d59fa 100644
--- a/bson/bsonelement.h
+++ b/bson/bsonelement.h
@@ -36,378 +36,384 @@ namespace mongo {
int compareElementValues(const BSONElement& l, const BSONElement& r);
-/** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
- 'a : 3' is the first element (key+value).
-
- The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
- for the life of the BSONElement.
-
- internals:
- <type><fieldName ><value>
- -------- size() ------------
- -fieldNameSize-
- value()
- type()
-*/
-class BSONElement {
-public:
- /** These functions, which start with a capital letter, throw a UserException if the
- element is not of the required type. Example:
-
- string foo = obj["foo"].String(); // exception if not a string type or DNE
+ /** BSONElement represents an "element" in a BSONObj. So for the object { a : 3, b : "abc" },
+ 'a : 3' is the first element (key+value).
+
+ The BSONElement object points into the BSONObj's data. Thus the BSONObj must stay in scope
+ for the life of the BSONElement.
+
+ internals:
+ <type><fieldName ><value>
+ -------- size() ------------
+ -fieldNameSize-
+ value()
+ type()
*/
- string String() const { return chk(mongo::String).valuestr(); }
- Date_t Date() const { return chk(mongo::Date).date(); }
- double Number() const { return chk(isNumber()).number(); }
- double Double() const { return chk(NumberDouble)._numberDouble(); }
- long long Long() const { return chk(NumberLong)._numberLong(); }
- int Int() const { return chk(NumberInt)._numberInt(); }
- bool Bool() const { return chk(mongo::Bool).boolean(); }
- BSONObj Obj() const;
- vector<BSONElement> Array() const; // see implementation for detailed comments
- mongo::OID OID() const { return chk(jstOID).__oid(); }
- void Null() const { chk(isNull()); }
- void OK() const { chk(ok()); }
-
- /** populate v with the value of the element. If type does not match, throw exception.
- useful in templates -- see also BSONObj::Vals().
+ class BSONElement {
+ public:
+ /** These functions, which start with a capital letter, throw a UserException if the
+ element is not of the required type. Example:
+
+ string foo = obj["foo"].String(); // exception if not a string type or DNE
*/
- void Val(Date_t& v) const { v = Date(); }
- void Val(long long& v) const { v = Long(); }
- void Val(bool& v) const { v = Bool(); }
- void Val(BSONObj& v) const;
- void Val(mongo::OID& v) const { v = OID(); }
- void Val(int& v) const { v = Int(); }
- void Val(double& v) const { v = Double(); }
- void Val(string& v) const { v = String(); }
-
- /** Use ok() to check if a value is assigned:
- if( myObj["foo"].ok() ) ...
- */
- bool ok() const { return !eoo(); }
+ string String() const { return chk(mongo::String).valuestr(); }
+ Date_t Date() const { return chk(mongo::Date).date(); }
+ double Number() const { return chk(isNumber()).number(); }
+ double Double() const { return chk(NumberDouble)._numberDouble(); }
+ long long Long() const { return chk(NumberLong)._numberLong(); }
+ int Int() const { return chk(NumberInt)._numberInt(); }
+ bool Bool() const { return chk(mongo::Bool).boolean(); }
+ vector<BSONElement> Array() const; // see implementation for detailed comments
+ mongo::OID OID() const { return chk(jstOID).__oid(); }
+ void Null() const { chk(isNull()); } // throw UserException if not null
+ void OK() const { chk(ok()); } // throw UserException if element DNE
+
+ /** @return the embedded object associated with this field.
+ Note the returned object is a reference to within the parent bson object. If that
+ object is out of scope, this pointer will no longer be valid. Call getOwned() on the
+ returned BSONObj if you need your own copy.
+ throws UserException if the element is not of type object.
+ */
+ BSONObj Obj() const;
+
+ /** populate v with the value of the element. If type does not match, throw exception.
+ useful in templates -- see also BSONObj::Vals().
+ */
+ void Val(Date_t& v) const { v = Date(); }
+ void Val(long long& v) const { v = Long(); }
+ void Val(bool& v) const { v = Bool(); }
+ void Val(BSONObj& v) const;
+ void Val(mongo::OID& v) const { v = OID(); }
+ void Val(int& v) const { v = Int(); }
+ void Val(double& v) const { v = Double(); }
+ void Val(string& v) const { v = String(); }
+
+ /** Use ok() to check if a value is assigned:
+ if( myObj["foo"].ok() ) ...
+ */
+ bool ok() const { return !eoo(); }
- string toString( bool includeFieldName = true, bool full=false) const;
- void toString(StringBuilder& s, bool includeFieldName = true, bool full=false) const;
- string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const;
- operator string() const { return toString(); }
+ string toString( bool includeFieldName = true, bool full=false) const;
+ void toString(StringBuilder& s, bool includeFieldName = true, bool full=false) const;
+ string jsonString( JsonStringFormat format, bool includeFieldNames = true, int pretty = 0 ) const;
+ operator string() const { return toString(); }
- /** Returns the type of the element */
- BSONType type() const { return (BSONType) *data; }
+ /** Returns the type of the element */
+ BSONType type() const { return (BSONType) *data; }
- /** retrieve a field within this element
- throws exception if *this is not an embedded object
- */
- BSONElement operator[] (const string& field) const;
-
- /** returns the tyoe of the element fixed for the main type
- the main purpose is numbers. any numeric type will return NumberDouble
- Note: if the order changes, indexes have to be re-built or than can be corruption
- */
- int canonicalType() const;
+ /** retrieve a field within this element
+ throws exception if *this is not an embedded object
+ */
+ BSONElement operator[] (const string& field) const;
- /** Indicates if it is the end-of-object element, which is present at the end of
- every BSON object.
- */
- bool eoo() const { return type() == EOO; }
+ /** returns the tyoe of the element fixed for the main type
+ the main purpose is numbers. any numeric type will return NumberDouble
+ Note: if the order changes, indexes have to be re-built or than can be corruption
+ */
+ int canonicalType() const;
- /** Size of the element.
- @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size.
- */
- int size( int maxLen = -1 ) const;
+ /** Indicates if it is the end-of-object element, which is present at the end of
+ every BSON object.
+ */
+ bool eoo() const { return type() == EOO; }
- /** Wrap this element up as a singleton object. */
- BSONObj wrap() const;
+ /** Size of the element.
+ @param maxLen If maxLen is specified, don't scan more than maxLen bytes to calculate size.
+ */
+ int size( int maxLen = -1 ) const;
- /** Wrap this element up as a singleton object with a new name. */
- BSONObj wrap( const char* newName) const;
+ /** Wrap this element up as a singleton object. */
+ BSONObj wrap() const;
- /** field name of the element. e.g., for
- name : "Joe"
- "name" is the fieldname
- */
- const char * fieldName() const {
- if ( eoo() ) return ""; // no fieldname for it.
- return data + 1;
- }
+ /** Wrap this element up as a singleton object with a new name. */
+ BSONObj wrap( const char* newName) const;
- /** raw data of the element's value (so be careful). */
- const char * value() const {
- return (data + fieldNameSize() + 1);
- }
- /** size in bytes of the element's value (when applicable). */
- int valuesize() const {
- return size() - fieldNameSize() - 1;
- }
+ /** field name of the element. e.g., for
+ name : "Joe"
+ "name" is the fieldname
+ */
+ const char * fieldName() const {
+ if ( eoo() ) return ""; // no fieldname for it.
+ return data + 1;
+ }
- bool isBoolean() const { return type() == mongo::Bool; }
+ /** raw data of the element's value (so be careful). */
+ const char * value() const {
+ return (data + fieldNameSize() + 1);
+ }
+ /** size in bytes of the element's value (when applicable). */
+ int valuesize() const {
+ return size() - fieldNameSize() - 1;
+ }
- /** @return value of a boolean element.
- You must assure element is a boolean before
- calling. */
- bool boolean() const {
- return *value() ? true : false;
- }
+ bool isBoolean() const { return type() == mongo::Bool; }
- /** Retrieve a java style date value from the element.
- Ensure element is of type Date before calling.
- */
- Date_t date() const {
- return *reinterpret_cast< const Date_t* >( value() );
- }
+ /** @return value of a boolean element.
+ You must assure element is a boolean before
+ calling. */
+ bool boolean() const {
+ return *value() ? true : false;
+ }
- /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
- (i.e., treat zero and null as false).
- */
- bool trueValue() const;
+ /** Retrieve a java style date value from the element.
+ Ensure element is of type Date before calling.
+ */
+ Date_t date() const {
+ return *reinterpret_cast< const Date_t* >( value() );
+ }
- /** True if number, string, bool, date, OID */
- bool isSimpleType() const;
+ /** Convert the value to boolean, regardless of its type, in a javascript-like fashion
+ (i.e., treat zero and null as false).
+ */
+ bool trueValue() const;
+
+ /** True if number, string, bool, date, OID */
+ bool isSimpleType() const;
+
+ /** True if element is of a numeric type. */
+ bool isNumber() const;
+
+ /** Return double value for this field. MUST be NumberDouble type. */
+ double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); }
+ /** Return double value for this field. MUST be NumberInt type. */
+ int _numberInt() const {return *reinterpret_cast< const int* >( value() ); }
+ /** Return double value for this field. MUST be NumberLong type. */
+ long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); }
+
+ /** Retrieve int value for the element safely. Zero returned if not a number. */
+ int numberInt() const;
+ /** Retrieve long value for the element safely. Zero returned if not a number. */
+ long long numberLong() const;
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double numberDouble() const;
+ /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
+ Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
+ */
+ double number() const { return numberDouble(); }
- /** True if element is of a numeric type. */
- bool isNumber() const;
+ /** Retrieve the object ID stored in the object.
+ You must ensure the element is of type jstOID first. */
+ const mongo::OID &__oid() const { return *reinterpret_cast< const mongo::OID* >( value() ); }
- /** Return double value for this field. MUST be NumberDouble type. */
- double _numberDouble() const {return *reinterpret_cast< const double* >( value() ); }
- /** Return double value for this field. MUST be NumberInt type. */
- int _numberInt() const {return *reinterpret_cast< const int* >( value() ); }
- /** Return double value for this field. MUST be NumberLong type. */
- long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); }
+ /** True if element is null. */
+ bool isNull() const {
+ return type() == jstNULL;
+ }
- /** Retrieve int value for the element safely. Zero returned if not a number. */
- int numberInt() const;
- /** Retrieve long value for the element safely. Zero returned if not a number. */
- long long numberLong() const;
- /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
- Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
- */
- double numberDouble() const;
- /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
- Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
- */
- double number() const { return numberDouble(); }
+ /** Size (length) of a string element.
+ You must assure of type String first. */
+ int valuestrsize() const {
+ return *reinterpret_cast< const int* >( value() );
+ }
- /** Retrieve the object ID stored in the object.
- You must ensure the element is of type jstOID first. */
- const mongo::OID &__oid() const { return *reinterpret_cast< const mongo::OID* >( value() ); }
+ // for objects the size *includes* the size of the size field
+ int objsize() const {
+ return *reinterpret_cast< const int* >( value() );
+ }
- /** True if element is null. */
- bool isNull() const {
- return type() == jstNULL;
- }
-
- /** Size (length) of a string element.
- You must assure of type String first. */
- int valuestrsize() const {
- return *reinterpret_cast< const int* >( value() );
- }
+ /** Get a string's value. Also gives you start of the real data for an embedded object.
+ You must assure data is of an appropriate type first -- see also valuestrsafe().
+ */
+ const char * valuestr() const {
+ return value() + 4;
+ }
- // for objects the size *includes* the size of the size field
- int objsize() const {
- return *reinterpret_cast< const int* >( value() );
- }
+ /** Get the string value of the element. If not a string returns "". */
+ const char *valuestrsafe() const {
+ return type() == mongo::String ? valuestr() : "";
+ }
+ /** Get the string value of the element. If not a string returns "". */
+ string str() const {
+ return type() == mongo::String ? string(valuestr(), valuestrsize()-1) : string();
+ }
- /** Get a string's value. Also gives you start of the real data for an embedded object.
- You must assure data is of an appropriate type first -- see also valuestrsafe().
- */
- const char * valuestr() const {
- return value() + 4;
- }
+ /** Get javascript code of a CodeWScope data element. */
+ const char * codeWScopeCode() const {
+ return value() + 8;
+ }
+ /** Get the scope SavedContext of a CodeWScope data element. */
+ const char * codeWScopeScopeData() const {
+ // TODO fix
+ return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
+ }
- /** Get the string value of the element. If not a string returns "". */
- const char *valuestrsafe() const {
- return type() == mongo::String ? valuestr() : "";
- }
- /** Get the string value of the element. If not a string returns "". */
- string str() const {
- return type() == mongo::String ? string(valuestr(), valuestrsize()-1) : string();
- }
+ /** Get the embedded object this element holds. */
+ BSONObj embeddedObject() const;
- /** Get javascript code of a CodeWScope data element. */
- const char * codeWScopeCode() const {
- return value() + 8;
- }
- /** Get the scope SavedContext of a CodeWScope data element. */
- const char * codeWScopeScopeData() const {
- // TODO fix
- return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
- }
+ /* uasserts if not an object */
+ BSONObj embeddedObjectUserCheck() const;
- /** Get the embedded object this element holds. */
- BSONObj embeddedObject() const;
+ BSONObj codeWScopeObject() const;
- /* uasserts if not an object */
- BSONObj embeddedObjectUserCheck() const;
+ /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
+ const char *binData(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ assert( type() == BinData );
+ len = valuestrsize();
+ return value() + 5;
+ }
+ /** Get binary data. Element must be of type BinData. Handles type 2 */
+ const char *binDataClean(int& len) const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ if (binDataType() != ByteArrayDeprecated) {
+ return binData(len);
+ }
+ else {
+ // Skip extra size
+ len = valuestrsize() - 4;
+ return value() + 5 + 4;
+ }
+ }
- BSONObj codeWScopeObject() const;
+ BinDataType binDataType() const {
+ // BinData: <int len> <byte subtype> <byte[len] data>
+ assert( type() == BinData );
+ unsigned char c = (value() + 4)[0];
+ return (BinDataType)c;
+ }
- /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
- const char *binData(int& len) const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- assert( type() == BinData );
- len = valuestrsize();
- return value() + 5;
- }
- /** Get binary data. Element must be of type BinData. Handles type 2 */
- const char *binDataClean(int& len) const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- if (binDataType() != ByteArrayDeprecated){
- return binData(len);
- } else {
- // Skip extra size
- len = valuestrsize() - 4;
- return value() + 5 + 4;
+ /** Retrieve the regex string for a Regex element */
+ const char *regex() const {
+ assert(type() == RegEx);
+ return value();
}
- }
-
- BinDataType binDataType() const {
- // BinData: <int len> <byte subtype> <byte[len] data>
- assert( type() == BinData );
- unsigned char c = (value() + 4)[0];
- return (BinDataType)c;
- }
- /** Retrieve the regex string for a Regex element */
- const char *regex() const {
- assert(type() == RegEx);
- return value();
- }
+ /** Retrieve the regex flags (options) for a Regex element */
+ const char *regexFlags() const {
+ const char *p = regex();
+ return p + strlen(p) + 1;
+ }
- /** Retrieve the regex flags (options) for a Regex element */
- const char *regexFlags() const {
- const char *p = regex();
- return p + strlen(p) + 1;
- }
+ /** like operator== but doesn't check the fieldname,
+ just the value.
+ */
+ bool valuesEqual(const BSONElement& r) const {
+ return woCompare( r , false ) == 0;
+ }
- /** like operator== but doesn't check the fieldname,
- just the value.
- */
- bool valuesEqual(const BSONElement& r) const {
- return woCompare( r , false ) == 0;
- }
+ /** Returns true if elements are equal. */
+ bool operator==(const BSONElement& r) const {
+ return woCompare( r , true ) == 0;
+ }
- /** Returns true if elements are equal. */
- bool operator==(const BSONElement& r) const {
- return woCompare( r , true ) == 0;
- }
+ /** Well ordered comparison.
+ @return <0: l<r. 0:l==r. >0:l>r
+ order by type, field name, and field value.
+ If considerFieldName is true, pay attention to the field name.
+ */
+ int woCompare( const BSONElement &e, bool considerFieldName = true ) const;
- /** Well ordered comparison.
- @return <0: l<r. 0:l==r. >0:l>r
- order by type, field name, and field value.
- If considerFieldName is true, pay attention to the field name.
- */
- int woCompare( const BSONElement &e, bool considerFieldName = true ) const;
+ const char * rawdata() const { return data; }
- const char * rawdata() const {
- return data;
- }
-
- /** 0 == Equality, just not defined yet */
- int getGtLtOp( int def = 0 ) const;
-
- /** Constructs an empty element */
- BSONElement();
-
- /** Check that data is internally consistent. */
- void validate() const;
-
- /** True if this element may contain subobjects. */
- bool mayEncapsulate() const {
- switch ( type() ){
- case Object:
- case mongo::Array:
- case CodeWScope:
- return true;
- default:
- return false;
+ /** 0 == Equality, just not defined yet */
+ int getGtLtOp( int def = 0 ) const;
+
+ /** Constructs an empty element */
+ BSONElement();
+
+ /** Check that data is internally consistent. */
+ void validate() const;
+
+ /** True if this element may contain subobjects. */
+ bool mayEncapsulate() const {
+ switch ( type() ) {
+ case Object:
+ case mongo::Array:
+ case CodeWScope:
+ return true;
+ default:
+ return false;
+ }
}
- }
- /** True if this element can be a BSONObj */
- bool isABSONObj() const {
- switch( type() ){
- case Object:
- case mongo::Array:
- return true;
- default:
- return false;
+ /** True if this element can be a BSONObj */
+ bool isABSONObj() const {
+ switch( type() ) {
+ case Object:
+ case mongo::Array:
+ return true;
+ default:
+ return false;
+ }
}
- }
- Date_t timestampTime() const{
- unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
- return t * 1000;
- }
- unsigned int timestampInc() const{
- return ((unsigned int*)(value() ))[0];
- }
+ Date_t timestampTime() const {
+ unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
+ return t * 1000;
+ }
+ unsigned int timestampInc() const {
+ return ((unsigned int*)(value() ))[0];
+ }
- const char * dbrefNS() const {
- uassert( 10063 , "not a dbref" , type() == DBRef );
- return value() + 4;
- }
+ const char * dbrefNS() const {
+ uassert( 10063 , "not a dbref" , type() == DBRef );
+ return value() + 4;
+ }
- const mongo::OID& dbrefOID() const {
- uassert( 10064 , "not a dbref" , type() == DBRef );
- const char * start = value();
- start += 4 + *reinterpret_cast< const int* >( start );
- return *reinterpret_cast< const mongo::OID* >( start );
- }
+ const mongo::OID& dbrefOID() const {
+ uassert( 10064 , "not a dbref" , type() == DBRef );
+ const char * start = value();
+ start += 4 + *reinterpret_cast< const int* >( start );
+ return *reinterpret_cast< const mongo::OID* >( start );
+ }
- bool operator<( const BSONElement& other ) const {
- int x = (int)canonicalType() - (int)other.canonicalType();
- if ( x < 0 ) return true;
- else if ( x > 0 ) return false;
- return compareElementValues(*this,other) < 0;
- }
-
- // If maxLen is specified, don't scan more than maxLen bytes.
- explicit BSONElement(const char *d, int maxLen = -1) : data(d) {
- fieldNameSize_ = -1;
- if ( eoo() )
- fieldNameSize_ = 0;
- else {
- if ( maxLen != -1 ) {
- int size = (int) strnlen( fieldName(), maxLen - 1 );
- massert( 10333 , "Invalid field name", size != -1 );
- fieldNameSize_ = size + 1;
- }
+ bool operator<( const BSONElement& other ) const {
+ int x = (int)canonicalType() - (int)other.canonicalType();
+ if ( x < 0 ) return true;
+ else if ( x > 0 ) return false;
+ return compareElementValues(*this,other) < 0;
}
- totalSize = -1;
- }
- string _asCode() const;
- OpTime _opTime() const;
+ // If maxLen is specified, don't scan more than maxLen bytes.
+ explicit BSONElement(const char *d, int maxLen = -1) : data(d) {
+ fieldNameSize_ = -1;
+ if ( eoo() )
+ fieldNameSize_ = 0;
+ else {
+ if ( maxLen != -1 ) {
+ int size = (int) strnlen( fieldName(), maxLen - 1 );
+ massert( 10333 , "Invalid field name", size != -1 );
+ fieldNameSize_ = size + 1;
+ }
+ }
+ totalSize = -1;
+ }
-private:
- const char *data;
- mutable int fieldNameSize_; // cached value
- int fieldNameSize() const {
- if ( fieldNameSize_ == -1 )
- fieldNameSize_ = (int)strlen( fieldName() ) + 1;
- return fieldNameSize_;
- }
- mutable int totalSize; /* caches the computed size */
+ string _asCode() const;
+ OpTime _opTime() const;
- friend class BSONObjIterator;
- friend class BSONObj;
- const BSONElement& chk(int t) const {
- if ( t != type() ){
- StringBuilder ss;
- ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t;
- uasserted(13111, ss.str() );
+ private:
+ const char *data;
+ mutable int fieldNameSize_; // cached value
+ int fieldNameSize() const {
+ if ( fieldNameSize_ == -1 )
+ fieldNameSize_ = (int)strlen( fieldName() ) + 1;
+ return fieldNameSize_;
}
- return *this;
- }
- const BSONElement& chk(bool expr) const {
- uassert(13118, "unexpected or missing type value in BSON object", expr);
- return *this;
- }
-};
+ mutable int totalSize; /* caches the computed size */
+
+ friend class BSONObjIterator;
+ friend class BSONObj;
+ const BSONElement& chk(int t) const {
+ if ( t != type() ) {
+ StringBuilder ss;
+ ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t;
+ uasserted(13111, ss.str() );
+ }
+ return *this;
+ }
+ const BSONElement& chk(bool expr) const {
+ uassert(13118, "unexpected or missing type value in BSON object", expr);
+ return *this;
+ }
+ };
inline int BSONElement::canonicalType() const {
BSONType t = type();
- switch ( t ){
+ switch ( t ) {
case MinKey:
case MaxKey:
return t;
@@ -448,7 +454,7 @@ private:
assert(0);
return -1;
}
- }
+ }
inline bool BSONElement::trueValue() const {
switch( type() ) {
@@ -464,7 +470,7 @@ private:
case jstNULL:
case Undefined:
return false;
-
+
default:
;
}
@@ -478,13 +484,13 @@ private:
case NumberDouble:
case NumberInt:
return true;
- default:
+ default:
return false;
}
}
inline bool BSONElement::isSimpleType() const {
- switch( type() ){
+ switch( type() ) {
case NumberLong:
case NumberDouble:
case NumberInt:
@@ -493,7 +499,7 @@ private:
case mongo::Date:
case jstOID:
return true;
- default:
+ default:
return false;
}
}
@@ -512,7 +518,7 @@ private:
}
/** Retrieve int value for the element safely. Zero returned if not a number. Converted to int if another numeric type. */
- inline int BSONElement::numberInt() const {
+ inline int BSONElement::numberInt() const {
switch( type() ) {
case NumberDouble:
return (int) _numberDouble();
@@ -526,7 +532,7 @@ private:
}
/** Retrieve long value for the element safely. Zero returned if not a number. */
- inline long long BSONElement::numberLong() const {
+ inline long long BSONElement::numberLong() const {
switch( type() ) {
case NumberDouble:
return (long long) _numberDouble();
@@ -537,7 +543,7 @@ private:
default:
return 0;
}
- }
+ }
inline BSONElement::BSONElement() {
static char z = 0;
diff --git a/bson/bsonmisc.h b/bson/bsonmisc.h
index 40ec6d3..96be12a 100644
--- a/bson/bsonmisc.h
+++ b/bson/bsonmisc.h
@@ -26,7 +26,7 @@ namespace mongo {
return l.woCompare( r, false ) < 0;
}
};
-
+
class BSONObjCmp {
public:
BSONObjCmp( const BSONObj &_order = BSONObj() ) : order( _order ) {}
@@ -54,26 +54,26 @@ namespace mongo {
FieldCompareResult compareDottedFieldNames( const string& l , const string& r );
-/** Use BSON macro to build a BSONObj from a stream
+ /** Use BSON macro to build a BSONObj from a stream
+
+ e.g.,
+ BSON( "name" << "joe" << "age" << 33 )
- e.g.,
- BSON( "name" << "joe" << "age" << 33 )
+ with auto-generated object id:
+ BSON( GENOID << "name" << "joe" << "age" << 33 )
- with auto-generated object id:
- BSON( GENOID << "name" << "joe" << "age" << 33 )
-
- The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction
- of a BSONObj, particularly when assembling a Query. For example,
- BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object
- { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }.
-*/
+ The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction
+ of a BSONObj, particularly when assembling a Query. For example,
+ BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object
+ { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }.
+ */
#define BSON(x) (( mongo::BSONObjBuilder(64) << x ).obj())
-/** Use BSON_ARRAY macro like BSON macro, but without keys
+ /** Use BSON_ARRAY macro like BSON macro, but without keys
- BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) );
+ BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) );
- */
+ */
#define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr())
/* Utility class to auto assign object IDs.
@@ -83,11 +83,18 @@ namespace mongo {
extern struct GENOIDLabeler { } GENOID;
/* Utility class to add a Date element with the current time
- Example:
+ Example:
cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 11:41:42" }
*/
extern struct DateNowLabeler { } DATENOW;
+ /* Utility class to add the minKey (minus infinity) to a given attribute
+ Example:
+ cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } }
+ */
+ extern struct MinKeyLabeler { } MINKEY;
+ extern struct MaxKeyLabeler { } MAXKEY;
+
// Utility class to implement GT, GTE, etc as described above.
class Labeler {
public:
@@ -99,17 +106,17 @@ namespace mongo {
template<class T>
BSONObjBuilder& operator<<( T value );
- /* the value of the element e is appended i.e. for
+ /* the value of the element e is appended i.e. for
"age" << GT << someElement
- one gets
- { age : { $gt : someElement's value } }
+ one gets
+ { age : { $gt : someElement's value } }
*/
BSONObjBuilder& operator<<( const BSONElement& e );
private:
const Label &l_;
BSONObjBuilderValueStream *s_;
};
-
+
extern Labeler::Label GT;
extern Labeler::Label GTE;
extern Labeler::Label LT;
@@ -126,7 +133,7 @@ namespace mongo {
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e);
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f);
// definitions in bsonobjbuilder.h b/c of incomplete types
-
+
// Utility class to implement BSON( key << val ) as described above.
class BSONObjBuilderValueStream : public boost::noncopyable {
public:
@@ -134,17 +141,20 @@ namespace mongo {
BSONObjBuilderValueStream( BSONObjBuilder * builder );
BSONObjBuilder& operator<<( const BSONElement& e );
-
- template<class T>
+
+ template<class T>
BSONObjBuilder& operator<<( T value );
BSONObjBuilder& operator<<(DateNowLabeler& id);
-
+
+ BSONObjBuilder& operator<<(MinKeyLabeler& id);
+ BSONObjBuilder& operator<<(MaxKeyLabeler& id);
+
Labeler operator<<( const Labeler::Label &l );
void endField( const char *nextFieldName = 0 );
bool subobjStarted() const { return _fieldName != 0; }
-
+
private:
const char * _fieldName;
BSONObjBuilder * _builder;
@@ -153,39 +163,39 @@ namespace mongo {
BSONObjBuilder *subobj();
auto_ptr< BSONObjBuilder > _subobj;
};
-
+
/**
used in conjuction with BSONObjBuilder, allows for proper buffer size to prevent crazy memory usage
*/
class BSONSizeTracker {
public:
- BSONSizeTracker(){
+ BSONSizeTracker() {
_pos = 0;
for ( int i=0; i<SIZE; i++ )
_sizes[i] = 512; // this is the default, so just be consistent
}
-
- ~BSONSizeTracker(){
+
+ ~BSONSizeTracker() {
}
-
- void got( int size ){
+
+ void got( int size ) {
_sizes[_pos++] = size;
if ( _pos >= SIZE )
_pos = 0;
}
-
+
/**
* right now choosing largest size
*/
int getSize() const {
int x = 16; // sane min
- for ( int i=0; i<SIZE; i++ ){
+ for ( int i=0; i<SIZE; i++ ) {
if ( _sizes[i] > x )
x = _sizes[i];
}
return x;
}
-
+
private:
enum { SIZE = 10 };
int _pos;
diff --git a/bson/bsonobj.h b/bson/bsonobj.h
index a802526..3ca6b8c 100644
--- a/bson/bsonobj.h
+++ b/bson/bsonobj.h
@@ -28,23 +28,23 @@ namespace mongo {
typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet;
/**
- C++ representation of a "BSON" object -- that is, an extended JSON-style
+ C++ representation of a "BSON" object -- that is, an extended JSON-style
object in a binary representation.
See bsonspec.org.
- Note that BSONObj's have a smart pointer capability built in -- so you can
+ Note that BSONObj's have a smart pointer capability built in -- so you can
pass them around by value. The reference counts used to implement this
do not use locking, so copying and destroying BSONObj's are not thread-safe
operations.
BSON object format:
-
+
code
<unsigned totalSize> {<byte BSONType><cstring FieldName><Data>}* EOO
-
+
totalSize includes itself.
-
+
Data:
Bool: <byte>
EOO: nothing follows
@@ -67,31 +67,65 @@ namespace mongo {
*/
class BSONObj {
public:
- /** Construct a BSONObj from data in the proper format.
- @param ifree true if the BSONObj should free() the msgdata when
- it destructs.
- */
+
+ /** Construct a BSONObj from data in the proper format.
+ @param ifree true if the BSONObj should free() the msgdata when
+ it destructs.
+ */
explicit BSONObj(const char *msgdata, bool ifree = false) {
init(msgdata, ifree);
}
- BSONObj(const Record *r);
+
+ explicit BSONObj(const Record *r);
+
/** Construct an empty BSONObj -- that is, {}. */
BSONObj();
- // defensive
- ~BSONObj() { _objdata = 0; }
- void appendSelfToBufBuilder(BufBuilder& b) const {
- assert( objsize() );
- b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsize());
- }
+ ~BSONObj() { /*defensive:*/ _objdata = 0; }
+
+ /**
+ A BSONObj can use a buffer it "owns" or one it does not.
+
+ OWNED CASE
+ If the BSONObj owns the buffer, the buffer can be shared among several BSONObj's (by assignment).
+ In this case the buffer is basically implemented as a shared_ptr.
+ Since BSONObj's are typically immutable, this works well.
+
+ UNOWNED CASE
+ A BSONObj can also point to BSON data in some other data structure it does not "own" or free later.
+ For example, in a memory mapped file. In this case, it is important the original data stays in
+ scope for as long as the BSONObj is in use. If you think the original data may go out of scope,
+ call BSONObj::getOwned() to promote your BSONObj to having its own copy.
+
+ On a BSONObj assignment, if the source is unowned, both the source and dest will have unowned
+ pointers to the original buffer after the assignment.
- /** Readable representation of a BSON object in an extended JSON-style notation.
+ If you are not sure about ownership but need the buffer to last as long as the BSONObj, call
+ getOwned(). getOwned() is a no-op if the buffer is already owned. If not already owned, a malloc
+ and memcpy will result.
+
+ Most ways to create BSONObj's create 'owned' variants. Unowned versions can be created with:
+ (1) specifying true for the ifree parameter in the constructor
+ (2) calling BSONObjBuilder::done(). Use BSONObjBuilder::obj() to get an owned copy
+ (3) retrieving a subobject retrieves an unowned pointer into the parent BSON object
+
+ @return true if this is in owned mode
+ */
+ bool isOwned() const { return _holder.get() != 0; }
+
+ /* make sure the data buffer is under the control of this BSONObj and not a remote buffer */
+ BSONObj getOwned() const;
+
+ /** @return a new full (and owned) copy of the object. */
+ BSONObj copy() const;
+
+ /** Readable representation of a BSON object in an extended JSON-style notation.
This is an abbreviated representation which might be used for logging.
*/
string toString( bool isArray = false, bool full=false ) const;
void toString(StringBuilder& s, bool isArray = false, bool full=false ) const;
-
- /** Properly formatted JSON string.
+
+ /** Properly formatted JSON string.
@param pretty if true we try to add some lf's and indentation
*/
string jsonString( JsonStringFormat format = Strict, int pretty = 0 ) const;
@@ -126,38 +160,36 @@ namespace mongo {
names with respect to the returned element. */
BSONElement getFieldDottedOrArray(const char *&name) const;
- /** Get the field of the specified name. eoo() is true on the returned
- element if not found.
+ /** Get the field of the specified name. eoo() is true on the returned
+ element if not found.
*/
BSONElement getField(const StringData& name) const;
- /** Get the field of the specified name. eoo() is true on the returned
- element if not found.
+ /** Get the field of the specified name. eoo() is true on the returned
+ element if not found.
*/
- BSONElement operator[] (const char *field) const {
+ BSONElement operator[] (const char *field) const {
return getField(field);
}
- BSONElement operator[] (const string& field) const {
+ BSONElement operator[] (const string& field) const {
return getField(field);
}
- BSONElement operator[] (int field) const {
+ BSONElement operator[] (int field) const {
StringBuilder ss;
ss << field;
string s = ss.str();
return getField(s.c_str());
}
- /** @return true if field exists */
- bool hasField( const char * name )const {
- return ! getField( name ).eoo();
- }
+ /** @return true if field exists */
+ bool hasField( const char * name ) const { return ! getField( name ).eoo(); }
/** @return "" if DNE or wrong type */
const char * getStringField(const char *name) const;
- /** @return subobject of the given name */
+ /** @return subobject of the given name */
BSONObj getObjectField(const char *name) const;
/** @return INT_MIN if not present - does some type conversions */
@@ -172,26 +204,24 @@ namespace mongo {
object.
*/
BSONObj extractFieldsUnDotted(BSONObj pattern) const;
-
+
/** extract items from object which match a pattern object.
- e.g., if pattern is { x : 1, y : 1 }, builds an object with
- x and y elements of this object, if they are present.
+ e.g., if pattern is { x : 1, y : 1 }, builds an object with
+ x and y elements of this object, if they are present.
returns elements with original field names
*/
BSONObj extractFields(const BSONObj &pattern , bool fillWithNull=false) const;
-
+
BSONObj filterFieldsUndotted(const BSONObj &filter, bool inFilter) const;
BSONElement getFieldUsingIndexNames(const char *fieldName, const BSONObj &indexKey) const;
-
+
/** @return the raw data of the object */
const char *objdata() const {
return _objdata;
}
/** @return total size of the BSON object in bytes */
- int objsize() const {
- return *(reinterpret_cast<const int*>(objdata()));
- }
+ int objsize() const { return *(reinterpret_cast<const int*>(objdata())); }
/** performs a cursory check on the object's size only. */
bool isValid();
@@ -201,32 +231,30 @@ namespace mongo {
*/
bool okForStorage() const;
- /** @return true if object is empty -- i.e., {} */
- bool isEmpty() const {
- return objsize() <= 5;
- }
+ /** @return true if object is empty -- i.e., {} */
+ bool isEmpty() const { return objsize() <= 5; }
void dump() const;
/** Alternative output format */
string hexDump() const;
-
+
/**wo='well ordered'. fields must be in same order in each object.
- Ordering is with respect to the signs of the elements
+ Ordering is with respect to the signs of the elements
and allows ascending / descending key mixing.
- @return <0 if l<r. 0 if l==r. >0 if l>r
+ @return <0 if l<r. 0 if l==r. >0 if l>r
*/
int woCompare(const BSONObj& r, const Ordering &o,
bool considerFieldName=true) const;
/**wo='well ordered'. fields must be in same order in each object.
- Ordering is with respect to the signs of the elements
+ Ordering is with respect to the signs of the elements
and allows ascending / descending key mixing.
- @return <0 if l<r. 0 if l==r. >0 if l>r
+ @return <0 if l<r. 0 if l==r. >0 if l>r
*/
int woCompare(const BSONObj& r, const BSONObj &ordering = BSONObj(),
bool considerFieldName=true) const;
-
+
bool operator<( const BSONObj& other ) const { return woCompare( other ) < 0; }
bool operator<=( const BSONObj& other ) const { return woCompare( other ) <= 0; }
@@ -249,31 +277,18 @@ namespace mongo {
return false;
}
- /** @return first field of the object */
- BSONElement firstElement() const {
- return BSONElement(objdata() + 4);
- }
+ /** @return first field of the object */
+ BSONElement firstElement() const { return BSONElement(objdata() + 4); }
- /** @return true if field exists in the object */
+ /** @return true if field exists in the object */
bool hasElement(const char *name) const;
- /** Get the _id field from the object. For good performance drivers should
- assure that _id is the first element of the object; however, correct operation
+ /** Get the _id field from the object. For good performance drivers should
+ assure that _id is the first element of the object; however, correct operation
is assured regardless.
@return true if found
- */
- bool getObjectID(BSONElement& e) const;
-
- /** makes a copy of the object. */
- BSONObj copy() const;
-
- /* make sure the data buffer is under the control of this BSONObj and not a remote buffer */
- BSONObj getOwned() const{
- if ( !isOwned() )
- return copy();
- return *this;
- }
- bool isOwned() const { return _holder.get() != 0; }
+ */
+ bool getObjectID(BSONElement& e) const;
/** @return A hash code for the object */
int hash() const {
@@ -289,18 +304,18 @@ namespace mongo {
// string identifier equivalents.
// TODO Support conversion of element types other than min and max.
BSONObj clientReadable() const;
-
+
/** Return new object with the field names replaced by those in the
passed object. */
BSONObj replaceFieldNames( const BSONObj &obj ) const;
-
+
/** true unless corrupt */
bool valid() const;
-
+
/** @return an md5 value for this object. */
string md5() const;
-
- bool operator==( const BSONObj& other ) const{
+
+ bool operator==( const BSONObj& other ) const {
return woCompare( other ) == 0;
}
@@ -324,14 +339,21 @@ namespace mongo {
opNEAR = 0x13,
opWITHIN = 0x14,
opMAX_DISTANCE=0x15
- };
+ };
/** add all elements of the object to the specified vector */
void elems(vector<BSONElement> &) const;
/** add all elements of the object to the specified list */
void elems(list<BSONElement> &) const;
- /** add all values of the object to the specified vector. If type mismatches, exception. */
+ /** add all values of the object to the specified vector. If type mismatches, exception.
+ this is most useful when the BSONObj is an array, but can be used with non-arrays too in theory.
+
+ example:
+ bo sub = y["subobj"].Obj();
+ vector<int> myints;
+ sub.Vals(myints);
+ */
template <class T>
void Vals(vector<T> &) const;
/** add all values of the object to the specified list. If type mismatches, exception. */
@@ -347,13 +369,25 @@ namespace mongo {
friend class BSONObjIterator;
typedef BSONObjIterator iterator;
+
+ /** use something like this:
+ for( BSONObj::iterator i = myObj.begin(); i.more(); ) {
+ BSONElement e = i.next();
+ ...
+ }
+ */
BSONObjIterator begin();
-private:
+ void appendSelfToBufBuilder(BufBuilder& b) const {
+ assert( objsize() );
+ b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsize());
+ }
+
+ private:
class Holder {
public:
Holder( const char *objdata ) :
- _objdata( objdata ) {
+ _objdata( objdata ) {
}
~Holder() {
free((void *)_objdata);
@@ -362,29 +396,27 @@ private:
private:
const char *_objdata;
};
+
const char *_objdata;
boost::shared_ptr< Holder > _holder;
+
+ void _assertInvalid() const;
void init(const char *data, bool ifree) {
if ( ifree )
_holder.reset( new Holder( data ) );
_objdata = data;
- if ( ! isValid() ){
- StringBuilder ss;
- int os = objsize();
- ss << "Invalid BSONObj spec size: " << os << " (" << toHex( &os, 4 ) << ")";
- try {
- BSONElement e = firstElement();
- ss << " first element:" << e.toString() << " ";
- }
- catch ( ... ){}
- string s = ss.str();
- massert( 10334 , s , 0 );
- }
+ if ( !isValid() )
+ _assertInvalid();
}
};
+
ostream& operator<<( ostream &s, const BSONObj &o );
ostream& operator<<( ostream &s, const BSONElement &e );
+ StringBuilder& operator<<( StringBuilder &s, const BSONObj &o );
+ StringBuilder& operator<<( StringBuilder &s, const BSONElement &e );
+
+
struct BSONArray : BSONObj {
// Don't add anything other than forwarding constructors!!!
BSONArray(): BSONObj() {}
diff --git a/bson/bsonobjbuilder.h b/bson/bsonobjbuilder.h
index fdfe4de..a39b529 100644
--- a/bson/bsonobjbuilder.h
+++ b/bson/bsonobjbuilder.h
@@ -36,7 +36,7 @@ namespace mongo {
template<typename T>
class BSONFieldValue {
public:
- BSONFieldValue( const string& name , const T& t ){
+ BSONFieldValue( const string& name , const T& t ) {
_name = name;
_t = t;
}
@@ -52,8 +52,8 @@ namespace mongo {
template<typename T>
class BSONField {
public:
- BSONField( const string& name , const string& longName="" )
- : _name(name), _longName(longName){}
+ BSONField( const string& name , const string& longName="" )
+ : _name(name), _longName(longName) {}
const string& name() const { return _name; }
operator string() const { return _name; }
@@ -65,11 +65,11 @@ namespace mongo {
BSONFieldValue<BSONObj> lt( const T& t ) const { return query( "$lt" , t ); }
BSONFieldValue<BSONObj> query( const char * q , const T& t ) const;
-
+
BSONFieldValue<T> operator()( const T& t ) const {
return BSONFieldValue<T>( _name , t );
}
-
+
private:
string _name;
string _longName;
@@ -85,17 +85,18 @@ namespace mongo {
_b.skip(4); /*leave room for size field*/
}
+ /* dm why do we have this/need this? not clear to me, comment please tx. */
/** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder */
BSONObjBuilder( BufBuilder &baseBuilder ) : _b( baseBuilder ), _buf( 0 ), _offset( baseBuilder.len() ), _s( this ) , _tracker(0) , _doneCalled(false) {
_b.skip( 4 );
}
-
+
BSONObjBuilder( const BSONSizeTracker & tracker ) : _b(_buf) , _buf(tracker.getSize() ), _offset(0), _s( this ) , _tracker( (BSONSizeTracker*)(&tracker) ) , _doneCalled(false) {
_b.skip( 4 );
}
- ~BSONObjBuilder(){
- if ( !_doneCalled && _b.buf() && _buf.getSize() == 0 ){
+ ~BSONObjBuilder() {
+ if ( !_doneCalled && _b.buf() && _buf.getSize() == 0 ) {
_done();
}
}
@@ -103,6 +104,9 @@ namespace mongo {
/** add all the fields from the object specified to this object */
BSONObjBuilder& appendElements(BSONObj x);
+ /** add all the fields from the object specified to this object if they don't exist already */
+ BSONObjBuilder& appendElementsUnique( BSONObj x );
+
/** append element to the object we are building */
BSONObjBuilder& append( const BSONElement& e) {
assert( !e.eoo() ); // do not append eoo, that would corrupt us. the builder auto appends when done() is called.
@@ -111,7 +115,7 @@ namespace mongo {
}
/** append an element but with a new name */
- BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fieldName) {
+ BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fieldName) {
assert( !e.eoo() ); // do not append eoo, that would corrupt us. the builder auto appends when done() is called.
_b.appendNum((char) e.type());
_b.appendStr(fieldName);
@@ -128,14 +132,14 @@ namespace mongo {
}
/** add a subobject as a member */
- BSONObjBuilder& appendObject(const StringData& fieldName, const char * objdata , int size = 0 ){
+ BSONObjBuilder& appendObject(const StringData& fieldName, const char * objdata , int size = 0 ) {
assert( objdata );
- if ( size == 0 ){
+ if ( size == 0 ) {
size = *((int*)objdata);
}
-
+
assert( size > 4 && size < 100000000 );
-
+
_b.appendNum((char) Object);
_b.appendStr(fieldName);
_b.appendBuf((void*)objdata, size );
@@ -150,7 +154,7 @@ namespace mongo {
_b.appendStr(fieldName);
return _b;
}
-
+
/** add a subobject as a member with type Array. Thus arr object should have "0", "1", ...
style fields in it.
*/
@@ -160,9 +164,9 @@ namespace mongo {
_b.appendBuf((void *) subObj.objdata(), subObj.objsize());
return *this;
}
- BSONObjBuilder& append(const StringData& fieldName, BSONArray arr) {
- return appendArray(fieldName, arr);
- }
+ BSONObjBuilder& append(const StringData& fieldName, BSONArray arr) {
+ return appendArray(fieldName, arr);
+ }
/** add header for a new subarray and return bufbuilder for writing to
the subarray's body */
@@ -171,7 +175,7 @@ namespace mongo {
_b.appendStr(fieldName);
return _b;
}
-
+
/** Append a boolean element */
BSONObjBuilder& appendBool(const StringData& fieldName, int val) {
_b.appendNum((char) Bool);
@@ -184,10 +188,10 @@ namespace mongo {
BSONObjBuilder& append(const StringData& fieldName, bool val) {
_b.appendNum((char) Bool);
_b.appendStr(fieldName);
- _b.appendNum((char) (val?1:0));
+ _b.appendNum((char) (val?1:0));
return *this;
}
-
+
/** Append a 32 bit integer element */
BSONObjBuilder& append(const StringData& fieldName, int n) {
_b.appendNum((char) NumberInt);
@@ -197,20 +201,20 @@ namespace mongo {
}
/** Append a 32 bit unsigned element - cast to a signed int. */
- BSONObjBuilder& append(const StringData& fieldName, unsigned n) {
- return append(fieldName, (int) n);
+ BSONObjBuilder& append(const StringData& fieldName, unsigned n) {
+ return append(fieldName, (int) n);
}
/** Append a NumberLong */
- BSONObjBuilder& append(const StringData& fieldName, long long n) {
+ BSONObjBuilder& append(const StringData& fieldName, long long n) {
_b.appendNum((char) NumberLong);
_b.appendStr(fieldName);
_b.appendNum(n);
- return *this;
+ return *this;
}
/** appends a number. if n < max(int)/2 then uses int, otherwise long long */
- BSONObjBuilder& appendIntOrLL( const StringData& fieldName , long long n ){
+ BSONObjBuilder& appendIntOrLL( const StringData& fieldName , long long n ) {
long long x = n;
if ( x < 0 )
x = x * -1;
@@ -225,15 +229,26 @@ namespace mongo {
* appendNumber is a series of method for appending the smallest sensible type
* mostly for JS
*/
- BSONObjBuilder& appendNumber( const StringData& fieldName , int n ){
+ BSONObjBuilder& appendNumber( const StringData& fieldName , int n ) {
return append( fieldName , n );
}
- BSONObjBuilder& appendNumber( const StringData& fieldName , double d ){
+ BSONObjBuilder& appendNumber( const StringData& fieldName , double d ) {
return append( fieldName , d );
}
- BSONObjBuilder& appendNumber( const StringData& fieldName , long long l ){
+ BSONObjBuilder& appendNumber( const StringData& fieldName , size_t n ) {
+ static size_t maxInt = (size_t)pow( 2.0 , 30.0 );
+
+ if ( n < maxInt )
+ append( fieldName , (int)n );
+ else
+ append( fieldName , (long long)n );
+ return *this;
+ }
+
+
+ BSONObjBuilder& appendNumber( const StringData& fieldName , long long l ) {
static long long maxInt = (int)pow( 2.0 , 30.0 );
static long long maxDouble = (long long)pow( 2.0 , 40.0 );
@@ -245,7 +260,7 @@ namespace mongo {
append( fieldName , l );
return *this;
}
-
+
/** Append a double element */
BSONObjBuilder& append(const StringData& fieldName, double n) {
_b.appendNum((char) NumberDouble);
@@ -259,8 +274,8 @@ namespace mongo {
*/
bool appendAsNumber( const StringData& fieldName , const string& data );
- /** Append a BSON Object ID (OID type).
- @deprecated Generally, it is preferred to use the append append(name, oid)
+ /** Append a BSON Object ID (OID type).
+ @deprecated Generally, it is preferred to use the append append(name, oid)
method for this.
*/
BSONObjBuilder& appendOID(const StringData& fieldName, OID *oid = 0 , bool generateIfBlank = false ) {
@@ -279,8 +294,8 @@ namespace mongo {
return *this;
}
- /**
- Append a BSON Object ID.
+ /**
+ Append a BSON Object ID.
@param fieldName Field name, e.g., "_id".
@returns the builder object
*/
@@ -309,14 +324,14 @@ namespace mongo {
_b.appendNum(static_cast<unsigned long long>(dt) * 1000);
return *this;
}
- /** Append a date.
- @param dt a Java-style 64 bit date value, that is
+ /** Append a date.
+ @param dt a Java-style 64 bit date value, that is
the number of milliseconds since January 1, 1970, 00:00:00 GMT
*/
BSONObjBuilder& appendDate(const StringData& fieldName, Date_t dt) {
/* easy to pass a time_t to this and get a bad result. thus this warning. */
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
- if( dt > 0 && dt <= 0xffffffff ) {
+ if( dt > 0 && dt <= 0xffffffff ) {
static int n;
if( n++ == 0 )
log() << "DEV WARNING appendDate() called with a tiny (but nonzero) date" << endl;
@@ -335,27 +350,22 @@ namespace mongo {
@param regex the regular expression pattern
@param regex options such as "i" or "g"
*/
- BSONObjBuilder& appendRegex(const StringData& fieldName, const char *regex, const char *options = "") {
+ BSONObjBuilder& appendRegex(const StringData& fieldName, const StringData& regex, const StringData& options = "") {
_b.appendNum((char) RegEx);
_b.appendStr(fieldName);
_b.appendStr(regex);
_b.appendStr(options);
return *this;
}
- /** Append a regular expression value
- @param regex the regular expression pattern
- @param regex options such as "i" or "g"
- */
- BSONObjBuilder& appendRegex(const StringData& fieldName, string regex, string options = "") {
- return appendRegex(fieldName, regex.c_str(), options.c_str());
- }
- BSONObjBuilder& appendCode(const StringData& fieldName, const char *code) {
+
+ BSONObjBuilder& appendCode(const StringData& fieldName, const StringData& code) {
_b.appendNum((char) Code);
_b.appendStr(fieldName);
- _b.appendNum((int) strlen(code)+1);
+ _b.appendNum((int) code.size()+1);
_b.appendStr(code);
return *this;
}
+
/** Append a string element. len DOES include terminating nul */
BSONObjBuilder& append(const StringData& fieldName, const char *str, int len) {
_b.appendNum((char) String);
@@ -369,48 +379,51 @@ namespace mongo {
return append(fieldName, str, (int) strlen(str)+1);
}
/** Append a string element */
- BSONObjBuilder& append(const StringData& fieldName, string str) {
+ BSONObjBuilder& append(const StringData& fieldName, const string& str) {
return append(fieldName, str.c_str(), (int) str.size()+1);
}
- BSONObjBuilder& appendSymbol(const StringData& fieldName, const char *symbol) {
+
+ BSONObjBuilder& appendSymbol(const StringData& fieldName, const StringData& symbol) {
_b.appendNum((char) Symbol);
_b.appendStr(fieldName);
- _b.appendNum((int) strlen(symbol)+1);
+ _b.appendNum((int) symbol.size()+1);
_b.appendStr(symbol);
- return *this; }
+ return *this;
+ }
/** Append a Null element to the object */
BSONObjBuilder& appendNull( const StringData& fieldName ) {
_b.appendNum( (char) jstNULL );
_b.appendStr( fieldName );
- return *this; }
+ return *this;
+ }
// Append an element that is less than all other keys.
BSONObjBuilder& appendMinKey( const StringData& fieldName ) {
_b.appendNum( (char) MinKey );
_b.appendStr( fieldName );
- return *this;
+ return *this;
}
// Append an element that is greater than all other keys.
BSONObjBuilder& appendMaxKey( const StringData& fieldName ) {
_b.appendNum( (char) MaxKey );
_b.appendStr( fieldName );
- return *this;
+ return *this;
}
-
+
// Append a Timestamp field -- will be updated to next OpTime on db insert.
BSONObjBuilder& appendTimestamp( const StringData& fieldName ) {
_b.appendNum( (char) Timestamp );
_b.appendStr( fieldName );
_b.appendNum( (unsigned long long) 0 );
- return *this;
+ return *this;
}
BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsigned long long val ) {
_b.appendNum( (char) Timestamp );
_b.appendStr( fieldName );
_b.appendNum( val );
- return *this;
+ return *this;
}
/**
@@ -419,24 +432,24 @@ namespace mongo {
@param time - in millis (but stored in seconds)
*/
BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsigned long long time , unsigned int inc );
-
+
/*
Append an element of the deprecated DBRef type.
- @deprecated
+ @deprecated
*/
- BSONObjBuilder& appendDBRef( const StringData& fieldName, const char *ns, const OID &oid ) {
+ BSONObjBuilder& appendDBRef( const StringData& fieldName, const StringData& ns, const OID &oid ) {
_b.appendNum( (char) DBRef );
_b.appendStr( fieldName );
- _b.appendNum( (int) strlen( ns ) + 1 );
+ _b.appendNum( (int) ns.size() + 1 );
_b.appendStr( ns );
_b.appendBuf( (void *) &oid, 12 );
- return *this;
+ return *this;
}
- /** Append a binary data element
+ /** Append a binary data element
@param fieldName name of the field
@param len length of the binary data in bytes
- @param subtype subtype information for the data. @see enum BinDataType in bsontypes.h.
+ @param subtype subtype information for the data. @see enum BinDataType in bsontypes.h.
Use BinDataGeneral if you don't care about the type.
@param data the byte array
*/
@@ -446,36 +459,36 @@ namespace mongo {
_b.appendNum( len );
_b.appendNum( (char) type );
_b.appendBuf( (void *) data, len );
- return *this;
+ return *this;
}
BSONObjBuilder& appendBinData( const StringData& fieldName, int len, BinDataType type, const unsigned char *data ) {
return appendBinData(fieldName, len, type, (const char *) data);
}
-
+
/**
Subtype 2 is deprecated.
Append a BSON bindata bytearray element.
@param data a byte array
@param len the length of data
*/
- BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldName , const char * data , int len ){
+ BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldName , const char * data , int len ) {
_b.appendNum( (char) BinData );
_b.appendStr( fieldName );
_b.appendNum( len + 4 );
_b.appendNum( (char)0x2 );
_b.appendNum( len );
- _b.appendBuf( (void *) data, len );
- return *this;
+ _b.appendBuf( (void *) data, len );
+ return *this;
}
- /** Append to the BSON object a field of type CodeWScope. This is a javascript code
+ /** Append to the BSON object a field of type CodeWScope. This is a javascript code
fragment accompanied by some scope that goes with it.
*/
- BSONObjBuilder& appendCodeWScope( const StringData& fieldName, const char *code, const BSONObj &scope ) {
+ BSONObjBuilder& appendCodeWScope( const StringData& fieldName, const StringData& code, const BSONObj &scope ) {
_b.appendNum( (char) CodeWScope );
_b.appendStr( fieldName );
- _b.appendNum( ( int )( 4 + 4 + strlen( code ) + 1 + scope.objsize() ) );
- _b.appendNum( ( int ) strlen( code ) + 1 );
+ _b.appendNum( ( int )( 4 + 4 + code.size() + 1 + scope.objsize() ) );
+ _b.appendNum( ( int ) code.size() + 1 );
_b.appendStr( code );
_b.appendBuf( ( void * )scope.objdata(), scope.objsize() );
return *this;
@@ -485,15 +498,12 @@ namespace mongo {
_b.appendNum( (char) Undefined );
_b.appendStr( fieldName );
}
-
+
/* helper function -- see Query::where() for primary way to do this. */
- void appendWhere( const char *code, const BSONObj &scope ){
+ void appendWhere( const StringData& code, const BSONObj &scope ) {
appendCodeWScope( "$where" , code , scope );
}
- void appendWhere( const string &code, const BSONObj &scope ){
- appendWhere( code.c_str(), scope );
- }
-
+
/**
these are the min/max when comparing, not strict min/max elements for a given type
*/
@@ -507,7 +517,11 @@ namespace mongo {
template < class T >
BSONObjBuilder& append( const StringData& fieldName, const list< T >& vals );
- /** The returned BSONObj will free the buffer when it is finished. */
+ /**
+ * destructive
+ * The returned BSONObj will free the buffer when it is finished.
+ * @return owned BSONObj
+ */
BSONObj obj() {
bool own = owned();
massert( 10335 , "builder does not own memory", own );
@@ -516,12 +530,12 @@ namespace mongo {
}
/** Fetch the object we have built.
- BSONObjBuilder still frees the object when the builder goes out of
- scope -- very important to keep in mind. Use obj() if you
- would like the BSONObj to last longer than the builder.
+ BSONObjBuilder still frees the object when the builder goes out of
+ scope -- very important to keep in mind. Use obj() if you
+ would like the BSONObj to last longer than the builder.
*/
BSONObj done() {
- return BSONObj(_done());
+ return BSONObj(_done(), /*ifree*/false);
}
// Like 'done' above, but does not construct a BSONObj to return to the caller.
@@ -591,25 +605,29 @@ namespace mongo {
BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) {
_s.endField( f.name().c_str() );
return _s;
- }
+ }
template<typename T>
BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) {
append( v.name().c_str() , v.value() );
return *this;
- }
-
+ }
+
/** @return true if we are using our own bufbuilder, and not an alternate that was given to us in our constructor */
bool owned() const { return &_b == &_buf; }
BSONObjIterator iterator() const ;
-
+
+ bool hasField( const StringData& name ) const ;
+
+ int len() const { return _b.len(); }
+
private:
char* _done() {
if ( _doneCalled )
return _b.buf() + _offset;
-
+
_doneCalled = true;
_s.endField();
_b.appendNum((char) EOO);
@@ -635,82 +653,89 @@ namespace mongo {
public:
BSONArrayBuilder() : _i(0), _b() {}
BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {}
+ BSONArrayBuilder( int initialSize ) : _i(0), _b(initialSize) {}
template <typename T>
- BSONArrayBuilder& append(const T& x){
- _b.append(num().c_str(), x);
+ BSONArrayBuilder& append(const T& x) {
+ _b.append(num(), x);
return *this;
}
- BSONArrayBuilder& append(const BSONElement& e){
+ BSONArrayBuilder& append(const BSONElement& e) {
_b.appendAs(e, num());
return *this;
}
-
+
template <typename T>
- BSONArrayBuilder& operator<<(const T& x){
+ BSONArrayBuilder& operator<<(const T& x) {
return append(x);
}
-
+
void appendNull() {
- _b.appendNull(num().c_str());
+ _b.appendNull(num());
}
- BSONArray arr(){ return BSONArray(_b.obj()); }
-
+ /**
+ * destructive - ownership moves to returned BSONArray
+ * @return owned BSONArray
+ */
+ BSONArray arr() { return BSONArray(_b.obj()); }
+
BSONObj done() { return _b.done(); }
-
+
void doneFast() { _b.doneFast(); }
-
+
template <typename T>
- BSONArrayBuilder& append(const StringData& name, const T& x){
+ BSONArrayBuilder& append(const StringData& name, const T& x) {
fill( name );
append( x );
return *this;
}
-
- BufBuilder &subobjStart( const char *name = "0" ) {
+
+ BufBuilder &subobjStart( const StringData& name = "0" ) {
fill( name );
- return _b.subobjStart( num().c_str() );
+ return _b.subobjStart( num() );
}
BufBuilder &subarrayStart( const char *name ) {
fill( name );
- return _b.subarrayStart( num().c_str() );
+ return _b.subarrayStart( num() );
}
-
+
void appendArray( const StringData& name, BSONObj subObj ) {
fill( name );
- _b.appendArray( num().c_str(), subObj );
+ _b.appendArray( num(), subObj );
}
-
- void appendAs( const BSONElement &e, const char *name ) {
+
+ void appendAs( const BSONElement &e, const char *name) {
fill( name );
append( e );
}
-
+
+ int len() const { return _b.len(); }
+
private:
void fill( const StringData& name ) {
char *r;
- int n = strtol( name.data(), &r, 10 );
+ long int n = strtol( name.data(), &r, 10 );
if ( *r )
uasserted( 13048, (string)"can't append to array using string field name [" + name.data() + "]" );
while( _i < n )
append( nullElt() );
}
-
+
static BSONElement nullElt() {
static BSONObj n = nullObj();
return n.firstElement();
}
-
+
static BSONObj nullObj() {
BSONObjBuilder _b;
_b.appendNull( "" );
return _b.obj();
}
-
- string num(){ return _b.numStr(_i++); }
+
+ string num() { return _b.numStr(_i++); }
int _i;
BSONObjBuilder _b;
};
@@ -736,14 +761,14 @@ namespace mongo {
// $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT 6));
inline BSONObj OR(const BSONObj& a, const BSONObj& b)
- { return BSON( "$or" << BSON_ARRAY(a << b) ); }
+ { return BSON( "$or" << BSON_ARRAY(a << b) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c)
- { return BSON( "$or" << BSON_ARRAY(a << b << c) ); }
+ { return BSON( "$or" << BSON_ARRAY(a << b << c) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d)
- { return BSON( "$or" << BSON_ARRAY(a << b << c << d) ); }
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e)
- { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e) ); }
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f)
- { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e << f) ); }
-
+ { return BSON( "$or" << BSON_ARRAY(a << b << c << d << e << f) ); }
+
}
diff --git a/bson/bsonobjiterator.h b/bson/bsonobjiterator.h
index c8224d2..6e6a69e 100644
--- a/bson/bsonobjiterator.h
+++ b/bson/bsonobjiterator.h
@@ -20,6 +20,7 @@
#include <boost/preprocessor/cat.hpp> // like the ## operator but works with __LINE__
namespace mongo {
+
/** iterator for a BSONObj
Note each BSONObj ends with an EOO element: so you will get more() on an empty
@@ -30,7 +31,7 @@ namespace mongo {
*/
class BSONObjIterator {
public:
- /** Create an iterator for a BSON object.
+ /** Create an iterator for a BSON object.
*/
BSONObjIterator(const BSONObj& jso) {
int sz = jso.objsize();
@@ -42,18 +43,17 @@ namespace mongo {
_theend = jso.objdata() + sz;
}
- BSONObjIterator( const char * start , const char * end ){
+ BSONObjIterator( const char * start , const char * end ) {
_pos = start + 4;
_theend = end;
}
-
+
/** @return true if more elements exist to be enumerated. */
- bool moreWithEOO() {
- return _pos < _theend;
- }
- bool more(){
- return _pos < _theend && _pos[0];
- }
+ bool more() { return _pos < _theend && _pos[0]; }
+
+ /** @return true if more elements exist to be enumerated INCLUDING the EOO element which is always at the end. */
+ bool moreWithEOO() { return _pos < _theend; }
+
/** @return the next element in the object. For the final element, element.eoo() will be true. */
BSONElement next( bool checkEnd = false ) {
assert( _pos < _theend );
@@ -78,18 +78,18 @@ namespace mongo {
class BSONObjIteratorSorted {
public:
BSONObjIteratorSorted( const BSONObj& o );
-
- ~BSONObjIteratorSorted(){
+
+ ~BSONObjIteratorSorted() {
assert( _fields );
delete[] _fields;
_fields = 0;
}
- bool more(){
+ bool more() {
return _cur < _nfields;
}
-
- BSONElement next(){
+
+ BSONElement next() {
assert( _fields );
if ( _cur < _nfields )
return BSONElement( _fields[_cur++] );
@@ -102,30 +102,30 @@ namespace mongo {
int _cur;
};
-/** Similar to BOOST_FOREACH
- *
- * because the iterator is defined outside of the for, you must use {} around
- * the surrounding scope. Don't do this:
- *
- * if (foo)
- * BSONForEach(e, obj)
- * doSomething(e);
- *
- * but this is OK:
- *
- * if (foo) {
- * BSONForEach(e, obj)
- * doSomething(e);
- * }
- *
- */
+ /** Similar to BOOST_FOREACH
+ *
+ * because the iterator is defined outside of the for, you must use {} around
+ * the surrounding scope. Don't do this:
+ *
+ * if (foo)
+ * BSONForEach(e, obj)
+ * doSomething(e);
+ *
+ * but this is OK:
+ *
+ * if (foo) {
+ * BSONForEach(e, obj)
+ * doSomething(e);
+ * }
+ *
+ */
#define BSONForEach(e, obj) \
BSONObjIterator BOOST_PP_CAT(it_,__LINE__)(obj); \
for ( BSONElement e; \
- (BOOST_PP_CAT(it_,__LINE__).more() ? \
- (e = BOOST_PP_CAT(it_,__LINE__).next(), true) : \
- false) ; \
- /*nothing*/ )
+ (BOOST_PP_CAT(it_,__LINE__).more() ? \
+ (e = BOOST_PP_CAT(it_,__LINE__).next(), true) : \
+ false) ; \
+ /*nothing*/ )
}
diff --git a/bson/bsontypes.h b/bson/bsontypes.h
index 27f2aaf..9d95e8e 100644
--- a/bson/bsontypes.h
+++ b/bson/bsontypes.h
@@ -39,69 +39,69 @@ namespace mongo {
extern BSONObj maxKey;
extern BSONObj minKey;
-/**
- the complete list of valid BSON types
- see also bsonspec.org
-*/
-enum BSONType {
- /** smaller than all other types */
- MinKey=-1,
- /** end of object */
- EOO=0,
- /** double precision floating point value */
- NumberDouble=1,
- /** character string, stored in utf8 */
- String=2,
- /** an embedded object */
- Object=3,
- /** an embedded array */
- Array=4,
- /** binary data */
- BinData=5,
- /** Undefined type */
- Undefined=6,
- /** ObjectId */
- jstOID=7,
- /** boolean type */
- Bool=8,
- /** date type */
- Date=9,
- /** null type */
- jstNULL=10,
- /** regular expression, a pattern with options */
- RegEx=11,
- /** deprecated / will be redesigned */
- DBRef=12,
- /** deprecated / use CodeWScope */
- Code=13,
- /** a programming language (e.g., Python) symbol */
- Symbol=14,
- /** javascript code that can execute on the database server, with SavedContext */
- CodeWScope=15,
- /** 32 bit signed integer */
- NumberInt = 16,
- /** Updated to a Date with value next OpTime on insert */
- Timestamp = 17,
- /** 64 bit integer */
- NumberLong = 18,
- /** max type that is not MaxKey */
- JSTypeMax=18,
- /** larger than all other types */
- MaxKey=127
-};
+ /**
+ the complete list of valid BSON types
+ see also bsonspec.org
+ */
+ enum BSONType {
+ /** smaller than all other types */
+ MinKey=-1,
+ /** end of object */
+ EOO=0,
+ /** double precision floating point value */
+ NumberDouble=1,
+ /** character string, stored in utf8 */
+ String=2,
+ /** an embedded object */
+ Object=3,
+ /** an embedded array */
+ Array=4,
+ /** binary data */
+ BinData=5,
+ /** Undefined type */
+ Undefined=6,
+ /** ObjectId */
+ jstOID=7,
+ /** boolean type */
+ Bool=8,
+ /** date type */
+ Date=9,
+ /** null type */
+ jstNULL=10,
+ /** regular expression, a pattern with options */
+ RegEx=11,
+ /** deprecated / will be redesigned */
+ DBRef=12,
+ /** deprecated / use CodeWScope */
+ Code=13,
+ /** a programming language (e.g., Python) symbol */
+ Symbol=14,
+ /** javascript code that can execute on the database server, with SavedContext */
+ CodeWScope=15,
+ /** 32 bit signed integer */
+ NumberInt = 16,
+ /** Updated to a Date with value next OpTime on insert */
+ Timestamp = 17,
+ /** 64 bit integer */
+ NumberLong = 18,
+ /** max type that is not MaxKey */
+ JSTypeMax=18,
+ /** larger than all other types */
+ MaxKey=127
+ };
/* subtypes of BinData.
bdtCustom and above are ones that the JS compiler understands, but are
opaque to the database.
*/
- enum BinDataType {
+ enum BinDataType {
BinDataGeneral=0,
- Function=1,
+ Function=1,
ByteArrayDeprecated=2, /* use BinGeneral instead */
- bdtUUID = 3,
- MD5Type=5,
- bdtCustom=128
+ bdtUUID = 3,
+ MD5Type=5,
+ bdtCustom=128
};
-
+
}
diff --git a/bson/inline_decls.h b/bson/inline_decls.h
index aab9810..1605611 100644
--- a/bson/inline_decls.h
+++ b/bson/inline_decls.h
@@ -26,7 +26,7 @@
#define NOINLINE_DECL __declspec(noinline)
-#else
+#else
#define NOINLINE_DECL
diff --git a/bson/oid.cpp b/bson/oid.cpp
new file mode 100644
index 0000000..6aa0730
--- /dev/null
+++ b/bson/oid.cpp
@@ -0,0 +1,154 @@
+// @file oid.cpp
+
+/* Copyright 2009 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pch.h"
+#include "oid.h"
+#include "util/atomic_int.h"
+#include "../db/nonce.h"
+
+BOOST_STATIC_ASSERT( sizeof(mongo::OID) == 12 );
+
+namespace mongo {
+
+ // machine # before folding in the process id
+ OID::MachineAndPid OID::ourMachine;
+
+ unsigned OID::ourPid() {
+ unsigned pid;
+#if defined(_WIN32)
+ pid = (unsigned short) GetCurrentProcessId();
+#elif defined(__linux__) || defined(__APPLE__) || defined(__sunos__)
+ pid = (unsigned short) getpid();
+#else
+ pid = (unsigned short) security.getNonce();
+#endif
+ return pid;
+ }
+
+ void OID::foldInPid(OID::MachineAndPid& x) {
+ unsigned p = ourPid();
+ x._pid ^= (unsigned short) p;
+ // when the pid is greater than 16 bits, let the high bits modulate the machine id field.
+ unsigned short& rest = (unsigned short &) x._machineNumber[1];
+ rest ^= p >> 16;
+ }
+
+ OID::MachineAndPid OID::genMachineAndPid() {
+ BOOST_STATIC_ASSERT( sizeof(mongo::OID::MachineAndPid) == 5 );
+
+ // this is not called often, so the following is not expensive, and gives us some
+ // testing that nonce generation is working right and that our OIDs are (perhaps) ok.
+ {
+ nonce a = security.getNonce();
+ nonce b = security.getNonce();
+ nonce c = security.getNonce();
+ assert( !(a==b && b==c) );
+ }
+
+ unsigned long long n = security.getNonce();
+ OID::MachineAndPid x = ourMachine = (OID::MachineAndPid&) n;
+ foldInPid(x);
+ return x;
+ }
+
+ // after folding in the process id
+ OID::MachineAndPid OID::ourMachineAndPid = OID::genMachineAndPid();
+
+ void OID::regenMachineId() {
+ ourMachineAndPid = genMachineAndPid();
+ }
+
+ inline bool OID::MachineAndPid::operator!=(const OID::MachineAndPid& rhs) const {
+ return _pid != rhs._pid || _machineNumber != rhs._machineNumber;
+ }
+
+ unsigned OID::getMachineId() {
+ unsigned char x[4];
+ x[0] = ourMachineAndPid._machineNumber[0];
+ x[1] = ourMachineAndPid._machineNumber[1];
+ x[2] = ourMachineAndPid._machineNumber[2];
+ x[3] = 0;
+ return (unsigned&) x[0];
+ }
+
+ void OID::justForked() {
+ MachineAndPid x = ourMachine;
+ // we let the random # for machine go into all 5 bytes of MachineAndPid, and then
+ // xor in the pid into _pid. this reduces the probability of collisions.
+ foldInPid(x);
+ ourMachineAndPid = genMachineAndPid();
+ assert( x != ourMachineAndPid );
+ ourMachineAndPid = x;
+ }
+
+ void OID::init() {
+ static AtomicUInt inc = (unsigned) security.getNonce();
+
+ {
+ unsigned t = (unsigned) time(0);
+ unsigned char *T = (unsigned char *) &t;
+ _time[0] = T[3]; // big endian order because we use memcmp() to compare OID's
+ _time[1] = T[2];
+ _time[2] = T[1];
+ _time[3] = T[0];
+ }
+
+ _machineAndPid = ourMachineAndPid;
+
+ {
+ int new_inc = inc++;
+ unsigned char *T = (unsigned char *) &new_inc;
+ _inc[0] = T[2];
+ _inc[1] = T[1];
+ _inc[2] = T[0];
+ }
+ }
+
+ void OID::init( string s ) {
+ assert( s.size() == 24 );
+ const char *p = s.c_str();
+ for( int i = 0; i < 12; i++ ) {
+ data[i] = fromHex(p);
+ p += 2;
+ }
+ }
+
+ void OID::init(Date_t date, bool max) {
+ int time = (int) (date / 1000);
+ char* T = (char *) &time;
+ data[0] = T[3];
+ data[1] = T[2];
+ data[2] = T[1];
+ data[3] = T[0];
+
+ if (max)
+ *(long long*)(data + 4) = 0xFFFFFFFFFFFFFFFFll;
+ else
+ *(long long*)(data + 4) = 0x0000000000000000ll;
+ }
+
+ time_t OID::asTimeT() {
+ int time;
+ char* T = (char *) &time;
+ T[0] = data[3];
+ T[1] = data[2];
+ T[2] = data[1];
+ T[3] = data[0];
+ return time;
+ }
+
+}
diff --git a/bson/oid.h b/bson/oid.h
index c1bf34d..bf06ee1 100644
--- a/bson/oid.h
+++ b/bson/oid.h
@@ -22,56 +22,48 @@
namespace mongo {
#pragma pack(1)
- /** Object ID type.
- BSON objects typically have an _id field for the object id. This field should be the first
- member of the object when present. class OID is a special type that is a 12 byte id which
+ /** Object ID type.
+ BSON objects typically have an _id field for the object id. This field should be the first
+ member of the object when present. class OID is a special type that is a 12 byte id which
is likely to be unique to the system. You may also use other types for _id's.
- When _id field is missing from a BSON object, on an insert the database may insert one
+ When _id field is missing from a BSON object, on an insert the database may insert one
automatically in certain circumstances.
Warning: You must call OID::newState() after a fork().
+
+ Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch),
+ a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must
+ be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure
+ a mostly increasing order.
*/
class OID {
- union {
- struct{
- long long a;
- unsigned b;
- };
- unsigned char data[12];
- };
- static unsigned _machine;
public:
- /** call this after a fork */
- static void newState();
+ OID() : a(0), b(0) { }
- /** initialize to 'null' */
- void clear() { a = 0; b = 0; }
+ /** init from a 24 char hex string */
+ explicit OID(const string &s) { init(s); }
- const unsigned char *getData() const { return data; }
+ /** initialize to 'null' */
+ void clear() { a = 0; b = 0; }
- bool operator==(const OID& r) {
- return a==r.a&&b==r.b;
- }
- bool operator!=(const OID& r) {
- return a!=r.a||b!=r.b;
- }
+ const unsigned char *getData() const { return data; }
- /** The object ID output as 24 hex digits. */
- string str() const {
- return toHexLower(data, 12);
- }
+ bool operator==(const OID& r) const { return a==r.a && b==r.b; }
+ bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; }
+ int compare( const OID& other ) const { return memcmp( data , other.data , 12 ); }
+ bool operator<( const OID& other ) const { return compare( other ) < 0; }
+ bool operator<=( const OID& other ) const { return compare( other ) <= 0; }
+ /** @return the object ID output as 24 hex digits */
+ string str() const { return toHexLower(data, 12); }
string toString() const { return str(); }
static OID gen() { OID o; o.init(); return o; }
-
- static unsigned staticMachine(){ return _machine; }
- /**
- sets the contents to a new oid / randomized value
- */
+
+ /** sets the contents to a new oid / randomized value */
void init();
- /** Set to the hex string value specified. */
+ /** init from a 24 char hex string */
void init( string s );
/** Set to the min/max OID that could be generated at given timestamp. */
@@ -79,12 +71,39 @@ namespace mongo {
time_t asTimeT();
Date_t asDateT() { return asTimeT() * (long long)1000; }
-
+
bool isSet() const { return a || b; }
-
- int compare( const OID& other ) const { return memcmp( data , other.data , 12 ); }
-
- bool operator<( const OID& other ) const { return compare( other ) < 0; }
+
+ /** call this after a fork to update the process id */
+ static void justForked();
+
+ static unsigned getMachineId(); // features command uses
+ static void regenMachineId(); // used by unit tests
+
+ private:
+ struct MachineAndPid {
+ unsigned char _machineNumber[3];
+ unsigned short _pid;
+ bool operator!=(const OID::MachineAndPid& rhs) const;
+ };
+ static MachineAndPid ourMachine, ourMachineAndPid;
+ union {
+ struct {
+ // 12 bytes total
+ unsigned char _time[4];
+ MachineAndPid _machineAndPid;
+ unsigned char _inc[3];
+ };
+ struct {
+ long long a;
+ unsigned b;
+ };
+ unsigned char data[12];
+ };
+
+ static unsigned ourPid();
+ static void foldInPid(MachineAndPid& x);
+ static MachineAndPid genMachineAndPid();
};
#pragma pack()
diff --git a/bson/ordering.h b/bson/ordering.h
index fbbfbec..749e20d 100644
--- a/bson/ordering.h
+++ b/bson/ordering.h
@@ -23,7 +23,7 @@ namespace mongo {
The constructor is private to make conversion more explicit so we notice where we call make().
Over time we should push this up higher and higher.
*/
- class Ordering {
+ class Ordering {
const unsigned bits;
const unsigned nkeys;
Ordering(unsigned b,unsigned n) : bits(b),nkeys(n) { }
@@ -32,13 +32,13 @@ namespace mongo {
get(0) == 1
get(1) == -1
*/
- int get(int i) const {
+ int get(int i) const {
return ((1 << i) & bits) ? -1 : 1;
}
// for woCompare...
unsigned descending(unsigned mask) const { return bits & mask; }
-
+
operator string() const {
StringBuilder buf(32);
for ( unsigned i=0; i<nkeys; i++)
@@ -50,7 +50,7 @@ namespace mongo {
unsigned b = 0;
BSONObjIterator k(obj);
unsigned n = 0;
- while( 1 ) {
+ while( 1 ) {
BSONElement e = k.next();
if( e.eoo() )
break;
@@ -62,5 +62,5 @@ namespace mongo {
return Ordering(b,n);
}
};
-
+
}
diff --git a/bson/stringdata.h b/bson/stringdata.h
index ccf30f7..46cdb7a 100644
--- a/bson/stringdata.h
+++ b/bson/stringdata.h
@@ -25,36 +25,49 @@ namespace mongo {
using std::string;
+ // A StringData object wraps a 'const string&' or a 'const char*' without
+ // copying its contents. The most common usage is as a function argument that
+ // takes any of the two forms of strings above. Fundamentally, this class tries
+ // go around the fact that string literals in C++ are char[N]'s.
+ //
+ // Note that the object StringData wraps around must be alive while the StringDAta
+ // is.
+
class StringData {
public:
- StringData( const char* c )
+ // Construct a StringData explicilty, for the case where the lenght of
+ // string is not known. 'c' must be a pointer to a null-terminated string.
+ StringData( const char* c )
: _data(c), _size((unsigned) strlen(c)) {}
+ // Construct a StringData explicitly, for the case where the length of the string
+ // is already known. 'c' must be a pointer to a null-terminated string, and strlenOfc
+ // must be the length that std::strlen(c) would return, a.k.a the index of the
+ // terminator in c.
+ StringData( const char* c, size_t strlenOfc )
+ : _data(c), _size((unsigned) strlenOfc) {}
+
+ // Construct a StringData explicitly, for the case of a std::string.
StringData( const string& s )
: _data(s.c_str()), _size((unsigned) s.size()) {}
-
+
+ // Construct a StringData explicitly, for the case of a literal whose size is
+ // known at compile time.
struct LiteralTag {};
template<size_t N>
StringData( const char (&val)[N], LiteralTag )
: _data(&val[0]), _size(N-1) {}
- // Construct a StringData explicitly, for the case where the
- // length of the string is already known. 'c' must be a
- // pointer to a null-terminated string, and strlenOfc must be
- // the length that std::strlen(c) would return, a.k.a the
- // index of the terminator in c.
- StringData( const char* c, size_t strlenOfc )
- : _data(c), _size((unsigned) strlenOfc) {}
+ // accessors
const char* const data() const { return _data; }
const unsigned size() const { return _size; }
private:
- // TODO - Hook this class up in the BSON machinery
- // There are two assumptions here that we may want to review then.
+ // There are two assumptions we use bellow.
// '_data' *always* finishes with a null terminator
// 'size' does *not* account for the null terminator
- // These assumptions may make it easier to minimize changes to existing code
+ // These assumptions may make it easier to minimize changes to existing code.
const char* const _data;
const unsigned _size;
};
diff --git a/bson/util/atomic_int.h b/bson/util/atomic_int.h
index f4d2749..1573552 100644
--- a/bson/util/atomic_int.h
+++ b/bson/util/atomic_int.h
@@ -24,51 +24,55 @@
namespace mongo {
- struct AtomicUInt{
+ struct AtomicUInt {
AtomicUInt() : x(0) {}
AtomicUInt(unsigned z) : x(z) { }
- volatile unsigned x;
- operator unsigned() const {
- return x;
- }
+
+ operator unsigned() const { return x; }
+ unsigned get() const { return x; }
+
inline AtomicUInt operator++(); // ++prefix
inline AtomicUInt operator++(int);// postfix++
inline AtomicUInt operator--(); // --prefix
inline AtomicUInt operator--(int); // postfix--
+
+ inline void zero() { x = 0; } // TODO: this isn't thread safe
+
+ volatile unsigned x;
};
#if defined(_WIN32)
- AtomicUInt AtomicUInt::operator++(){
+ AtomicUInt AtomicUInt::operator++() {
// InterlockedIncrement returns the new value
return InterlockedIncrement((volatile long*)&x); //long is 32bits in Win64
}
- AtomicUInt AtomicUInt::operator++(int){
+ AtomicUInt AtomicUInt::operator++(int) {
return InterlockedIncrement((volatile long*)&x)-1;
}
- AtomicUInt AtomicUInt::operator--(){
+ AtomicUInt AtomicUInt::operator--() {
return InterlockedDecrement((volatile long*)&x);
}
- AtomicUInt AtomicUInt::operator--(int){
+ AtomicUInt AtomicUInt::operator--(int) {
return InterlockedDecrement((volatile long*)&x)+1;
}
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// this is in GCC >= 4.1
- AtomicUInt AtomicUInt::operator++(){
+ AtomicUInt AtomicUInt::operator++() {
return __sync_add_and_fetch(&x, 1);
}
- AtomicUInt AtomicUInt::operator++(int){
+ AtomicUInt AtomicUInt::operator++(int) {
return __sync_fetch_and_add(&x, 1);
}
- AtomicUInt AtomicUInt::operator--(){
+ AtomicUInt AtomicUInt::operator--() {
return __sync_add_and_fetch(&x, -1);
}
- AtomicUInt AtomicUInt::operator--(int){
+ AtomicUInt AtomicUInt::operator--(int) {
return __sync_fetch_and_add(&x, -1);
}
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
// from boost 1.39 interprocess/detail/atomic.hpp
- inline unsigned atomic_int_helper(volatile unsigned *x, int val){
+ inline unsigned atomic_int_helper(volatile unsigned *x, int val) {
int r;
asm volatile
(
@@ -80,16 +84,16 @@ namespace mongo {
);
return r;
}
- AtomicUInt AtomicUInt::operator++(){
+ AtomicUInt AtomicUInt::operator++() {
return atomic_int_helper(&x, 1)+1;
}
- AtomicUInt AtomicUInt::operator++(int){
+ AtomicUInt AtomicUInt::operator++(int) {
return atomic_int_helper(&x, 1);
}
- AtomicUInt AtomicUInt::operator--(){
+ AtomicUInt AtomicUInt::operator--() {
return atomic_int_helper(&x, -1)-1;
}
- AtomicUInt AtomicUInt::operator--(int){
+ AtomicUInt AtomicUInt::operator--(int) {
return atomic_int_helper(&x, -1);
}
#else
diff --git a/bson/util/builder.h b/bson/util/builder.h
index 9d9eda2..6f4ff9e 100644
--- a/bson/util/builder.h
+++ b/bson/util/builder.h
@@ -27,6 +27,24 @@
namespace mongo {
+ /* Note the limit here is rather arbitrary and is simply a standard. generally the code works
+ with any object that fits in ram.
+
+ Also note that the server has some basic checks to enforce this limit but those checks are not exhaustive
+ for example need to check for size too big after
+ update $push (append) operation
+ various db.eval() type operations
+ */
+ const int BSONObjMaxUserSize = 16 * 1024 * 1024;
+
+ /*
+ Sometimeswe we need objects slightly larger - an object in the replication local.oplog
+ is slightly larger than a user object for example.
+ */
+ const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
+
+ const int BufferMaxSize = 64 * 1024 * 1024;
+
class StringBuilder;
void msgasserted(int msgid, const char *msg);
@@ -38,7 +56,8 @@ namespace mongo {
data = (char *) malloc(size);
if( data == 0 )
msgasserted(10000, "out of memory BufBuilder");
- } else {
+ }
+ else {
data = 0;
}
l = 0;
@@ -54,16 +73,18 @@ namespace mongo {
}
}
- void reset( int maxSize = 0 ){
+ void reset( int maxSize = 0 ) {
l = 0;
- if ( maxSize && size > maxSize ){
+ if ( maxSize && size > maxSize ) {
free(data);
data = (char*)malloc(maxSize);
size = maxSize;
- }
+ }
}
- /* leave room for some stuff later */
+ /** leave room for some stuff later
+ @return point to region that was skipped. pointer may change later (on realloc), so for immediate use only
+ */
char* skip(int n) { return grow(n); }
/* note this may be deallocated (realloced) if you keep writing. */
@@ -73,10 +94,10 @@ namespace mongo {
/* assume ownership of the buffer - you must then free() it */
void decouple() { data = 0; }
- void appendChar(char j){
+ void appendChar(char j) {
*((char*)grow(sizeof(char))) = j;
}
- void appendNum(char j){
+ void appendNum(char j) {
*((char*)grow(sizeof(char))) = j;
}
void appendNum(short j) {
@@ -105,18 +126,19 @@ namespace mongo {
memcpy(grow((int) len), src, len);
}
+ template<class T>
+ void appendStruct(const T& s) {
+ appendBuf(&s, sizeof(T));
+ }
+
void appendStr(const StringData &str , bool includeEOO = true ) {
const int len = str.size() + ( includeEOO ? 1 : 0 );
memcpy(grow(len), str.data(), len);
}
- int len() const {
- return l;
- }
-
- void setlen( int newLen ){
- l = newLen;
- }
+ int len() const { return l; }
+ void setlen( int newLen ) { l = newLen; }
+ int getSize() const { return size; }
/* returns the pre-grow write position */
inline char* grow(int by) {
@@ -128,18 +150,16 @@ namespace mongo {
return data + oldlen;
}
- int getSize() const { return size; }
-
private:
/* "slow" portion of 'grow()' */
- void NOINLINE_DECL grow_reallocate(){
+ void NOINLINE_DECL grow_reallocate() {
int a = size * 2;
if ( a == 0 )
a = 512;
if ( l > a )
a = l + 16 * 1024;
- if( a > 64 * 1024 * 1024 )
- msgasserted(10000, "BufBuilder grow() > 64MB");
+ if ( a > BufferMaxSize )
+ msgasserted(13548, "BufBuilder grow() > 64MB");
data = (char *) realloc(data, a);
size= a;
}
@@ -152,87 +172,90 @@ namespace mongo {
};
#if defined(_WIN32)
+#pragma warning( push )
+// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
#pragma warning( disable : 4996 )
#endif
+ /** stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 */
class StringBuilder {
public:
StringBuilder( int initsize=256 )
- : _buf( initsize ){
+ : _buf( initsize ) {
}
-#define SBNUM(val,maxSize,macro) \
- int prev = _buf.l; \
- int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \
- assert( z >= 0 ); \
- _buf.l = prev + z; \
- return *this;
-
- StringBuilder& operator<<( double x ){
- SBNUM( x , 25 , "%g" );
+ StringBuilder& operator<<( double x ) {
+ return SBNUM( x , 25 , "%g" );
}
- StringBuilder& operator<<( int x ){
- SBNUM( x , 11 , "%d" );
+ StringBuilder& operator<<( int x ) {
+ return SBNUM( x , 11 , "%d" );
}
- StringBuilder& operator<<( unsigned x ){
- SBNUM( x , 11 , "%u" );
+ StringBuilder& operator<<( unsigned x ) {
+ return SBNUM( x , 11 , "%u" );
}
- StringBuilder& operator<<( long x ){
- SBNUM( x , 22 , "%ld" );
+ StringBuilder& operator<<( long x ) {
+ return SBNUM( x , 22 , "%ld" );
}
- StringBuilder& operator<<( unsigned long x ){
- SBNUM( x , 22 , "%lu" );
+ StringBuilder& operator<<( unsigned long x ) {
+ return SBNUM( x , 22 , "%lu" );
}
- StringBuilder& operator<<( long long x ){
- SBNUM( x , 22 , "%lld" );
+ StringBuilder& operator<<( long long x ) {
+ return SBNUM( x , 22 , "%lld" );
}
- StringBuilder& operator<<( unsigned long long x ){
- SBNUM( x , 22 , "%llu" );
+ StringBuilder& operator<<( unsigned long long x ) {
+ return SBNUM( x , 22 , "%llu" );
}
- StringBuilder& operator<<( short x ){
- SBNUM( x , 8 , "%hd" );
+ StringBuilder& operator<<( short x ) {
+ return SBNUM( x , 8 , "%hd" );
}
- StringBuilder& operator<<( char c ){
+ StringBuilder& operator<<( char c ) {
_buf.grow( 1 )[0] = c;
return *this;
}
-#undef SBNUM
- void appendDoubleNice( double x ){
+ void appendDoubleNice( double x ) {
int prev = _buf.l;
char * start = _buf.grow( 32 );
int z = sprintf( start , "%.16g" , x );
assert( z >= 0 );
_buf.l = prev + z;
- if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ){
+ if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) {
write( ".0" , 2 );
}
}
- void write( const char* buf, int len){
- memcpy( _buf.grow( len ) , buf , len );
- }
+ void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
- void append( const StringData& str ){
- memcpy( _buf.grow( str.size() ) , str.data() , str.size() );
- }
- StringBuilder& operator<<( const StringData& str ){
+ void append( const StringData& str ) { memcpy( _buf.grow( str.size() ) , str.data() , str.size() ); }
+
+ StringBuilder& operator<<( const StringData& str ) {
append( str );
return *this;
}
-
- // access
- void reset( int maxSize = 0 ){
- _buf.reset( maxSize );
- }
-
- std::string str(){
- return std::string(_buf.data, _buf.l);
- }
+ void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
+
+ std::string str() const { return std::string(_buf.data, _buf.l); }
private:
BufBuilder _buf;
+
+ // non-copyable, non-assignable
+ StringBuilder( const StringBuilder& );
+ StringBuilder& operator=( const StringBuilder& );
+
+ template <typename T>
+ StringBuilder& SBNUM(T val,int maxSize,const char *macro) {
+ int prev = _buf.l;
+ int z = sprintf( _buf.grow(maxSize) , macro , (val) );
+ assert( z >= 0 );
+ _buf.l = prev + z;
+ return *this;
+ }
};
+#if defined(_WIN32)
+#pragma warning( pop )
+#endif
+
} // namespace mongo
diff --git a/bson/util/misc.h b/bson/util/misc.h
index cad9a28..b31f36f 100644
--- a/bson/util/misc.h
+++ b/bson/util/misc.h
@@ -34,7 +34,7 @@ namespace mongo {
buf[24] = 0; // don't want the \n
}
- inline string time_t_to_String(time_t t = time(0) ){
+ inline string time_t_to_String(time_t t = time(0) ) {
char buf[64];
#if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t);
@@ -76,7 +76,7 @@ namespace mongo {
Date_t(unsigned long long m): millis(m) {}
operator unsigned long long&() { return millis; }
operator const unsigned long long&() const { return millis; }
- string toString() const {
+ string toString() const {
char buf[64];
time_t_to_String(millis/1000, buf);
return buf;