2010-05-26 02:39:57 +02:00
|
|
|
// @file goodies.h
|
2010-09-16 15:18:46 +02:00
|
|
|
// miscellaneous
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-10-27 20:58:27 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#pragma once
|
|
|
|
|
2010-04-25 00:25:58 +02:00
|
|
|
#include "../bson/util/misc.h"
|
2010-05-26 02:39:57 +02:00
|
|
|
#include "concurrency/mutex.h"
|
2010-04-24 22:43:09 +02:00
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
|
|
|
|
2010-12-12 16:59:16 +01:00
|
|
|
/* @return a dump of the buffer as hex byte ascii output */
|
|
|
|
string hexdump(const char *data, unsigned len);
|
|
|
|
|
2011-01-03 18:22:00 +01:00
|
|
|
/**
|
|
|
|
* @return if this name has an increasing counter associated, return the value
|
|
|
|
* otherwise 0
|
|
|
|
*/
|
|
|
|
unsigned setThreadName(const char * name);
|
2010-06-30 00:10:40 +02:00
|
|
|
string getThreadName();
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-05-05 22:33:35 +02:00
|
|
|
template<class T>
|
2011-01-04 06:40:41 +01:00
|
|
|
inline string ToString(const T& t) {
|
2010-05-05 22:33:35 +02:00
|
|
|
stringstream s;
|
|
|
|
s << t;
|
|
|
|
return s.str();
|
|
|
|
}
|
|
|
|
|
2010-06-20 22:29:03 +02:00
|
|
|
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !defined(__openbsd__) && !defined(__sun__)
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
} // namespace mongo
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#include <pthread.h>
|
2009-09-22 02:32:17 +02:00
|
|
|
#include <execinfo.h>
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
2010-11-25 03:41:31 +01:00
|
|
|
inline pthread_t GetCurrentThreadId() {
|
|
|
|
return pthread_self();
|
|
|
|
}
|
2009-01-14 23:09:51 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/* use "addr2line -CFe <exe>" to parse. */
|
2009-02-02 15:52:14 +01:00
|
|
|
inline void printStackTrace( ostream &o = cout ) {
|
2009-02-06 19:26:12 +01:00
|
|
|
void *b[20];
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2010-12-23 20:40:54 +01:00
|
|
|
int size = backtrace(b, 20);
|
|
|
|
for (int i = 0; i < size; i++)
|
2009-04-10 17:53:47 +02:00
|
|
|
o << hex << b[i] << dec << ' ';
|
2010-08-09 21:25:06 +02:00
|
|
|
o << endl;
|
|
|
|
|
|
|
|
char **strings;
|
|
|
|
|
|
|
|
strings = backtrace_symbols(b, size);
|
2010-12-23 20:40:54 +01:00
|
|
|
for (int i = 0; i < size; i++)
|
2010-11-25 03:41:31 +01:00
|
|
|
o << ' ' << strings[i] << '\n';
|
2010-08-31 17:16:18 +02:00
|
|
|
o.flush();
|
2009-01-15 16:17:11 +01:00
|
|
|
free (strings);
|
|
|
|
}
|
2008-06-27 20:35:05 +02:00
|
|
|
#else
|
2009-08-12 20:54:53 +02:00
|
|
|
inline void printStackTrace( ostream &o = cout ) { }
|
2008-06-06 15:43:15 +02:00
|
|
|
#endif
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
bool isPrime(int n);
|
|
|
|
int nextPrime(int n);
|
|
|
|
|
|
|
|
inline void dumpmemory(const char *data, int len) {
|
|
|
|
if ( len > 1024 )
|
|
|
|
len = 1024;
|
|
|
|
try {
|
|
|
|
const char *q = data;
|
|
|
|
const char *p = q;
|
|
|
|
while ( len > 0 ) {
|
|
|
|
for ( int i = 0; i < 16; i++ ) {
|
|
|
|
if ( *p >= 32 && *p <= 126 )
|
|
|
|
cout << *p;
|
|
|
|
else
|
|
|
|
cout << '.';
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
cout << " ";
|
|
|
|
p -= 16;
|
|
|
|
for ( int i = 0; i < 16; i++ )
|
|
|
|
cout << (unsigned) ((unsigned char)*p++) << ' ';
|
|
|
|
cout << endl;
|
|
|
|
len -= 16;
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
catch (...) {
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
|
|
|
}
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-12-11 20:29:10 +01:00
|
|
|
// PRINT(2+2); prints "2+2: 4"
|
2010-04-24 01:54:00 +02:00
|
|
|
#define MONGO_PRINT(x) cout << #x ": " << (x) << endl
|
|
|
|
#define PRINT MONGO_PRINT
|
2009-12-11 20:29:10 +01:00
|
|
|
// PRINTFL; prints file:line
|
2010-04-24 01:54:00 +02:00
|
|
|
#define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl
|
|
|
|
#define PRINTFL MONGO_PRINTFL
|
2009-12-11 20:29:10 +01:00
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#undef assert
|
2010-04-24 02:09:32 +02:00
|
|
|
#define assert MONGO_assert
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
struct WrappingInt {
|
|
|
|
WrappingInt() {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
WrappingInt(unsigned z) : x(z) { }
|
2010-01-26 01:32:00 +01:00
|
|
|
unsigned x;
|
2009-01-15 16:17:11 +01:00
|
|
|
operator unsigned() const {
|
|
|
|
return x;
|
|
|
|
}
|
2009-12-02 01:28:27 +01:00
|
|
|
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
static int diff(unsigned a, unsigned b) {
|
|
|
|
return a-b;
|
|
|
|
}
|
|
|
|
bool operator<=(WrappingInt r) {
|
|
|
|
// platform dependent
|
|
|
|
int df = (r.x - x);
|
|
|
|
return df >= 0;
|
|
|
|
}
|
|
|
|
bool operator>(WrappingInt r) {
|
|
|
|
return !(r<=*this);
|
|
|
|
}
|
|
|
|
};
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/*
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
class DebugMutex : boost::noncopyable {
|
2011-01-04 06:40:41 +01:00
|
|
|
friend class lock;
|
|
|
|
mongo::mutex m;
|
|
|
|
int locked;
|
2009-01-15 16:17:11 +01:00
|
|
|
public:
|
2011-01-04 06:40:41 +01:00
|
|
|
DebugMutex() : locked(0); { }
|
|
|
|
bool isLocked() { return locked; }
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
2008-07-31 19:37:32 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
*/
|
2008-07-31 19:37:32 +02:00
|
|
|
|
2010-03-15 17:42:01 +01:00
|
|
|
//typedef scoped_lock lock;
|
2008-09-03 22:43:00 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline bool startsWith(const char *str, const char *prefix) {
|
2010-01-28 23:21:26 +01:00
|
|
|
size_t l = strlen(prefix);
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( strlen(str) < l ) return false;
|
|
|
|
return strncmp(str, prefix, l) == 0;
|
|
|
|
}
|
2010-04-27 20:37:41 +02:00
|
|
|
inline bool startsWith(string s, string p) { return startsWith(s.c_str(), p.c_str()); }
|
2008-09-11 15:15:34 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline bool endsWith(const char *p, const char *suffix) {
|
2010-01-28 23:21:26 +01:00
|
|
|
size_t a = strlen(p);
|
|
|
|
size_t b = strlen(suffix);
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( b > a ) return false;
|
|
|
|
return strcmp(p + a - b, suffix) == 0;
|
|
|
|
}
|
2008-09-03 22:43:00 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline unsigned long swapEndian(unsigned long x) {
|
|
|
|
return
|
|
|
|
((x & 0xff) << 24) |
|
|
|
|
((x & 0xff00) << 8) |
|
|
|
|
((x & 0xff0000) >> 8) |
|
|
|
|
((x & 0xff000000) >> 24);
|
|
|
|
}
|
2008-09-04 16:33:56 +02:00
|
|
|
|
|
|
|
#if defined(BOOST_LITTLE_ENDIAN)
|
2009-01-15 16:17:11 +01:00
|
|
|
inline unsigned long fixEndian(unsigned long x) {
|
|
|
|
return x;
|
|
|
|
}
|
2008-09-04 16:33:56 +02:00
|
|
|
#else
|
2009-01-15 16:17:11 +01:00
|
|
|
inline unsigned long fixEndian(unsigned long x) {
|
|
|
|
return swapEndian(x);
|
|
|
|
}
|
2008-09-04 16:33:56 +02:00
|
|
|
#endif
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-06-04 13:25:58 +02:00
|
|
|
#if !defined(_WIN32)
|
|
|
|
typedef int HANDLE;
|
|
|
|
inline void strcpy_s(char *dst, unsigned len, const char *src) {
|
2010-11-24 16:20:34 +01:00
|
|
|
assert( strlen(src) < len );
|
2009-06-04 13:25:58 +02:00
|
|
|
strcpy(dst, src);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
typedef void *HANDLE;
|
|
|
|
#endif
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-13 18:55:23 +02:00
|
|
|
/* thread local "value" rather than a pointer
|
|
|
|
good for things which have copy constructors (and the copy constructor is fast enough)
|
2011-01-04 06:40:41 +01:00
|
|
|
e.g.
|
2009-10-13 18:55:23 +02:00
|
|
|
ThreadLocalValue<int> myint;
|
|
|
|
*/
|
|
|
|
template<class T>
|
|
|
|
class ThreadLocalValue {
|
2009-09-11 17:56:57 +02:00
|
|
|
public:
|
2009-10-13 18:55:23 +02:00
|
|
|
ThreadLocalValue( T def = 0 ) : _default( def ) { }
|
2009-09-11 17:56:57 +02:00
|
|
|
|
2010-10-07 06:10:18 +02:00
|
|
|
T get() const {
|
2009-10-13 18:55:23 +02:00
|
|
|
T * val = _val.get();
|
2009-09-11 17:56:57 +02:00
|
|
|
if ( val )
|
|
|
|
return *val;
|
2009-10-13 18:55:23 +02:00
|
|
|
return _default;
|
2009-09-11 17:56:57 +02:00
|
|
|
}
|
2009-12-03 19:48:45 +01:00
|
|
|
|
2009-10-13 18:55:23 +02:00
|
|
|
void set( const T& i ) {
|
|
|
|
T *v = _val.get();
|
2011-01-04 06:40:41 +01:00
|
|
|
if( v ) {
|
2009-10-13 18:55:23 +02:00
|
|
|
*v = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
v = new T(i);
|
|
|
|
_val.reset( v );
|
2009-09-11 17:56:57 +02:00
|
|
|
}
|
2009-12-03 19:48:45 +01:00
|
|
|
|
2009-09-11 17:56:57 +02:00
|
|
|
private:
|
2009-10-13 18:55:23 +02:00
|
|
|
boost::thread_specific_ptr<T> _val;
|
2010-10-07 06:56:12 +02:00
|
|
|
const T _default;
|
2009-09-11 17:56:57 +02:00
|
|
|
};
|
2009-01-14 23:09:51 +01:00
|
|
|
|
2010-05-07 18:19:00 +02:00
|
|
|
class ProgressMeter : boost::noncopyable {
|
2009-10-05 21:09:18 +02:00
|
|
|
public:
|
2011-01-04 06:40:41 +01:00
|
|
|
ProgressMeter( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) {
|
2010-03-15 16:18:08 +01:00
|
|
|
reset( total , secondsBetween , checkInterval );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
ProgressMeter() {
|
2010-03-15 16:18:08 +01:00
|
|
|
_active = 0;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void reset( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) {
|
2010-03-15 16:18:08 +01:00
|
|
|
_total = total;
|
|
|
|
_secondsBetween = secondsBetween;
|
|
|
|
_checkInterval = checkInterval;
|
|
|
|
|
|
|
|
_done = 0;
|
|
|
|
_hits = 0;
|
|
|
|
_lastTime = (int)time(0);
|
|
|
|
|
|
|
|
_active = 1;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void finished() {
|
2010-03-15 16:18:08 +01:00
|
|
|
_active = 0;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
bool isActive() {
|
2010-03-15 16:18:08 +01:00
|
|
|
return _active;
|
2009-10-05 21:09:18 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-11-11 07:54:37 +01:00
|
|
|
/**
|
|
|
|
* @return if row was printed
|
|
|
|
*/
|
2011-01-04 06:40:41 +01:00
|
|
|
bool hit( int n = 1 ) {
|
|
|
|
if ( ! _active ) {
|
2010-03-15 17:29:14 +01:00
|
|
|
cout << "warning: hit on in-active ProgressMeter" << endl;
|
2010-11-11 07:54:37 +01:00
|
|
|
return false;
|
2010-03-15 17:29:14 +01:00
|
|
|
}
|
2010-03-15 16:18:08 +01:00
|
|
|
|
2009-10-05 21:09:18 +02:00
|
|
|
_done += n;
|
|
|
|
_hits++;
|
|
|
|
if ( _hits % _checkInterval )
|
2009-10-08 16:11:26 +02:00
|
|
|
return false;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-06 22:17:11 +02:00
|
|
|
int t = (int) time(0);
|
2009-10-05 21:09:18 +02:00
|
|
|
if ( t - _lastTime < _secondsBetween )
|
2009-10-08 16:11:26 +02:00
|
|
|
return false;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
if ( _total > 0 ) {
|
2009-10-08 16:11:26 +02:00
|
|
|
int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
|
|
|
|
cout << "\t\t" << _done << "/" << _total << "\t" << per << "%" << endl;
|
|
|
|
}
|
2009-10-05 21:09:18 +02:00
|
|
|
_lastTime = t;
|
2009-10-08 16:11:26 +02:00
|
|
|
return true;
|
2009-10-05 21:09:18 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
unsigned long long done() {
|
2009-10-05 21:09:18 +02:00
|
|
|
return _done;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
unsigned long long hits() {
|
2009-10-05 21:09:18 +02:00
|
|
|
return _hits;
|
|
|
|
}
|
|
|
|
|
2010-03-15 16:18:08 +01:00
|
|
|
string toString() const {
|
|
|
|
if ( ! _active )
|
|
|
|
return "";
|
|
|
|
stringstream buf;
|
|
|
|
buf << _done << "/" << _total << " " << (_done*100)/_total << "%";
|
|
|
|
return buf.str();
|
|
|
|
}
|
2010-05-07 18:19:00 +02:00
|
|
|
|
|
|
|
bool operator==( const ProgressMeter& other ) const {
|
|
|
|
return this == &other;
|
|
|
|
}
|
2009-10-05 21:09:18 +02:00
|
|
|
private:
|
2010-03-15 16:18:08 +01:00
|
|
|
|
|
|
|
bool _active;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-11-28 05:48:42 +01:00
|
|
|
unsigned long long _total;
|
2009-10-05 21:09:18 +02:00
|
|
|
int _secondsBetween;
|
|
|
|
int _checkInterval;
|
|
|
|
|
2010-11-28 05:48:42 +01:00
|
|
|
unsigned long long _done;
|
|
|
|
unsigned long long _hits;
|
2009-10-05 21:09:18 +02:00
|
|
|
int _lastTime;
|
|
|
|
};
|
|
|
|
|
2010-05-07 18:19:00 +02:00
|
|
|
class ProgressMeterHolder : boost::noncopyable {
|
|
|
|
public:
|
|
|
|
ProgressMeterHolder( ProgressMeter& pm )
|
2011-01-04 06:40:41 +01:00
|
|
|
: _pm( pm ) {
|
2010-05-07 18:19:00 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
~ProgressMeterHolder() {
|
2010-05-07 18:19:00 +02:00
|
|
|
_pm.finished();
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
ProgressMeter* operator->() {
|
2010-05-07 18:19:00 +02:00
|
|
|
return &_pm;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
bool hit( int n = 1 ) {
|
2010-05-07 18:19:00 +02:00
|
|
|
return _pm.hit( n );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void finished() {
|
2010-05-07 18:19:00 +02:00
|
|
|
_pm.finished();
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
bool operator==( const ProgressMeter& other ) {
|
2010-05-07 18:19:00 +02:00
|
|
|
return _pm == other;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-05-07 18:19:00 +02:00
|
|
|
private:
|
|
|
|
ProgressMeter& _pm;
|
|
|
|
};
|
|
|
|
|
2009-12-29 20:09:53 +01:00
|
|
|
class TicketHolder {
|
|
|
|
public:
|
2010-05-26 06:46:49 +02:00
|
|
|
TicketHolder( int num ) : _mutex("TicketHolder") {
|
2009-12-29 20:09:53 +01:00
|
|
|
_outof = num;
|
|
|
|
_num = num;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
bool tryAcquire() {
|
2010-03-15 17:42:01 +01:00
|
|
|
scoped_lock lk( _mutex );
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( _num <= 0 ) {
|
|
|
|
if ( _num < 0 ) {
|
2009-12-29 20:09:53 +01:00
|
|
|
cerr << "DISASTER! in TicketHolder" << endl;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
_num--;
|
|
|
|
return true;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void release() {
|
2010-03-15 17:42:01 +01:00
|
|
|
scoped_lock lk( _mutex );
|
2009-12-29 20:09:53 +01:00
|
|
|
_num++;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void resize( int newSize ) {
|
|
|
|
scoped_lock lk( _mutex );
|
2009-12-29 20:09:53 +01:00
|
|
|
int used = _outof - _num;
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( used > newSize ) {
|
2009-12-29 20:09:53 +01:00
|
|
|
cout << "ERROR: can't resize since we're using (" << used << ") more than newSize(" << newSize << ")" << endl;
|
|
|
|
return;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-12-29 20:09:53 +01:00
|
|
|
_outof = newSize;
|
|
|
|
_num = _outof - used;
|
|
|
|
}
|
|
|
|
|
2010-08-13 00:56:09 +02:00
|
|
|
int available() const {
|
2009-12-29 20:09:53 +01:00
|
|
|
return _num;
|
|
|
|
}
|
|
|
|
|
2010-08-13 00:56:09 +02:00
|
|
|
int used() const {
|
2009-12-29 20:09:53 +01:00
|
|
|
return _outof - _num;
|
|
|
|
}
|
|
|
|
|
2010-08-13 00:56:09 +02:00
|
|
|
int outof() const { return _outof; }
|
|
|
|
|
2009-12-29 20:09:53 +01:00
|
|
|
private:
|
|
|
|
int _outof;
|
|
|
|
int _num;
|
2010-03-15 17:42:01 +01:00
|
|
|
mongo::mutex _mutex;
|
2009-12-29 20:09:53 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class TicketHolderReleaser {
|
|
|
|
public:
|
2011-01-04 06:40:41 +01:00
|
|
|
TicketHolderReleaser( TicketHolder * holder ) {
|
2009-12-29 20:09:53 +01:00
|
|
|
_holder = holder;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
~TicketHolderReleaser() {
|
2009-12-29 20:09:53 +01:00
|
|
|
_holder->release();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
TicketHolder * _holder;
|
|
|
|
};
|
2010-02-26 17:33:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this is a thread safe string
|
|
|
|
* you will never get a bad pointer, though data may be mungedd
|
|
|
|
*/
|
|
|
|
class ThreadSafeString {
|
|
|
|
public:
|
|
|
|
ThreadSafeString( size_t size=256 )
|
2011-01-04 06:40:41 +01:00
|
|
|
: _size( 256 ) , _buf( new char[256] ) {
|
2010-02-26 17:33:20 +01:00
|
|
|
memset( _buf , 0 , _size );
|
|
|
|
}
|
|
|
|
|
2010-02-26 18:07:46 +01:00
|
|
|
ThreadSafeString( const ThreadSafeString& other )
|
2011-01-04 06:40:41 +01:00
|
|
|
: _size( other._size ) , _buf( new char[_size] ) {
|
2010-02-26 18:07:46 +01:00
|
|
|
strncpy( _buf , other._buf , _size );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
~ThreadSafeString() {
|
2010-02-26 18:07:46 +01:00
|
|
|
delete[] _buf;
|
2010-02-26 17:33:20 +01:00
|
|
|
_buf = 0;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-07-19 18:39:14 +02:00
|
|
|
string toString() const {
|
2010-02-26 18:07:46 +01:00
|
|
|
string s = _buf;
|
|
|
|
return s;
|
2010-02-26 17:33:20 +01:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
ThreadSafeString& operator=( const char * str ) {
|
2010-02-26 17:33:20 +01:00
|
|
|
size_t s = strlen(str);
|
|
|
|
if ( s >= _size - 2 )
|
|
|
|
s = _size - 2;
|
|
|
|
strncpy( _buf , str , s );
|
|
|
|
_buf[s] = 0;
|
|
|
|
return *this;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-02-26 18:07:46 +01:00
|
|
|
bool operator==( const ThreadSafeString& other ) const {
|
|
|
|
return strcmp( _buf , other._buf ) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==( const char * str ) const {
|
|
|
|
return strcmp( _buf , str ) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=( const char * str ) const {
|
2010-06-06 02:55:11 +02:00
|
|
|
return strcmp( _buf , str ) != 0;
|
2010-02-26 18:07:46 +01:00
|
|
|
}
|
2010-02-26 17:33:20 +01:00
|
|
|
|
|
|
|
bool empty() const {
|
2010-08-03 23:37:59 +02:00
|
|
|
return _buf == 0 || _buf[0] == 0;
|
2010-02-26 17:33:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t _size;
|
2011-01-04 06:40:41 +01:00
|
|
|
char * _buf;
|
2010-02-26 17:33:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
ostream& operator<<( ostream &s, const ThreadSafeString &o );
|
2010-03-02 21:29:54 +01:00
|
|
|
|
|
|
|
inline bool isNumber( char c ) {
|
|
|
|
return c >= '0' && c <= '9';
|
|
|
|
}
|
2010-04-21 22:14:28 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-02 22:16:20 +01:00
|
|
|
// for convenience, '{' is greater than anything and stops number parsing
|
2010-03-02 21:29:54 +01:00
|
|
|
inline int lexNumCmp( const char *s1, const char *s2 ) {
|
2010-08-26 00:30:51 +02:00
|
|
|
//cout << "START : " << s1 << "\t" << s2 << endl;
|
2010-03-02 21:29:54 +01:00
|
|
|
while( *s1 && *s2 ) {
|
2010-03-26 20:30:29 +01:00
|
|
|
|
2010-08-26 00:30:51 +02:00
|
|
|
bool p1 = ( *s1 == (char)255 );
|
|
|
|
bool p2 = ( *s2 == (char)255 );
|
|
|
|
//cout << "\t\t " << p1 << "\t" << p2 << endl;
|
2010-03-02 22:16:20 +01:00
|
|
|
if ( p1 && !p2 )
|
|
|
|
return 1;
|
|
|
|
if ( p2 && !p1 )
|
|
|
|
return -1;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-02 21:29:54 +01:00
|
|
|
bool n1 = isNumber( *s1 );
|
|
|
|
bool n2 = isNumber( *s2 );
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-02 21:29:54 +01:00
|
|
|
if ( n1 && n2 ) {
|
2010-08-26 21:17:41 +02:00
|
|
|
// get rid of leading 0s
|
|
|
|
while ( *s1 == '0' ) s1++;
|
|
|
|
while ( *s2 == '0' ) s2++;
|
|
|
|
|
|
|
|
char * e1 = (char*)s1;
|
|
|
|
char * e2 = (char*)s2;
|
|
|
|
|
|
|
|
// find length
|
|
|
|
// if end of string, will break immediately ('\0')
|
|
|
|
while ( isNumber (*e1) ) e1++;
|
|
|
|
while ( isNumber (*e2) ) e2++;
|
|
|
|
|
2010-12-23 20:40:54 +01:00
|
|
|
int len1 = (int)(e1-s1);
|
|
|
|
int len2 = (int)(e2-s2);
|
2010-08-26 21:17:41 +02:00
|
|
|
|
|
|
|
int result;
|
|
|
|
// if one is longer than the other, return
|
|
|
|
if ( len1 > len2 ) {
|
2010-03-02 21:29:54 +01:00
|
|
|
return 1;
|
2010-08-26 21:17:41 +02:00
|
|
|
}
|
|
|
|
else if ( len2 > len1 ) {
|
2010-03-02 21:29:54 +01:00
|
|
|
return -1;
|
2010-08-26 21:17:41 +02:00
|
|
|
}
|
|
|
|
// if the lengths are equal, just strcmp
|
|
|
|
else if ( (result = strncmp(s1, s2, len1)) != 0 ) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, the numbers are equal
|
2010-03-26 20:30:29 +01:00
|
|
|
s1 = e1;
|
|
|
|
s2 = e2;
|
|
|
|
continue;
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( n1 )
|
2010-03-26 20:30:29 +01:00
|
|
|
return 1;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
if ( n2 )
|
2010-03-26 20:30:29 +01:00
|
|
|
return -1;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-26 20:30:29 +01:00
|
|
|
if ( *s1 > *s2 )
|
|
|
|
return 1;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-26 20:30:29 +01:00
|
|
|
if ( *s2 > *s1 )
|
|
|
|
return -1;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-03-26 20:30:29 +01:00
|
|
|
s1++; s2++;
|
2010-03-02 21:29:54 +01:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
if ( *s1 )
|
2010-03-02 21:29:54 +01:00
|
|
|
return 1;
|
2010-03-26 20:30:29 +01:00
|
|
|
if ( *s2 )
|
2010-03-02 21:29:54 +01:00
|
|
|
return -1;
|
2010-03-26 20:30:29 +01:00
|
|
|
return 0;
|
2010-03-02 21:29:54 +01:00
|
|
|
}
|
2010-05-20 01:27:04 +02:00
|
|
|
|
|
|
|
/** A generic pointer type for function arguments.
|
|
|
|
* It will convert from any pointer type except auto_ptr.
|
|
|
|
* Semantics are the same as passing the pointer returned from get()
|
|
|
|
* const ptr<T> => T * const
|
|
|
|
* ptr<const T> => T const * or const T*
|
|
|
|
*/
|
|
|
|
template <typename T>
|
2011-01-04 06:40:41 +01:00
|
|
|
struct ptr {
|
|
|
|
|
2010-05-20 01:27:04 +02:00
|
|
|
ptr() : _p(NULL) {}
|
|
|
|
|
|
|
|
// convert to ptr<T>
|
2010-05-20 04:47:15 +02:00
|
|
|
ptr(T* p) : _p(p) {} // needed for NULL
|
|
|
|
template<typename U> ptr(U* p) : _p(p) {}
|
|
|
|
template<typename U> ptr(const ptr<U>& p) : _p(p) {}
|
2010-05-20 13:38:47 +02:00
|
|
|
template<typename U> ptr(const boost::shared_ptr<U>& p) : _p(p.get()) {}
|
2010-05-26 02:39:57 +02:00
|
|
|
template<typename U> ptr(const boost::scoped_ptr<U>& p) : _p(p.get()) {}
|
2010-05-20 04:47:15 +02:00
|
|
|
//template<typename U> ptr(const auto_ptr<U>& p) : _p(p.get()) {}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-05-20 01:27:04 +02:00
|
|
|
// assign to ptr<T>
|
2010-05-20 04:47:15 +02:00
|
|
|
ptr& operator= (T* p) { _p = p; return *this; } // needed for NULL
|
|
|
|
template<typename U> ptr& operator= (U* p) { _p = p; return *this; }
|
|
|
|
template<typename U> ptr& operator= (const ptr<U>& p) { _p = p; return *this; }
|
2010-05-20 13:38:47 +02:00
|
|
|
template<typename U> ptr& operator= (const boost::shared_ptr<U>& p) { _p = p.get(); return *this; }
|
2010-05-26 02:39:57 +02:00
|
|
|
template<typename U> ptr& operator= (const boost::scoped_ptr<U>& p) { _p = p.get(); return *this; }
|
2010-05-20 04:47:15 +02:00
|
|
|
//template<typename U> ptr& operator= (const auto_ptr<U>& p) { _p = p.get(); return *this; }
|
2010-05-20 01:27:04 +02:00
|
|
|
|
|
|
|
// use
|
|
|
|
T* operator->() const { return _p; }
|
2010-05-20 04:47:15 +02:00
|
|
|
T& operator*() const { return *_p; }
|
2010-05-20 01:27:04 +02:00
|
|
|
|
|
|
|
// convert from ptr<T>
|
|
|
|
operator T* () const { return _p; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
T* _p;
|
|
|
|
};
|
2010-05-26 02:39:57 +02:00
|
|
|
|
|
|
|
/** Hmmmm */
|
|
|
|
using namespace boost;
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
} // namespace mongo
|