Move ./modules to ./src

This commit is contained in:
Vinnie Falco
2013-09-11 11:17:22 -07:00
parent 6d828ae476
commit 45eccf2ccf
386 changed files with 1673 additions and 1674 deletions

View File

@@ -0,0 +1,221 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_KEYCACHE_H_INCLUDED
#define RIPPLE_KEYCACHE_H_INCLUDED
// This tag is for helping track the locks
struct KeyCacheBase
{
};
/** Maintains a cache of keys with no associated data.
The cache has a target size and an expiration time. When cached items become
older than the maximum age they are eligible for removal during a
call to @ref sweep.
@note
Timer must provide this function:
@code
static int getElapsedSeconds ();
@endcode
@ingroup ripple_basics
*/
template <class Key, class Timer>
class KeyCache : public KeyCacheBase
{
public:
/** Provides a type for the key.
*/
typedef Key key_type;
/** Construct with the specified name.
@param size The initial target size.
@param age The initial expiration time.
*/
KeyCache (const std::string& name,
int size = 0,
int age = 120)
: mLock (static_cast <KeyCacheBase*> (this), String ("KeyCache") +
"('" + name + "')", __FILE__, __LINE__)
, mName (name)
, mTargetSize (size)
, mTargetAge (age)
{
assert ((size >= 0) && (age > 2));
}
/** Returns the current size.
*/
unsigned int getSize ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mCache.size ();
}
/** Returns the desired target size.
*/
unsigned int getTargetSize ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mTargetSize;
}
/** Returns the desired target age.
*/
unsigned int getTargetAge ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mTargetAge;
}
/** Simultaneously set the target size and age.
@param size The target size.
@param age The target age.
*/
void setTargets (int size, int age)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mTargetSize = size;
mTargetAge = age;
assert ((mTargetSize >= 0) && (mTargetAge > 2));
}
/** Retrieve the name of this object.
*/
std::string const& getName ()
{
return mName;
}
/** Determine if the specified key is cached, and optionally refresh it.
@param key The key to check
@param refresh Whether or not to refresh the entry.
@return `true` if the key was found.
*/
bool isPresent (const key_type& key, bool refresh = true)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
map_iterator it = mCache.find (key);
if (it == mCache.end ())
return false;
if (refresh)
it->second = Timer::getElapsedSeconds ();
return true;
}
/** Remove the specified cache entry.
@param key The key to remove.
@return `false` if the key was not found.
*/
bool del (const key_type& key)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
map_iterator it = mCache.find (key);
if (it == mCache.end ())
return false;
mCache.erase (it);
return true;
}
/** Add the specified cache entry.
@param key The key to add.
@return `true` if the key did not previously exist.
*/
bool add (const key_type& key)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
map_iterator it = mCache.find (key);
if (it != mCache.end ())
{
it->second = Timer::getElapsedSeconds ();
return false;
}
mCache.insert (std::make_pair (key, Timer::getElapsedSeconds ()));
return true;
}
/** Empty the cache
*/
void clear ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mCache.clear ();
}
/** Remove stale entries from the cache.
*/
void sweep ()
{
int now = Timer::getElapsedSeconds ();
ScopedLockType sl (mLock, __FILE__, __LINE__);
int target;
if ((mTargetSize == 0) || (mCache.size () <= mTargetSize))
target = now - mTargetAge;
else
{
target = now - (mTargetAge * mTargetSize / mCache.size ());
if (target > (now - 2))
target = now - 2;
}
map_iterator it = mCache.begin ();
while (it != mCache.end ())
{
if (it->second > now)
{
it->second = now;
++it;
}
else if (it->second < target)
{
it = mCache.erase (it);
}
else
{
++it;
}
}
}
protected:
/** Provides a type for the underlying map. */
typedef boost::unordered_map<key_type, int> map_type;
/** The type of the iterator used for traversals. */
typedef typename map_type::iterator map_iterator;
typedef RippleMutex LockType;
typedef LockType::ScopedLockType ScopedLockType;
LockType mLock;
std::string const mName;
map_type mCache;
unsigned int mTargetSize, mTargetAge;
};
#endif

View File

@@ -0,0 +1,317 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (RangeSet)
// VFALCO NOTE std::min and std::max not good enough?
// NOTE Why isn't this written as a template?
// TODO Replace this with std calls.
//
inline uint32 min (uint32 x, uint32 y)
{
return (x < y) ? x : y;
}
inline uint32 max (uint32 x, uint32 y)
{
return (x > y) ? x : y;
}
bool RangeSet::hasValue (uint32 v) const
{
BOOST_FOREACH (const value_type & it, mRanges)
{
if (contains (it, v))
return true;
}
return false;
}
uint32 RangeSet::getFirst () const
{
const_iterator it = mRanges.begin ();
if (it == mRanges.end ())
return absent;
return it->first;
}
uint32 RangeSet::getNext (uint32 v) const
{
BOOST_FOREACH (const value_type & it, mRanges)
{
if (it.first > v)
return it.first;
if (contains (it, v + 1))
return v + 1;
}
return absent;
}
uint32 RangeSet::getLast () const
{
const_reverse_iterator it = mRanges.rbegin ();
if (it == mRanges.rend ())
return absent;
return it->second;
}
uint32 RangeSet::getPrev (uint32 v) const
{
BOOST_REVERSE_FOREACH (const value_type & it, mRanges)
{
if (it.second < v)
return it.second;
if (contains (it, v + 1))
return v - 1;
}
return absent;
}
// Return the largest number not in the set that is less than the given number
//
uint32 RangeSet::prevMissing (uint32 v) const
{
uint32 result = absent;
if (v != 0)
{
checkInternalConsistency ();
// Handle the case where the loop reaches the terminating condition
//
result = v - 1;
for (const_reverse_iterator cur = mRanges.rbegin (); cur != mRanges.rend (); ++cur)
{
// See if v-1 is in the range
if (contains (*cur, result))
{
result = cur->first - 1;
break;
}
}
}
bassert (result == absent || !hasValue (result));
return result;
}
void RangeSet::setValue (uint32 v)
{
if (!hasValue (v))
{
mRanges[v] = v;
simplify ();
}
}
void RangeSet::setRange (uint32 minV, uint32 maxV)
{
while (hasValue (minV))
{
++minV;
if (minV >= maxV)
return;
}
mRanges[minV] = maxV;
simplify ();
}
void RangeSet::clearValue (uint32 v)
{
for (iterator it = mRanges.begin (); it != mRanges.end (); ++it)
{
if (contains (*it, v))
{
if (it->first == v)
{
if (it->second == v)
{
mRanges.erase (it);
}
else
{
uint32 oldEnd = it->second;
mRanges.erase(it);
mRanges[v + 1] = oldEnd;
}
}
else if (it->second == v)
{
-- (it->second);
}
else
{
uint32 oldEnd = it->second;
it->second = v - 1;
mRanges[v + 1] = oldEnd;
}
checkInternalConsistency();
return;
}
}
}
std::string RangeSet::toString () const
{
std::string ret;
BOOST_FOREACH (value_type const & it, mRanges)
{
if (!ret.empty ())
ret += ",";
if (it.first == it.second)
ret += lexicalCastThrow <std::string> ((it.first));
else
ret += lexicalCastThrow <std::string> (it.first) + "-"
+ lexicalCastThrow <std::string> (it.second);
}
if (ret.empty ())
return "empty";
return ret;
}
void RangeSet::simplify ()
{
iterator it = mRanges.begin ();
while (1)
{
iterator nit = it;
if (++nit == mRanges.end ())
{
checkInternalConsistency();
return;
}
if (it->second >= (nit->first - 1))
{
// ranges overlap
it->second = nit->second;
mRanges.erase (nit);
}
else
{
it = nit;
}
}
}
void RangeSet::checkInternalConsistency () const noexcept
{
#if BEAST_DEBUG
if (mRanges.size () > 1)
{
const_iterator const last = std::prev (mRanges.end ());
for (const_iterator cur = mRanges.begin (); cur != last; ++cur)
{
const_iterator const next = std::next (cur);
bassert (cur->first <= cur->second);
bassert (next->first <= next->second);
bassert (cur->second + 1 < next->first);
}
}
else if (mRanges.size () == 1)
{
const_iterator const iter = mRanges.begin ();
bassert (iter->first <= iter->second);
}
#endif
}
//------------------------------------------------------------------------------
class RangeSetTests : public UnitTest
{
public:
RangeSetTests () : UnitTest ("RangeSet", "ripple")
{
}
RangeSet createPredefinedSet ()
{
RangeSet set;
// Set will include:
// [ 0, 5]
// [10,15]
// [20,25]
// etc...
for (int i = 0; i < 10; ++i)
set.setRange (10 * i, 10 * i + 5);
return set;
}
void testMembership ()
{
beginTestCase ("membership");
RangeSet r1, r2;
r1.setRange (1, 10);
r1.clearValue (5);
r1.setRange (11, 20);
r2.setRange (1, 4);
r2.setRange (6, 10);
r2.setRange (10, 20);
expect (!r1.hasValue (5));
expect (r2.hasValue (9));
}
void testPrevMissing ()
{
beginTestCase ("prevMissing");
RangeSet const set = createPredefinedSet ();
for (int i = 0; i < 100; ++i)
{
int const oneBelowRange = (10*(i/10))-1;
int const expectedPrevMissing =
((i % 10) > 6) ? (i-1) : oneBelowRange;
expect (set.prevMissing (i) == expectedPrevMissing);
}
}
void runTest ()
{
testMembership ();
testPrevMissing ();
// TODO: Traverse functions must be tested
}
};
static RangeSetTests rangeSetTests;

View File

@@ -0,0 +1,67 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RANGESET_H_INCLUDED
#define RIPPLE_RANGESET_H_INCLUDED
/** A sparse set of integers.
*/
// VFALCO TODO Replace with juce::SparseSet
class RangeSet
{
public:
static const uint32 absent = static_cast <uint32> (-1);
public:
RangeSet () { }
bool hasValue (uint32) const;
uint32 getFirst () const;
uint32 getNext (uint32) const;
uint32 getLast () const;
uint32 getPrev (uint32) const;
// largest number not in the set that is less than the given number
uint32 prevMissing (uint32) const;
// Add an item to the set
void setValue (uint32);
// Add the closed interval to the set
void setRange (uint32, uint32);
void clearValue (uint32);
std::string toString () const;
/** Check invariants of the data.
This is for diagnostics, and does nothing in release builds.
*/
void checkInternalConsistency () const noexcept;
private:
void simplify ();
private:
typedef std::map <uint32, uint32> Map;
typedef Map::const_iterator const_iterator;
typedef Map::const_reverse_iterator const_reverse_iterator;
typedef Map::value_type value_type;
typedef Map::iterator iterator;
static bool contains (value_type const& it, uint32 v)
{
return (it.first <= v) && (it.second >= v);
}
// First is lowest value in range, last is highest value in range
Map mRanges;
};
#endif

View File

@@ -0,0 +1,59 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SECUREALLOCATOR_H_INCLUDED
#define RIPPLE_SECUREALLOCATOR_H_INCLUDED
//
// Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion.
//
template<typename T>
struct secure_allocator : public std::allocator<T>
{
// MSVC8 default copy constructor is broken
typedef std::allocator<T> base;
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::const_pointer const_pointer;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
secure_allocator () throw () {}
secure_allocator (const secure_allocator& a) throw () : base (a) {}
template <typename U>
secure_allocator (const secure_allocator<U>& a) throw () : base (a) {}
~secure_allocator () throw () {}
template<typename _Other> struct rebind
{
typedef secure_allocator<_Other> other;
};
T* allocate (std::size_t n, const void* hint = 0)
{
T* p;
p = std::allocator<T>::allocate (n, hint);
if (p != NULL)
mlock (p, sizeof (T) * n);
return p;
}
void deallocate (T* p, std::size_t n)
{
if (p != NULL)
{
memset (p, 0, sizeof (T) * n);
munlock (p, sizeof (T) * n);
}
std::allocator<T>::deallocate (p, n);
}
};
#endif

View File

@@ -0,0 +1,7 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOGN (TaggedCacheLog,"TaggedCache")

View File

@@ -0,0 +1,505 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_TAGGEDCACHE_H
#define RIPPLE_TAGGEDCACHE_H
// This class implements a cache and a map. The cache keeps objects alive
// in the map. The map allows multiple code paths that reference objects
// with the same tag to get the same actual object.
// So long as data is in the cache, it will stay in memory.
// If it stays in memory even after it is ejected from the cache,
// the map will track it.
// CAUTION: Callers must not modify data objects that are stored in the cache
// unless they hold their own lock over all cache operations.
struct TaggedCacheLog;
// Common base
class TaggedCache
{
public:
typedef RippleRecursiveMutex LockType;
typedef LockType::ScopedLockType ScopedLockType;
};
/** Combination cache/map container.
NOTE:
Timer must have this interface:
static int Timer::getElapsedSeconds ();
*/
template <typename c_Key, typename c_Data, class Timer>
class TaggedCacheType : public TaggedCache
{
public:
typedef c_Key key_type;
typedef c_Data data_type;
typedef boost::weak_ptr<data_type> weak_data_ptr;
typedef boost::shared_ptr<data_type> data_ptr;
public:
typedef TaggedCache::LockType LockType;
typedef TaggedCache::ScopedLockType ScopedLockType;
TaggedCacheType (const char* name, int size, int age)
: mLock (static_cast <TaggedCache const*>(this), "TaggedCache", __FILE__, __LINE__)
, mName (name)
, mTargetSize (size)
, mTargetAge (age)
, mCacheCount (0)
, mHits (0)
, mMisses (0)
{
}
int getTargetSize () const;
int getTargetAge () const;
int getCacheSize ();
int getTrackSize ();
float getHitRate ();
void clearStats ();
void setTargetSize (int size);
void setTargetAge (int age);
void sweep ();
void clear ();
/** Refresh the expiration time on a key.
@param key The key to refresh.
@return `true` if the key was found and the object is cached.
*/
bool refreshIfPresent (const key_type& key)
{
bool found = false;
// If present, make current in cache
ScopedLockType sl (mLock, __FILE__, __LINE__);
cache_iterator cit = mCache.find (key);
if (cit != mCache.end ())
{
cache_entry& entry = cit->second;
if (! entry.isCached ())
{
// Convert weak to strong.
entry.ptr = entry.lock ();
if (entry.isCached ())
{
// We just put the object back in cache
++mCacheCount;
entry.touch ();
found = true;
}
else
{
// Couldn't get strong pointer,
// object fell out of the cache so remove the entry.
mCache.erase (cit);
}
}
else
{
// It's cached so update the timer
entry.touch ();
found = true;
}
}
else
{
// not present
}
return found;
}
bool del (const key_type& key, bool valid);
/** Replace aliased objects with originals.
Due to concurrency it is possible for two separate objects with
the same content and referring to the same unique "thing" to exist.
This routine eliminates the duplicate and performs a replacement
on the callers shared pointer if needed.
@param key The key corresponding to the object
@param data A shared pointer to the data corresponding to the object.
@param replace `true` if `data` is the up to date version of the object.
@return `true` if the operation was successful.
*/
bool canonicalize (const key_type& key, boost::shared_ptr<c_Data>& data, bool replace = false);
bool store (const key_type& key, const c_Data& data);
boost::shared_ptr<c_Data> fetch (const key_type& key);
bool retrieve (const key_type& key, c_Data& data);
LockType& peekMutex ()
{
return mLock;
}
private:
class cache_entry
{
public:
int last_use;
data_ptr ptr;
weak_data_ptr weak_ptr;
cache_entry (int l, const data_ptr& d) : last_use (l), ptr (d), weak_ptr (d)
{
;
}
bool isWeak ()
{
return !ptr;
}
bool isCached ()
{
return !!ptr;
}
bool isExpired ()
{
return weak_ptr.expired ();
}
data_ptr lock ()
{
return weak_ptr.lock ();
}
void touch ()
{
last_use = Timer::getElapsedSeconds ();
}
};
typedef std::pair<key_type, cache_entry> cache_pair;
typedef boost::unordered_map<key_type, cache_entry> cache_type;
typedef typename cache_type::iterator cache_iterator;
mutable LockType mLock;
std::string mName; // Used for logging
int mTargetSize; // Desired number of cache entries (0 = ignore)
int mTargetAge; // Desired maximum cache age
int mCacheCount; // Number of items cached
cache_type mCache; // Hold strong reference to recent objects
uint64 mHits, mMisses;
};
template<typename c_Key, typename c_Data, class Timer>
int TaggedCacheType<c_Key, c_Data, Timer>::getTargetSize () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mTargetSize;
}
template<typename c_Key, typename c_Data, class Timer>
void TaggedCacheType<c_Key, c_Data, Timer>::setTargetSize (int s)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mTargetSize = s;
if (s > 0)
mCache.rehash (static_cast<std::size_t> ((s + (s >> 2)) / mCache.max_load_factor () + 1));
WriteLog (lsDEBUG, TaggedCacheLog) << mName << " target size set to " << s;
}
template<typename c_Key, typename c_Data, class Timer>
int TaggedCacheType<c_Key, c_Data, Timer>::getTargetAge () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mTargetAge;
}
template<typename c_Key, typename c_Data, class Timer>
void TaggedCacheType<c_Key, c_Data, Timer>::setTargetAge (int s)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mTargetAge = s;
WriteLog (lsDEBUG, TaggedCacheLog) << mName << " target age set to " << s;
}
template<typename c_Key, typename c_Data, class Timer>
int TaggedCacheType<c_Key, c_Data, Timer>::getCacheSize ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mCacheCount;
}
template<typename c_Key, typename c_Data, class Timer>
int TaggedCacheType<c_Key, c_Data, Timer>::getTrackSize ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mCache.size ();
}
template<typename c_Key, typename c_Data, class Timer>
float TaggedCacheType<c_Key, c_Data, Timer>::getHitRate ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return (static_cast<float> (mHits) * 100) / (1.0f + mHits + mMisses);
}
template<typename c_Key, typename c_Data, class Timer>
void TaggedCacheType<c_Key, c_Data, Timer>::clearStats ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mHits = 0;
mMisses = 0;
}
template<typename c_Key, typename c_Data, class Timer>
void TaggedCacheType<c_Key, c_Data, Timer>::clear ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mCache.clear ();
mCacheCount = 0;
}
template<typename c_Key, typename c_Data, class Timer>
void TaggedCacheType<c_Key, c_Data, Timer>::sweep ()
{
int cacheRemovals = 0;
int mapRemovals = 0;
int cc = 0;
// Keep references to all the stuff we sweep
// so that we can destroy them outside the lock.
//
std::vector <data_ptr> stuffToSweep;
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
int const now = Timer::getElapsedSeconds ();
int target = now - mTargetAge;
if ((mTargetSize != 0) && (static_cast<int> (mCache.size ()) > mTargetSize))
{
target = now - (mTargetAge * mTargetSize / mCache.size ());
if (target > (now - 2))
target = now - 2;
WriteLog (lsINFO, TaggedCacheLog) << mName << " is growing fast " <<
mCache.size () << " of " << mTargetSize <<
" aging at " << (now - target) << " of " << mTargetAge;
}
stuffToSweep.reserve (mCache.size ());
cache_iterator cit = mCache.begin ();
while (cit != mCache.end ())
{
if (cit->second.isWeak ())
{
// weak
if (cit->second.isExpired ())
{
++mapRemovals;
cit = mCache.erase (cit);
}
else
{
++cit;
}
}
else if (cit->second.last_use < target)
{
// strong, expired
--mCacheCount;
++cacheRemovals;
if (cit->second.ptr.unique ())
{
stuffToSweep.push_back (cit->second.ptr);
++mapRemovals;
cit = mCache.erase (cit);
}
else
{
// remains weakly cached
cit->second.ptr.reset ();
++cit;
}
}
else
{
// strong, not expired
++cc;
++cit;
}
}
}
if (ShouldLog (lsTRACE, TaggedCacheLog) && (mapRemovals || cacheRemovals))
{
WriteLog (lsTRACE, TaggedCacheLog) << mName << ": cache = " << mCache.size () << "-" << cacheRemovals <<
", map-=" << mapRemovals;
}
// At this point stuffToSweep will go out of scope outside the lock
// and decrement the reference count on each strong pointer.
}
template<typename c_Key, typename c_Data, class Timer>
bool TaggedCacheType<c_Key, c_Data, Timer>::del (const key_type& key, bool valid)
{
// Remove from cache, if !valid, remove from map too. Returns true if removed from cache
ScopedLockType sl (mLock, __FILE__, __LINE__);
cache_iterator cit = mCache.find (key);
if (cit == mCache.end ())
return false;
cache_entry& entry = cit->second;
bool ret = false;
if (entry.isCached ())
{
--mCacheCount;
entry.ptr.reset ();
ret = true;
}
if (!valid || entry.isExpired ())
mCache.erase (cit);
return ret;
}
// VFALCO NOTE What does it mean to canonicalize the data?
template<typename c_Key, typename c_Data, class Timer>
bool TaggedCacheType<c_Key, c_Data, Timer>::canonicalize (const key_type& key, boost::shared_ptr<c_Data>& data, bool replace)
{
// Return canonical value, store if needed, refresh in cache
// Return values: true=we had the data already
ScopedLockType sl (mLock, __FILE__, __LINE__);
cache_iterator cit = mCache.find (key);
if (cit == mCache.end ())
{
mCache.insert (cache_pair (key, cache_entry (Timer::getElapsedSeconds (), data)));
++mCacheCount;
return false;
}
cache_entry& entry = cit->second;
entry.touch ();
if (entry.isCached ())
{
if (replace)
{
entry.ptr = data;
entry.weak_ptr = data;
}
else
data = entry.ptr;
return true;
}
data_ptr cachedData = entry.lock ();
if (cachedData)
{
if (replace)
{
entry.ptr = data;
entry.weak_ptr = data;
}
else
{
entry.ptr = cachedData;
data = cachedData;
}
++mCacheCount;
return true;
}
entry.ptr = data;
entry.weak_ptr = data;
++mCacheCount;
return false;
}
template<typename c_Key, typename c_Data, class Timer>
boost::shared_ptr<c_Data> TaggedCacheType<c_Key, c_Data, Timer>::fetch (const key_type& key)
{
// fetch us a shared pointer to the stored data object
ScopedLockType sl (mLock, __FILE__, __LINE__);
cache_iterator cit = mCache.find (key);
if (cit == mCache.end ())
{
++mMisses;
return data_ptr ();
}
cache_entry& entry = cit->second;
entry.touch ();
if (entry.isCached ())
{
++mHits;
return entry.ptr;
}
entry.ptr = entry.lock ();
if (entry.isCached ())
{
// independent of cache size, so not counted as a hit
++mCacheCount;
return entry.ptr;
}
mCache.erase (cit);
++mMisses;
return data_ptr ();
}
template<typename c_Key, typename c_Data, class Timer>
bool TaggedCacheType<c_Key, c_Data, Timer>::store (const key_type& key, const c_Data& data)
{
data_ptr d = boost::make_shared<c_Data> (boost::cref (data));
return canonicalize (key, d);
}
template<typename c_Key, typename c_Data, class Timer>
bool TaggedCacheType<c_Key, c_Data, Timer>::retrieve (const key_type& key, c_Data& data)
{
// retrieve the value of the stored data
data_ptr entry = fetch (key);
if (!entry)
return false;
data = *entry;
return true;
}
#endif

