mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Move ./modules to ./src
This commit is contained in:
221
src/ripple_basics/containers/ripple_KeyCache.h
Normal file
221
src/ripple_basics/containers/ripple_KeyCache.h
Normal 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
|
||||
317
src/ripple_basics/containers/ripple_RangeSet.cpp
Normal file
317
src/ripple_basics/containers/ripple_RangeSet.cpp
Normal 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;
|
||||
|
||||
67
src/ripple_basics/containers/ripple_RangeSet.h
Normal file
67
src/ripple_basics/containers/ripple_RangeSet.h
Normal 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
|
||||
59
src/ripple_basics/containers/ripple_SecureAllocator.h
Normal file
59
src/ripple_basics/containers/ripple_SecureAllocator.h
Normal 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
|
||||
7
src/ripple_basics/containers/ripple_TaggedCache.cpp
Normal file
7
src/ripple_basics/containers/ripple_TaggedCache.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOGN (TaggedCacheLog,"TaggedCache")
|
||||
505
src/ripple_basics/containers/ripple_TaggedCache.h
Normal file
505
src/ripple_basics/containers/ripple_TaggedCache.h
Normal 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
|
||||
BIN
src/ripple_basics/json/LICENSE
Normal file
BIN
src/ripple_basics/json/LICENSE
Normal file
Binary file not shown.
28
src/ripple_basics/json/json_autolink.h
Normal file
28
src/ripple_basics/json/json_autolink.h
Normal 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
|
||||
132
src/ripple_basics/json/json_batchallocator.h
Normal file
132
src/ripple_basics/json/json_batchallocator.h
Normal 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
|
||||
|
||||
49
src/ripple_basics/json/json_config.h
Normal file
49
src/ripple_basics/json/json_config.h
Normal 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
|
||||
47
src/ripple_basics/json/json_features.h
Normal file
47
src/ripple_basics/json/json_features.h
Normal 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
|
||||
44
src/ripple_basics/json/json_forwards.h
Normal file
44
src/ripple_basics/json/json_forwards.h
Normal 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
|
||||
484
src/ripple_basics/json/json_internalarray.inl
Normal file
484
src/ripple_basics/json/json_internalarray.inl
Normal 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;
|
||||
}
|
||||
658
src/ripple_basics/json/json_internalmap.inl
Normal file
658
src/ripple_basics/json/json_internalmap.inl
Normal 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 ¤t->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 = ¤t->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;
|
||||
}
|
||||
1023
src/ripple_basics/json/json_reader.cpp
Normal file
1023
src/ripple_basics/json/json_reader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
196
src/ripple_basics/json/json_reader.h
Normal file
196
src/ripple_basics/json/json_reader.h
Normal 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
|
||||
1923
src/ripple_basics/json/json_value.cpp
Normal file
1923
src/ripple_basics/json/json_value.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1065
src/ripple_basics/json/json_value.h
Normal file
1065
src/ripple_basics/json/json_value.h
Normal file
File diff suppressed because it is too large
Load Diff
329
src/ripple_basics/json/json_valueiterator.inl
Normal file
329
src/ripple_basics/json/json_valueiterator.inl
Normal 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;
|
||||
}
|
||||
931
src/ripple_basics/json/json_writer.cpp
Normal file
931
src/ripple_basics/json/json_writer.cpp
Normal 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
|
||||
176
src/ripple_basics/json/json_writer.h
Normal file
176
src/ripple_basics/json/json_writer.h
Normal 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
|
||||
1
src/ripple_basics/json/version
Normal file
1
src/ripple_basics/json/version
Normal file
@@ -0,0 +1 @@
|
||||
0.5.0
|
||||
99
src/ripple_basics/ripple_basics.cpp
Normal file
99
src/ripple_basics/ripple_basics.cpp
Normal 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"
|
||||
|
||||
}
|
||||
130
src/ripple_basics/ripple_basics.h
Normal file
130
src/ripple_basics/ripple_basics.h
Normal 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
|
||||
51
src/ripple_basics/system/ripple_BoostIncludes.h
Normal file
51
src/ripple_basics/system/ripple_BoostIncludes.h
Normal 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
|
||||
23
src/ripple_basics/system/ripple_OpenSSLIncludes.h
Normal file
23
src/ripple_basics/system/ripple_OpenSSLIncludes.h
Normal 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
|
||||
36
src/ripple_basics/system/ripple_StandardIncludes.h
Normal file
36
src/ripple_basics/system/ripple_StandardIncludes.h
Normal 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
|
||||
38
src/ripple_basics/types/ripple_BasicTypes.h
Normal file
38
src/ripple_basics/types/ripple_BasicTypes.h
Normal 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
|
||||
119
src/ripple_basics/types/ripple_HashMaps.h
Normal file
119
src/ripple_basics/types/ripple_HashMaps.h
Normal 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
|
||||
20
src/ripple_basics/types/ripple_UInt256.cpp
Normal file
20
src/ripple_basics/types/ripple_UInt256.cpp
Normal 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);
|
||||
}
|
||||
|
||||
942
src/ripple_basics/types/ripple_UInt256.h
Normal file
942
src/ripple_basics/types/ripple_UInt256.h
Normal 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
|
||||
44
src/ripple_basics/utility/ripple_ByteOrder.cpp
Normal file
44
src/ripple_basics/utility/ripple_ByteOrder.cpp
Normal 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
|
||||
45
src/ripple_basics/utility/ripple_ByteOrder.h
Normal file
45
src/ripple_basics/utility/ripple_ByteOrder.h
Normal 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
|
||||
78
src/ripple_basics/utility/ripple_CountedObject.cpp
Normal file
78
src/ripple_basics/utility/ripple_CountedObject.cpp
Normal 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.
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
140
src/ripple_basics/utility/ripple_CountedObject.h
Normal file
140
src/ripple_basics/utility/ripple_CountedObject.h
Normal 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
|
||||
37
src/ripple_basics/utility/ripple_DiffieHellmanUtil.cpp
Normal file
37
src/ripple_basics/utility/ripple_DiffieHellmanUtil.cpp
Normal 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
|
||||
15
src/ripple_basics/utility/ripple_DiffieHellmanUtil.h
Normal file
15
src/ripple_basics/utility/ripple_DiffieHellmanUtil.h
Normal 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
|
||||
95
src/ripple_basics/utility/ripple_HashUtilities.h
Normal file
95
src/ripple_basics/utility/ripple_HashUtilities.h
Normal 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
|
||||
162
src/ripple_basics/utility/ripple_IniFile.cpp
Normal file
162
src/ripple_basics/utility/ripple_IniFile.cpp
Normal 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;
|
||||
}
|
||||
|
||||
30
src/ripple_basics/utility/ripple_IniFile.h
Normal file
30
src/ripple_basics/utility/ripple_IniFile.h
Normal 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
|
||||
267
src/ripple_basics/utility/ripple_Log.cpp
Normal file
267
src/ripple_basics/utility/ripple_Log.cpp
Normal 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
|
||||
227
src/ripple_basics/utility/ripple_Log.h
Normal file
227
src/ripple_basics/utility/ripple_Log.h
Normal 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
|
||||
69
src/ripple_basics/utility/ripple_LogFile.cpp
Normal file
69
src/ripple_basics/utility/ripple_LogFile.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
93
src/ripple_basics/utility/ripple_LogFile.h
Normal file
93
src/ripple_basics/utility/ripple_LogFile.h
Normal 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
|
||||
114
src/ripple_basics/utility/ripple_LoggedTimings.h
Normal file
114
src/ripple_basics/utility/ripple_LoggedTimings.h
Normal 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
|
||||
39
src/ripple_basics/utility/ripple_PlatformMacros.h
Normal file
39
src/ripple_basics/utility/ripple_PlatformMacros.h
Normal 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
|
||||
217
src/ripple_basics/utility/ripple_RandomNumbers.cpp
Normal file
217
src/ripple_basics/utility/ripple_RandomNumbers.cpp
Normal 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
|
||||
}
|
||||
73
src/ripple_basics/utility/ripple_RandomNumbers.h
Normal file
73
src/ripple_basics/utility/ripple_RandomNumbers.h
Normal 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
|
||||
369
src/ripple_basics/utility/ripple_StringUtilities.cpp
Normal file
369
src/ripple_basics/utility/ripple_StringUtilities.cpp
Normal 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;
|
||||
187
src/ripple_basics/utility/ripple_StringUtilities.h
Normal file
187
src/ripple_basics/utility/ripple_StringUtilities.h
Normal 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
|
||||
96
src/ripple_basics/utility/ripple_Sustain.cpp
Normal file
96
src/ripple_basics/utility/ripple_Sustain.cpp
Normal 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
|
||||
20
src/ripple_basics/utility/ripple_Sustain.h
Normal file
20
src/ripple_basics/utility/ripple_Sustain.h
Normal 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
|
||||
80
src/ripple_basics/utility/ripple_ThreadName.cpp
Normal file
80
src/ripple_basics/utility/ripple_ThreadName.cpp
Normal 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
|
||||
12
src/ripple_basics/utility/ripple_ThreadName.h
Normal file
12
src/ripple_basics/utility/ripple_ThreadName.h
Normal 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
|
||||
44
src/ripple_basics/utility/ripple_Time.cpp
Normal file
44
src/ripple_basics/utility/ripple_Time.cpp
Normal 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 ();
|
||||
}
|
||||
15
src/ripple_basics/utility/ripple_Time.h
Normal file
15
src/ripple_basics/utility/ripple_Time.h
Normal 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
|
||||
61
src/ripple_basics/utility/ripple_UptimeTimer.cpp
Normal file
61
src/ripple_basics/utility/ripple_UptimeTimer.cpp
Normal 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;
|
||||
}
|
||||
43
src/ripple_basics/utility/ripple_UptimeTimer.h
Normal file
43
src/ripple_basics/utility/ripple_UptimeTimer.h
Normal 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
|
||||
Reference in New Issue
Block a user