diff options
Diffstat (limited to 'bson/util')
-rw-r--r-- | bson/util/atomic_int.h | 11 | ||||
-rw-r--r-- | bson/util/builder.h | 87 | ||||
-rw-r--r-- | bson/util/misc.h | 21 |
3 files changed, 99 insertions, 20 deletions
diff --git a/bson/util/atomic_int.h b/bson/util/atomic_int.h index 1573552..e85a023 100644 --- a/bson/util/atomic_int.h +++ b/bson/util/atomic_int.h @@ -36,15 +36,17 @@ namespace mongo { inline AtomicUInt operator--(); // --prefix inline AtomicUInt operator--(int); // postfix-- - inline void zero() { x = 0; } // TODO: this isn't thread safe + inline void zero(); volatile unsigned x; }; #if defined(_WIN32) + void AtomicUInt::zero() { + InterlockedExchange((volatile long*)&x, 0); + } AtomicUInt AtomicUInt::operator++() { - // InterlockedIncrement returns the new value - return InterlockedIncrement((volatile long*)&x); //long is 32bits in Win64 + return InterlockedIncrement((volatile long*)&x); } AtomicUInt AtomicUInt::operator++(int) { return InterlockedIncrement((volatile long*)&x)-1; @@ -57,6 +59,7 @@ namespace mongo { } #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) // this is in GCC >= 4.1 + inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread safe - maybe AtomicUInt AtomicUInt::operator++() { return __sync_add_and_fetch(&x, 1); } @@ -70,8 +73,8 @@ namespace mongo { return __sync_fetch_and_add(&x, -1); } #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread safe // from boost 1.39 interprocess/detail/atomic.hpp - inline unsigned atomic_int_helper(volatile unsigned *x, int val) { int r; asm volatile diff --git a/bson/util/builder.h b/bson/util/builder.h index 6f4ff9e..710c2d4 100644 --- a/bson/util/builder.h +++ b/bson/util/builder.h @@ -20,8 +20,6 @@ #include <string> #include <string.h> #include <stdio.h> -#include <boost/shared_ptr.hpp> - #include "../inline_decls.h" #include "../stringdata.h" @@ -49,11 +47,47 @@ namespace mongo { void msgasserted(int msgid, const char *msg); - class BufBuilder { + class TrivialAllocator { + public: + void* Malloc(size_t sz) { return malloc(sz); } + void* Realloc(void *p, size_t sz) { return realloc(p, sz); } + void Free(void *p) { free(p); } + }; + + class StackAllocator { + public: + enum { SZ = 512 }; + void* Malloc(size_t sz) { + if( sz <= SZ ) return buf; + return malloc(sz); + } + void* Realloc(void *p, size_t sz) { + if( p == buf ) { + if( sz <= SZ ) return buf; + void *d = malloc(sz); + memcpy(d, p, SZ); + return d; + } + return realloc(p, sz); + } + void Free(void *p) { + if( p != buf ) + free(p); + } + private: + char buf[SZ]; + }; + + template< class Allocator > + class _BufBuilder { + // non-copyable, non-assignable + _BufBuilder( const _BufBuilder& ); + _BufBuilder& operator=( const _BufBuilder& ); + Allocator al; public: - BufBuilder(int initsize = 512) : size(initsize) { + _BufBuilder(int initsize = 512) : size(initsize) { if ( size > 0 ) { - data = (char *) malloc(size); + data = (char *) al.Malloc(size); if( data == 0 ) msgasserted(10000, "out of memory BufBuilder"); } @@ -62,22 +96,23 @@ namespace mongo { } l = 0; } - ~BufBuilder() { - kill(); - } + ~_BufBuilder() { kill(); } void kill() { if ( data ) { - free(data); + al.Free(data); data = 0; } } - void reset( int maxSize = 0 ) { + void reset() { + l = 0; + } + void reset( int maxSize ) { l = 0; if ( maxSize && size > maxSize ) { - free(data); - data = (char*)malloc(maxSize); + al.Free(data); + data = (char*)al.Malloc(maxSize); size = maxSize; } } @@ -94,6 +129,9 @@ namespace mongo { /* assume ownership of the buffer - you must then free() it */ void decouple() { data = 0; } + void appendUChar(unsigned char j) { + *((unsigned char*)grow(sizeof(unsigned char))) = j; + } void appendChar(char j) { *((char*)grow(sizeof(char))) = j; } @@ -131,13 +169,15 @@ namespace mongo { appendBuf(&s, sizeof(T)); } - void appendStr(const StringData &str , bool includeEOO = true ) { - const int len = str.size() + ( includeEOO ? 1 : 0 ); + void appendStr(const StringData &str , bool includeEndingNull = true ) { + const int len = str.size() + ( includeEndingNull ? 1 : 0 ); memcpy(grow(len), str.data(), len); } + /** @return length of current string */ int len() const { return l; } void setlen( int newLen ) { l = newLen; } + /** @return size of the buffer */ int getSize() const { return size; } /* returns the pre-grow write position */ @@ -160,7 +200,7 @@ namespace mongo { a = l + 16 * 1024; if ( a > BufferMaxSize ) msgasserted(13548, "BufBuilder grow() > 64MB"); - data = (char *) realloc(data, a); + data = (char *) al.Realloc(data, a); size= a; } @@ -171,6 +211,21 @@ namespace mongo { friend class StringBuilder; }; + typedef _BufBuilder<TrivialAllocator> BufBuilder; + + /** The StackBufBuilder builds smaller datasets on the stack instead of using malloc. + this can be significantly faster for small bufs. However, you can not decouple() the + buffer with StackBufBuilder. + While designed to be a variable on the stack, if you were to dynamically allocate one, + nothing bad would happen. In fact in some circumstances this might make sense, say, + embedded in some other object. + */ + class StackBufBuilder : public _BufBuilder<StackAllocator> { + public: + StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { } + void decouple(); // not allowed. not implemented. + }; + #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. @@ -236,6 +291,8 @@ namespace mongo { void reset( int maxSize = 0 ) { _buf.reset( maxSize ); } std::string str() const { return std::string(_buf.data, _buf.l); } + + int len() const { return _buf.l; } private: BufBuilder _buf; diff --git a/bson/util/misc.h b/bson/util/misc.h index b31f36f..33764e3 100644 --- a/bson/util/misc.h +++ b/bson/util/misc.h @@ -1,4 +1,4 @@ -/* @file util.h +/* @file misc.h */ /* @@ -91,4 +91,23 @@ namespace mongo { return i; return -1; } + + inline bool isNumber( char c ) { + return c >= '0' && c <= '9'; + } + + inline unsigned stringToNum(const char *str) { + unsigned x = 0; + const char *p = str; + while( 1 ) { + if( !isNumber(*p) ) { + if( *p == 0 && p != str ) + break; + throw 0; + } + x = x * 10 + *p++ - '0'; + } + return x; + } + } |