Binary file not shown.

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef JSON_AUTOLINK_H_INCLUDED
#define JSON_AUTOLINK_H_INCLUDED
// VFALCO TODO remove this file
#error This file is deprecated!
# include "config.h"
# ifdef JSON_IN_CPPTL
# include <cpptl/cpptl_autolink.h>
# endif
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
# define CPPTL_AUTOLINK_NAME "json"
# undef CPPTL_AUTOLINK_DLL
# ifdef JSON_DLL
# define CPPTL_AUTOLINK_DLL
# endif
# include "autolink.h"
# endif
#endif // JSON_AUTOLINK_H_INCLUDED

View File

@@ -0,0 +1,132 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
namespace Json
{
/* Fast memory allocator.
*
* This memory allocator allocates memory for a batch of object (specified by
* the page size, the number of object in each page).
*
* It does not allow the destruction of a single object. All the allocated objects
* can be destroyed at once. The memory can be either released or reused for future
* allocation.
*
* The in-place new operator must be used to construct the object using the pointer
* returned by allocate.
*/
template < typename AllocatedType
, const unsigned int objectPerAllocation >
class BatchAllocator
{
public:
typedef AllocatedType Type;
BatchAllocator ( unsigned int objectsPerPage = 255 )
: freeHead_ ( 0 )
, objectsPerPage_ ( objectsPerPage )
{
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
assert ( sizeof (AllocatedType) * objectPerAllocation >= sizeof (AllocatedType*) ); // We must be able to store a slist in the object free space.
assert ( objectsPerPage >= 16 );
batches_ = allocateBatch ( 0 ); // allocated a dummy page
currentBatch_ = batches_;
}
~BatchAllocator ()
{
for ( BatchInfo* batch = batches_; batch; )
{
BatchInfo* nextBatch = batch->next_;
free ( batch );
batch = nextBatch;
}
}
/// allocate space for an array of objectPerAllocation object.
/// @warning it is the responsability of the caller to call objects constructors.
AllocatedType* allocate ()
{
if ( freeHead_ ) // returns node from free list.
{
AllocatedType* object = freeHead_;
freeHead_ = * (AllocatedType**)object;
return object;
}
if ( currentBatch_->used_ == currentBatch_->end_ )
{
currentBatch_ = currentBatch_->next_;
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
currentBatch_ = currentBatch_->next_;
if ( !currentBatch_ ) // no free batch found, allocate a new one
{
currentBatch_ = allocateBatch ( objectsPerPage_ );
currentBatch_->next_ = batches_; // insert at the head of the list
batches_ = currentBatch_;
}
}
AllocatedType* allocated = currentBatch_->used_;
currentBatch_->used_ += objectPerAllocation;
return allocated;
}
/// Release the object.
/// @warning it is the responsability of the caller to actually destruct the object.
void release ( AllocatedType* object )
{
assert ( object != 0 );
* (AllocatedType**)object = freeHead_;
freeHead_ = object;
}
private:
struct BatchInfo
{
BatchInfo* next_;
AllocatedType* used_;
AllocatedType* end_;
AllocatedType buffer_[objectPerAllocation];
};
// disabled copy constructor and assignement operator.
BatchAllocator ( const BatchAllocator& );
void operator = ( const BatchAllocator&);
static BatchInfo* allocateBatch ( unsigned int objectsPerPage )
{
const unsigned int mallocSize = sizeof (BatchInfo) - sizeof (AllocatedType) * objectPerAllocation
+ sizeof (AllocatedType) * objectPerAllocation * objectsPerPage;
BatchInfo* batch = static_cast<BatchInfo*> ( malloc ( mallocSize ) );
batch->next_ = 0;
batch->used_ = batch->buffer_;
batch->end_ = batch->buffer_ + objectsPerPage;
return batch;
}
BatchInfo* batches_;
BatchInfo* currentBatch_;
/// Head of a single linked list within the allocated space of freeed object
AllocatedType* freeHead_;
unsigned int objectsPerPage_;
};
} // namespace Json
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED

View File

@@ -0,0 +1,49 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
/// If defined, indicates that Json specific container should be used
/// (hash table & simple deque container with customizable allocator).
/// THIS FEATURE IS STILL EXPERIMENTAL!
//# define JSON_VALUE_USE_INTERNAL_MAP 1
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
/// as if it was a POD) that may cause some validation tool to report errors.
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
/// If defined, indicates that Json use exception to report invalid type manipulation
/// instead of C assert macro.
# define JSON_USE_EXCEPTION 1
# ifdef JSON_IN_CPPTL
# include <cpptl/config.h>
# ifndef JSON_USE_CPPTL
# define JSON_USE_CPPTL 1
# endif
# endif
# ifdef JSON_IN_CPPTL
# define JSON_API CPPTL_API
# elif defined(JSON_DLL_BUILD)
# define JSON_API __declspec(dllexport)
# elif defined(JSON_DLL)
# define JSON_API __declspec(dllimport)
# else
# define JSON_API
# endif
#endif // JSON_CONFIG_H_INCLUDED

View File

@@ -0,0 +1,47 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
#define CPPTL_JSON_FEATURES_H_INCLUDED
namespace Json
{
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features
{
public:
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all ();
/** \brief A configuration that is strictly compatible with the JSON specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode ();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features ();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_;
/// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_;
};
} // namespace Json
#endif // CPPTL_JSON_FEATURES_H_INCLUDED

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef JSON_FORWARDS_H_INCLUDED
#define JSON_FORWARDS_H_INCLUDED
namespace Json
{
// writer.h
class FastWriter;
class StyledWriter;
// reader.h
class Reader;
// features.h
class Features;
// value.h
typedef int Int;
typedef unsigned int UInt;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
#ifdef JSON_VALUE_USE_INTERNAL_MAP
class ValueAllocator;
class ValueMapAllocator;
class ValueInternalLink;
class ValueInternalArray;
class ValueInternalMap;
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED

View File

@@ -0,0 +1,484 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// included by json_value.cpp
// everything is within Json namespace
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueInternalArray
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueArrayAllocator::~ValueArrayAllocator ()
{
}
// //////////////////////////////////////////////////////////////////
// class DefaultValueArrayAllocator
// //////////////////////////////////////////////////////////////////
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
class DefaultValueArrayAllocator : public ValueArrayAllocator
{
public: // overridden from ValueArrayAllocator
virtual ~DefaultValueArrayAllocator ()
{
}
virtual ValueInternalArray* newArray ()
{
return new ValueInternalArray ();
}
virtual ValueInternalArray* newArrayCopy ( const ValueInternalArray& other )
{
return new ValueInternalArray ( other );
}
virtual void destructArray ( ValueInternalArray* array )
{
delete array;
}
virtual void reallocateArrayPageIndex ( Value**& indexes,
ValueInternalArray::PageIndex& indexCount,
ValueInternalArray::PageIndex minNewIndexCount )
{
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
if ( minNewIndexCount > newIndexCount )
newIndexCount = minNewIndexCount;
void* newIndexes = realloc ( indexes, sizeof (Value*) * newIndexCount );
if ( !newIndexes )
throw std::bad_alloc ();
indexCount = newIndexCount;
indexes = static_cast<Value**> ( newIndexes );
}
virtual void releaseArrayPageIndex ( Value** indexes,
ValueInternalArray::PageIndex indexCount )
{
if ( indexes )
free ( indexes );
}
virtual Value* allocateArrayPage ()
{
return static_cast<Value*> ( malloc ( sizeof (Value) * ValueInternalArray::itemsPerPage ) );
}
virtual void releaseArrayPage ( Value* value )
{
if ( value )
free ( value );
}
};
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
/// @todo make this thread-safe (lock when accessign batch allocator)
class DefaultValueArrayAllocator : public ValueArrayAllocator
{
public: // overridden from ValueArrayAllocator
virtual ~DefaultValueArrayAllocator ()
{
}
virtual ValueInternalArray* newArray ()
{
ValueInternalArray* array = arraysAllocator_.allocate ();
new (array) ValueInternalArray (); // placement new
return array;
}
virtual ValueInternalArray* newArrayCopy ( const ValueInternalArray& other )
{
ValueInternalArray* array = arraysAllocator_.allocate ();
new (array) ValueInternalArray ( other ); // placement new
return array;
}
virtual void destructArray ( ValueInternalArray* array )
{
if ( array )
{
array->~ValueInternalArray ();
arraysAllocator_.release ( array );
}
}
virtual void reallocateArrayPageIndex ( Value**& indexes,
ValueInternalArray::PageIndex& indexCount,
ValueInternalArray::PageIndex minNewIndexCount )
{
ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
if ( minNewIndexCount > newIndexCount )
newIndexCount = minNewIndexCount;
void* newIndexes = realloc ( indexes, sizeof (Value*) * newIndexCount );
if ( !newIndexes )
throw std::bad_alloc ();
indexCount = newIndexCount;
indexes = static_cast<Value**> ( newIndexes );
}
virtual void releaseArrayPageIndex ( Value** indexes,
ValueInternalArray::PageIndex indexCount )
{
if ( indexes )
free ( indexes );
}
virtual Value* allocateArrayPage ()
{
return static_cast<Value*> ( pagesAllocator_.allocate () );
}
virtual void releaseArrayPage ( Value* value )
{
if ( value )
pagesAllocator_.release ( value );
}
private:
BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
};
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
static ValueArrayAllocator*& arrayAllocator ()
{
static DefaultValueArrayAllocator defaultAllocator;
static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
return arrayAllocator;
}
static struct DummyArrayAllocatorInitializer
{
DummyArrayAllocatorInitializer ()
{
arrayAllocator (); // ensure arrayAllocator() statics are initialized before main().
}
} dummyArrayAllocatorInitializer;
// //////////////////////////////////////////////////////////////////
// class ValueInternalArray
// //////////////////////////////////////////////////////////////////
bool
ValueInternalArray::equals ( const IteratorState& x,
const IteratorState& other )
{
return x.array_ == other.array_
&& x.currentItemIndex_ == other.currentItemIndex_
&& x.currentPageIndex_ == other.currentPageIndex_;
}
void
ValueInternalArray::increment ( IteratorState& it )
{
JSON_ASSERT_MESSAGE ( it.array_ &&
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
!= it.array_->size_,
"ValueInternalArray::increment(): moving iterator beyond end" );
++ (it.currentItemIndex_);
if ( it.currentItemIndex_ == itemsPerPage )
{
it.currentItemIndex_ = 0;
++ (it.currentPageIndex_);
}
}
void
ValueInternalArray::decrement ( IteratorState& it )
{
JSON_ASSERT_MESSAGE ( it.array_ && it.currentPageIndex_ == it.array_->pages_
&& it.currentItemIndex_ == 0,
"ValueInternalArray::decrement(): moving iterator beyond end" );
if ( it.currentItemIndex_ == 0 )
{
it.currentItemIndex_ = itemsPerPage - 1;
-- (it.currentPageIndex_);
}
else
{
-- (it.currentItemIndex_);
}
}
Value&
ValueInternalArray::unsafeDereference ( const IteratorState& it )
{
return (* (it.currentPageIndex_))[it.currentItemIndex_];
}
Value&
ValueInternalArray::dereference ( const IteratorState& it )
{
JSON_ASSERT_MESSAGE ( it.array_ &&
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
< it.array_->size_,
"ValueInternalArray::dereference(): dereferencing invalid iterator" );
return unsafeDereference ( it );
}
void
ValueInternalArray::makeBeginIterator ( IteratorState& it ) const
{
it.array_ = const_cast<ValueInternalArray*> ( this );
it.currentItemIndex_ = 0;
it.currentPageIndex_ = pages_;
}
void
ValueInternalArray::makeIterator ( IteratorState& it, ArrayIndex index ) const
{
it.array_ = const_cast<ValueInternalArray*> ( this );
it.currentItemIndex_ = index % itemsPerPage;
it.currentPageIndex_ = pages_ + index / itemsPerPage;
}
void
ValueInternalArray::makeEndIterator ( IteratorState& it ) const
{
makeIterator ( it, size_ );
}
ValueInternalArray::ValueInternalArray ()
: pages_ ( 0 )
, size_ ( 0 )
, pageCount_ ( 0 )
{
}
ValueInternalArray::ValueInternalArray ( const ValueInternalArray& other )
: pages_ ( 0 )
, pageCount_ ( 0 )
, size_ ( other.size_ )
{
PageIndex minNewPages = other.size_ / itemsPerPage;
arrayAllocator ()->reallocateArrayPageIndex ( pages_, pageCount_, minNewPages );
JSON_ASSERT_MESSAGE ( pageCount_ >= minNewPages,
"ValueInternalArray::reserve(): bad reallocation" );
IteratorState itOther;
other.makeBeginIterator ( itOther );
Value* value;
for ( ArrayIndex index = 0; index < size_; ++index, increment (itOther) )
{
if ( index % itemsPerPage == 0 )
{
PageIndex pageIndex = index / itemsPerPage;
value = arrayAllocator ()->allocateArrayPage ();
pages_[pageIndex] = value;
}
new (value) Value ( dereference ( itOther ) );
}
}
ValueInternalArray&
ValueInternalArray::operator = ( const ValueInternalArray& other )
{
ValueInternalArray temp ( other );
swap ( temp );
return *this;
}
ValueInternalArray::~ValueInternalArray ()
{
// destroy all constructed items
IteratorState it;
IteratorState itEnd;
makeBeginIterator ( it);
makeEndIterator ( itEnd );
for ( ; !equals (it, itEnd); increment (it) )
{
Value* value = &dereference (it);
value->~Value ();
}
// release all pages
PageIndex lastPageIndex = size_ / itemsPerPage;
for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
arrayAllocator ()->releaseArrayPage ( pages_[pageIndex] );
// release pages index
arrayAllocator ()->releaseArrayPageIndex ( pages_, pageCount_ );
}
void
ValueInternalArray::swap ( ValueInternalArray& other )
{
Value** tempPages = pages_;
pages_ = other.pages_;
other.pages_ = tempPages;
ArrayIndex tempSize = size_;
size_ = other.size_;
other.size_ = tempSize;
PageIndex tempPageCount = pageCount_;
pageCount_ = other.pageCount_;
other.pageCount_ = tempPageCount;
}
void
ValueInternalArray::clear ()
{
ValueInternalArray dummy;
swap ( dummy );
}
void
ValueInternalArray::resize ( ArrayIndex newSize )
{
if ( newSize == 0 )
clear ();
else if ( newSize < size_ )
{
IteratorState it;
IteratorState itEnd;
makeIterator ( it, newSize );
makeIterator ( itEnd, size_ );
for ( ; !equals (it, itEnd); increment (it) )
{
Value* value = &dereference (it);
value->~Value ();
}
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
PageIndex lastPageIndex = size_ / itemsPerPage;
for ( ; pageIndex < lastPageIndex; ++pageIndex )
arrayAllocator ()->releaseArrayPage ( pages_[pageIndex] );
size_ = newSize;
}
else if ( newSize > size_ )
resolveReference ( newSize );
}
void
ValueInternalArray::makeIndexValid ( ArrayIndex index )
{
// Need to enlarge page index ?
if ( index >= pageCount_ * itemsPerPage )
{
PageIndex minNewPages = (index + 1) / itemsPerPage;
arrayAllocator ()->reallocateArrayPageIndex ( pages_, pageCount_, minNewPages );
JSON_ASSERT_MESSAGE ( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
}
// Need to allocate new pages ?
ArrayIndex nextPageIndex =
(size_ % itemsPerPage) != 0 ? size_ - (size_ % itemsPerPage) + itemsPerPage
: size_;
if ( nextPageIndex <= index )
{
PageIndex pageIndex = nextPageIndex / itemsPerPage;
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
for ( ; pageToAllocate-- > 0; ++pageIndex )
pages_[pageIndex] = arrayAllocator ()->allocateArrayPage ();
}
// Initialize all new entries
IteratorState it;
IteratorState itEnd;
makeIterator ( it, size_ );
size_ = index + 1;
makeIterator ( itEnd, size_ );
for ( ; !equals (it, itEnd); increment (it) )
{
Value* value = &dereference (it);
new (value) Value (); // Construct a default value using placement new
}
}
Value&
ValueInternalArray::resolveReference ( ArrayIndex index )
{
if ( index >= size_ )
makeIndexValid ( index );
return pages_[index / itemsPerPage][index % itemsPerPage];
}
Value*
ValueInternalArray::find ( ArrayIndex index ) const
{
if ( index >= size_ )
return 0;
return & (pages_[index / itemsPerPage][index % itemsPerPage]);
}
ValueInternalArray::ArrayIndex
ValueInternalArray::size () const
{
return size_;
}
int
ValueInternalArray::distance ( const IteratorState& x, const IteratorState& y )
{
return indexOf (y) - indexOf (x);
}
ValueInternalArray::ArrayIndex
ValueInternalArray::indexOf ( const IteratorState& iterator )
{
if ( !iterator.array_ )
return ArrayIndex (-1);
return ArrayIndex (
(iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
+ iterator.currentItemIndex_ );
}
int
ValueInternalArray::compare ( const ValueInternalArray& other ) const
{
int sizeDiff ( size_ - other.size_ );
if ( sizeDiff != 0 )
return sizeDiff;
for ( ArrayIndex index = 0; index < size_; ++index )
{
int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare (
other.pages_[index / itemsPerPage][index % itemsPerPage] );
if ( diff != 0 )
return diff;
}
return 0;
}

View File

@@ -0,0 +1,658 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// included by json_value.cpp
// everything is within Json namespace
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueInternalMap
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
* This optimization is used by the fast allocator.
*/
ValueInternalLink::ValueInternalLink ()
: previous_ ( 0 )
, next_ ( 0 )
{
}
ValueInternalLink::~ValueInternalLink ()
{
for ( int index = 0; index < itemPerLink; ++index )
{
if ( !items_[index].isItemAvailable () )
{
if ( !items_[index].isMemberNameStatic () )
free ( keys_[index] );
}
else
break;
}
}
ValueMapAllocator::~ValueMapAllocator ()
{
}
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
class DefaultValueMapAllocator : public ValueMapAllocator
{
public: // overridden from ValueMapAllocator
virtual ValueInternalMap* newMap ()
{
return new ValueInternalMap ();
}
virtual ValueInternalMap* newMapCopy ( const ValueInternalMap& other )
{
return new ValueInternalMap ( other );
}
virtual void destructMap ( ValueInternalMap* map )
{
delete map;
}
virtual ValueInternalLink* allocateMapBuckets ( unsigned int size )
{
return new ValueInternalLink[size];
}
virtual void releaseMapBuckets ( ValueInternalLink* links )
{
delete [] links;
}
virtual ValueInternalLink* allocateMapLink ()
{
return new ValueInternalLink ();
}
virtual void releaseMapLink ( ValueInternalLink* link )
{
delete link;
}
};
#else
/// @todo make this thread-safe (lock when accessign batch allocator)
class DefaultValueMapAllocator : public ValueMapAllocator
{
public: // overridden from ValueMapAllocator
virtual ValueInternalMap* newMap ()
{
ValueInternalMap* map = mapsAllocator_.allocate ();
new (map) ValueInternalMap (); // placement new
return map;
}
virtual ValueInternalMap* newMapCopy ( const ValueInternalMap& other )
{
ValueInternalMap* map = mapsAllocator_.allocate ();
new (map) ValueInternalMap ( other ); // placement new
return map;
}
virtual void destructMap ( ValueInternalMap* map )
{
if ( map )
{
map->~ValueInternalMap ();
mapsAllocator_.release ( map );
}
}
virtual ValueInternalLink* allocateMapBuckets ( unsigned int size )
{
return new ValueInternalLink[size];
}
virtual void releaseMapBuckets ( ValueInternalLink* links )
{
delete [] links;
}
virtual ValueInternalLink* allocateMapLink ()
{
ValueInternalLink* link = linksAllocator_.allocate ();
memset ( link, 0, sizeof (ValueInternalLink) );
return link;
}
virtual void releaseMapLink ( ValueInternalLink* link )
{
link->~ValueInternalLink ();
linksAllocator_.release ( link );
}
private:
BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
BatchAllocator<ValueInternalLink, 1> linksAllocator_;
};
#endif
static ValueMapAllocator*& mapAllocator ()
{
static DefaultValueMapAllocator defaultAllocator;
static ValueMapAllocator* mapAllocator = &defaultAllocator;
return mapAllocator;
}
static struct DummyMapAllocatorInitializer
{
DummyMapAllocatorInitializer ()
{
mapAllocator (); // ensure mapAllocator() statics are initialized before main().
}
} dummyMapAllocatorInitializer;
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
/*
use linked list hash map.
buckets array is a container.
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
value have extra state: valid, available, deleted
*/
ValueInternalMap::ValueInternalMap ()
: buckets_ ( 0 )
, tailLink_ ( 0 )
, bucketsSize_ ( 0 )
, itemCount_ ( 0 )
{
}
ValueInternalMap::ValueInternalMap ( const ValueInternalMap& other )
: buckets_ ( 0 )
, tailLink_ ( 0 )
, bucketsSize_ ( 0 )
, itemCount_ ( 0 )
{
reserve ( other.itemCount_ );
IteratorState it;
IteratorState itEnd;
other.makeBeginIterator ( it );
other.makeEndIterator ( itEnd );
for ( ; !equals (it, itEnd); increment (it) )
{
bool isStatic;
const char* memberName = key ( it, isStatic );
const Value& aValue = value ( it );
resolveReference (memberName, isStatic) = aValue;
}
}
ValueInternalMap&
ValueInternalMap::operator = ( const ValueInternalMap& other )
{
ValueInternalMap dummy ( other );
swap ( dummy );
return *this;
}
ValueInternalMap::~ValueInternalMap ()
{
if ( buckets_ )
{
for ( BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_; ++bucketIndex )
{
ValueInternalLink* link = buckets_[bucketIndex].next_;
while ( link )
{
ValueInternalLink* linkToRelease = link;
link = link->next_;
mapAllocator ()->releaseMapLink ( linkToRelease );
}
}
mapAllocator ()->releaseMapBuckets ( buckets_ );
}
}
void
ValueInternalMap::swap ( ValueInternalMap& other )
{
ValueInternalLink* tempBuckets = buckets_;
buckets_ = other.buckets_;
other.buckets_ = tempBuckets;
ValueInternalLink* tempTailLink = tailLink_;
tailLink_ = other.tailLink_;
other.tailLink_ = tempTailLink;
BucketIndex tempBucketsSize = bucketsSize_;
bucketsSize_ = other.bucketsSize_;
other.bucketsSize_ = tempBucketsSize;
BucketIndex tempItemCount = itemCount_;
itemCount_ = other.itemCount_;
other.itemCount_ = tempItemCount;
}
void
ValueInternalMap::clear ()
{
ValueInternalMap dummy;
swap ( dummy );
}
ValueInternalMap::BucketIndex
ValueInternalMap::size () const
{
return itemCount_;
}
bool
ValueInternalMap::reserveDelta ( BucketIndex growth )
{
return reserve ( itemCount_ + growth );
}
bool
ValueInternalMap::reserve ( BucketIndex newItemCount )
{
if ( !buckets_ && newItemCount > 0 )
{
buckets_ = mapAllocator ()->allocateMapBuckets ( 1 );
bucketsSize_ = 1;
tailLink_ = &buckets_[0];
}
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
return true;
}
const Value*
ValueInternalMap::find ( const char* key ) const
{
if ( !bucketsSize_ )
return 0;
HashKey hashedKey = hash ( key );
BucketIndex bucketIndex = hashedKey % bucketsSize_;
for ( const ValueInternalLink* current = &buckets_[bucketIndex];
current != 0;
current = current->next_ )
{
for ( BucketIndex index = 0; index < ValueInternalLink::itemPerLink; ++index )
{
if ( current->items_[index].isItemAvailable () )
return 0;
if ( strcmp ( key, current->keys_[index] ) == 0 )
return &current->items_[index];
}
}
return 0;
}
Value*
ValueInternalMap::find ( const char* key )
{
const ValueInternalMap* constThis = this;
return const_cast<Value*> ( constThis->find ( key ) );
}
Value&
ValueInternalMap::resolveReference ( const char* key,
bool isStatic )
{
HashKey hashedKey = hash ( key );
if ( bucketsSize_ )
{
BucketIndex bucketIndex = hashedKey % bucketsSize_;
ValueInternalLink** previous = 0;
BucketIndex index;
for ( ValueInternalLink* current = &buckets_[bucketIndex];
current != 0;
previous = &current->next_, current = current->next_ )
{
for ( index = 0; index < ValueInternalLink::itemPerLink; ++index )
{
if ( current->items_[index].isItemAvailable () )
return setNewItem ( key, isStatic, current, index );
if ( strcmp ( key, current->keys_[index] ) == 0 )
return current->items_[index];
}
}
}
reserveDelta ( 1 );
return unsafeAdd ( key, isStatic, hashedKey );
}
void
ValueInternalMap::remove ( const char* key )
{
HashKey hashedKey = hash ( key );
if ( !bucketsSize_ )
return;
BucketIndex bucketIndex = hashedKey % bucketsSize_;
for ( ValueInternalLink* link = &buckets_[bucketIndex];
link != 0;
link = link->next_ )
{
BucketIndex index;
for ( index = 0; index < ValueInternalLink::itemPerLink; ++index )
{
if ( link->items_[index].isItemAvailable () )
return;
if ( strcmp ( key, link->keys_[index] ) == 0 )
{
doActualRemove ( link, index, bucketIndex );
return;
}
}
}
}
void
ValueInternalMap::doActualRemove ( ValueInternalLink* link,
BucketIndex index,
BucketIndex bucketIndex )
{
// find last item of the bucket and swap it with the 'removed' one.
// set removed items flags to 'available'.
// if last page only contains 'available' items, then desallocate it (it's empty)
ValueInternalLink*& lastLink = getLastLinkInBucket ( index );
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
for ( ;
lastItemIndex < ValueInternalLink::itemPerLink;
++lastItemIndex ) // may be optimized with dicotomic search
{
if ( lastLink->items_[lastItemIndex].isItemAvailable () )
break;
}
BucketIndex lastUsedIndex = lastItemIndex - 1;
Value* valueToDelete = &link->items_[index];
Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
if ( valueToDelete != valueToPreserve )
valueToDelete->swap ( *valueToPreserve );
if ( lastUsedIndex == 0 ) // page is now empty
{
// remove it from bucket linked list and delete it.
ValueInternalLink* linkPreviousToLast = lastLink->previous_;
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
{
mapAllocator ()->releaseMapLink ( lastLink );
linkPreviousToLast->next_ = 0;
lastLink = linkPreviousToLast;
}
}
else
{
Value dummy;
valueToPreserve->swap ( dummy ); // restore deleted to default Value.
valueToPreserve->setItemUsed ( false );
}
--itemCount_;
}
ValueInternalLink*&
ValueInternalMap::getLastLinkInBucket ( BucketIndex bucketIndex )
{
if ( bucketIndex == bucketsSize_ - 1 )
return tailLink_;
ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
if ( !previous )
previous = &buckets_[bucketIndex];
return previous;
}
Value&
ValueInternalMap::setNewItem ( const char* key,
bool isStatic,
ValueInternalLink* link,
BucketIndex index )
{
char* duplicatedKey = valueAllocator ()->makeMemberName ( key );
++itemCount_;
link->keys_[index] = duplicatedKey;
link->items_[index].setItemUsed ();
link->items_[index].setMemberNameIsStatic ( isStatic );
return link->items_[index]; // items already default constructed.
}
Value&
ValueInternalMap::unsafeAdd ( const char* key,
bool isStatic,
HashKey hashedKey )
{
JSON_ASSERT_MESSAGE ( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
BucketIndex bucketIndex = hashedKey % bucketsSize_;
ValueInternalLink*& previousLink = getLastLinkInBucket ( bucketIndex );
ValueInternalLink* link = previousLink;
BucketIndex index;
for ( index = 0; index < ValueInternalLink::itemPerLink; ++index )
{
if ( link->items_[index].isItemAvailable () )
break;
}
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
{
ValueInternalLink* newLink = mapAllocator ()->allocateMapLink ();
index = 0;
link->next_ = newLink;
previousLink = newLink;
link = newLink;
}
return setNewItem ( key, isStatic, link, index );
}
ValueInternalMap::HashKey
ValueInternalMap::hash ( const char* key ) const
{
HashKey hash = 0;
while ( *key )
hash += *key++ * 37;
return hash;
}
int
ValueInternalMap::compare ( const ValueInternalMap& other ) const
{
int sizeDiff ( itemCount_ - other.itemCount_ );
if ( sizeDiff != 0 )
return sizeDiff;
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
IteratorState it;
IteratorState itEnd;
makeBeginIterator ( it );
makeEndIterator ( itEnd );
for ( ; !equals (it, itEnd); increment (it) )
{
if ( !other.find ( key ( it ) ) )
return 1;
}
// All keys are equals, let's compare values
makeBeginIterator ( it );
for ( ; !equals (it, itEnd); increment (it) )
{
const Value* otherValue = other.find ( key ( it ) );
int valueDiff = value (it).compare ( *otherValue );
if ( valueDiff != 0 )
return valueDiff;
}
return 0;
}
void
ValueInternalMap::makeBeginIterator ( IteratorState& it ) const
{
it.map_ = const_cast<ValueInternalMap*> ( this );
it.bucketIndex_ = 0;
it.itemIndex_ = 0;
it.link_ = buckets_;
}
void
ValueInternalMap::makeEndIterator ( IteratorState& it ) const
{
it.map_ = const_cast<ValueInternalMap*> ( this );
it.bucketIndex_ = bucketsSize_;
it.itemIndex_ = 0;
it.link_ = 0;
}
bool
ValueInternalMap::equals ( const IteratorState& x, const IteratorState& other )
{
return x.map_ == other.map_
&& x.bucketIndex_ == other.bucketIndex_
&& x.link_ == other.link_
&& x.itemIndex_ == other.itemIndex_;
}
void
ValueInternalMap::incrementBucket ( IteratorState& iterator )
{
++iterator.bucketIndex_;
JSON_ASSERT_MESSAGE ( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
"ValueInternalMap::increment(): attempting to iterate beyond end." );
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
iterator.link_ = 0;
else
iterator.link_ = & (iterator.map_->buckets_[iterator.bucketIndex_]);
iterator.itemIndex_ = 0;
}
void
ValueInternalMap::increment ( IteratorState& iterator )
{
JSON_ASSERT_MESSAGE ( iterator.map_, "Attempting to iterator using invalid iterator." );
++iterator.itemIndex_;
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
{
JSON_ASSERT_MESSAGE ( iterator.link_ != 0,
"ValueInternalMap::increment(): attempting to iterate beyond end." );
iterator.link_ = iterator.link_->next_;
if ( iterator.link_ == 0 )
incrementBucket ( iterator );
}
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable () )
{
incrementBucket ( iterator );
}
}
void
ValueInternalMap::decrement ( IteratorState& iterator )
{
if ( iterator.itemIndex_ == 0 )
{
JSON_ASSERT_MESSAGE ( iterator.map_, "Attempting to iterate using invalid iterator." );
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
{
JSON_ASSERT_MESSAGE ( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
-- (iterator.bucketIndex_);
}
iterator.link_ = iterator.link_->previous_;
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
}
}
const char*
ValueInternalMap::key ( const IteratorState& iterator )
{
JSON_ASSERT_MESSAGE ( iterator.link_, "Attempting to iterate using invalid iterator." );
return iterator.link_->keys_[iterator.itemIndex_];
}
const char*
ValueInternalMap::key ( const IteratorState& iterator, bool& isStatic )
{
JSON_ASSERT_MESSAGE ( iterator.link_, "Attempting to iterate using invalid iterator." );
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic ();
return iterator.link_->keys_[iterator.itemIndex_];
}
Value&
ValueInternalMap::value ( const IteratorState& iterator )
{
JSON_ASSERT_MESSAGE ( iterator.link_, "Attempting to iterate using invalid iterator." );
return iterator.link_->items_[iterator.itemIndex_];
}
int
ValueInternalMap::distance ( const IteratorState& x, const IteratorState& y )
{
int offset = 0;
IteratorState it = x;
while ( !equals ( it, y ) )
increment ( it );
return offset;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,196 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef CPPTL_JSON_READER_H_INCLUDED
# define CPPTL_JSON_READER_H_INCLUDED
namespace Json
{
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
*
*/
class JSON_API Reader
{
public:
typedef char Char;
typedef const Char* Location;
/** \brief Constructs a Reader allowing all features
* for parsing.
*/
Reader ();
/** \brief Constructs a Reader allowing the specified feature set
* for parsing.
*/
Reader ( const Features& features );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse ( const std::string& document,
Value& root,
bool collectComments = true );
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
* \param document UTF-8 encoded string containing the document to read.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
* \return \c true if the document was successfully parsed, \c false if an error occurred.
*/
bool parse ( const char* beginDoc, const char* endDoc,
Value& root,
bool collectComments = true );
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse ( std::istream& is,
Value& root,
bool collectComments = true );
/** \brief Returns a user friendly string that list errors in the parsed document.
* \return Formatted error message with the list of errors with their location in
* the parsed document. An empty string is returned if no error occurred
* during parsing.
*/
std::string getFormatedErrorMessages () const;
private:
enum TokenType
{
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token
{
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo
{
public:
Token token_;
std::string message_;
Location extra_;
};
typedef std::deque<ErrorInfo> Errors;
bool expectToken ( TokenType type, Token& token, const char* message );
bool readToken ( Token& token );
void skipSpaces ();
bool match ( Location pattern,
int patternLength );
bool readComment ();
bool readCStyleComment ();
bool readCppStyleComment ();
bool readString ();
void readNumber ();
bool readValue ();
bool readObject ( Token& token );
bool readArray ( Token& token );
bool decodeNumber ( Token& token );
bool decodeString ( Token& token );
bool decodeString ( Token& token, std::string& decoded );
bool decodeDouble ( Token& token );
bool decodeUnicodeCodePoint ( Token& token,
Location& current,
Location end,
unsigned int& unicode );
bool decodeUnicodeEscapeSequence ( Token& token,
Location& current,
Location end,
unsigned int& unicode );
bool addError ( const std::string& message,
Token& token,
Location extra = 0 );
bool recoverFromError ( TokenType skipUntilToken );
bool addErrorAndRecover ( const std::string& message,
Token& token,
TokenType skipUntilToken );
void skipUntilSpace ();
Value& currentValue ();
Char getNextChar ();
void getLocationLineAndColumn ( Location location,
int& line,
int& column ) const;
std::string getLocationLineAndColumn ( Location location ) const;
void addComment ( Location begin,
Location end,
CommentPlacement placement );
void skipCommentTokens ( Token& token );
typedef std::stack<Value*> Nodes;
Nodes nodes_;
Errors errors_;
std::string document_;
Location begin_;
Location end_;
Location current_;
Location lastValueEnd_;
Value* lastValue_;
std::string commentsBefore_;
Features features_;
bool collectComments_;
};
/** \brief Read from 'sin' into 'root'.
Always keep comments from the input JSON.
This can be used to read a file into a particular sub-object.
For example:
\code
Json::Value root;
cin >> root["dir"]["file"];
cout << root;
\endcode
Result:
\verbatim
{
"dir": {
"file": {
// The input stream JSON would be nested here.
}
}
}
\endverbatim
\throw std::exception on parse error.
\see Json::operator<<()
*/
std::istream& operator>> ( std::istream&, Value& );
} // namespace Json
#endif // CPPTL_JSON_READER_H_INCLUDED

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,329 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// included by json_value.cpp
// everything is within Json namespace
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIteratorBase
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIteratorBase::ValueIteratorBase ()
#ifndef JSON_VALUE_USE_INTERNAL_MAP
: current_ ()
, isNull_ ( true )
{
}
#else
:
isArray_ ( true )
, isNull_ ( true )
{
iterator_.array_ = ValueInternalArray::IteratorState ();
}
#endif
#ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueIteratorBase::ValueIteratorBase ( const Value::ObjectValues::iterator& current )
: current_ ( current )
, isNull_ ( false )
{
}
#else
ValueIteratorBase::ValueIteratorBase ( const ValueInternalArray::IteratorState& state )
: isArray_ ( true )
{
iterator_.array_ = state;
}
ValueIteratorBase::ValueIteratorBase ( const ValueInternalMap::IteratorState& state )
: isArray_ ( false )
{
iterator_.map_ = state;
}
#endif
Value&
ValueIteratorBase::deref () const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
return current_->second;
#else
if ( isArray_ )
return ValueInternalArray::dereference ( iterator_.array_ );
return ValueInternalMap::value ( iterator_.map_ );
#endif
}
void
ValueIteratorBase::increment ()
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
++current_;
#else
if ( isArray_ )
ValueInternalArray::increment ( iterator_.array_ );
ValueInternalMap::increment ( iterator_.map_ );
#endif
}
void
ValueIteratorBase::decrement ()
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
--current_;
#else
if ( isArray_ )
ValueInternalArray::decrement ( iterator_.array_ );
ValueInternalMap::decrement ( iterator_.map_ );
#endif
}
ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance ( const SelfType& other ) const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
# ifdef JSON_USE_CPPTL_SMALLMAP
return current_ - other.current_;
# else
// Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default
// std::map::iterator. As begin() and end() are two instance
// of the default std::map::iterator, they can not be compared.
// To allow this, we handle this comparison specifically.
if ( isNull_ && other.isNull_ )
{
return 0;
}
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
// which is the one used by default).
// Using a portable hand-made version for non random iterator instead:
// return difference_type( std::distance( current_, other.current_ ) );
difference_type myDistance = 0;
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
{
++myDistance;
}
return myDistance;
# endif
#else
if ( isArray_ )
return ValueInternalArray::distance ( iterator_.array_, other.iterator_.array_ );
return ValueInternalMap::distance ( iterator_.map_, other.iterator_.map_ );
#endif
}
bool
ValueIteratorBase::isEqual ( const SelfType& other ) const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
if ( isNull_ )
{
return other.isNull_;
}
return current_ == other.current_;
#else
if ( isArray_ )
return ValueInternalArray::equals ( iterator_.array_, other.iterator_.array_ );
return ValueInternalMap::equals ( iterator_.map_, other.iterator_.map_ );
#endif
}
void
ValueIteratorBase::copy ( const SelfType& other )
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
current_ = other.current_;
#else
if ( isArray_ )
iterator_.array_ = other.iterator_.array_;
iterator_.map_ = other.iterator_.map_;
#endif
}
Value
ValueIteratorBase::key () const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
const Value::CZString czstring = (*current_).first;
if ( czstring.c_str () )
{
if ( czstring.isStaticString () )
return Value ( StaticString ( czstring.c_str () ) );
return Value ( czstring.c_str () );
}
return Value ( czstring.index () );
#else
if ( isArray_ )
return Value ( ValueInternalArray::indexOf ( iterator_.array_ ) );
bool isStatic;
const char* memberName = ValueInternalMap::key ( iterator_.map_, isStatic );
if ( isStatic )
return Value ( StaticString ( memberName ) );
return Value ( memberName );
#endif
}
UInt
ValueIteratorBase::index () const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
const Value::CZString czstring = (*current_).first;
if ( !czstring.c_str () )
return czstring.index ();
return Value::UInt ( -1 );
#else
if ( isArray_ )
return Value::UInt ( ValueInternalArray::indexOf ( iterator_.array_ ) );
return Value::UInt ( -1 );
#endif
}
const char*
ValueIteratorBase::memberName () const
{
#ifndef JSON_VALUE_USE_INTERNAL_MAP
const char* name = (*current_).first.c_str ();
return name ? name : "";
#else
if ( !isArray_ )
return ValueInternalMap::key ( iterator_.map_ );
return "";
#endif
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueConstIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator ()
{
}
#ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueConstIterator::ValueConstIterator ( const Value::ObjectValues::iterator& current )
: ValueIteratorBase ( current )
{
}
#else
ValueConstIterator::ValueConstIterator ( const ValueInternalArray::IteratorState& state )
: ValueIteratorBase ( state )
{
}
ValueConstIterator::ValueConstIterator ( const ValueInternalMap::IteratorState& state )
: ValueIteratorBase ( state )
{
}
#endif
ValueConstIterator&
ValueConstIterator::operator = ( const ValueIteratorBase& other )
{
copy ( other );
return *this;
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator ()
{
}
#ifndef JSON_VALUE_USE_INTERNAL_MAP
ValueIterator::ValueIterator ( const Value::ObjectValues::iterator& current )
: ValueIteratorBase ( current )
{
}
#else
ValueIterator::ValueIterator ( const ValueInternalArray::IteratorState& state )
: ValueIteratorBase ( state )
{
}
ValueIterator::ValueIterator ( const ValueInternalMap::IteratorState& state )
: ValueIteratorBase ( state )
{
}
#endif
ValueIterator::ValueIterator ( const ValueConstIterator& other )
: ValueIteratorBase ( other )
{
}
ValueIterator::ValueIterator ( const ValueIterator& other )
: ValueIteratorBase ( other )
{
}
ValueIterator&
ValueIterator::operator = ( const SelfType& other )
{
copy ( other );
return *this;
}

View File

@@ -0,0 +1,931 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace Json
{
static bool isControlCharacter (char ch)
{
return ch > 0 && ch <= 0x1F;
}
static bool containsControlCharacter ( const char* str )
{
while ( *str )
{
if ( isControlCharacter ( * (str++) ) )
return true;
}
return false;
}
static void uintToString ( unsigned int value,
char*& current )
{
*--current = 0;
do
{
*--current = (value % 10) + '0';
value /= 10;
}
while ( value != 0 );
}
std::string valueToString ( Int value )
{
char buffer[32];
char* current = buffer + sizeof (buffer);
bool isNegative = value < 0;
if ( isNegative )
value = -value;
uintToString ( UInt (value), current );
if ( isNegative )
*--current = '-';
assert ( current >= buffer );
return current;
}
std::string valueToString ( UInt value )
{
char buffer[32];
char* current = buffer + sizeof (buffer);
uintToString ( value, current );
assert ( current >= buffer );
return current;
}
std::string valueToString ( double value )
{
char buffer[32];
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
sprintf_s (buffer, sizeof (buffer), "%#f", value);
#else
sprintf (buffer, "%#f", value);
#endif
char* ch = buffer + strlen (buffer) - 1;
if (*ch != '0') return buffer; // nothing to truncate, so save time
while (ch > buffer && *ch == '0')
{
--ch;
}
char* last_nonzero = ch;
while (ch >= buffer)
{
switch (*ch)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
--ch;
continue;
case '.':
// Truncate zeroes to save bytes in output, but keep one.
* (last_nonzero + 2) = '\0';
return buffer;
default:
return buffer;
}
}
return buffer;
}
std::string valueToString ( bool value )
{
return value ? "true" : "false";
}
std::string valueToQuotedString ( const char* value )
{
// Not sure how to handle unicode...
if (strpbrk (value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter ( value ))
return std::string ("\"") + value + "\"";
// We have to walk value and escape any special characters.
// Appending to std::string is not efficient, but this should be rare.
// (Note: forward slashes are *not* rare, but I am not escaping them.)
unsigned maxsize = strlen (value) * 2 + 3; // allescaped+quotes+NULL
std::string result;
result.reserve (maxsize); // to avoid lots of mallocs
result += "\"";
for (const char* c = value; *c != 0; ++c)
{
switch (*c)
{
case '\"':
result += "\\\"";
break;
case '\\':
result += "\\\\";
break;
case '\b':
result += "\\b";
break;
case '\f':
result += "\\f";
break;
case '\n':
result += "\\n";
break;
case '\r':
result += "\\r";
break;
case '\t':
result += "\\t";
break;
//case '/':
// Even though \/ is considered a legal escape in JSON, a bare
// slash is also legal, so I see no reason to escape it.
// (I hope I am not misunderstanding something.
// blep notes: actually escaping \/ may be useful in javascript to avoid </
// sequence.
// Should add a flag to allow this compatibility mode and prevent this
// sequence from occurring.
default:
if ( isControlCharacter ( *c ) )
{
std::ostringstream oss;
oss << "\\u" << std::hex << std::uppercase << std::setfill ('0') << std::setw (4) << static_cast<int> (*c);
result += oss.str ();
}
else
{
result += *c;
}
break;
}
}
result += "\"";
return result;
}
// Class Writer
// //////////////////////////////////////////////////////////////////
Writer::~Writer ()
{
}
// Class FastWriter
// //////////////////////////////////////////////////////////////////
FastWriter::FastWriter ()
: yamlCompatiblityEnabled_ ( false )
{
}
void
FastWriter::enableYAMLCompatibility ()
{
yamlCompatiblityEnabled_ = true;
}
std::string
FastWriter::write ( const Value& root )
{
document_ = "";
writeValue ( root );
document_ += "\n";
return document_;
}
void
FastWriter::writeValue ( const Value& value )
{
switch ( value.type () )
{
case nullValue:
document_ += "null";
break;
case intValue:
document_ += valueToString ( value.asInt () );
break;
case uintValue:
document_ += valueToString ( value.asUInt () );
break;
case realValue:
document_ += valueToString ( value.asDouble () );
break;
case stringValue:
document_ += valueToQuotedString ( value.asCString () );
break;
case booleanValue:
document_ += valueToString ( value.asBool () );
break;
case arrayValue:
{
document_ += "[";
int size = value.size ();
for ( int index = 0; index < size; ++index )
{
if ( index > 0 )
document_ += ",";
writeValue ( value[index] );
}
document_ += "]";
}
break;
case objectValue:
{
Value::Members members ( value.getMemberNames () );
document_ += "{";
for ( Value::Members::iterator it = members.begin ();
it != members.end ();
++it )
{
const std::string& name = *it;
if ( it != members.begin () )
document_ += ",";
document_ += valueToQuotedString ( name.c_str () );
document_ += yamlCompatiblityEnabled_ ? ": "
: ":";
writeValue ( value[name] );
}
document_ += "}";
}
break;
}
}
// Class StyledWriter
// //////////////////////////////////////////////////////////////////
StyledWriter::StyledWriter ()
: rightMargin_ ( 74 )
, indentSize_ ( 3 )
{
}
std::string
StyledWriter::write ( const Value& root )
{
document_ = "";
addChildValues_ = false;
indentString_ = "";
writeCommentBeforeValue ( root );
writeValue ( root );
writeCommentAfterValueOnSameLine ( root );
document_ += "\n";
return document_;
}
void
StyledWriter::writeValue ( const Value& value )
{
switch ( value.type () )
{
case nullValue:
pushValue ( "null" );
break;
case intValue:
pushValue ( valueToString ( value.asInt () ) );
break;
case uintValue:
pushValue ( valueToString ( value.asUInt () ) );
break;
case realValue:
pushValue ( valueToString ( value.asDouble () ) );
break;
case stringValue:
pushValue ( valueToQuotedString ( value.asCString () ) );
break;
case booleanValue:
pushValue ( valueToString ( value.asBool () ) );
break;
case arrayValue:
writeArrayValue ( value);
break;
case objectValue:
{
Value::Members members ( value.getMemberNames () );
if ( members.empty () )
pushValue ( "{}" );
else
{
writeWithIndent ( "{" );
indent ();
Value::Members::iterator it = members.begin ();
while ( true )
{
const std::string& name = *it;
const Value& childValue = value[name];
writeCommentBeforeValue ( childValue );
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
document_ += " : ";
writeValue ( childValue );
if ( ++it == members.end () )
{
writeCommentAfterValueOnSameLine ( childValue );
break;
}
document_ += ",";
writeCommentAfterValueOnSameLine ( childValue );
}
unindent ();
writeWithIndent ( "}" );
}
}
break;
}
}
void
StyledWriter::writeArrayValue ( const Value& value )
{
unsigned size = value.size ();
if ( size == 0 )
pushValue ( "[]" );
else
{
bool isArrayMultiLine = isMultineArray ( value );
if ( isArrayMultiLine )
{
writeWithIndent ( "[" );
indent ();
bool hasChildValue = !childValues_.empty ();
unsigned index = 0;
while ( true )
{
const Value& childValue = value[index];
writeCommentBeforeValue ( childValue );
if ( hasChildValue )
writeWithIndent ( childValues_[index] );
else
{
writeIndent ();
writeValue ( childValue );
}
if ( ++index == size )
{
writeCommentAfterValueOnSameLine ( childValue );
break;
}
document_ += ",";
writeCommentAfterValueOnSameLine ( childValue );
}
unindent ();
writeWithIndent ( "]" );
}
else // output on a single line
{
assert ( childValues_.size () == size );
document_ += "[ ";
for ( unsigned index = 0; index < size; ++index )
{
if ( index > 0 )
document_ += ", ";
document_ += childValues_[index];
}
document_ += " ]";
}
}
}
bool
StyledWriter::isMultineArray ( const Value& value )
{
int size = value.size ();
bool isMultiLine = size * 3 >= rightMargin_ ;
childValues_.clear ();
for ( int index = 0; index < size && !isMultiLine; ++index )
{
const Value& childValue = value[index];
isMultiLine = isMultiLine ||
( (childValue.isArray () || childValue.isObject ()) &&
childValue.size () > 0 );
}
if ( !isMultiLine ) // check if line length > max line length
{
childValues_.reserve ( size );
addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for ( int index = 0; index < size && !isMultiLine; ++index )
{
writeValue ( value[index] );
lineLength += int ( childValues_[index].length () );
isMultiLine = isMultiLine && hasCommentForValue ( value[index] );
}
addChildValues_ = false;
isMultiLine = isMultiLine || lineLength >= rightMargin_;
}
return isMultiLine;
}
void
StyledWriter::pushValue ( const std::string& value )
{
if ( addChildValues_ )
childValues_.push_back ( value );
else
document_ += value;
}
void
StyledWriter::writeIndent ()
{
if ( !document_.empty () )
{
char last = document_[document_.length () - 1];
if ( last == ' ' ) // already indented
return;
if ( last != '\n' ) // Comments may add new-line
document_ += '\n';
}
document_ += indentString_;
}
void
StyledWriter::writeWithIndent ( const std::string& value )
{
writeIndent ();
document_ += value;
}
void
StyledWriter::indent ()
{
indentString_ += std::string ( indentSize_, ' ' );
}
void
StyledWriter::unindent ()
{
assert ( int (indentString_.size ()) >= indentSize_ );
indentString_.resize ( indentString_.size () - indentSize_ );
}
void
StyledWriter::writeCommentBeforeValue ( const Value& root )
{
if ( !root.hasComment ( commentBefore ) )
return;
document_ += normalizeEOL ( root.getComment ( commentBefore ) );
document_ += "\n";
}
void
StyledWriter::writeCommentAfterValueOnSameLine ( const Value& root )
{
if ( root.hasComment ( commentAfterOnSameLine ) )
document_ += " " + normalizeEOL ( root.getComment ( commentAfterOnSameLine ) );
if ( root.hasComment ( commentAfter ) )
{
document_ += "\n";
document_ += normalizeEOL ( root.getComment ( commentAfter ) );
document_ += "\n";
}
}
bool
StyledWriter::hasCommentForValue ( const Value& value )
{
return value.hasComment ( commentBefore )
|| value.hasComment ( commentAfterOnSameLine )
|| value.hasComment ( commentAfter );
}
std::string
StyledWriter::normalizeEOL ( const std::string& text )
{
std::string normalized;
normalized.reserve ( text.length () );
const char* begin = text.c_str ();
const char* end = begin + text.length ();
const char* current = begin;
while ( current != end )
{
char c = *current++;
if ( c == '\r' ) // mac or dos EOL
{
if ( *current == '\n' ) // convert dos EOL
++current;
normalized += '\n';
}
else // handle unix EOL & other char
normalized += c;
}
return normalized;
}
// Class StyledStreamWriter
// //////////////////////////////////////////////////////////////////
StyledStreamWriter::StyledStreamWriter ( std::string indentation )
: document_ (NULL)
, rightMargin_ ( 74 )
, indentation_ ( indentation )
{
}
void
StyledStreamWriter::write ( std::ostream& out, const Value& root )
{
document_ = &out;
addChildValues_ = false;
indentString_ = "";
writeCommentBeforeValue ( root );
writeValue ( root );
writeCommentAfterValueOnSameLine ( root );
*document_ << "\n";
document_ = NULL; // Forget the stream, for safety.
}
void
StyledStreamWriter::writeValue ( const Value& value )
{
switch ( value.type () )
{
case nullValue:
pushValue ( "null" );
break;
case intValue:
pushValue ( valueToString ( value.asInt () ) );
break;
case uintValue:
pushValue ( valueToString ( value.asUInt () ) );
break;
case realValue:
pushValue ( valueToString ( value.asDouble () ) );
break;
case stringValue:
pushValue ( valueToQuotedString ( value.asCString () ) );
break;
case booleanValue:
pushValue ( valueToString ( value.asBool () ) );
break;
case arrayValue:
writeArrayValue ( value);
break;
case objectValue:
{
Value::Members members ( value.getMemberNames () );
if ( members.empty () )
pushValue ( "{}" );
else
{
writeWithIndent ( "{" );
indent ();
Value::Members::iterator it = members.begin ();
while ( true )
{
const std::string& name = *it;
const Value& childValue = value[name];
writeCommentBeforeValue ( childValue );
writeWithIndent ( valueToQuotedString ( name.c_str () ) );
*document_ << " : ";
writeValue ( childValue );
if ( ++it == members.end () )
{
writeCommentAfterValueOnSameLine ( childValue );
break;
}
*document_ << ",";
writeCommentAfterValueOnSameLine ( childValue );
}
unindent ();
writeWithIndent ( "}" );
}
}
break;
}
}
void
StyledStreamWriter::writeArrayValue ( const Value& value )
{
unsigned size = value.size ();
if ( size == 0 )
pushValue ( "[]" );
else
{
bool isArrayMultiLine = isMultineArray ( value );
if ( isArrayMultiLine )
{
writeWithIndent ( "[" );
indent ();
bool hasChildValue = !childValues_.empty ();
unsigned index = 0;
while ( true )
{
const Value& childValue = value[index];
writeCommentBeforeValue ( childValue );
if ( hasChildValue )
writeWithIndent ( childValues_[index] );
else
{
writeIndent ();
writeValue ( childValue );
}
if ( ++index == size )
{
writeCommentAfterValueOnSameLine ( childValue );
break;
}
*document_ << ",";
writeCommentAfterValueOnSameLine ( childValue );
}
unindent ();
writeWithIndent ( "]" );
}
else // output on a single line
{
assert ( childValues_.size () == size );
*document_ << "[ ";
for ( unsigned index = 0; index < size; ++index )
{
if ( index > 0 )
*document_ << ", ";
*document_ << childValues_[index];
}
*document_ << " ]";
}
}
}
bool
StyledStreamWriter::isMultineArray ( const Value& value )
{
int size = value.size ();
bool isMultiLine = size * 3 >= rightMargin_ ;
childValues_.clear ();
for ( int index = 0; index < size && !isMultiLine; ++index )
{
const Value& childValue = value[index];
isMultiLine = isMultiLine ||
( (childValue.isArray () || childValue.isObject ()) &&
childValue.size () > 0 );
}
if ( !isMultiLine ) // check if line length > max line length
{
childValues_.reserve ( size );
addChildValues_ = true;
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
for ( int index = 0; index < size && !isMultiLine; ++index )
{
writeValue ( value[index] );
lineLength += int ( childValues_[index].length () );
isMultiLine = isMultiLine && hasCommentForValue ( value[index] );
}
addChildValues_ = false;
isMultiLine = isMultiLine || lineLength >= rightMargin_;
}
return isMultiLine;
}
void
StyledStreamWriter::pushValue ( const std::string& value )
{
if ( addChildValues_ )
childValues_.push_back ( value );
else
*document_ << value;
}
void
StyledStreamWriter::writeIndent ()
{
/*
Some comments in this method would have been nice. ;-)
if ( !document_.empty() )
{
char last = document_[document_.length()-1];
if ( last == ' ' ) // already indented
return;
if ( last != '\n' ) // Comments may add new-line
*document_ << '\n';
}
*/
*document_ << '\n' << indentString_;
}
void
StyledStreamWriter::writeWithIndent ( const std::string& value )
{
writeIndent ();
*document_ << value;
}
void
StyledStreamWriter::indent ()
{
indentString_ += indentation_;
}
void
StyledStreamWriter::unindent ()
{
assert ( indentString_.size () >= indentation_.size () );
indentString_.resize ( indentString_.size () - indentation_.size () );
}
void
StyledStreamWriter::writeCommentBeforeValue ( const Value& root )
{
if ( !root.hasComment ( commentBefore ) )
return;
*document_ << normalizeEOL ( root.getComment ( commentBefore ) );
*document_ << "\n";
}
void
StyledStreamWriter::writeCommentAfterValueOnSameLine ( const Value& root )
{
if ( root.hasComment ( commentAfterOnSameLine ) )
*document_ << " " + normalizeEOL ( root.getComment ( commentAfterOnSameLine ) );
if ( root.hasComment ( commentAfter ) )
{
*document_ << "\n";
*document_ << normalizeEOL ( root.getComment ( commentAfter ) );
*document_ << "\n";
}
}
bool
StyledStreamWriter::hasCommentForValue ( const Value& value )
{
return value.hasComment ( commentBefore )
|| value.hasComment ( commentAfterOnSameLine )
|| value.hasComment ( commentAfter );
}
std::string
StyledStreamWriter::normalizeEOL ( const std::string& text )
{
std::string normalized;
normalized.reserve ( text.length () );
const char* begin = text.c_str ();
const char* end = begin + text.length ();
const char* current = begin;
while ( current != end )
{
char c = *current++;
if ( c == '\r' ) // mac or dos EOL
{
if ( *current == '\n' ) // convert dos EOL
++current;
normalized += '\n';
}
else // handle unix EOL & other char
normalized += c;
}
return normalized;
}
std::ostream& operator<< ( std::ostream& sout, const Value& root )
{
Json::StyledStreamWriter writer;
writer.write (sout, root);
return sout;
}
} // namespace Json

View File

@@ -0,0 +1,176 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef JSON_WRITER_H_INCLUDED
#define JSON_WRITER_H_INCLUDED
namespace Json
{
class Value;
/** \brief Abstract class for writers.
*/
class JSON_API Writer
{
public:
virtual ~Writer ();
virtual std::string write ( const Value& root ) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human' consumption,
* but may be usefull to support feature such as RPC where bandwith is limited.
* \sa Reader, Value
*/
class JSON_API FastWriter : public Writer
{
public:
FastWriter ();
virtual ~FastWriter () {}
void enableYAMLCompatibility ();
public: // overridden from Writer
virtual std::string write ( const Value& root );
private:
void writeValue ( const Value& value );
std::string document_;
bool yamlCompatiblityEnabled_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledWriter: public Writer
{
public:
StyledWriter ();
virtual ~StyledWriter () {}
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
virtual std::string write ( const Value& root );
private:
void writeValue ( const Value& value );
void writeArrayValue ( const Value& value );
bool isMultineArray ( const Value& value );
void pushValue ( const std::string& value );
void writeIndent ();
void writeWithIndent ( const std::string& value );
void indent ();
void unindent ();
void writeCommentBeforeValue ( const Value& root );
void writeCommentAfterValueOnSameLine ( const Value& root );
bool hasCommentForValue ( const Value& value );
static std::string normalizeEOL ( const std::string& text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::string document_;
std::string indentString_;
int rightMargin_;
int indentSize_;
bool addChildValues_;
};
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value types,
* and all the values fit on one lines, then print the array on a single line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their #CommentPlacement.
*
* \param indentation Each level will be indented by this amount extra.
* \sa Reader, Value, Value::setComment()
*/
class JSON_API StyledStreamWriter
{
public:
StyledStreamWriter ( std::string indentation = "\t" );
~StyledStreamWriter () {}
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not return a value.
*/
void write ( std::ostream& out, const Value& root );
private:
void writeValue ( const Value& value );
void writeArrayValue ( const Value& value );
bool isMultineArray ( const Value& value );
void pushValue ( const std::string& value );
void writeIndent ();
void writeWithIndent ( const std::string& value );
void indent ();
void unindent ();
void writeCommentBeforeValue ( const Value& root );
void writeCommentAfterValueOnSameLine ( const Value& root );
bool hasCommentForValue ( const Value& value );
static std::string normalizeEOL ( const std::string& text );
typedef std::vector<std::string> ChildValues;
ChildValues childValues_;
std::ostream* document_;
std::string indentString_;
int rightMargin_;
std::string indentation_;
bool addChildValues_;
};
std::string JSON_API valueToString ( Int value );
std::string JSON_API valueToString ( UInt value );
std::string JSON_API valueToString ( double value );
std::string JSON_API valueToString ( bool value );
std::string JSON_API valueToQuotedString ( const char* value );
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
std::ostream& operator<< ( std::ostream&, const Value& root );
} // namespace Json
#endif // JSON_WRITER_H_INCLUDED

View File

@@ -0,0 +1 @@
0.5.0

View File

@@ -0,0 +1,99 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/** Add this to get the @ref ripple_basics module.
@file ripple_basics.cpp
@ingroup ripple_basics
*/
#include "BeastConfig.h"
#include "ripple_basics.h"
//------------------------------------------------------------------------------
// For Sustain Linux variants
//
// VFALCO TODO Rewrite Sustain to use beast::Process
#ifdef __linux__
#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#endif
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/wait.h>
#endif
//------------------------------------------------------------------------------
// For json/
//
#ifdef JSON_USE_CPPTL
# include <cpptl/conststring.h>
#endif
#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
#include "json/json_batchallocator.h"
#endif
#define JSON_ASSERT_UNREACHABLE assert( false )
#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );
//------------------------------------------------------------------------------
// For random numbers
//
// VFALCO TODO Replace OpenSSL randomness with a dependency-free implementation
// Perhaps Schneier's Fortuna or a variant. Abstract the collection of
// entropy and provide OS-specific implementation. We can re-use the
// BearShare source code for this.
//
// Add Random number generation to beast
//
#include <openssl/rand.h> // Because of ripple_RandomNumbers.cpp
#ifdef BEAST_WIN32
# include <windows.h> // for ripple_RandomNumbers.cpp
# include <wincrypt.h> // for ripple_RandomNumbers.cpp
# include <Winsock2.h> // for ripple_ByteOrder.cpp
// <Winsock2.h> defines 'max' and does other stupid things
# ifdef max
# undef max
# endif
#endif
//------------------------------------------------------------------------------
namespace ripple
{
#include "containers/ripple_RangeSet.cpp"
#include "containers/ripple_TaggedCache.cpp"
#include "json/json_reader.cpp"
#include "json/json_value.cpp"
#include "json/json_writer.cpp"
#include "utility/ripple_Log.cpp"
#include "utility/ripple_LogFile.cpp"
#include "utility/ripple_ByteOrder.cpp"
#include "utility/ripple_CountedObject.cpp"
#include "utility/ripple_DiffieHellmanUtil.cpp"
#include "utility/ripple_IniFile.cpp"
#include "utility/ripple_StringUtilities.cpp"
#include "utility/ripple_Sustain.cpp"
#include "utility/ripple_ThreadName.cpp"
#include "utility/ripple_Time.cpp"
#include "utility/ripple_UptimeTimer.cpp"
#include "utility/ripple_RandomNumbers.cpp" // has Win32/Posix dependencies
#include "types/ripple_UInt256.cpp"
}

View File

@@ -0,0 +1,130 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/** Include this to get the @ref ripple_basics module.
@file ripple_basics.h
@ingroup ripple_basics
*/
/** Basic classes.
This module provides utility classes and types used in the Ripple system.
@defgroup ripple_basics
*/
#ifndef RIPPLE_BASICS_RIPPLEHEADER
#define RIPPLE_BASICS_RIPPLEHEADER
#include "system/ripple_StandardIncludes.h"
//------------------------------------------------------------------------------
// For json/
//
// VFALCO TODO Clean up these one-offs
#include "json/json_config.h" // Needed before these cpptl includes
#ifndef JSON_USE_CPPTL_SMALLMAP
# include <map>
#else
# include <cpptl/smallmap.h>
#endif
#ifdef JSON_USE_CPPTL
# include <cpptl/forwards.h>
#endif
//------------------------------------------------------------------------------
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
#include "system/ripple_BoostIncludes.h"
#include "system/ripple_OpenSSLIncludes.h"
#include "beast/modules/beast_crypto/beast_crypto.h"
#ifndef RIPPLE_TRACK_MUTEXES
# define RIPPLE_TRACK_MUTEXES 0
#endif
//------------------------------------------------------------------------------
// From
// http://stackoverflow.com/questions/4682343/how-to-resolve-conflict-between-boostshared-ptr-and-using-stdshared-ptr
//
#if __cplusplus > 201100L
namespace boost
{
template <class T>
const T* get_pointer (std::shared_ptr<T> const& ptr)
{
return ptr.get();
}
template <class T>
T* get_pointer (std::shared_ptr<T>& ptr)
{
return ptr.get();
}
}
#endif
//------------------------------------------------------------------------------
// ByteOrder
#if BEAST_WIN32
// (nothing)
#elif __APPLE__
# include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
#endif
#include "beast/modules/beast_core/beast_core.h"
namespace ripple
{
using namespace beast;
#include "types/ripple_BasicTypes.h"
#include "utility/ripple_LogFile.h"
#include "utility/ripple_Log.h" // Needed by others
#include "utility/ripple_ByteOrder.h"
#include "utility/ripple_CountedObject.h"
#include "utility/ripple_DiffieHellmanUtil.h"
#include "utility/ripple_IniFile.h"
#include "utility/ripple_PlatformMacros.h"
#include "utility/ripple_RandomNumbers.h"
#include "utility/ripple_StringUtilities.h"
#include "utility/ripple_Sustain.h"
#include "utility/ripple_ThreadName.h"
#include "utility/ripple_Time.h"
#include "utility/ripple_LoggedTimings.h"
#include "utility/ripple_UptimeTimer.h"
#include "types/ripple_UInt256.h"
#include "utility/ripple_HashUtilities.h" // requires UInt256
#include "types/ripple_HashMaps.h"
#include "containers/ripple_KeyCache.h"
#include "containers/ripple_RangeSet.h"
#include "containers/ripple_SecureAllocator.h"
#include "containers/ripple_TaggedCache.h"
#include "json/json_forwards.h"
#include "json/json_features.h"
#include "json/json_value.h"
#include "json/json_reader.h"
#include "json/json_writer.h"
}
#endif

View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_BOOSTINCLUDES_RIPPLEHEADER
#define RIPPLE_BOOSTINCLUDES_RIPPLEHEADER
// All Boost includes used throughout Ripple.
//
// This shows all the dependencies in one place. Please do not add
// boost includes anywhere else in the source code. If possible, do
// not add any more includes.
//
// A long term goal is to reduce and hopefully eliminate the usage of boost.
//
#include <boost/version.hpp>
#if BOOST_VERSION < 104700
# error Ripple requires Boost version 1.47 or later
#endif
// This is better than setting it in some Makefile or IDE Project file.
//
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/function.hpp>
#include <boost/functional/hash.hpp>
#include <boost/make_shared.hpp>
#include <boost/ptr_container/ptr_vector.hpp> // VFALCO NOTE this looks like junk
#include <boost/ref.hpp>
#include <boost/regex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/unordered_map.hpp>
#endif

View File

@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_OPENSSLINCLUDES_RIPPLEHEADER
#define RIPPLE_OPENSSLINCLUDES_RIPPLEHEADER
// All OpenSSL includes we need
#include <openssl/bn.h>
#include <openssl/buffer.h>
#include <openssl/dh.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/obj_mac.h>
#include <openssl/ripemd.h>
#include <openssl/sha.h>
#endif

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_STANDARDINCLUDES_RIPPLEHEADER
#define RIPPLE_STANDARDINCLUDES_RIPPLEHEADER
// All required Standard C++ Library includes
#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <string>
#include <vector>
#endif

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_BASICTYPES_H
#define RIPPLE_BASICTYPES_H
/** Storage for linear binary data.
Blocks of binary data appear often in various idioms and structures.
*/
typedef std::vector <unsigned char> Blob;
/** Synchronization primitives.
This lets us switch between tracked and untracked mutexes.
*/
#if RIPPLE_TRACK_MUTEXES
typedef TrackedMutexType <boost::mutex> RippleMutex;
typedef TrackedMutexType <boost::recursive_mutex> RippleRecursiveMutex;
#else
typedef UntrackedMutexType <boost::mutex> RippleMutex;
typedef UntrackedMutexType <boost::recursive_mutex> RippleRecursiveMutex;
#endif
typedef boost::recursive_mutex DeprecatedRecursiveMutex;
typedef DeprecatedRecursiveMutex::scoped_lock DeprecatedScopedLock;
//------------------------------------------------------------------------------
/** A container used to hold a public key in binary format. */
typedef UnsignedInteger <33> RipplePublicKey;
/** A container holding the hash of a public key in binary format. */
typedef UnsignedInteger <20> RipplePublicKeyHash;
#endif

View File

@@ -0,0 +1,119 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_HASHMAPS_H
#define RIPPLE_HASHMAPS_H
/** Management helper of hash functions used in hash map containers.
The nonce is used to prevent attackers from feeding carefully crafted
inputs in order to cause denegerate hash map data structures. This is
done by seeding the hashing function with a random number generated
at program startup.
*/
class HashMaps : public Uncopyable
{
public:
/** Golden ratio constant used in hashing functions.
The magic number is supposed to be 32 random bits, where each is
equally likely to be 0 or 1, and with no simple correlation between
the bits. A common way to find a string of such bits is to use the
binary expansion of an irrational number; in this case, that number
is the reciprocal of the golden ratio:
@code
phi = (1 + sqrt(5)) / 2
2^32 / phi = 0x9e3779b9
@endcode
References:
http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
http://burtleburtle.net/bob/hash/doobs.html
*/
static std::size_t const goldenRatio = 0x9e3779b9;
/** Retrieve the singleton.
@return The global instance of the singleton.
*/
static HashMaps const& getInstance ()
{
static HashMaps instance;
return instance;
}
/** Instantiate a nonce for a type.
@note This may be used during program initialization
to avoid concurrency issues. Only C++11 provides thread
safety guarantees for function-local static objects.
*/
template <class T>
void initializeNonce () const
{
getNonceHolder <T> ();
}
/** Get the nonce for a type.
The nonces are generated when they are first used.
This code is thread safe.
*/
template <class T>
T getNonce () const
{
return getNonceHolder <T> ().getNonce ();
}
private:
HashMaps ()
{
}
~HashMaps ()
{
}
/** Creates and holds a nonce for a type.
*/
template <class T>
class NonceHolder
{
public:
NonceHolder ()
{
// VFALCO NOTE this can be dangerous if T is an object type
RandomNumbers::getInstance ().fill (&m_nonce);
}
inline T getNonce () const
{
return m_nonce;
}
private:
T m_nonce;
};
/** Retrieve the nonce holder for a type.
@note This routine will be called concurrently.
*/
template <class T>
NonceHolder <T> const& getNonceHolder () const
{
static NonceHolder <T> nonceHolder;
return nonceHolder;
}
};
#endif

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
std::size_t hash_value (uint256 const& u)
{
std::size_t seed = HashMaps::getInstance ().getNonce <size_t> ();
return u.hash_combine (seed);
}
std::size_t hash_value (const uint160& u)
{
std::size_t seed = HashMaps::getInstance ().getNonce <size_t> ();
return u.hash_combine (seed);
}

View File

@@ -0,0 +1,942 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef RIPPLE_UINT256_H
#define RIPPLE_UINT256_H
// These classes all store their values internally
// in big-endian form
inline int Testuint256AdHoc (std::vector<std::string> vArg);
// We have to keep a separate base class without constructors
// so the compiler will let us use it in a union
//
// VFALCO NOTE This class produces undefined behavior when
// BITS is not a multiple of 32!!!
//
template<unsigned int BITS>
class base_uint
{
protected:
enum { WIDTH = BITS / 32 };
// This is really big-endian in byte order.
// We sometimes use unsigned int for speed.
unsigned int pn[WIDTH];
public:
base_uint ()
{
}
protected:
// This is to disambiguate from other 1 parameter ctors
struct FromVoid { };
/** Construct from a raw pointer.
The buffer pointed to by `data` must be at least 32 bytes.
*/
base_uint (void const* data, FromVoid)
{
// BITS must be a multiple of 32
static_bassert ((BITS % 32) == 0);
memcpy (&pn [0], data, BITS / 8);
}
public:
bool isZero () const
{
for (int i = 0; i < WIDTH; i++)
if (pn[i] != 0)
return false;
return true;
}
bool isNonZero () const
{
return !isZero ();
}
bool operator! () const
{
return isZero ();
}
const base_uint operator~ () const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
ret.pn[i] = ~pn[i];
return ret;
}
base_uint& operator= (uint64 uHost)
{
zero ();
// Put in least significant bits.
((uint64*) end ())[-1] = htobe64 (uHost);
return *this;
}
base_uint& operator^= (const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] ^= b.pn[i];
return *this;
}
base_uint& operator&= (const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] &= b.pn[i];
return *this;
}
base_uint& operator|= (const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] |= b.pn[i];
return *this;
}
base_uint& operator++ ()
{
// prefix operator
for (int i = WIDTH - 1; i >= 0; --i)
{
pn[i] = htobe32 (be32toh (pn[i]) + 1);
if (pn[i] != 0)
break;
}
return *this;
}
const base_uint operator++ (int)
{
// postfix operator
const base_uint ret = *this;
++ (*this);
return ret;
}
base_uint& operator-- ()
{
for (int i = WIDTH - 1; i >= 0; --i)
{
uint32 prev = pn[i];
pn[i] = htobe32 (be32toh (pn[i]) - 1);
if (prev != 0)
break;
}
return *this;
}
const base_uint operator-- (int)
{
// postfix operator
const base_uint ret = *this;
-- (*this);
return ret;
}
base_uint& operator+= (const base_uint& b)
{
uint64 carry = 0;
for (int i = WIDTH; i--;)
{
uint64 n = carry + be32toh (pn[i]) + be32toh (b.pn[i]);
pn[i] = htobe32 (n & 0xffffffff);
carry = n >> 32;
}
return *this;
}
std::size_t hash_combine (std::size_t& seed) const
{
for (int i = 0; i < WIDTH; ++i)
boost::hash_combine (seed, pn[i]);
return seed;
}
friend inline int compare (const base_uint& a, const base_uint& b)
{
const unsigned char* pA = a.begin ();
const unsigned char* pAEnd = a.end ();
const unsigned char* pB = b.begin ();
while (*pA == *pB)
{
if (++pA == pAEnd)
return 0;
++pB;
}
return (*pA < *pB) ? -1 : 1;
}
friend inline bool operator< (const base_uint& a, const base_uint& b)
{
return compare (a, b) < 0;
}
friend inline bool operator<= (const base_uint& a, const base_uint& b)
{
return compare (a, b) <= 0;
}
friend inline bool operator> (const base_uint& a, const base_uint& b)
{
return compare (a, b) > 0;
}
friend inline bool operator>= (const base_uint& a, const base_uint& b)
{
return compare (a, b) >= 0;
}
friend inline bool operator== (const base_uint& a, const base_uint& b)
{
return memcmp (a.pn, b.pn, sizeof (a.pn)) == 0;
}
friend inline bool operator!= (const base_uint& a, const base_uint& b)
{
return memcmp (a.pn, b.pn, sizeof (a.pn)) != 0;
}
std::string GetHex () const
{
return strHex (begin (), size ());
}
void SetHexExact (const char* psz)
{
// must be precisely the correct number of hex digits
static signed char phexdigit[256] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
char* pOut = reinterpret_cast<char*> (pn);
for (int i = 0; i < sizeof (pn); ++i)
{
*pOut = phexdigit[*psz++] << 4;
*pOut++ |= phexdigit[*psz++];
}
assert (*psz == 0);
assert (pOut == reinterpret_cast<char*> (end ()));
}
// Allow leading whitespace.
// Allow leading "0x".
// To be valid must be '\0' terminated.
bool SetHex (const char* psz, bool bStrict = false)
{
// skip leading spaces
if (!bStrict)
while (isspace (*psz))
psz++;
// skip 0x
if (!bStrict && psz[0] == '0' && tolower (psz[1]) == 'x')
psz += 2;
// hex char to int
static signed char phexdigit[256] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
const unsigned char* pEnd = reinterpret_cast<const unsigned char*> (psz);
const unsigned char* pBegin = pEnd;
// Find end.
while (phexdigit[*pEnd] >= 0)
pEnd++;
// Take only last digits of over long string.
if ((unsigned int) (pEnd - pBegin) > 2 * size ())
pBegin = pEnd - 2 * size ();
unsigned char* pOut = end () - ((pEnd - pBegin + 1) / 2);
zero ();
if ((pEnd - pBegin) & 1)
*pOut++ = phexdigit[*pBegin++];
while (pBegin != pEnd)
{
unsigned char cHigh = phexdigit[*pBegin++] << 4;
unsigned char cLow = pBegin == pEnd
? 0
: phexdigit[*pBegin++];
*pOut++ = cHigh | cLow;
}
return !*pEnd;
}
bool SetHex (const std::string& str, bool bStrict = false)
{
return SetHex (str.c_str (), bStrict);
}
void SetHexExact (const std::string& str)
{
SetHexExact (str.c_str ());
}
std::string ToString () const
{
return GetHex ();
}
unsigned char* begin ()
{
return reinterpret_cast<unsigned char*> (pn);
}
unsigned char* end ()
{
return reinterpret_cast<unsigned char*> (pn + WIDTH);
}
unsigned char const* cbegin () const noexcept
{
return reinterpret_cast <unsigned char const*> (pn);
}
unsigned char const* cend () const noexcept
{
return reinterpret_cast<unsigned char const*> (pn + WIDTH);
}
const unsigned char* begin () const noexcept
{
return cbegin ();
}
const unsigned char* end () const noexcept
{
return cend ();
}
unsigned int size () const
{
return sizeof (pn);
}
void zero ()
{
memset (&pn[0], 0, sizeof (pn));
}
unsigned int GetSerializeSize (int nType = 0) const
{
return sizeof (pn);
}
template<typename Stream>
void Serialize (Stream& s, int nType = 0) const
{
s.write ((char*)pn, sizeof (pn));
}
template<typename Stream>
void Unserialize (Stream& s, int nType = 0)
{
s.read ((char*)pn, sizeof (pn));
}
friend class uint128;
friend class uint160;
friend class uint256;
friend inline int Testuint256AdHoc (std::vector<std::string> vArg);
};
typedef base_uint<128> base_uint128;
typedef base_uint<160> base_uint160;
typedef base_uint<256> base_uint256;
//
// uint128, uint160, & uint256 could be implemented as templates, but to keep
// compile errors and debugging cleaner, they're copy and pasted.
//
//////////////////////////////////////////////////////////////////////////////
//
// uint128
//
class uint128 : public base_uint128
{
public:
typedef base_uint128 basetype;
uint128 ()
{
zero ();
}
uint128 (const basetype& b)
{
*this = b;
}
uint128& operator= (const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
explicit uint128 (const base_uint256& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
explicit uint128 (Blob const& vch)
{
if (vch.size () == size ())
memcpy (pn, &vch[0], size ());
else
zero ();
}
};
//////////////////////////////////////////////////////////////////////////////
//
// uint256
//
class uint256 : public base_uint256
{
public:
typedef base_uint256 basetype;
uint256 ()
{
zero ();
}
uint256 (const basetype& b)
{
*this = b;
}
uint256& operator= (const basetype& b)
{
if (pn != b.pn)
memcpy (pn, b.pn, sizeof (pn));
return *this;
}
uint256 (uint64 b)
{
*this = b;
}
private:
uint256 (void const* data, FromVoid)
: base_uint256 (data, FromVoid ())
{
}
public:
static uint256 fromVoid (void const* data)
{
return uint256 (data, FromVoid ());
}
uint256& operator= (uint64 uHost)
{
zero ();
// Put in least significant bits.
((uint64*) end ())[-1] = htobe64 (uHost);
return *this;
}
explicit uint256 (const std::string& str)
{
SetHex (str);
}
explicit uint256 (Blob const& vch)
{
if (vch.size () == sizeof (pn))
memcpy (pn, &vch[0], sizeof (pn));
else
{
assert (false);
zero ();
}
}
};
inline bool operator== (uint256 const& a, uint64 b)
{
return (base_uint256)a == b;
}
inline bool operator!= (uint256 const& a, uint64 b)
{
return (base_uint256)a != b;
}
inline const uint256 operator^ (const base_uint256& a, const base_uint256& b)
{
return uint256 (a) ^= b;
}
inline const uint256 operator& (const base_uint256& a, const base_uint256& b)
{
return uint256 (a) &= b;
}
inline const uint256 operator| (const base_uint256& a, const base_uint256& b)
{
return uint256 (a) |= b;
}
inline bool operator== (const base_uint256& a, uint256 const& b)
{
return (base_uint256)a == (base_uint256)b;
}
inline bool operator!= (const base_uint256& a, uint256 const& b)
{
return (base_uint256)a != (base_uint256)b;
}
inline const uint256 operator^ (const base_uint256& a, uint256 const& b)
{
return (base_uint256)a ^ (base_uint256)b;
}
inline const uint256 operator& (const base_uint256& a, uint256 const& b)
{
return (base_uint256)a & (base_uint256)b;
}
inline const uint256 operator| (const base_uint256& a, uint256 const& b)
{
return (base_uint256)a | (base_uint256)b;
}
inline bool operator== (uint256 const& a, const base_uint256& b)
{
return (base_uint256)a == (base_uint256)b;
}
inline bool operator!= (uint256 const& a, const base_uint256& b)
{
return (base_uint256)a != (base_uint256)b;
}
inline const uint256 operator^ (uint256 const& a, const base_uint256& b)
{
return (base_uint256)a ^ (base_uint256)b;
}
inline const uint256 operator& (uint256 const& a, const base_uint256& b)
{
return uint256 (a) &= b;
}
inline const uint256 operator| (uint256 const& a, const base_uint256& b)
{
return (base_uint256)a | (base_uint256)b;
}
inline bool operator== (uint256 const& a, uint256 const& b)
{
return (base_uint256)a == (base_uint256)b;
}
inline bool operator!= (uint256 const& a, uint256 const& b)
{
return (base_uint256)a != (base_uint256)b;
}
inline const uint256 operator^ (uint256 const& a, uint256 const& b)
{
return (base_uint256)a ^ (base_uint256)b;
}
inline const uint256 operator& (uint256 const& a, uint256 const& b)
{
return (base_uint256)a & (base_uint256)b;
}
inline const uint256 operator| (uint256 const& a, uint256 const& b)
{
return (base_uint256)a | (base_uint256)b;
}
template<unsigned int BITS> inline std::ostream& operator<< (std::ostream& out, const base_uint<BITS>& u)
{
return out << u.GetHex ();
}
inline int Testuint256AdHoc (std::vector<std::string> vArg)
{
uint256 g (uint64 (0));
printf ("%s\n", g.ToString ().c_str ());
--g;
printf ("--g\n");
printf ("%s\n", g.ToString ().c_str ());
g--;
printf ("g--\n");
printf ("%s\n", g.ToString ().c_str ());
g++;
printf ("g++\n");
printf ("%s\n", g.ToString ().c_str ());
++g;
printf ("++g\n");
printf ("%s\n", g.ToString ().c_str ());
g++;
printf ("g++\n");
printf ("%s\n", g.ToString ().c_str ());
++g;
printf ("++g\n");
printf ("%s\n", g.ToString ().c_str ());
uint256 a (7);
printf ("a=7\n");
printf ("%s\n", a.ToString ().c_str ());
uint256 b;
printf ("b undefined\n");
printf ("%s\n", b.ToString ().c_str ());
int c = 3;
a = c;
a.pn[3] = 15;
printf ("%s\n", a.ToString ().c_str ());
uint256 k (c);
a = 5;
a.pn[3] = 15;
printf ("%s\n", a.ToString ().c_str ());
b = 1;
// b <<= 52;
a |= b;
// a ^= 0x500;
printf ("a %s\n", a.ToString ().c_str ());
a = a | b | (uint256)0x1000;
printf ("a %s\n", a.ToString ().c_str ());
printf ("b %s\n", b.ToString ().c_str ());
a = 0xfffffffe;
a.pn[4] = 9;
printf ("%s\n", a.ToString ().c_str ());
a++;
printf ("%s\n", a.ToString ().c_str ());
a++;
printf ("%s\n", a.ToString ().c_str ());
a++;
printf ("%s\n", a.ToString ().c_str ());
a++;
printf ("%s\n", a.ToString ().c_str ());
a--;
printf ("%s\n", a.ToString ().c_str ());
a--;
printf ("%s\n", a.ToString ().c_str ());
a--;
printf ("%s\n", a.ToString ().c_str ());
uint256 d = a--;
printf ("%s\n", d.ToString ().c_str ());
printf ("%s\n", a.ToString ().c_str ());
a--;
printf ("%s\n", a.ToString ().c_str ());
a--;
printf ("%s\n", a.ToString ().c_str ());
d = a;
printf ("%s\n", d.ToString ().c_str ());
for (int i = uint256::WIDTH - 1; i >= 0; i--) printf ("%08x", d.pn[i]);
printf ("\n");
uint256 neg = d;
neg = ~neg;
printf ("%s\n", neg.ToString ().c_str ());
uint256 e = uint256 ("0xABCDEF123abcdef12345678909832180000011111111");
printf ("\n");
printf ("%s\n", e.ToString ().c_str ());
printf ("\n");
uint256 x1 = uint256 ("0xABCDEF123abcdef12345678909832180000011111111");
uint256 x2;
printf ("%s\n", x1.ToString ().c_str ());
for (int i = 0; i < 270; i += 4)
{
// x2 = x1 << i;
printf ("%s\n", x2.ToString ().c_str ());
}
printf ("\n");
printf ("%s\n", x1.ToString ().c_str ());
for (int i = 0; i < 270; i += 4)
{
x2 = x1;
// x2 >>= i;
printf ("%s\n", x2.ToString ().c_str ());
}
#if 0
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256 (0) >> i);
printf ("%s\n", k.ToString ().c_str ());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256 (0) << i);
printf ("%s\n", k.ToString ().c_str ());
}
#endif
return (0);
}
//////////////////////////////////////////////////////////////////////////////
//
// uint160
//
class uint160 : public base_uint160
{
public:
typedef base_uint160 basetype;
uint160 ()
{
zero ();
}
uint160 (const basetype& b)
{
*this = b;
}
uint160& operator= (const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
uint160 (uint64 b)
{
*this = b;
}
uint160& operator= (uint64 uHost)
{
zero ();
// Put in least significant bits.
((uint64*) end ())[-1] = htobe64 (uHost);
return *this;
}
explicit uint160 (const std::string& str)
{
SetHex (str);
}
explicit uint160 (Blob const& vch)
{
if (vch.size () == sizeof (pn))
memcpy (pn, &vch[0], sizeof (pn));
else
zero ();
}
base_uint256 to256 () const
{
uint256 m;
memcpy (m.begin (), begin (), size ());
return m;
}
};
inline bool operator== (const uint160& a, uint64 b)
{
return (base_uint160)a == b;
}
inline bool operator!= (const uint160& a, uint64 b)
{
return (base_uint160)a != b;
}
inline const uint160 operator^ (const base_uint160& a, const base_uint160& b)
{
return uint160 (a) ^= b;
}
inline const uint160 operator& (const base_uint160& a, const base_uint160& b)
{
return uint160 (a) &= b;
}
inline const uint160 operator| (const base_uint160& a, const base_uint160& b)
{
return uint160 (a) |= b;
}
inline bool operator== (const base_uint160& a, const uint160& b)
{
return (base_uint160)a == (base_uint160)b;
}
inline bool operator!= (const base_uint160& a, const uint160& b)
{
return (base_uint160)a != (base_uint160)b;
}
inline const uint160 operator^ (const base_uint160& a, const uint160& b)
{
return (base_uint160)a ^ (base_uint160)b;
}
inline const uint160 operator& (const base_uint160& a, const uint160& b)
{
return (base_uint160)a & (base_uint160)b;
}
inline const uint160 operator| (const base_uint160& a, const uint160& b)
{
return (base_uint160)a | (base_uint160)b;
}
inline bool operator== (const uint160& a, const base_uint160& b)
{
return (base_uint160)a == (base_uint160)b;
}
inline bool operator!= (const uint160& a, const base_uint160& b)
{
return (base_uint160)a != (base_uint160)b;
}
inline const uint160 operator^ (const uint160& a, const base_uint160& b)
{
return (base_uint160)a ^ (base_uint160)b;
}
inline const uint160 operator& (const uint160& a, const base_uint160& b)
{
return (base_uint160)a & (base_uint160)b;
}
inline const uint160 operator| (const uint160& a, const base_uint160& b)
{
return (base_uint160)a | (base_uint160)b;
}
inline bool operator== (const uint160& a, const uint160& b)
{
return (base_uint160)a == (base_uint160)b;
}
inline bool operator!= (const uint160& a, const uint160& b)
{
return (base_uint160)a != (base_uint160)b;
}
inline const uint160 operator^ (const uint160& a, const uint160& b)
{
return (base_uint160)a ^ (base_uint160)b;
}
inline const uint160 operator& (const uint160& a, const uint160& b)
{
return (base_uint160)a & (base_uint160)b;
}
inline const uint160 operator| (const uint160& a, const uint160& b)
{
return (base_uint160)a | (base_uint160)b;
}
inline const std::string strHex (const uint160& ui)
{
return strHex (ui.begin (), ui.size ());
}
extern std::size_t hash_value (const uint160&);
extern std::size_t hash_value (uint256 const& );
#endif
// vim:ts=4
// vim:ts=4

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#if BEAST_WIN32
// from: http://stackoverflow.com/questions/3022552/is-there-any-standard-htonl-like-function-for-64-bits-integers-in-c
// but we don't need to check the endianness
uint64_t htobe64 (uint64_t value)
{
// The answer is 42
//static const int num = 42;
// Check the endianness
//if (*reinterpret_cast<const char*>(&num) == num)
//{
const uint32_t high_part = htonl (static_cast<uint32_t> (value >> 32));
const uint32_t low_part = htonl (static_cast<uint32_t> (value & 0xFFFFFFFFLL));
return (static_cast<uint64_t> (low_part) << 32) | high_part;
//} else
//{
// return value;
//}
}
uint64_t be64toh (uint64_t value)
{
return (_byteswap_uint64 (value));
}
uint32_t htobe32 (uint32_t value)
{
return (htonl (value));
}
uint32_t be32toh (uint32_t value)
{
return ( _byteswap_ulong (value));
}
#endif

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_BYTEORDER_H
#define RIPPLE_BYTEORDER_H
// Routines for converting endianness
// Reference: http://www.mail-archive.com/licq-commits@googlegroups.com/msg02334.html
#if BEAST_WIN32
extern uint64_t htobe64 (uint64_t value);
extern uint64_t be64toh (uint64_t value);
extern uint32_t htobe32 (uint32_t value);
extern uint32_t be32toh (uint32_t value);
#elif __APPLE__
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#elif defined(__OpenBSD__)
#define be16toh(x) betoh16(x)
#define be32toh(x) betoh32(x)
#define be64toh(x) betoh64(x)
#endif
#endif

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
CountedObjects& CountedObjects::getInstance ()
{
static CountedObjects instance;
return instance;
}
CountedObjects::CountedObjects ()
{
}
CountedObjects::~CountedObjects ()
{
}
CountedObjects::List CountedObjects::getCounts (int minimumThreshold) const
{
List counts;
// When other operations are concurrent, the count
// might be temporarily less than the actual count.
int const count = m_count.get ();
counts.reserve (count);
CounterBase* counter = m_head.get ();
while (counter != nullptr)
{
if (counter->getCount () >= minimumThreshold)
{
Entry entry;
entry.first = counter->getName ();
entry.second = counter->getCount ();
counts.push_back (entry);
}
counter = counter->getNext ();
}
return counts;
}
//------------------------------------------------------------------------------
CountedObjects::CounterBase::CounterBase ()
{
// Insert ourselves at the front of the lock-free linked list
CountedObjects& instance = CountedObjects::getInstance ();
CounterBase* head;
do
{
head = instance.m_head.get ();
m_next = head;
}
while (! instance.m_head.compareAndSetBool (this, head));
++instance.m_count;
}
CountedObjects::CounterBase::~CounterBase ()
{
// VFALCO NOTE If the counters are destroyed before the singleton,
// undefined behavior will result if the singleton's member
// functions are called.
}
//------------------------------------------------------------------------------

View File

@@ -0,0 +1,140 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_COUNTEDOBJECT_RIPPLEHEADER
#define RIPPLE_COUNTEDOBJECT_RIPPLEHEADER
//------------------------------------------------------------------------------
/** Manages all counted object types.
*/
class CountedObjects
{
public:
static CountedObjects& getInstance ();
typedef std::pair <std::string, int> Entry;
typedef std::vector <Entry> List;
List getCounts (int minimumThreshold) const;
public:
/** Implementation for @ref CountedObject.
@internal
*/
class CounterBase
{
public:
CounterBase ();
virtual ~CounterBase ();
inline int increment () noexcept
{
return ++m_count;
}
inline int decrement () noexcept
{
return --m_count;
}
inline int getCount () const noexcept
{
return m_count.get ();
}
inline CounterBase* getNext () const noexcept
{
return m_next;
}
virtual char const* getName () const = 0;
private:
virtual void checkPureVirtual () const = 0;
protected:
beast::Atomic <int> m_count;
CounterBase* m_next;
};
private:
CountedObjects ();
~CountedObjects ();
private:
beast::Atomic <int> m_count;
beast::Atomic <CounterBase*> m_head;
};
//------------------------------------------------------------------------------
/** Tracks the number of instances of an object.
Derived classes have their instances counted automatically. This is used
for reporting purposes.
@ingroup ripple_basics
*/
template <class Object>
class CountedObject : LeakChecked <CountedObject <Object> >
{
public:
CountedObject ()
{
getCounter ().increment ();
}
CountedObject (CountedObject const&)
{
getCounter ().increment ();
}
~CountedObject ()
{
getCounter ().decrement ();
}
private:
class Counter : public CountedObjects::CounterBase
{
public:
Counter () noexcept { }
char const* getName () const noexcept
{
return Object::getCountedObjectName ();
}
void checkPureVirtual () const { }
};
private:
static Counter& getCounter () noexcept
{
// VFALCO TODO Research the thread safety of static initializers
// on all supported platforms
static Counter counter;
return counter;
/*
static Counter* volatile s_instance;
static beast::Static::Initializer s_initializer;
if (s_initializer.begin ())
{
static char s_storage [sizeof (Counter)];
s_instance = new (s_storage) Counter;
s_initializer.end ();
}
return *s_instance;
*/
}
};
#endif

View File

@@ -0,0 +1,37 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
std::string DH_der_gen (int iKeyLength)
{
DH* dh = 0;
int iCodes;
std::string strDer;
do
{
dh = DH_generate_parameters (iKeyLength, DH_GENERATOR_5, NULL, NULL);
iCodes = 0;
DH_check (dh, &iCodes);
}
while (iCodes & (DH_CHECK_P_NOT_PRIME | DH_CHECK_P_NOT_SAFE_PRIME | DH_UNABLE_TO_CHECK_GENERATOR | DH_NOT_SUITABLE_GENERATOR));
strDer.resize (i2d_DHparams (dh, NULL));
unsigned char* next = reinterpret_cast<unsigned char*> (&strDer[0]);
(void) i2d_DHparams (dh, &next);
return strDer;
}
DH* DH_der_load (const std::string& strDer)
{
const unsigned char* pbuf = reinterpret_cast<const unsigned char*> (&strDer[0]);
return d2i_DHparams (NULL, &pbuf, strDer.size ());
}
// vim:ts=4

View File

@@ -0,0 +1,15 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_DIFFIEHELLMANUTIL_H
#define RIPPLE_DIFFIEHELLMANUTIL_H
extern DH* DH_der_load (const std::string& strDer);
extern std::string DH_der_gen (int iKeyLength);
#endif
// vim:ts=4

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_HASHUTILITIES_H
#define RIPPLE_HASHUTILITIES_H
// VFALCO NOTE these came from BitcoinUtil.h
// VFALCO TODO Rewrite the callers so we don't need templates,
// then define these in a .cpp so they are no longer inline.
//
template<typename T1>
inline uint256 SHA256Hash (const T1 pbegin, const T1 pend)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256 ((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof (pbegin[0]), (unsigned char*)&hash1);
uint256 hash2;
SHA256 ((unsigned char*)&hash1, sizeof (hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2>
inline uint256 SHA256Hash (const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof (p1begin[0]));
SHA256_Update (&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof (p2begin[0]));
SHA256_Final ((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256 ((unsigned char*)&hash1, sizeof (hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2, typename T3>
inline uint256 SHA256Hash (const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end,
const T3 p3begin, const T3 p3end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof (p1begin[0]));
SHA256_Update (&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof (p2begin[0]));
SHA256_Update (&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof (p3begin[0]));
SHA256_Final ((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256 ((unsigned char*)&hash1, sizeof (hash1), (unsigned char*)&hash2);
return hash2;
}
inline uint160 Hash160 (Blob const& vch)
{
uint256 hash1;
SHA256 (&vch[0], vch.size (), (unsigned char*)&hash1);
uint160 hash2;
RIPEMD160 ((unsigned char*)&hash1, sizeof (hash1), (unsigned char*)&hash2);
return hash2;
}
/*
#if BEAST_WIN32
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#include <windows.h>
#define mlock(p, n) VirtualLock((p), (n));
#define munlock(p, n) VirtualUnlock((p), (n));
#else
#include <sys/mman.h>
#include <limits.h>
// This comes from limits.h if it's not defined there set a sane default
#ifndef PAGESIZE
#include <unistd.h>
#define PAGESIZE sysconf(_SC_PAGESIZE)
#endif
#define mlock(a,b) \
mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#define munlock(a,b) \
munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#endif
*/
#endif

View File

@@ -0,0 +1,162 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#define SECTION_DEFAULT_NAME ""
struct ParseSectionLog; // for Log
SETUP_LOGN (ParseSectionLog,"ParseSection")
Section ParseSection (const std::string& strInput, const bool bTrim)
{
std::string strData (strInput);
std::vector<std::string> vLines;
Section secResult;
// Convert DOS format to unix.
boost::algorithm::replace_all (strData, "\r\n", "\n");
// Convert MacOS format to unix.
boost::algorithm::replace_all (strData, "\r", "\n");
boost::algorithm::split (vLines, strData, boost::algorithm::is_any_of ("\n"));
// Set the default Section name.
std::string strSection = SECTION_DEFAULT_NAME;
// Initialize the default Section.
secResult[strSection] = Section::mapped_type ();
// Parse each line.
BOOST_FOREACH (std::string & strValue, vLines)
{
if (strValue.empty () || strValue[0] == '#')
{
// Blank line or comment, do nothing.
nothing ();
}
else if (strValue[0] == '[' && strValue[strValue.length () - 1] == ']')
{
// New Section.
strSection = strValue.substr (1, strValue.length () - 2);
secResult[strSection] = Section::mapped_type ();
}
else
{
// Another line for Section.
if (bTrim)
boost::algorithm::trim (strValue);
if (!strValue.empty ())
secResult[strSection].push_back (strValue);
}
}
return secResult;
}
void SectionEntriesPrint (std::vector<std::string>* vspEntries, const std::string& strSection)
{
Log::out() << "[" << strSection << "]";
if (vspEntries)
{
BOOST_FOREACH (std::string & strValue, *vspEntries)
{
Log::out() << strValue;
}
}
}
void SectionPrint (Section secInput)
{
BOOST_FOREACH (Section::value_type & pairSection, secInput)
{
SectionEntriesPrint (&pairSection.second, pairSection.first);
}
}
Section::mapped_type* SectionEntries (Section& secSource, const std::string& strSection)
{
Section::iterator it;
Section::mapped_type* smtResult;
it = secSource.find (strSection);
if (it == secSource.end ())
{
smtResult = 0;
}
else
{
//Section::mapped_type& vecEntries = it->second;
smtResult = & (it->second);
}
return smtResult;
}
int SectionCount (Section& secSource, const std::string& strSection)
{
Section::mapped_type* pmtEntries = SectionEntries (secSource, strSection);
return pmtEntries ? pmtEntries->size () : 0;
}
bool SectionSingleB (Section& secSource, const std::string& strSection, std::string& strValue)
{
Section::mapped_type* pmtEntries = SectionEntries (secSource, strSection);
bool bSingle = pmtEntries && 1 == pmtEntries->size ();
if (bSingle)
{
strValue = (*pmtEntries)[0];
}
else if (pmtEntries)
{
WriteLog (lsWARNING, ParseSectionLog) << boost::str (boost::format ("Section [%s]: requires 1 line not %d lines.")
% strSection
% pmtEntries->size ());
}
return bSingle;
}
StringPairArray parseKeyValueSection (Section& secSource, String const& strSection)
{
StringPairArray result;
// yuck.
std::string const stdStrSection (strSection.toStdString ());
typedef Section::mapped_type Entries;
Entries* const entries = SectionEntries (secSource, stdStrSection);
if (entries != nullptr)
{
for (Entries::const_iterator iter = entries->begin (); iter != entries->end (); ++iter)
{
String const line (iter->c_str ());
int const equalPos = line.indexOfChar ('=');
if (equalPos != -1)
{
String const key = line.substring (0, equalPos);
String const value = line.substring (equalPos + 1, line.length ());
result.set (key, value);
}
}
}
return result;
}

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_INIFILE_RIPPLEHEADER
#define RIPPLE_INIFILE_RIPPLEHEADER
// VFALCO TODO Rename to IniFile and clean up
typedef std::map <const std::string, std::vector<std::string> > Section;
// VFALCO TODO Wrap this up in a class interface
//
Section ParseSection (const std::string& strInput, const bool bTrim);
void SectionPrint (Section secInput);
void SectionEntriesPrint (std::vector<std::string>* vspEntries, const std::string& strSection);
bool SectionSingleB (Section& secSource, const std::string& strSection, std::string& strValue);
int SectionCount (Section& secSource, const std::string& strSection);
Section::mapped_type* SectionEntries (Section& secSource, const std::string& strSection);
/** Parse a section of lines as a key/value array.
Each line is in the form <key>=<value>.
Spaces are considered part of the key and value.
*/
StringPairArray parseKeyValueSection (Section& secSource, String const& strSection);
#endif

View File

@@ -0,0 +1,267 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
LogFile Log::s_logFile;
Log::StaticLockType Log::s_lock ("Log", __FILE__, __LINE__);
LogSeverity Log::sMinSeverity = lsINFO;
//------------------------------------------------------------------------------
LogPartition* LogPartition::headLog = NULL;
LogPartition::LogPartition (char const* partitionName)
: mNextLog (headLog)
, mMinSeverity (lsWARNING)
{
const char* ptr = strrchr (partitionName, '/');
mName = (ptr == NULL) ? partitionName : (ptr + 1);
size_t p = mName.find (".cpp");
if (p != std::string::npos)
mName.erase (mName.begin () + p, mName.end ());
headLog = this;
}
std::vector< std::pair<std::string, std::string> > LogPartition::getSeverities ()
{
std::vector< std::pair<std::string, std::string> > sevs;
for (LogPartition* l = headLog; l != NULL; l = l->mNextLog)
sevs.push_back (std::make_pair (l->mName, Log::severityToString (l->mMinSeverity)));
return sevs;
}
//------------------------------------------------------------------------------
std::string Log::replaceFirstSecretWithAsterisks (std::string s)
{
using namespace std;
char const* secretToken = "\"secret\"";
// Look for the first occurrence of "secret" in the string.
//
size_t startingPosition = s.find (secretToken);
if (startingPosition != string::npos)
{
// Found it, advance past the token.
//
startingPosition += strlen (secretToken);
// Replace the next 35 characters at most, without overwriting the end.
//
size_t endingPosition = std::min (startingPosition + 35, s.size () - 1);
for (size_t i = startingPosition; i < endingPosition; ++i)
s [i] = '*';
}
return s;
}
//------------------------------------------------------------------------------
Log::~Log ()
{
std::string logMsg = boost::posix_time::to_simple_string (boost::posix_time::second_clock::universal_time ());
if (!mPartitionName.empty ())
logMsg += " " + mPartitionName + ":";
else
logMsg += " ";
switch (mSeverity)
{
case lsTRACE:
logMsg += "TRC ";
break;
case lsDEBUG:
logMsg += "DBG ";
break;
case lsINFO:
logMsg += "NFO ";
break;
case lsWARNING:
logMsg += "WRN ";
break;
case lsERROR:
logMsg += "ERR ";
break;
case lsFATAL:
logMsg += "FTL ";
break;
case lsINVALID:
assert (false);
return;
}
logMsg += replaceFirstSecretWithAsterisks (oss.str ());
if (logMsg.size () > maximumMessageCharacters)
{
logMsg.resize (maximumMessageCharacters);
logMsg += "...";
}
print (logMsg, mSeverity >= sMinSeverity);
}
void Log::print (std::string const& text, bool toStdErr)
{
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
// Does nothing if not open.
s_logFile.writeln (text);
if (toStdErr)
{
#if 0 //BEAST_MSVC
if (beast_isRunningUnderDebugger ())
{
// Send it to the attached debugger's Output window
//
Logger::outputDebugString (text);
}
else
#endif
{
std::cerr << text << std::endl;
}
}
}
void Log::print (StringArray const& strings, bool toStdErr)
{
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
for (int i = 0; i < strings.size (); ++i)
print (strings [i].toStdString (), toStdErr);
}
std::string Log::rotateLog ()
{
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
bool const wasOpened = s_logFile.closeAndReopen ();
if (wasOpened)
{
return "The log file was closed and reopened.";
}
else
{
return "The log file could not be closed and reopened.";
}
}
void Log::setMinSeverity (LogSeverity s, bool all)
{
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
sMinSeverity = s;
if (all)
LogPartition::setSeverity (s);
}
LogSeverity Log::getMinSeverity ()
{
StaticScopedLockType sl (s_lock, __FILE__, __LINE__);
return sMinSeverity;
}
std::string Log::severityToString (LogSeverity s)
{
switch (s)
{
case lsTRACE:
return "Trace";
case lsDEBUG:
return "Debug";
case lsINFO:
return "Info";
case lsWARNING:
return "Warning";
case lsERROR:
return "Error";
case lsFATAL:
return "Fatal";
default:
assert (false);
return "Unknown";
}
}
LogSeverity Log::stringToSeverity (const std::string& s)
{
if (boost::iequals (s, "trace"))
return lsTRACE;
if (boost::iequals (s, "debug"))
return lsDEBUG;
if (boost::iequals (s, "info") || boost::iequals (s, "information"))
return lsINFO;
if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings"))
return lsWARNING;
if (boost::iequals (s, "error") || boost::iequals (s, "errors"))
return lsERROR;
if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals"))
return lsFATAL;
return lsINVALID;
}
void Log::setLogFile (boost::filesystem::path const& path)
{
bool const wasOpened = s_logFile.open (path.c_str ());
if (! wasOpened)
{
Log (lsFATAL) << "Unable to open logfile " << path;
}
}
bool LogPartition::setSeverity (const std::string& partition, LogSeverity severity)
{
for (LogPartition* p = headLog; p != NULL; p = p->mNextLog)
if (boost::iequals (p->mName, partition))
{
p->mMinSeverity = severity;
return true;
}
return false;
}
void LogPartition::setSeverity (LogSeverity severity)
{
for (LogPartition* p = headLog; p != NULL; p = p->mNextLog)
p->mMinSeverity = severity;
}
// vim:ts=4

View File

@@ -0,0 +1,227 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOG_H_INCLUDED
#define RIPPLE_LOG_H_INCLUDED
enum LogSeverity
{
lsINVALID = -1, // used to indicate an invalid severity
lsTRACE = 0, // Very low-level progress information, details inside an operation
lsDEBUG = 1, // Function-level progress information, operations
lsINFO = 2, // Server-level progress information, major operations
lsWARNING = 3, // Conditions that warrant human attention, may indicate a problem
lsERROR = 4, // A condition that indicates a problem
lsFATAL = 5 // A severe condition that indicates a server problem
};
//------------------------------------------------------------------------------
// VFALCO TODO make this a nested class in Log?
class LogPartition // : public List <LogPartition>::Node
{
public:
LogPartition (const char* partitionName);
/** Retrieve the LogPartition associated with an object.
Each LogPartition is a singleton.
*/
template <class Key>
static LogPartition const& get ()
{
static LogPartition logPartition (getPartitionName <Key> ());
return logPartition;
}
bool doLog (LogSeverity s) const
{
return s >= mMinSeverity;
}
const std::string& getName () const
{
return mName;
}
static bool setSeverity (const std::string& partition, LogSeverity severity);
static void setSeverity (LogSeverity severity);
static std::vector< std::pair<std::string, std::string> > getSeverities ();
private:
/** Retrieve the name for a log partition.
*/
template <class Key>
static char const* getPartitionName ();
private:
// VFALCO TODO Use an intrusive linked list
//
static LogPartition* headLog;
LogPartition* mNextLog;
LogSeverity mMinSeverity;
std::string mName;
};
#define SETUP_LOG(Class) \
template <> char const* LogPartition::getPartitionName <Class> () { return #Class; } \
struct Class##Instantiator { Class##Instantiator () { LogPartition::get <Class> (); } }; \
static Class##Instantiator Class##Instantiator_instance;
#define SETUP_LOGN(Class,Name) \
template <> char const* LogPartition::getPartitionName <Class> () { return Name; } \
struct Class##Instantiator { Class##Instantiator () { LogPartition::get <Class> (); } }; \
static Class##Instantiator Class##Instantiator_instance;
//------------------------------------------------------------------------------
class Log : public Uncopyable
{
public:
explicit Log (LogSeverity s) : mSeverity (s)
{
}
Log (LogSeverity s, LogPartition const& p)
: mSeverity (s)
, mPartitionName (p.getName ())
{
}
~Log ();
template <class T>
std::ostream& operator<< (const T& t) const
{
return oss << t;
}
std::ostringstream& ref () const
{
return oss;
}
static std::string severityToString (LogSeverity);
static LogSeverity stringToSeverity (std::string const&);
static LogSeverity getMinSeverity ();
static void setMinSeverity (LogSeverity, bool all);
static void setLogFile (boost::filesystem::path const& pathToLogFile);
/** Rotate the log file.
The log file is closed and reopened. This is for compatibility
with log management tools.
@return A human readable string describing the result of the operation.
*/
static std::string rotateLog ();
public:
/** Write to log output.
All logging eventually goes through this function. If a
debugger is attached, the string goes to the debugging console,
else it goes to the standard error output. If a log file is
open, then the message is additionally written to the open log
file.
The text should not contain a newline, it will be automatically
added as needed.
@note This acquires a global mutex.
@param text The text to write.
@param toStdErr `true` to also write to std::cerr
*/
static void print (std::string const& text,
bool toStdErr = true);
static void print (StringArray const& strings, bool toStdErr = true);
/** Output stream for logging
This is a convenient replacement for writing to `std::cerr`.
Usage:
@code
Log::out () << "item1" << 2;
@endcode
It is not necessary to append a newline.
*/
class out
{
public:
out ()
{
}
~out ()
{
Log::print (m_ss.str ());
}
template <class T>
out& operator<< (T t)
{
m_ss << t;
return *this;
}
private:
std::stringstream m_ss;
};
private:
enum
{
/** Maximum line length for log messages.
If the message exceeds this length it will be truncated
with elipses.
*/
maximumMessageCharacters = 12 * 1024
};
static std::string replaceFirstSecretWithAsterisks (std::string s);
// Singleton variables
//
typedef RippleRecursiveMutex StaticLockType;
typedef StaticLockType::ScopedLockType StaticScopedLockType;
static StaticLockType s_lock;
static LogFile s_logFile;
static LogSeverity sMinSeverity;
mutable std::ostringstream oss;
LogSeverity mSeverity;
std::string mPartitionName;
};
// Manually test for whether we should log
//
#define ShouldLog(s, k) (LogPartition::get <k> ().doLog (s))
// Write to the log at the given severity level
//
#define WriteLog(s, k) if (!ShouldLog (s, k)) do {} while (0); else Log (s, LogPartition::get <k> ())
// Write to the log conditionally
//
#define CondLog(c, s, k) if (!ShouldLog (s, k) || !(c)) do {} while(0); else Log(s, LogPartition::get <k> ())
#endif
// vim:ts=4

View File

@@ -0,0 +1,69 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
LogFile::LogFile ()
: m_stream (nullptr)
{
}
LogFile::~LogFile ()
{
}
bool LogFile::isOpen () const noexcept
{
return m_stream != nullptr;
}
bool LogFile::open (boost::filesystem::path const& path)
{
close ();
bool wasOpened = false;
// VFALCO TODO Make this work with Unicode file paths
ScopedPointer <std::ofstream> stream (
new std::ofstream (path.c_str (), std::fstream::app));
if (stream->good ())
{
m_path = path;
m_stream = stream.release ();
wasOpened = true;
}
return wasOpened;
}
bool LogFile::closeAndReopen ()
{
close ();
return open (m_path);
}
void LogFile::close ()
{
m_stream = nullptr;
}
void LogFile::write (char const* text)
{
if (m_stream != nullptr)
(*m_stream) << text;
}
void LogFile::writeln (char const* text)
{
if (m_stream != nullptr)
{
(*m_stream) << text;
(*m_stream) << std::endl;
}
}

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOGFILE_H_INCLUDED
#define RIPPLE_LOGFILE_H_INCLUDED
/** Manages a system file containing logged output.
The system file remains open during program execution. Interfaces
are provided for interoperating with standard log management
tools like logrotate(8):
http://linuxcommand.org/man_pages/logrotate8.html
@note None of the listed interfaces are thread-safe.
*/
class LogFile : public Uncopyable
{
public:
/** Construct with no associated system file.
A system file may be associated later with @ref open.
@see open
*/
LogFile ();
/** Destroy the object.
If a system file is associated, it will be flushed and closed.
*/
~LogFile ();
/** Determine if a system file is associated with the log.
@return `true` if a system file is associated and opened for writing.
*/
bool isOpen () const noexcept;
/** Associate a system file with the log.
If the file does not exist an attempt is made to create it
and open it for writing. If the file already exists an attempt is
made to open it for appending.
If a system file is already associated with the log, it is closed first.
@return `true` if the file was opened.
*/
// VFALCO NOTE The parameter is unfortunately a boost type because it
// can be either wchar or char based depending on platform.
// TODO Replace with beast::File
//
bool open (boost::filesystem::path const& path);
/** Close and re-open the system file associated with the log
This assists in interoperating with external log management tools.
@return `true` if the file was opened.
*/
bool closeAndReopen ();
/** Close the system file if it is open.
*/
void close ();
/** write to the log file.
Does nothing if there is no associated system file.
*/
void write (char const* text);
/** write to the log file and append an end of line marker.
Does nothing if there is no associated system file.
*/
void writeln (char const* text);
/** Write to the log file using std::string.
*/
inline void write (std::string const& str) { write (str.c_str ()); }
inline void writeln (std::string const& str) { writeln (str.c_str ()); }
private:
ScopedPointer <std::ofstream> m_stream;
boost::filesystem::path m_path;
};
#endif

View File

@@ -0,0 +1,114 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOGGEDTIMINGS_H_INCLUDED
#define RIPPLE_LOGGEDTIMINGS_H_INCLUDED
namespace detail
{
/** Template class that performs destruction of an object.
Default implementation simply calls delete
*/
template <typename Object>
struct Destroyer
{
static void destroy (Object& object)
{
delete &object;
}
};
/** Specialization for boost::shared_ptr.
*/
template <typename Object>
struct Destroyer <boost::shared_ptr <Object> >
{
static void destroy (boost::shared_ptr <Object>& p)
{
p.reset ();
}
};
/** Specialization for boost::unordered_map
*/
template <typename Key, typename Value>
struct Destroyer <boost::unordered_map <Key, Value> >
{
static void destroy (boost::unordered_map <Key, Value>& v)
{
v.clear ();
}
};
/** Cleans up an elaspsed time so it prints nicely */
inline double cleanElapsed (double seconds) noexcept
{
if (seconds >= 10)
return std::floor (seconds + 0.5);
return static_cast <int> ((seconds * 10 + 0.5) / 10);
}
}
//------------------------------------------------------------------------------
/** Measure the time required to destroy an object.
*/
template <typename Object>
double timedDestroy (Object& object)
{
int64 const startTime (Time::getHighResolutionTicks ());
detail::Destroyer <Object>::destroy (object);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
/** Log the timed destruction of an object if the time exceeds a threshold.
*/
template <typename PartitionKey, typename Object>
void logTimedDestroy (
Object& object, String objectDescription, double thresholdSeconds = 1)
{
double const seconds = timedDestroy (object);
if (seconds > thresholdSeconds)
{
LogSeverity const severity = lsWARNING;
Log (severity, LogPartition::get <PartitionKey> ()) <<
objectDescription << " took "<<
String (detail::cleanElapsed (seconds)) <<
" seconds to destroy";
}
}
//------------------------------------------------------------------------------
/** Log a timed function call if the time exceeds a threshold. */
template <typename PartitionKey, typename Function>
void logTimedCall (String description, char const* fileName, int lineNumber,
Function f, double thresholdSeconds = 1)
{
double const seconds = measureFunctionCallTime (f);
if (seconds > thresholdSeconds)
{
LogSeverity const severity = lsWARNING;
Log (severity, LogPartition::get <PartitionKey> ()) <<
description << " took "<<
String (detail::cleanElapsed (seconds)) <<
" seconds to execute at " <<
Debug::getSourceLocation (fileName, lineNumber);
}
}
#endif

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_PLATFORMMACROS_H
#define RIPPLE_PLATFORMMACROS_H
#define FUNCTION_TYPE beast::function
#define BIND_TYPE beast::bind
#define P_1 beast::_1
#define P_2 beast::_2
#define P_3 beast::_3
#define P_4 beast::_4
// VFALCO TODO Clean this up
#if (!defined(FORCE_NO_C11X) && (__cplusplus > 201100L)) || defined(FORCE_C11X)
// VFALCO TODO Get rid of the C11X macro
#define C11X
#define UPTR_T std::unique_ptr
#define MOVE_P(p) std::move(p)
#else
#define UPTR_T std::auto_ptr
#define MOVE_P(p) (p)
#endif
// VFALCO TODO Clean this stuff up. Remove as much as possible
#define nothing() do {} while (0)
#define fallthru() do {} while (0)
#define NUMBER(x) (sizeof(x)/sizeof((x)[0]))
#define isSetBit(x,y) (!!((x) & (y)))
#endif

View File

@@ -0,0 +1,217 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
RandomNumbers::RandomNumbers ()
: m_initialized (false)
{
}
RandomNumbers::~RandomNumbers ()
{
}
bool RandomNumbers::initialize ()
{
assert (!m_initialized);
bool success = platformAddEntropy ();
if (success)
m_initialized = true;
return success;
}
void RandomNumbers::fillBytes (void* destinationBuffer, int numberOfBytes)
{
// VFALCO NOTE this assert is here to remind us that the code is not yet
// thread safe.
assert (m_initialized);
// VFALCO NOTE When a spinlock is available in beast, use it here.
if (! m_initialized)
{
if (! initialize ())
{
char const* message = "Unable to add system entropy";
Log::out() << message;
throw std::runtime_error (message);
}
}
#ifdef PURIFY
memset (destinationBuffer, 0, numberOfBytes);
#endif
if (RAND_bytes (reinterpret_cast <unsigned char*> (destinationBuffer), numberOfBytes) != 1)
{
assert (false);
throw std::runtime_error ("Entropy pool not seeded");
}
}
RandomNumbers& RandomNumbers::getInstance ()
{
static RandomNumbers instance;
return instance;
}
//------------------------------------------------------------------------------
#if BEAST_WIN32
// Get entropy from the Windows crypto provider
bool RandomNumbers::platformAddEntropy ()
{
char name[512], rand[128];
DWORD count = 500;
HCRYPTPROV cryptoHandle;
if (!CryptGetDefaultProviderA (PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, name, &count))
{
#ifdef BEAST_DEBUG
Log::out() << "Unable to get default crypto provider";
#endif
return false;
}
if (!CryptAcquireContextA (&cryptoHandle, NULL, name, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
#ifdef BEAST_DEBUG
Log::out() << "Unable to acquire crypto provider";
#endif
return false;
}
if (!CryptGenRandom (cryptoHandle, 128, reinterpret_cast<BYTE*> (rand)))
{
#ifdef BEAST_DEBUG
Log::out() << "Unable to get entropy from crypto provider";
#endif
CryptReleaseContext (cryptoHandle, 0);
return false;
}
CryptReleaseContext (cryptoHandle, 0);
RAND_seed (rand, 128);
return true;
}
#else
bool RandomNumbers::platformAddEntropy ()
{
char rand[128];
std::ifstream reader;
reader.open ("/dev/urandom", std::ios::in | std::ios::binary);
if (!reader.is_open ())
{
#ifdef BEAST_DEBUG
Log::out() << "Unable to open random source";
#endif
return false;
}
reader.read (rand, 128);
int bytesRead = reader.gcount ();
if (bytesRead == 0)
{
#ifdef BEAST_DEBUG
Log::out() << "Unable to read from random source";
#endif
return false;
}
RAND_seed (rand, bytesRead);
return bytesRead >= 64;
}
#endif
//------------------------------------------------------------------------------
//
// "Never go to sea with two chronometers; take one or three."
// Our three time sources are:
// - System clock
// - Median of other nodes's clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
void RandomNumbers::platformAddPerformanceMonitorEntropy ()
{
// VFALCO TODO Remove all this fancy stuff
struct
{
int64 operator () () const
{
return time (NULL);
}
} GetTime;
struct
{
void operator () ()
{
struct
{
// VFALCO TODO clean this up
int64 operator () () const
{
int64 nCounter = 0;
#if BEAST_WIN32
QueryPerformanceCounter ((LARGE_INTEGER*)&nCounter);
#else
timeval t;
gettimeofday (&t, NULL);
nCounter = t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}
} GetPerformanceCounter;
// Seed with CPU performance counter
int64 nCounter = GetPerformanceCounter ();
RAND_add (&nCounter, sizeof (nCounter), 1.5);
memset (&nCounter, 0, sizeof (nCounter));
}
} RandAddSeed;
RandAddSeed ();
// This can take up to 2 seconds, so only do it every 10 minutes
static int64 nLastPerfmon;
if (GetTime () < nLastPerfmon + 10 * 60)
return;
nLastPerfmon = GetTime ();
#if BEAST_WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata[250000];
memset (pdata, 0, sizeof (pdata));
unsigned long nSize = sizeof (pdata);
long ret = RegQueryValueExA (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
RegCloseKey (HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS)
{
RAND_add (pdata, nSize, nSize / 100.0);
memset (pdata, 0, nSize);
//printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
}
#endif
}

View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RANDOMNUMBERS_H
#define RIPPLE_RANDOMNUMBERS_H
/** Cryptographically secure random number source.
*/
class RandomNumbers
{
public:
/** Retrieve the instance of the generator.
*/
static RandomNumbers& getInstance ();
/** Initialize the generator.
If the generator is not manually initialized, it will be
automatically initialized on first use. If automatic initialization
fails, an exception is thrown.
@return `true` if enough entropy could be retrieved.
*/
bool initialize ();
/** Generate secure random numbers.
The generated data is suitable for cryptography.
@invariant The destination buffer must be large enough or
undefined behavior results.
@param destinationBuffer The place to store the bytes.
@param numberOfBytes The number of bytes to generate.
*/
void fillBytes (void* destinationBuffer, int numberOfBytes);
/** Generate secure random numbers.
The generated data is suitable for cryptography.
Fills the memory for the object with random numbers.
This is a type-safe alternative to the function above.
@param object A pointer to the object to fill.
@tparam T The type of `object`
@note Undefined behavior results if `T` is not a POD type.
*/
template <class T>
void fill (T* object)
{
fillBytes (object, sizeof (T));
}
private:
RandomNumbers ();
~RandomNumbers ();
bool platformAddEntropy ();
void platformAddPerformanceMonitorEntropy ();
private:
bool m_initialized;
};
#endif

View File

@@ -0,0 +1,369 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO TODO Replace these with something more robust and without macros.
//
#if ! BEAST_MSVC
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#endif
std::string strprintf (const char* format, ...)
{
char buffer[50000];
char* p = buffer;
int limit = sizeof (buffer);
int ret;
for (;;)
{
va_list arg_ptr;
va_start (arg_ptr, format);
ret = _vsnprintf (p, limit, format, arg_ptr);
va_end (arg_ptr);
if (ret >= 0 && ret < limit)
break;
if (p != buffer)
delete[] p;
limit *= 2;
p = new char[limit];
if (p == NULL)
throw std::bad_alloc ();
}
std::string str (p, p + ret);
if (p != buffer)
delete[] p;
return str;
}
char charHex (int iDigit)
{
return iDigit < 10 ? '0' + iDigit : 'A' - 10 + iDigit;
}
int charUnHex (char cDigit)
{
return cDigit >= '0' && cDigit <= '9'
? cDigit - '0'
: cDigit >= 'A' && cDigit <= 'F'
? cDigit - 'A' + 10
: cDigit >= 'a' && cDigit <= 'f'
? cDigit - 'a' + 10
: -1;
}
int strUnHex (std::string& strDst, const std::string& strSrc)
{
int iBytes = (strSrc.size () + 1) / 2;
strDst.resize (iBytes);
const char* pSrc = &strSrc[0];
char* pDst = &strDst[0];
if (strSrc.size () & 1)
{
int c = charUnHex (*pSrc++);
if (c < 0)
{
iBytes = -1;
}
else
{
*pDst++ = c;
}
}
for (int i = 0; iBytes >= 0 && i != iBytes; i++)
{
int cHigh = charUnHex (*pSrc++);
int cLow = charUnHex (*pSrc++);
if (cHigh < 0 || cLow < 0)
{
iBytes = -1;
}
else
{
strDst[i] = (cHigh << 4) | cLow;
}
}
if (iBytes < 0)
strDst.clear ();
return iBytes;
}
Blob strUnHex (const std::string& strSrc)
{
std::string strTmp;
strUnHex (strTmp, strSrc);
return strCopy (strTmp);
}
uint64_t uintFromHex (const std::string& strSrc)
{
uint64_t uValue = 0;
BOOST_FOREACH (char c, strSrc)
uValue = (uValue << 4) | charUnHex (c);
return uValue;
}
//
// Misc string
//
Blob strCopy (const std::string& strSrc)
{
Blob vucDst;
vucDst.resize (strSrc.size ());
std::copy (strSrc.begin (), strSrc.end (), vucDst.begin ());
return vucDst;
}
std::string strCopy (Blob const& vucSrc)
{
std::string strDst;
strDst.resize (vucSrc.size ());
std::copy (vucSrc.begin (), vucSrc.end (), strDst.begin ());
return strDst;
}
extern std::string urlEncode (const std::string& strSrc)
{
std::string strDst;
int iOutput = 0;
int iSize = strSrc.length ();
strDst.resize (iSize * 3);
for (int iInput = 0; iInput < iSize; iInput++)
{
unsigned char c = strSrc[iInput];
if (c == ' ')
{
strDst[iOutput++] = '+';
}
else if (isalnum (c))
{
strDst[iOutput++] = c;
}
else
{
strDst[iOutput++] = '%';
strDst[iOutput++] = charHex (c >> 4);
strDst[iOutput++] = charHex (c & 15);
}
}
strDst.resize (iOutput);
return strDst;
}
//
// IP Port parsing
//
// <-- iPort: "" = -1
// VFALCO TODO Make this not require boost... and especially boost::asio
bool parseIpPort (const std::string& strSource, std::string& strIP, int& iPort)
{
boost::smatch smMatch;
bool bValid = false;
static boost::regex reEndpoint ("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'");
if (boost::regex_match (strSource, smMatch, reEndpoint))
{
boost::system::error_code err;
std::string strIPRaw = smMatch[1];
std::string strPortRaw = smMatch[2];
boost::asio::ip::address addrIP = boost::asio::ip::address::from_string (strIPRaw, err);
bValid = !err;
if (bValid)
{
strIP = addrIP.to_string ();
iPort = strPortRaw.empty () ? -1 : lexicalCastThrow <int> (strPortRaw);
}
}
return bValid;
}
bool parseUrl (const std::string& strUrl, std::string& strScheme, std::string& strDomain, int& iPort, std::string& strPath)
{
// scheme://username:password@hostname:port/rest
static boost::regex reUrl ("(?i)\\`\\s*([[:alpha:]][-+.[:alpha:][:digit:]]*)://([^:/]+)(?::(\\d+))?(/.*)?\\s*?\\'");
boost::smatch smMatch;
bool bMatch = boost::regex_match (strUrl, smMatch, reUrl); // Match status code.
if (bMatch)
{
std::string strPort;
strScheme = smMatch[1];
strDomain = smMatch[2];
strPort = smMatch[3];
strPath = smMatch[4];
boost::algorithm::to_lower (strScheme);
iPort = strPort.empty () ? -1 : lexicalCast <int> (strPort);
// Log::out() << strUrl << " : " << bMatch << " : '" << strDomain << "' : '" << strPort << "' : " << iPort << " : '" << strPath << "'";
}
// Log::out() << strUrl << " : " << bMatch << " : '" << strDomain << "' : '" << strPath << "'";
return bMatch;
}
//
// Quality parsing
// - integers as is.
// - floats multiplied by a billion
bool parseQuality (const std::string& strSource, uint32& uQuality)
{
uQuality = lexicalCast <uint32> (strSource);
if (!uQuality)
{
float fQuality = lexicalCast <float> (strSource);
if (fQuality)
uQuality = (uint32) (QUALITY_ONE * fQuality);
}
return !!uQuality;
}
std::string addressToString (void const* address)
{
// VFALCO TODO Clean this up, use uintptr_t and only produce a 32 bit
// output on 32 bit platforms
//
return strHex (static_cast <char const*> (address) - static_cast <char const*> (0));
}
StringPairArray parseDelimitedKeyValueString (String parameters, beast_wchar delimiter)
{
StringPairArray keyValues;
while (parameters.isNotEmpty ())
{
String pair;
{
int const delimiterPos = parameters.indexOfChar (delimiter);
if (delimiterPos != -1)
{
pair = parameters.substring (0, delimiterPos);
parameters = parameters.substring (delimiterPos + 1);
}
else
{
pair = parameters;
parameters = String::empty;
}
}
int const equalPos = pair.indexOfChar ('=');
if (equalPos != -1)
{
String const key = pair.substring (0, equalPos);
String const value = pair.substring (equalPos + 1, pair.length ());
keyValues.set (key, value);
}
}
return keyValues;
}
//------------------------------------------------------------------------------
class StringUtilitiesTests : public UnitTest
{
public:
StringUtilitiesTests () : UnitTest ("StringUtilities", "ripple")
{
}
void runTest ()
{
beginTestCase ("parseUrl");
std::string strScheme;
std::string strDomain;
int iPort;
std::string strPath;
unexpected (!parseUrl ("lower://domain", strScheme, strDomain, iPort, strPath),
"parseUrl: lower://domain failed");
unexpected (strScheme != "lower",
"parseUrl: lower://domain : scheme failed");
unexpected (strDomain != "domain",
"parseUrl: lower://domain : domain failed");
unexpected (iPort != -1,
"parseUrl: lower://domain : port failed");
unexpected (strPath != "",
"parseUrl: lower://domain : path failed");
unexpected (!parseUrl ("UPPER://domain:234/", strScheme, strDomain, iPort, strPath),
"parseUrl: UPPER://domain:234/ failed");
unexpected (strScheme != "upper",
"parseUrl: UPPER://domain:234/ : scheme failed");
unexpected (iPort != 234,
boost::str (boost::format ("parseUrl: UPPER://domain:234/ : port failed: %d") % iPort));
unexpected (strPath != "/",
"parseUrl: UPPER://domain:234/ : path failed");
unexpected (!parseUrl ("Mixed://domain/path", strScheme, strDomain, iPort, strPath),
"parseUrl: Mixed://domain/path failed");
unexpected (strScheme != "mixed",
"parseUrl: Mixed://domain/path tolower failed");
unexpected (strPath != "/path",
"parseUrl: Mixed://domain/path path failed");
}
};
static StringUtilitiesTests stringUtilitiesTests;

View File

@@ -0,0 +1,187 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_STRINGUTILITIES_H
#define RIPPLE_STRINGUTILITIES_H
/** String utility functions.
*/
//------------------------------------------------------------------------------
// Ripple specific constant used for parsing qualities and other things
//
#define QUALITY_ONE 1000000000 // 10e9
//------------------------------------------------------------------------------
// Terminal output color codes
#define vt_f_black "\033[30m"
#define vt_f_red "\033[31m"
#define vt_f_green "\033[32m"
#define vt_f_yellow "\033[33m"
#define vt_f_blue "\033[34m"
#define vt_f_megenta "\033[35m"
#define vt_f_cyan "\033[36m"
#define vt_f_white "\033[37m"
#define vt_f_default "\033[39m"
#define vt_b_black "\033[40m"
#define vt_b_red "\033[41m"
#define vt_b_green "\033[42m"
#define vt_b_yellow "\033[43m"
#define vt_b_blue "\033[44m"
#define vt_b_megenta "\033[45m"
#define vt_b_cyan "\033[46m"
#define vt_b_white "\033[47m"
#define vt_b_default "\033[49m"
#define vt_f_bold_black "\033[1m\033[30m"
#define vt_f_bold_red "\033[1m\033[31m"
#define vt_f_bold_green "\033[1m\033[32m"
#define vt_f_bold_yellow "\033[1m\033[33m"
#define vt_f_bold_blue "\033[1m\033[34m"
#define vt_f_bold_megenta "\033[1m\033[35m"
#define vt_f_bold_cyan "\033[1m\033[36m"
#define vt_f_bold_white "\033[1m\033[37m"
#define vt_f_bold_default "\033[1m\033[39m"
#define vt_bold "\033[1m"
#define vt_dim "\033[2m" // does not work for xterm
#define vt_normal "\033[22m" // intensity
#define vt_n_enable "\033[7m" // negative
#define vt_n_disable "\033[27m"
#define vt_u_single "\033[4m" // underline
#define vt_u_double "\033[21m" // does not work for xterm
#define vt_u_disable "\033[24m"
#define vt_reset vt_f_default vt_b_default vt_normal vt_n_disable vt_u_disable
//------------------------------------------------------------------------------
extern std::string strprintf (const char* format, ...);
extern std::string urlEncode (const std::string& strSrc);
template<class Iterator>
std::string strJoin (Iterator first, Iterator last, std::string strSeperator)
{
std::ostringstream ossValues;
for (Iterator start = first; first != last; first++)
{
ossValues << str (boost::format ("%s%s") % (start == first ? "" : strSeperator) % *first);
}
return ossValues.str ();
}
char charHex (int iDigit);
template<class Iterator>
std::string strHex (Iterator first, int iSize)
{
std::string strDst;
strDst.resize (iSize * 2);
for (int i = 0; i < iSize; i++)
{
unsigned char c = *first++;
strDst[i * 2] = charHex (c >> 4);
strDst[i * 2 + 1] = charHex (c & 15);
}
return strDst;
}
inline const std::string strHex (const std::string& strSrc)
{
return strHex (strSrc.begin (), strSrc.size ());
}
inline std::string strHex (Blob const& vucData)
{
return strHex (vucData.begin (), vucData.size ());
}
inline std::string strHex (const uint64 uiHost)
{
uint64_t uBig = htobe64 (uiHost);
return strHex ((unsigned char*) &uBig, sizeof (uBig));
}
inline static std::string sqlEscape (const std::string& strSrc)
{
static boost::format f ("X'%s'");
return str (boost::format (f) % strHex (strSrc));
}
inline static std::string sqlEscape (Blob const& vecSrc)
{
size_t size = vecSrc.size ();
if (size == 0)
return "X''";
std::string j (size * 2 + 3, 0);
unsigned char* oPtr = reinterpret_cast<unsigned char*> (&*j.begin ());
const unsigned char* iPtr = &vecSrc[0];
*oPtr++ = 'X';
*oPtr++ = '\'';
for (int i = size; i != 0; --i)
{
unsigned char c = *iPtr++;
*oPtr++ = charHex (c >> 4);
*oPtr++ = charHex (c & 15);
}
*oPtr++ = '\'';
return j;
}
int charUnHex (char cDigit);
int strUnHex (std::string& strDst, const std::string& strSrc);
uint64_t uintFromHex (const std::string& strSrc);
Blob strUnHex (const std::string& strSrc);
Blob strCopy (const std::string& strSrc);
std::string strCopy (Blob const& vucSrc);
bool parseIpPort (const std::string& strSource, std::string& strIP, int& iPort);
bool parseQuality (const std::string& strSource, uint32& uQuality);
inline std::string strGetEnv (const std::string& strKey)
{
return getenv (strKey.c_str ()) ? getenv (strKey.c_str ()) : "";
}
bool parseUrl (const std::string& strUrl, std::string& strScheme, std::string& strDomain, int& iPort, std::string& strPath);
#define ADDRESS(p) strHex(uint64( ((char*) p) - ((char*) 0)))
/** Convert a pointer address to a string for display purposes.
*/
extern std::string addressToString (void const* address);
/** Create a Parameters from a String.
Parameter strings have the format:
<key>=<value>['|'<key>=<value>]
*/
extern StringPairArray parseDelimitedKeyValueString (String s, beast_wchar delimiter='|');
#endif

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifdef __unix__
static pid_t pManager = static_cast<pid_t> (0);
static pid_t pChild = static_cast<pid_t> (0);
static void pass_signal (int a)
{
kill (pChild, a);
}
static void stop_manager (int)
{
kill (pChild, SIGINT);
_exit (0);
}
bool HaveSustain ()
{
return true;
}
std::string StopSustain ()
{
if (getppid () != pManager)
return std::string ();
kill (pManager, SIGHUP);
return "Terminating monitor";
}
std::string DoSustain (std::string logFile)
{
int childCount = 0;
pManager = getpid ();
signal (SIGINT, stop_manager);
signal (SIGHUP, stop_manager);
signal (SIGUSR1, pass_signal);
signal (SIGUSR2, pass_signal);
while (1)
{
++childCount;
pChild = fork ();
if (pChild == -1)
_exit (0);
if (pChild == 0)
{
setCallingThreadName ("main");
signal (SIGINT, SIG_DFL);
signal (SIGHUP, SIG_DFL);
signal (SIGUSR1, SIG_DFL);
signal (SIGUSR2, SIG_DFL);
return str (boost::format ("Launching child %d") % childCount);;
}
setCallingThreadName (boost::str (boost::format ("#%d") % childCount).c_str ());
do
{
int i;
sleep (10);
waitpid (-1, &i, 0);
}
while (kill (pChild, 0) == 0);
rename ("core", boost::str (boost::format ("core.%d") % static_cast<int> (pChild)).c_str ());
if (!logFile.empty())
rename (logFile.c_str(),
boost::str (boost::format ("%s.%d") % logFile % static_cast<int> (pChild)).c_str ());
}
}
#else
bool HaveSustain ()
{
return false;
}
std::string DoSustain (std::string)
{
return std::string ();
}
std::string StopSustain ()
{
return std::string ();
}
#endif

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SUSTAIN_H
#define RIPPLE_SUSTAIN_H
// "Sustain" is a system for a buddy process that monitors the main process
// and relaunches it on a fault.
//
// VFALCO TODO Rename this and put it in a class.
// VFALCO TODO Reimplement cross-platform using beast::Process and its ilk
//
extern bool HaveSustain ();
extern std::string StopSustain ();
extern std::string DoSustain (std::string logFile);
#endif

View File

@@ -0,0 +1,80 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO TODO use beast::Thread::setCurrentThreadName() or something similar.
#if _MSC_VER
void setCallingThreadName (char const* threadName)
{
struct ThreadInfo
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
};
ThreadInfo info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = GetCurrentThreadId ();
info.dwFlags = 0;
__try
{
// This is a VisualStudio specific exception
RaiseException (0x406d1388, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
#else
#ifdef PR_SET_NAME
#define HAVE_NAME_THREAD
extern void setCallingThreadName (const char* n)
{
static std::string pName;
if (pName.empty ())
{
std::ifstream cLine ("/proc/self/cmdline", std::ios::in);
cLine >> pName;
if (pName.empty ())
pName = "rippled";
else
{
size_t zero = pName.find_first_of ('\0');
if ((zero != std::string::npos) && (zero != 0))
pName = pName.substr (0, zero);
size_t slash = pName.find_last_of ('/');
if (slash != std::string::npos)
pName = pName.substr (slash + 1);
}
pName += " ";
}
// VFALCO TODO Use beast::Thread::setCurrentThreadName here
//
prctl (PR_SET_NAME, (pName + n).c_str (), 0, 0, 0);
}
#endif
#ifndef HAVE_NAME_THREAD
extern void setCallingThreadName (const char*)
{
;
}
#endif
#endif

View File

@@ -0,0 +1,12 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_THREADNAME_H
#define RIPPLE_THREADNAME_H
extern void setCallingThreadName (char const*);
#endif

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO TODO Tidy this up into a RippleTime object
//
// Time support
// We have our own epoch.
//
boost::posix_time::ptime ptEpoch ()
{
return boost::posix_time::ptime (boost::gregorian::date (2000, boost::gregorian::Jan, 1));
}
int iToSeconds (boost::posix_time::ptime ptWhen)
{
return ptWhen.is_not_a_date_time ()
? -1
: (ptWhen - ptEpoch ()).total_seconds ();
}
// Convert our time in seconds to a ptime.
boost::posix_time::ptime ptFromSeconds (int iSeconds)
{
return iSeconds < 0
? boost::posix_time::ptime (boost::posix_time::not_a_date_time)
: ptEpoch () + boost::posix_time::seconds (iSeconds);
}
// Convert from our time to UNIX time in seconds.
uint64_t utFromSeconds (int iSeconds)
{
boost::posix_time::time_duration tdDelta =
boost::posix_time::ptime (boost::gregorian::date (2000, boost::gregorian::Jan, 1))
- boost::posix_time::ptime (boost::gregorian::date (1970, boost::gregorian::Jan, 1))
+ boost::posix_time::seconds (iSeconds)
;
return tdDelta.total_seconds ();
}

View File

@@ -0,0 +1,15 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_TIME_H
#define RIPPLE_TIME_H
boost::posix_time::ptime ptEpoch ();
int iToSeconds (boost::posix_time::ptime ptWhen);
boost::posix_time::ptime ptFromSeconds (int iSeconds);
uint64_t utFromSeconds (int iSeconds);
#endif

View File

@@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
UptimeTimer::UptimeTimer ()
: m_elapsedTime (0)
, m_startTime (::time (0))
, m_isUpdatingManually (false)
{
}
UptimeTimer::~UptimeTimer ()
{
}
int UptimeTimer::getElapsedSeconds () const
{
int result;
if (m_isUpdatingManually)
{
// memoryBarrier();
result = m_elapsedTime;
}
else
{
// VFALCO TODO use time_t instead of int return
result = static_cast <int> (::time (0) - m_startTime);
}
return result;
}
void UptimeTimer::beginManualUpdates ()
{
//assert (!m_isUpdatingManually);
m_isUpdatingManually = true;
}
void UptimeTimer::endManualUpdates ()
{
//assert (m_isUpdatingManually);
m_isUpdatingManually = false;
}
void UptimeTimer::incrementElapsedTime ()
{
//assert (m_isUpdatingManually);
++m_elapsedTime;
}
UptimeTimer& UptimeTimer::getInstance ()
{
static UptimeTimer instance;
return instance;
}

View File

@@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_UPTIMETIMER_H
#define RIPPLE_UPTIMETIMER_H
/** Tracks program uptime.
The timer can be switched to a manual system of updating, to reduce
system calls. (?)
*/
// VFALCO TODO determine if the non-manual timing is actually needed
class UptimeTimer
{
private:
UptimeTimer ();
~UptimeTimer ();
public:
int getElapsedSeconds () const;
void beginManualUpdates ();
void endManualUpdates ();
void incrementElapsedTime ();
static UptimeTimer& getInstance ();
private:
// VFALCO DEPRECATED, Use a memory barrier instead of forcing a cache line
int m_pad1; // make sure m_elapsedTime fits in its own cache line
int volatile m_elapsedTime;
int m_pad2;
time_t m_startTime;
bool m_isUpdatingManually;
};
#endif