Merge pull request #4 from Noughmad/GRPH-50-network_broadcast_api-fix

[GRPH-50] network broadcast api fix
This commit is contained in:
pbattu123 2019-10-04 09:24:17 -03:00 committed by GitHub
commit f13d0632b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 2441 additions and 1641 deletions

View file

@ -102,14 +102,14 @@ namespace fc {
{ return 0 != memcmp( a.data, b.data, N*sizeof(T) ); }
template<typename T, size_t N>
void to_variant( const array<T,N>& bi, variant& v )
void to_variant( const array<T,N>& bi, variant& v, uint32_t max_depth = 1 )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, 1 );
}
template<typename T, size_t N>
void from_variant( const variant& v, array<T,N>& bi )
void from_variant( const variant& v, array<T,N>& bi, uint32_t max_depth = 1 )
{
std::vector<char> ve = v.as< std::vector<char> >();
std::vector<char> ve = v.as< std::vector<char> >( 1 );
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );

9
include/fc/config.hpp Normal file
View file

@ -0,0 +1,9 @@
#ifndef FC_PACK_MAX_DEPTH
// The maximum level of object nesting is around 20% of this value
#define FC_PACK_MAX_DEPTH 1000
#endif
#ifndef FC_MAX_LOG_OBJECT_DEPTH
// how many levels of nested objects are displayed in log messages
#define FC_MAX_LOG_OBJECT_DEPTH 200
#endif

View file

@ -1,13 +1,14 @@
#pragma once
#include <fc/config.hpp>
#include <deque>
namespace fc {
namespace raw {
template<typename Stream, typename T>
void pack( Stream& s, const std::deque<T>& value );
void pack( Stream& s, const std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T>
void unpack( Stream& s, std::deque<T>& value );
void unpack( Stream& s, std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
}
} // namespace fc

View file

@ -8,61 +8,71 @@
namespace fc {
namespace raw {
template<typename Stream, typename T>
inline void pack( Stream& s, const flat_set<T>& value ) {
pack( s, unsigned_int((uint32_t)value.size()) );
inline void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
auto itr = value.begin();
auto end = value.end();
while( itr != end ) {
fc::raw::pack( s, *itr );
fc::raw::pack( s, *itr, _max_depth );
++itr;
}
}
template<typename Stream, typename T>
inline void unpack( Stream& s, flat_set<T>& value ) {
unsigned_int size; unpack( s, size );
inline void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int size; unpack( s, size, _max_depth );
value.clear();
FC_ASSERT( size.value*sizeof(T) < MAX_ARRAY_ALLOC_SIZE );
value.reserve(size.value);
for( uint32_t i = 0; i < size.value; ++i )
{
T tmp;
fc::raw::unpack( s, tmp );
fc::raw::unpack( s, tmp, _max_depth );
value.insert( std::move(tmp) );
}
}
template<typename Stream, typename K, typename... V>
inline void pack( Stream& s, const flat_map<K,V...>& value ) {
pack( s, unsigned_int((uint32_t)value.size()) );
inline void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
auto itr = value.begin();
auto end = value.end();
while( itr != end ) {
fc::raw::pack( s, *itr );
fc::raw::pack( s, *itr, _max_depth );
++itr;
}
}
template<typename Stream, typename K, typename V, typename... A>
inline void unpack( Stream& s, flat_map<K,V,A...>& value )
inline void unpack( Stream& s, flat_map<K,V,A...>& value, uint32_t _max_depth )
{
unsigned_int size; unpack( s, size );
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int size; unpack( s, size, _max_depth );
value.clear();
FC_ASSERT( size.value*(sizeof(K)+sizeof(V)) < MAX_ARRAY_ALLOC_SIZE );
value.reserve(size.value);
for( uint32_t i = 0; i < size.value; ++i )
{
std::pair<K,V> tmp;
fc::raw::unpack( s, tmp );
fc::raw::unpack( s, tmp, _max_depth );
value.insert( std::move(tmp) );
}
}
template<typename Stream, typename T, typename A>
void pack( Stream& s, const bip::vector<T,A>& value ) {
pack( s, unsigned_int((uint32_t)value.size()) );
void pack( Stream& s, const bip::vector<T,A>& value, uint32_t _max_depth ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
if( !std::is_fundamental<T>::value ) {
auto itr = value.begin();
auto end = value.end();
while( itr != end ) {
fc::raw::pack( s, *itr );
fc::raw::pack( s, *itr, _max_depth );
++itr;
}
} else {
@ -71,13 +81,15 @@ namespace fc {
}
template<typename Stream, typename T, typename A>
void unpack( Stream& s, bip::vector<T,A>& value ) {
void unpack( Stream& s, bip::vector<T,A>& value, uint32_t _max_depth ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int size;
unpack( s, size );
unpack( s, size, _max_depth );
value.resize( size );
if( !std::is_fundamental<T>::value ) {
for( auto& item : value )
unpack( s, item );
unpack( s, item, _max_depth );
} else {
s.read( (char*)value.data(), value.size() );
}
@ -87,41 +99,48 @@ namespace fc {
template<typename T>
void to_variant( const flat_set<T>& var, variant& vo )
void to_variant( const flat_set<T>& var, variant& vo, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
std::vector<variant> vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = variant(*itr);
for( const auto& item : var )
vars[i++] = variant( item, _max_depth );
vo = vars;
}
template<typename T>
void from_variant( const variant& var, flat_set<T>& vo )
void from_variant( const variant& var, flat_set<T>& vo, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
const variants& vars = var.get_array();
vo.clear();
vo.reserve( vars.size() );
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as<T>() );
for( const auto& item : vars )
vo.insert( item.as<T>(_max_depth) );
}
template<typename K, typename... T>
void to_variant( const flat_map<K, T...>& var, variant& vo )
void to_variant( const flat_map<K, T...>& var, variant& vo, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
std::vector< variant > vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = fc::variant(*itr);
for( const auto& item : var )
vars[i++] = variant( item, _max_depth );
vo = vars;
}
template<typename K, typename T, typename... A>
void from_variant( const variant& var, flat_map<K, T, A...>& vo )
void from_variant( const variant& var, flat_map<K, T, A...>& vo, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
const variants& vars = var.get_array();
vo.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as< std::pair<K,T> >() );
for( const auto& item : vars )
vo.insert( item.as<std::pair<K,T>>(_max_depth) );
}
}

View file

@ -1,7 +1,8 @@
#pragma once
#pragma once
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <fc/config.hpp>
namespace fc {
@ -11,19 +12,19 @@ namespace fc {
namespace raw {
template<typename Stream, typename T>
void pack( Stream& s, const flat_set<T>& value );
void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T>
void unpack( Stream& s, flat_set<T>& value );
void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename... V>
void pack( Stream& s, const flat_map<K,V...>& value );
void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V, typename... A>
void unpack(Stream& s, flat_map<K, V, A...>& value);
void unpack(Stream& s, flat_map<K, V, A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T, typename A>
void pack( Stream& s, const bip::vector<T,A>& value );
void pack( Stream& s, const bip::vector<T,A>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T, typename A>
void unpack( Stream& s, bip::vector<T,A>& value );
void unpack( Stream& s, bip::vector<T,A>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
} // namespace raw
} // fc

View file

@ -69,8 +69,8 @@ namespace fc {
class variant;
/** encodes the big int as base64 string, or a number */
void to_variant( const bigint& bi, variant& v );
void to_variant( const bigint& bi, variant& v, uint32_t max_depth = 1 );
/** decodes the big int as base64 string, or a number */
void from_variant( const variant& v, bigint& bi );
void from_variant( const variant& v, bigint& bi, uint32_t max_depth = 1 );
} // namespace fc

View file

@ -230,39 +230,43 @@ namespace fc {
} // namespace ecc
void to_variant( const ecc::private_key& var, variant& vo );
void from_variant( const variant& var, ecc::private_key& vo );
void to_variant( const ecc::public_key& var, variant& vo );
void from_variant( const variant& var, ecc::public_key& vo );
void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth );
void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth );
namespace raw
{
template<typename Stream>
void unpack( Stream& s, fc::ecc::public_key& pk)
void unpack( Stream& s, fc::ecc::public_key& pk, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
ecc::public_key_data ser;
fc::raw::unpack(s,ser);
fc::raw::unpack( s, ser, _max_depth - 1 );
pk = fc::ecc::public_key( ser );
}
template<typename Stream>
void pack( Stream& s, const fc::ecc::public_key& pk)
void pack( Stream& s, const fc::ecc::public_key& pk, uint32_t _max_depth )
{
fc::raw::pack( s, pk.serialize() );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
}
template<typename Stream>
void unpack( Stream& s, fc::ecc::private_key& pk)
void unpack( Stream& s, fc::ecc::private_key& pk, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
fc::sha256 sec;
unpack( s, sec );
unpack( s, sec, _max_depth - 1 );
pk = ecc::private_key::regenerate(sec);
}
template<typename Stream>
void pack( Stream& s, const fc::ecc::private_key& pk)
void pack( Stream& s, const fc::ecc::private_key& pk, uint32_t _max_depth )
{
fc::raw::pack( s, pk.get_secret() );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, pk.get_secret(), _max_depth - 1 );
}
} // namespace raw

View file

@ -67,8 +67,8 @@ class md5
};
class variant;
void to_variant( const md5& bi, variant& v );
void from_variant( const variant& v, md5& bi );
void to_variant( const md5& bi, variant& v, uint32_t max_depth = 1 );
void from_variant( const variant& v, md5& bi, uint32_t max_depth = 1 );
} // fc

View file

@ -76,38 +76,42 @@ namespace fc {
namespace raw
{
template<typename Stream>
void unpack( Stream& s, fc::public_key& pk)
void unpack( Stream& s, fc::public_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
FC_ASSERT( _max_depth > 0 );
bytes ser;
fc::raw::unpack(s,ser);
fc::raw::unpack( s, ser, _max_depth - 1 );
pk = fc::public_key( ser );
}
template<typename Stream>
void pack( Stream& s, const fc::public_key& pk)
void pack( Stream& s, const fc::public_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
fc::raw::pack( s, pk.serialize() );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
}
template<typename Stream>
void unpack( Stream& s, fc::private_key& pk)
void unpack( Stream& s, fc::private_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
FC_ASSERT( _max_depth > 0 );
bytes ser;
fc::raw::unpack(s,ser);
fc::raw::unpack( s, ser, _max_depth - 1 );
pk = fc::private_key( ser );
}
template<typename Stream>
void pack( Stream& s, const fc::private_key& pk)
void pack( Stream& s, const fc::private_key& pk, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
fc::raw::pack( s, pk.serialize() );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, pk.serialize(), _max_depth - 1 );
}
}
class variant;
void to_variant( const public_key& bi, variant& v );
void from_variant( const variant& v, public_key& bi );
void to_variant( const private_key& bi, variant& v );
void from_variant( const variant& v, private_key& bi );
void to_variant( const public_key& bi, variant& v, uint32_t max_depth = 1 );
void from_variant( const variant& v, public_key& bi, uint32_t max_depth = 1 );
void to_variant( const private_key& bi, variant& v, uint32_t max_depth = 1 );
void from_variant( const variant& v, private_key& bi, uint32_t max_depth = 1 );
} // fc

View file

@ -72,8 +72,8 @@ class ripemd160
};
class variant;
void to_variant( const ripemd160& bi, variant& v );
void from_variant( const variant& v, ripemd160& bi );
void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth );
void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth );
typedef ripemd160 uint160_t;
typedef ripemd160 uint160;

View file

@ -66,8 +66,8 @@ class sha1
};
class variant;
void to_variant( const sha1& bi, variant& v );
void from_variant( const variant& v, sha1& bi );
void to_variant( const sha1& bi, variant& v, uint32_t max_depth );
void from_variant( const variant& v, sha1& bi, uint32_t max_depth );
} // namespace fc

View file

@ -71,8 +71,8 @@ class sha224
};
class variant;
void to_variant( const sha224& bi, variant& v );
void from_variant( const variant& v, sha224& bi );
void to_variant( const sha224& bi, variant& v, uint32_t max_depth );
void from_variant( const variant& v, sha224& bi, uint32_t max_depth );
} // fc
namespace std

View file

@ -101,8 +101,8 @@ class sha256
typedef sha256 uint256;
class variant;
void to_variant( const sha256& bi, variant& v );
void from_variant( const variant& v, sha256& bi );
void to_variant( const sha256& bi, variant& v, uint32_t max_depth );
void from_variant( const variant& v, sha256& bi, uint32_t max_depth );
uint64_t hash64(const char* buf, size_t len);

View file

@ -69,8 +69,8 @@ class sha512
typedef fc::sha512 uint512;
class variant;
void to_variant( const sha512& bi, variant& v );
void from_variant( const variant& v, sha512& bi );
void to_variant( const sha512& bi, variant& v, uint32_t max_depth );
void from_variant( const variant& v, sha512& bi, uint32_t max_depth );
} // fc

View file

@ -116,8 +116,8 @@ namespace fc
*/
virtual std::shared_ptr<exception> dynamic_copy_exception()const;
friend void to_variant( const exception& e, variant& v );
friend void from_variant( const variant& e, exception& ll );
friend void to_variant( const exception& e, variant& v, uint32_t max_depth );
friend void from_variant( const variant& e, exception& ll, uint32_t max_depth );
exception& operator=( const exception& copy );
exception& operator=( exception&& copy );
@ -125,8 +125,8 @@ namespace fc
std::unique_ptr<detail::exception_impl> my;
};
void to_variant( const exception& e, variant& v );
void from_variant( const variant& e, exception& ll );
void to_variant( const exception& e, variant& v, uint32_t max_depth );
void from_variant( const variant& e, exception& ll, uint32_t max_depth );
typedef std::shared_ptr<exception> exception_ptr;
typedef optional<exception> oexception;

View file

@ -182,8 +182,8 @@ namespace fc {
const fc::path& current_path();
class variant;
void to_variant( const fc::path&, fc::variant& );
void from_variant( const fc::variant& , fc::path& );
void to_variant( const fc::path&, fc::variant&, uint32_t max_depth = 1 );
void from_variant( const fc::variant&, fc::path&, uint32_t max_depth = 1 );
template<> struct get_typename<path> { static const char* name() { return "path"; } };

View file

@ -98,16 +98,18 @@ namespace fc {
namespace raw
{
template<typename Stream, typename Storage>
inline void pack( Stream& s, const fc::fixed_string<Storage>& u ) {
inline void pack( Stream& s, const fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
FC_ASSERT( _max_depth > 0 );
unsigned_int size = u.size();
pack( s, size );
pack( s, size, _max_depth - 1 );
s.write( (const char*)&u.data, size );
}
template<typename Stream, typename Storage>
inline void unpack( Stream& s, fc::fixed_string<Storage>& u ) {
inline void unpack( Stream& s, fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
FC_ASSERT( _max_depth > 0 );
unsigned_int size;
fc::raw::unpack( s, size );
fc::raw::unpack( s, size, _max_depth - 1 );
if( size.value > 0 ) {
if( size.value > sizeof(Storage) ) {
s.read( (char*)&u.data, sizeof(Storage) );
@ -119,43 +121,23 @@ namespace fc {
left -= 1024;
}
s.read( buf, left );
/*
s.seekp( s.tellp() + (size.value - sizeof(Storage)) );
char tmp;
size.value -= sizeof(storage);
while( size.value ){ s.read( &tmp, 1 ); --size.value; }
*/
// s.skip( size.value - sizeof(Storage) );
} else {
s.read( (char*)&u.data, size.value );
}
}
}
/*
template<typename Stream, typename... Args>
inline void pack( Stream& s, const boost::multiprecision::number<Args...>& d ) {
s.write( (const char*)&d, sizeof(d) );
}
template<typename Stream, typename... Args>
inline void unpack( Stream& s, boost::multiprecision::number<Args...>& u ) {
s.read( (const char*)&u, sizeof(u) );
}
*/
}
}
#include <fc/variant.hpp>
namespace fc {
template<typename Storage>
void to_variant( const fixed_string<Storage>& s, variant& v ) {
void to_variant( const fixed_string<Storage>& s, variant& v, uint32_t max_depth = 1 ) {
v = std::string(s);
}
template<typename Storage>
void from_variant( const variant& v, fixed_string<Storage>& s ) {
void from_variant( const variant& v, fixed_string<Storage>& s, uint32_t max_depth = 1 ) {
s = v.as_string();
}
}

View file

@ -9,6 +9,7 @@
#include <boost/interprocess/containers/set.hpp>
#include <boost/interprocess/containers/deque.hpp>
#include <fc/crypto/hex.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/raw_fwd.hpp>
namespace fc {
@ -16,87 +17,76 @@ namespace fc {
namespace bip = boost::interprocess;
template<typename... T >
void to_variant( const bip::deque< T... >& t, fc::variant& v ) {
void to_variant( const bip::deque< T... >& t, fc::variant& v, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
std::vector<variant> vars(t.size());
for( size_t i = 0; i < t.size(); ++i ) {
vars[i] = t[i];
to_variant( t[i], vars[i], max_depth );
}
v = std::move(vars);
}
template<typename T, typename... A>
void from_variant( const fc::variant& v, bip::deque< T, A... >& d ) {
void from_variant( const fc::variant& v, bip::deque< T, A... >& d, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
const variants& vars = v.get_array();
d.clear();
d.resize( vars.size() );
for( uint32_t i = 0; i < vars.size(); ++i ) {
from_variant( vars[i], d[i] );
from_variant( vars[i], d[i], max_depth );
}
}
//bip::map == boost::map
template<typename K, typename V, typename... T >
void to_variant( const bip::map< K, V, T... >& var, fc::variant& vo ) {
void to_variant( const bip::map< K, V, T... >& var, fc::variant& vo, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
std::vector< variant > vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = fc::variant(*itr);
vars[i] = fc::variant( *itr, max_depth );
vo = vars;
}
/*
template<typename K, typename V, typename... A>
void from_variant( const variant& var, bip::map<K, V, A...>& vo )
{
const variants& vars = var.get_array();
vo.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as< std::pair<K,V> >() ); Not safe for interprocess. Needs allocator
}
*/
template<typename... T >
void to_variant( const bip::vector< T... >& t, fc::variant& v ) {
void to_variant( const bip::vector< T... >& t, fc::variant& v, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
std::vector<variant> vars(t.size());
for( size_t i = 0; i < t.size(); ++i ) {
vars[i] = t[i];
to_variant( t[i], vars[i], max_depth );
}
v = std::move(vars);
}
template<typename T, typename... A>
void from_variant( const fc::variant& v, bip::vector< T, A... >& d ) {
void from_variant( const fc::variant& v, bip::vector< T, A... >& d, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
const variants& vars = v.get_array();
d.clear();
d.resize( vars.size() );
for( uint32_t i = 0; i < vars.size(); ++i ) {
from_variant( vars[i], d[i] );
from_variant( vars[i], d[i], max_depth );
}
}
template<typename... T >
void to_variant( const bip::set< T... >& t, fc::variant& v ) {
void to_variant( const bip::set< T... >& t, fc::variant& v, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
--max_depth;
std::vector<variant> vars;
vars.reserve(t.size());
for( const auto& item : t ) {
vars.emplace_back( item );
vars.emplace_back( variant( item, max_depth ) );
}
v = std::move(vars);
}
/*
template<typename T, typename... A>
void from_variant( const fc::variant& v, bip::set< T, A... >& d ) {
const variants& vars = v.get_array();
d.clear();
d.reserve( vars.size() );
for( uint32_t i = 0; i < vars.size(); ++i ) {
from_variant( vars[i], d[i] ); Not safe for interprocess. Needs allocator
}
}
*/
template<typename... A>
void to_variant( const bip::vector<char, A...>& t, fc::variant& v )
void to_variant( const bip::vector<char, A...>& t, fc::variant& v, uint32_t max_depth = 1 )
{
if( t.size() )
v = variant(fc::to_hex(t.data(), t.size()));
@ -105,7 +95,7 @@ namespace fc {
}
template<typename... A>
void from_variant( const fc::variant& v, bip::vector<char, A...>& d )
void from_variant( const fc::variant& v, bip::vector<char, A...>& d, uint32_t max_depth = 1 )
{
auto str = v.as_string();
d.resize( str.size() / 2 );
@ -114,30 +104,32 @@ namespace fc {
size_t r = fc::from_hex( str, d.data(), d.size() );
FC_ASSERT( r == d.size() );
}
// std::string b64 = base64_decode( var.as_string() );
// vo = std::vector<char>( b64.c_str(), b64.c_str() + b64.size() );
}
namespace raw {
namespace bip = boost::interprocess;
template<typename Stream, typename T, typename... A>
inline void pack( Stream& s, const bip::vector<T,A...>& value ) {
pack( s, unsigned_int((uint32_t)value.size()) );
auto itr = value.begin();
auto end = value.end();
while( itr != end ) {
fc::raw::pack( s, *itr );
++itr;
}
inline void pack( Stream& s, const bip::vector<T,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
pack( s, unsigned_int((uint32_t)value.size()), _max_depth );
auto itr = value.begin();
auto end = value.end();
while( itr != end ) {
fc::raw::pack( s, *itr, _max_depth );
++itr;
}
}
template<typename Stream, typename T, typename... A>
inline void unpack( Stream& s, bip::vector<T,A...>& value ) {
unsigned_int size;
unpack( s, size );
value.clear(); value.resize(size);
for( auto& item : value )
fc::raw::unpack( s, item );
inline void unpack( Stream& s, bip::vector<T,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) {
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int size;
unpack( s, size, _max_depth );
value.clear(); value.resize(size);
for( auto& item : value )
fc::raw::unpack( s, item, _max_depth );
}
}
}

View file

@ -11,16 +11,16 @@ namespace fc
public:
enum_type( EnumType t )
:value(t){}
enum_type( IntType t )
:value( (EnumType)t ){}
enum_type(){}
explicit operator IntType()const { return static_cast<IntType>(value); }
operator EnumType()const { return value; }
operator std::string()const { return fc::reflector<EnumType>::to_string(value); }
enum_type& operator=( IntType i ) { value = (EnumType)i; return *this;}
enum_type& operator=( EnumType i ) { value = i; return *this;}
bool operator<( EnumType i ) const { return value < i; }
@ -48,31 +48,33 @@ namespace fc
template<typename IntType, typename EnumType>
void to_variant( const enum_type<IntType,EnumType>& var, variant& vo )
void to_variant( const enum_type<IntType,EnumType>& var, variant& vo, uint32_t max_depth = 1 )
{
vo = (EnumType)var.value;
to_variant( var.value, vo, max_depth );
}
template<typename IntType, typename EnumType>
void from_variant( const variant& var, enum_type<IntType,EnumType>& vo )
void from_variant( const variant& var, enum_type<IntType,EnumType>& vo, uint32_t max_depth )
{
vo.value = var.as<EnumType>();
vo.value = var.as<EnumType>(1);
}
/** serializes like an IntType */
namespace raw
{
namespace raw
{
template<typename Stream, typename IntType, typename EnumType>
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp )
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth )
{
fc::raw::pack( s, static_cast<IntType>(tp) );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, static_cast<IntType>(tp), _max_depth - 1 );
}
template<typename Stream, typename IntType, typename EnumType>
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp )
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
IntType t;
fc::raw::unpack( s, t );
fc::raw::unpack( s, t, _max_depth - 1 );
tp = t;
}
}

View file

@ -2,6 +2,8 @@
#include <fc/variant.hpp>
#include <fc/filesystem.hpp>
#define DEFAULT_MAX_RECURSION_DEPTH 200
namespace fc
{
class ostream;
@ -18,62 +20,69 @@ namespace fc
enum parse_type
{
legacy_parser = 0,
#ifdef WITH_EXOTIC_JSON_PARSERS
strict_parser = 1,
relaxed_parser = 2,
legacy_parser_with_string_doubles = 3
legacy_parser_with_string_doubles = 3,
#endif
broken_nul_parser = 4
};
enum output_formatting
{
stringify_large_ints_and_doubles = 0,
#ifdef WITH_EXOTIC_JSON_PARSERS
legacy_generator = 1
#endif
};
static ostream& to_stream( ostream& out, const fc::string&);
static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles );
static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles );
static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles );
static ostream& to_stream( ostream& out, const fc::string& );
static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser );
static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser );
static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser );
static string to_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
static string to_pretty_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static string to_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static string to_pretty_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static bool is_valid( const std::string& json_str, parse_type ptype = legacy_parser );
static bool is_valid( const std::string& json_str, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
template<typename T>
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
{
save_to_file( variant(v), fi, pretty, format );
save_to_file( variant(v, max_depth), fi, pretty, format, max_depth );
}
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles );
static variant from_file( const fc::path& p, parse_type ptype = legacy_parser );
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
static variant from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH );
template<typename T>
static T from_file( const fc::path& p, parse_type ptype = legacy_parser )
static T from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
{
return json::from_file(p, ptype).as<T>();
return json::from_file(p, ptype, max_depth).as<T>(max_depth);
}
template<typename T>
static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
{
return to_string( variant(v), format );
return to_string( variant(v, max_depth), format, max_depth );
}
template<typename T>
static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
{
return to_pretty_string( variant(v), format );
return to_pretty_string( variant(v, max_depth), format, max_depth );
}
template<typename T>
static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
{
save_to_file( variant(v), fc::path(p), pretty );
save_to_file( variant(v, max_depth), fc::path(p), pretty, format, max_depth );
}
};
} // fc
#undef DEFAULT_MAX_RECURSION_DEPTH

View file

@ -21,7 +21,7 @@
namespace fc { namespace json_relaxed
{
template<typename T, bool strict>
variant variant_from_stream( T& in );
variant variant_from_stream( T& in, uint32_t max_depth );
template<typename T>
fc::string tokenFromStream( T& in )
@ -104,8 +104,15 @@ namespace fc { namespace json_relaxed
if( in.peek() == q )
{
in.get();
if( in.peek() != q )
return fc::string();
try
{
if( in.peek() != q )
return fc::string();
}
catch( const fc::eof_exception& e )
{
return fc::string();
}
// triple quote processing
if( strict )
@ -562,86 +569,18 @@ namespace fc { namespace json_relaxed
} FC_CAPTURE_AND_RETHROW( (token) ) }
template<typename T, bool strict>
variant_object objectFromStream( T& in )
variant_object objectFromStream( T& in, uint32_t max_depth )
{
mutable_variant_object obj;
try
{
char c = in.peek();
if( c != '{' )
FC_THROW_EXCEPTION( parse_error_exception,
"Expected '{', but read '${char}'",
("char",string(&c, &c + 1)) );
in.get();
skip_white_space(in);
while( in.peek() != '}' )
{
if( in.peek() == ',' )
{
in.get();
continue;
}
if( skip_white_space(in) ) continue;
string key = json_relaxed::stringFromStream<T, strict>( in );
skip_white_space(in);
if( in.peek() != ':' )
{
FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"",
("key", key) );
}
in.get();
auto val = json_relaxed::variant_from_stream<T, strict>( in );
obj(std::move(key),std::move(val));
skip_white_space(in);
}
if( in.peek() == '}' )
{
in.get();
return obj;
}
FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) );
}
catch( const fc::eof_exception& e )
{
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) );
}
catch( const std::ios_base::failure& e )
{
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) );
} FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" );
std::function<std::string(T&)> get_key = []( T& in ){ return json_relaxed::stringFromStream<T, strict>( in ); };
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, max_depth ); };
return objectFromStreamBase<T>( in, get_key, get_value );
}
template<typename T, bool strict>
variants arrayFromStream( T& in )
variants arrayFromStream( T& in, uint32_t max_depth )
{
variants ar;
try
{
if( in.peek() != '[' )
FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
in.get();
skip_white_space(in);
while( in.peek() != ']' )
{
if( in.peek() == ',' )
{
in.get();
continue;
}
if( skip_white_space(in) ) continue;
ar.push_back( json_relaxed::variant_from_stream<T, strict>(in) );
skip_white_space(in);
}
if( in.peek() != ']' )
FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
("variant", ar) );
in.get();
} FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}",
("array", ar ) );
return ar;
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, max_depth ); };
return arrayFromStreamBase<T>( in, get_value );
}
template<typename T, bool strict>
@ -686,60 +625,53 @@ namespace fc { namespace json_relaxed
}
template<typename T, bool strict>
variant variant_from_stream( T& in )
variant variant_from_stream( T& in, uint32_t max_depth )
{
if( max_depth == 0 )
FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
skip_white_space(in);
variant var;
while( signed char c = in.peek() )
signed char c = in.peek();
switch( c )
{
switch( c )
{
case ' ':
case '\t':
case '\n':
case '\r':
in.get();
continue;
case '"':
return json_relaxed::stringFromStream<T, strict>( in );
case '{':
return json_relaxed::objectFromStream<T, strict>( in );
case '[':
return json_relaxed::arrayFromStream<T, strict>( in );
case '-':
case '+':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return json_relaxed::numberFromStream<T, strict>( in );
// null, true, false, or 'warning' / string
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '_': case '/':
return json_relaxed::wordFromStream<T, strict>( in );
case 0x04: // ^D end of transmission
case EOF:
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
default:
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
("c", c)("s", stringFromToken(in)) );
}
case '"':
return json_relaxed::stringFromStream<T, strict>( in );
case '{':
return json_relaxed::objectFromStream<T, strict>( in, max_depth - 1 );
case '[':
return json_relaxed::arrayFromStream<T, strict>( in, max_depth - 1 );
case '-':
case '+':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return json_relaxed::numberFromStream<T, strict>( in );
// null, true, false, or 'warning' / string
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '_': case '/':
return json_relaxed::wordFromStream<T, strict>( in );
case 0x04: // ^D end of transmission
case EOF:
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
case 0:
default:
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
("c", c)("s", stringFromToken(in)) );
}
return variant();
}
} } // fc::json_relaxed

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
#pragma once
#include <fc/config.hpp>
#include <fc/container/flat_fwd.hpp>
#include <fc/container/deque_fwd.hpp>
#include <fc/io/varint.hpp>
@ -11,9 +12,9 @@
#include <unordered_map>
#include <set>
#define MAX_ARRAY_ALLOC_SIZE (1024*1024*10)
#define MAX_ARRAY_ALLOC_SIZE (1024*1024*10)
namespace fc {
namespace fc {
class time_point;
class time_point_sec;
class variant;
@ -31,94 +32,94 @@ namespace fc {
template<typename T>
inline size_t pack_size( const T& v );
template<typename Stream, typename Storage> inline void pack( Stream& s, const fc::fixed_string<Storage>& u );
template<typename Stream, typename Storage> inline void unpack( Stream& s, fc::fixed_string<Storage>& u );
template<typename Stream, typename Storage> inline void pack( Stream& s, const fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename Storage> inline void unpack( Stream& s, fc::fixed_string<Storage>& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename IntType, typename EnumType>
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp );
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename IntType, typename EnumType>
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp );
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value );
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value );
template<typename Stream, typename T> inline void pack( Stream& s, const std::unordered_set<T>& value );
template<typename Stream, typename T> inline void unpack( Stream& s, std::unordered_set<T>& value );
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const std::unordered_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void unpack( Stream& s, std::unordered_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename... T> void pack( Stream& s, const static_variant<T...>& sv );
template<typename Stream, typename... T> void unpack( Stream& s, static_variant<T...>& sv );
template<typename Stream, typename... T> void pack( Stream& s, const static_variant<T...>& sv, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename... T> void unpack( Stream& s, static_variant<T...>& sv, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const flat_set<T>& value );
template<typename Stream, typename T> inline void unpack( Stream& s, flat_set<T>& value );
//template<typename Stream, typename T> inline void pack( Stream& s, const flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
//template<typename Stream, typename T> inline void unpack( Stream& s, flat_set<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const std::deque<T>& value );
template<typename Stream, typename T> inline void unpack( Stream& s, std::deque<T>& value );
//template<typename Stream, typename T> inline void pack( Stream& s, const std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
//template<typename Stream, typename T> inline void unpack( Stream& s, std::deque<T>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::unordered_map<K,V>& value );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::unordered_map<K,V>& value );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::unordered_map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::unordered_map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::map<K,V>& value );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::map<K,V>& value );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::map<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename... V> inline void pack( Stream& s, const flat_map<K,V...>& value );
template<typename Stream, typename K, typename V, typename... A> inline void unpack( Stream& s, flat_map<K,V,A...>& value );
//template<typename Stream, typename K, typename... V> inline void pack( Stream& s, const flat_map<K,V...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
//template<typename Stream, typename K, typename V, typename... A> inline void unpack( Stream& s, flat_map<K,V,A...>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::pair<K,V>& value );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::pair<K,V>& value );
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::pair<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::pair<K,V>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const variant_object& v );
template<typename Stream> inline void unpack( Stream& s, variant_object& v );
template<typename Stream> inline void pack( Stream& s, const variant& v );
template<typename Stream> inline void unpack( Stream& s, variant& v );
template<typename Stream> inline void pack( Stream& s, const variant_object& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, variant_object& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const variant& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, variant& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const path& v );
template<typename Stream> inline void unpack( Stream& s, path& v );
template<typename Stream> inline void pack( Stream& s, const ip::endpoint& v );
template<typename Stream> inline void unpack( Stream& s, ip::endpoint& v );
template<typename Stream> inline void pack( Stream& s, const path& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, path& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const ip::endpoint& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, ip::endpoint& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> void unpack( Stream& s, fc::optional<T>& v );
template<typename Stream, typename T> void unpack( Stream& s, const T& v );
template<typename Stream, typename T> void pack( Stream& s, const fc::optional<T>& v );
template<typename Stream, typename T> void pack( Stream& s, const safe<T>& v );
template<typename Stream, typename T> void unpack( Stream& s, fc::safe<T>& v );
template<typename Stream, typename T> void unpack( Stream& s, fc::optional<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> void unpack( Stream& s, const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> void pack( Stream& s, const fc::optional<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> void pack( Stream& s, const safe<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> void unpack( Stream& s, fc::safe<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void unpack( Stream& s, time_point& );
template<typename Stream> void pack( Stream& s, const time_point& );
template<typename Stream> void unpack( Stream& s, time_point_sec& );
template<typename Stream> void pack( Stream& s, const time_point_sec& );
template<typename Stream> void unpack( Stream& s, std::string& );
template<typename Stream> void pack( Stream& s, const std::string& );
template<typename Stream> void unpack( Stream& s, fc::ecc::public_key& );
template<typename Stream> void pack( Stream& s, const fc::ecc::public_key& );
template<typename Stream> void unpack( Stream& s, fc::ecc::private_key& );
template<typename Stream> void pack( Stream& s, const fc::ecc::private_key& );
template<typename Stream> void unpack( Stream& s, time_point&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void pack( Stream& s, const time_point&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void unpack( Stream& s, time_point_sec&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void pack( Stream& s, const time_point_sec&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void unpack( Stream& s, std::string&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void pack( Stream& s, const std::string&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void unpack( Stream& s, fc::ecc::public_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void pack( Stream& s, const fc::ecc::public_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void unpack( Stream& s, fc::ecc::private_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> void pack( Stream& s, const fc::ecc::private_key&, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const T& v );
template<typename Stream, typename T> inline void unpack( Stream& s, T& v );
template<typename Stream, typename T> inline void pack( Stream& s, const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void unpack( Stream& s, T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void pack( Stream& s, const std::vector<T>& v );
template<typename Stream, typename T> inline void unpack( Stream& s, std::vector<T>& v );
template<typename Stream, typename T> inline void pack( Stream& s, const std::vector<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T> inline void unpack( Stream& s, std::vector<T>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const signed_int& v );
template<typename Stream> inline void unpack( Stream& s, signed_int& vi );
template<typename Stream> inline void pack( Stream& s, const signed_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, signed_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const unsigned_int& v );
template<typename Stream> inline void unpack( Stream& s, unsigned_int& vi );
template<typename Stream> inline void pack( Stream& s, const unsigned_int& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, unsigned_int& vi, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const char* v );
template<typename Stream> inline void pack( Stream& s, const std::vector<char>& value );
template<typename Stream> inline void unpack( Stream& s, std::vector<char>& value );
template<typename Stream> inline void pack( Stream& s, const char* v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void pack( Stream& s, const std::vector<char>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, std::vector<char>& value, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T, size_t N> inline void pack( Stream& s, const fc::array<T,N>& v);
template<typename Stream, typename T, size_t N> inline void unpack( Stream& s, fc::array<T,N>& v);
template<typename Stream, typename T, size_t N> inline void pack( Stream& s, const fc::array<T,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream, typename T, size_t N> inline void unpack( Stream& s, fc::array<T,N>& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH);
template<typename Stream> inline void pack( Stream& s, const bool& v );
template<typename Stream> inline void unpack( Stream& s, bool& v );
template<typename Stream> inline void pack( Stream& s, const bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename Stream> inline void unpack( Stream& s, bool& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename T> inline std::vector<char> pack( const T& v );
template<typename T> inline T unpack( const std::vector<char>& s );
template<typename T> inline T unpack( const char* d, uint32_t s );
template<typename T> inline void unpack( const char* d, uint32_t s, T& v );
template<typename T> inline std::vector<char> pack( const T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename T> inline T unpack( const std::vector<char>& s, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename T> inline T unpack( const char* d, uint32_t s, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
template<typename T> inline void unpack( const char* d, uint32_t s, T& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH );
} }

View file

@ -10,53 +10,61 @@ namespace fc { namespace raw {
class variant_packer : public variant::visitor
{
public:
variant_packer( Stream& _s ):s(_s){}
variant_packer( Stream& _s, uint32_t _max_depth ):s(_s),max_depth(_max_depth - 1)
{
FC_ASSERT( _max_depth > 0 );
}
virtual void handle()const { }
virtual void handle( const int64_t& v )const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const uint64_t& v )const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const double& v )const
virtual void handle( const double& v )const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const bool& v )const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const string& v )const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const variant_object& v)const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
virtual void handle( const variants& v)const
{
fc::raw::pack( s, v );
fc::raw::pack( s, v, max_depth );
}
Stream& s;
const uint32_t max_depth;
};
template<typename Stream>
inline void pack( Stream& s, const variant& v )
template<typename Stream>
inline void pack( Stream& s, const variant& v, uint32_t _max_depth )
{
pack( s, uint8_t(v.get_type()) );
v.visit( variant_packer<Stream>(s) );
FC_ASSERT( _max_depth > 0 );
--_max_depth;
pack( s, uint8_t(v.get_type()), _max_depth );
v.visit( variant_packer<Stream>( s, _max_depth ) );
}
template<typename Stream>
inline void unpack( Stream& s, variant& v )
template<typename Stream>
inline void unpack( Stream& s, variant& v, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
uint8_t t;
unpack( s, t );
unpack( s, t, _max_depth );
switch( t )
{
case variant::null_type:
@ -64,49 +72,49 @@ namespace fc { namespace raw {
case variant::int64_type:
{
int64_t val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = val;
return;
}
case variant::uint64_type:
{
uint64_t val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = val;
return;
}
case variant::double_type:
{
double val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = val;
return;
}
case variant::bool_type:
{
bool val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = val;
return;
}
case variant::string_type:
{
fc::string val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = fc::move(val);
return;
}
case variant::array_type:
{
variants val;
raw::unpack(s,val);
raw::unpack( s, val, _max_depth );
v = fc::move(val);
return;
}
case variant::object_type:
{
variant_object val;
raw::unpack(s,val);
variant_object val;
raw::unpack( s, val, _max_depth );
v = fc::move(val);
return;
}
@ -115,22 +123,26 @@ namespace fc { namespace raw {
}
}
template<typename Stream>
inline void pack( Stream& s, const variant_object& v )
template<typename Stream>
inline void pack( Stream& s, const variant_object& v, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int vs = (uint32_t)v.size();
pack( s, vs );
pack( s, vs, _max_depth );
for( auto itr = v.begin(); itr != v.end(); ++itr )
{
pack( s, itr->key() );
pack( s, itr->value() );
pack( s, itr->key(), _max_depth );
pack( s, itr->value(), _max_depth );
}
}
template<typename Stream>
inline void unpack( Stream& s, variant_object& v )
template<typename Stream>
inline void unpack( Stream& s, variant_object& v, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
unsigned_int vs;
unpack( s, vs );
unpack( s, vs, _max_depth );
mutable_variant_object mvo;
mvo.reserve(vs.value);
@ -138,8 +150,8 @@ namespace fc { namespace raw {
{
fc::string key;
fc::variant value;
fc::raw::unpack(s,key);
fc::raw::unpack(s,value);
fc::raw::unpack( s, key, _max_depth );
fc::raw::unpack( s, value, _max_depth );
mvo.set( fc::move(key), fc::move(value) );
}
v = fc::move(mvo);

View file

@ -70,10 +70,10 @@ struct signed_int {
class variant;
void to_variant( const signed_int& var, variant& vo );
void from_variant( const variant& var, signed_int& vo );
void to_variant( const unsigned_int& var, variant& vo );
void from_variant( const variant& var, unsigned_int& vo );
void to_variant( const signed_int& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, signed_int& vo, uint32_t max_depth = 1 );
void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth = 1 );
} // namespace fc

View file

@ -38,11 +38,12 @@ namespace fc
{
config()
:format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ),
stream(console_appender::stream::std_error),flush(true){}
stream(console_appender::stream::std_error),max_object_depth(FC_MAX_LOG_OBJECT_DEPTH),flush(true){}
fc::string format;
console_appender::stream::type stream;
std::vector<level_color> level_colors;
uint32_t max_object_depth;
bool flush;
};
@ -69,4 +70,4 @@ namespace fc
FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) )
FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) )
FC_REFLECT( fc::console_appender::level_color, (level)(color) )
FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) )
FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(max_object_depth)(flush) )

View file

@ -19,6 +19,7 @@ class file_appender : public appender {
microseconds rotation_interval;
microseconds rotation_limit;
bool rotation_compression = false;
uint32_t max_object_depth;
};
file_appender( const variant& args );
~file_appender();
@ -32,4 +33,4 @@ class file_appender : public appender {
#include <fc/reflect/reflect.hpp>
FC_REFLECT( fc::file_appender::config,
(format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(rotation_compression) )
(format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(rotation_compression)(max_object_depth) )

View file

@ -15,6 +15,7 @@ namespace fc
{
string endpoint = "127.0.0.1:12201";
string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server)
uint32_t max_object_depth;
};
gelf_appender(const variant& args);
@ -29,4 +30,4 @@ namespace fc
#include <fc/reflect/reflect.hpp>
FC_REFLECT(fc::gelf_appender::config,
(endpoint)(host))
(endpoint)(host)(max_object_depth))

View file

@ -3,6 +3,7 @@
* @file log_message.hpp
* @brief Defines types and helper macros necessary for generating log messages.
*/
#include <fc/config.hpp>
#include <fc/time.hpp>
#include <fc/variant_object.hpp>
#include <fc/shared_ptr.hpp>
@ -51,8 +52,8 @@ namespace fc
values value;
};
void to_variant( log_level e, variant& v );
void from_variant( const variant& e, log_level& ll );
void to_variant( log_level e, variant& v, uint32_t max_depth = 1 );
void from_variant( const variant& e, log_level& ll, uint32_t max_depth = 1 );
/**
* @brief provides information about where and when a log message was generated.
@ -69,8 +70,8 @@ namespace fc
uint64_t line,
const char* method );
~log_context();
explicit log_context( const variant& v );
variant to_variant()const;
explicit log_context( const variant& v, uint32_t max_depth );
variant to_variant( uint32_t max_depth )const;
string get_file()const;
uint64_t get_line_number()const;
@ -89,8 +90,8 @@ namespace fc
std::shared_ptr<detail::log_context_impl> my;
};
void to_variant( const log_context& l, variant& v );
void from_variant( const variant& l, log_context& c );
void to_variant( const log_context& l, variant& v, uint32_t max_depth );
void from_variant( const variant& l, log_context& c, uint32_t max_depth );
/**
* @brief aggregates a message along with the context and associated meta-information.
@ -120,8 +121,8 @@ namespace fc
log_message( log_context ctx, std::string format, variant_object args = variant_object() );
~log_message();
log_message( const variant& v );
variant to_variant()const;
log_message( const variant& v, uint32_t max_depth );
variant to_variant(uint32_t max_depth)const;
string get_message()const;
@ -133,8 +134,8 @@ namespace fc
std::shared_ptr<detail::log_message_impl> my;
};
void to_variant( const log_message& l, variant& v );
void from_variant( const variant& l, log_message& c );
void to_variant( const log_message& l, variant& v, uint32_t max_depth );
void from_variant( const variant& l, log_message& c, uint32_t max_depth );
typedef std::vector<log_message> log_messages;
@ -165,8 +166,8 @@ FC_REFLECT_TYPENAME( fc::log_message );
* @param FORMAT A const char* string containing zero or more references to keys as "${key}"
* @param ... A set of key/value pairs denoted as ("key",val)("key2",val2)...
*/
#define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME(VALUE) BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(VALUE), fc::variant(VALUE) BOOST_PP_RPAREN()
#define FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME(NAME, VALUE) BOOST_PP_LPAREN() NAME, fc::variant(VALUE) BOOST_PP_RPAREN()
#define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME(VALUE) BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(VALUE), fc::variant(VALUE, FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN()
#define FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME(NAME, VALUE) BOOST_PP_LPAREN() NAME, fc::variant(VALUE, FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN()
#define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAMES_IF_NEEDED(r, data, PARAMETER_AND_MAYBE_NAME) BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE PARAMETER_AND_MAYBE_NAME,1),FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME,FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME)PARAMETER_AND_MAYBE_NAME
#define FC_LOG_MESSAGE_STRING_ONLY(LOG_LEVEL, FORMAT) \
@ -174,6 +175,5 @@ FC_REFLECT_TYPENAME( fc::log_message );
#define FC_LOG_MESSAGE_WITH_SUBSTITUTIONS(LOG_LEVEL, FORMAT, ...) \
fc::log_message(FC_LOG_CONTEXT(LOG_LEVEL), FORMAT, fc::mutable_variant_object() BOOST_PP_SEQ_FOR_EACH(FC_LOG_MESSAGE_GENERATE_PARAMETER_NAMES_IF_NEEDED, _, BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__)))
#define FC_LOG_MESSAGE(LOG_LEVEL, ...) \
BOOST_PP_EXPAND(BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),1),FC_LOG_MESSAGE_STRING_ONLY,FC_LOG_MESSAGE_WITH_SUBSTITUTIONS)(LOG_LEVEL,__VA_ARGS__))

View file

@ -1,4 +1,5 @@
#pragma once
#include <fc/config.hpp>
#include <fc/string.hpp>
#include <fc/time.hpp>
#include <fc/shared_ptr.hpp>
@ -145,7 +146,7 @@ namespace fc
BOOST_PP_STRINGIZE(base) ": ${" BOOST_PP_STRINGIZE( base ) "} "
#define FC_FORMAT_ARGS(r, unused, base) \
BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base) BOOST_PP_RPAREN()
BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base,FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN()
#define FC_FORMAT( SEQ )\
BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARG, v, SEQ )

View file

@ -40,7 +40,7 @@ namespace fc {
private:
uint32_t _ip;
};
class endpoint {
public:
endpoint();
@ -58,63 +58,69 @@ namespace fc {
friend bool operator==( const endpoint& a, const endpoint& b );
friend bool operator!=( const endpoint& a, const endpoint& b );
friend bool operator< ( const endpoint& a, const endpoint& b );
private:
/**
* The compiler pads endpoint to a full 8 bytes, so while
* a port number is limited in range to 16 bits, we specify
* a full 32 bits so that memcmp can be used with sizeof(),
* otherwise 2 bytes will be 'random' and you do not know
* a full 32 bits so that memcmp can be used with sizeof(),
* otherwise 2 bytes will be 'random' and you do not know
* where they are stored.
*/
uint32_t _port;
uint32_t _port;
address _ip;
};
}
class variant;
void to_variant( const ip::endpoint& var, variant& vo );
void from_variant( const variant& var, ip::endpoint& vo );
void to_variant( const ip::endpoint& var, variant& vo, uint32_t _max_depth = 2 );
void from_variant( const variant& var, ip::endpoint& vo, uint32_t _max_depth = 2 );
void to_variant( const ip::address& var, variant& vo );
void from_variant( const variant& var, ip::address& vo );
void to_variant( const ip::address& var, variant& vo, uint32_t _max_depth = 1 );
void from_variant( const variant& var, ip::address& vo, uint32_t _max_depth = 1 );
namespace raw
namespace raw
{
template<typename Stream>
inline void pack( Stream& s, const ip::address& v )
template<typename Stream>
inline void pack( Stream& s, const ip::address& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
fc::raw::pack( s, uint32_t(v) );
FC_ASSERT( _max_depth > 0 );
fc::raw::pack( s, uint32_t(v), _max_depth - 1 );
}
template<typename Stream>
inline void unpack( Stream& s, ip::address& v )
template<typename Stream>
inline void unpack( Stream& s, ip::address& v, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{
FC_ASSERT( _max_depth > 0 );
uint32_t _ip;
fc::raw::unpack( s, _ip );
fc::raw::unpack( s, _ip, _max_depth - 1 );
v = ip::address(_ip);
}
template<typename Stream>
inline void pack( Stream& s, const ip::endpoint& v )
template<typename Stream>
inline void pack( Stream& s, const ip::endpoint& v, uint32_t _max_depth )
{
fc::raw::pack( s, v.get_address() );
fc::raw::pack( s, v.port() );
FC_ASSERT( _max_depth > 0 );
--_max_depth;
fc::raw::pack( s, v.get_address(), _max_depth );
fc::raw::pack( s, v.port(), _max_depth );
}
template<typename Stream>
inline void unpack( Stream& s, ip::endpoint& v )
template<typename Stream>
inline void unpack( Stream& s, ip::endpoint& v, uint32_t _max_depth )
{
FC_ASSERT( _max_depth > 0 );
--_max_depth;
ip::address a;
uint16_t p;
fc::raw::unpack( s, a );
fc::raw::unpack( s, p );
fc::raw::unpack( s, a, _max_depth );
fc::raw::unpack( s, p, _max_depth );
v = ip::endpoint(a,p);
}
}
} // namespace fc
FC_REFLECT_TYPENAME( fc::ip::address )
FC_REFLECT_TYPENAME( fc::ip::endpoint )
FC_REFLECT_TYPENAME( fc::ip::address )
FC_REFLECT_TYPENAME( fc::ip::endpoint )
namespace std
{
template<>

View file

@ -56,8 +56,8 @@ namespace fc {
std::shared_ptr<detail::url_impl> my;
};
void to_variant( const url& u, fc::variant& v );
void from_variant( const fc::variant& v, url& u );
void to_variant( const url& u, fc::variant& v, uint32_t max_depth = 1 );
void from_variant( const fc::variant& v, url& u, uint32_t max_depth = 1 );
/**
* Used to create / manipulate a URL

View file

@ -1,5 +1,5 @@
#pragma once
#include <fc/uint128.hpp>
#include <fc/uint128.hpp>
#define FC_REAL128_PRECISION (uint64_t(1000000) * uint64_t(1000000) * uint64_t(1000000))
@ -27,7 +27,7 @@ namespace fc {
real128& operator -= ( const real128& o );
real128& operator /= ( const real128& o );
real128& operator *= ( const real128& o );
static real128 from_fixed( const uint128& fixed );
uint64_t to_uint64()const;
@ -36,15 +36,18 @@ namespace fc {
uint128 fixed;
};
void to_variant( const real128& var, variant& vo );
void from_variant( const variant& var, real128& vo );
void to_variant( const real128& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, real128& vo, uint32_t max_depth = 1 );
namespace raw
namespace raw
{
template<typename Stream>
inline void pack( Stream& s, const real128& value_to_pack ) { s.write( (char*)&value_to_pack, sizeof(value_to_pack) ); }
inline void pack( Stream& s, const real128& value_to_pack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{ s.write( (char*)&value_to_pack, sizeof(value_to_pack) ); }
template<typename Stream>
inline void unpack( Stream& s, real128& value_to_unpack ) { s.read( (char*)&value_to_unpack, sizeof(value_to_unpack) ); }
inline void unpack( Stream& s, real128& value_to_unpack, uint32_t _max_depth=FC_PACK_MAX_DEPTH )
{ s.read( (char*)&value_to_unpack, sizeof(value_to_unpack) ); }
}

View file

@ -5,17 +5,19 @@
namespace fc
{
template<typename T>
void to_variant( const T& o, variant& v );
void to_variant( const T& o, variant& v, uint32_t max_depth );
template<typename T>
void from_variant( const variant& v, T& o );
void from_variant( const variant& v, T& o, uint32_t max_depth );
template<typename T>
class to_variant_visitor
{
public:
to_variant_visitor( mutable_variant_object& mvo, const T& v )
:vo(mvo),val(v){}
to_variant_visitor( mutable_variant_object& mvo, const T& v, uint32_t max_depth )
:vo(mvo),val(v),_max_depth(max_depth - 1) {
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
}
template<typename Member, class Class, Member (Class::*member)>
void operator()( const char* name )const
@ -28,63 +30,67 @@ namespace fc
void add( mutable_variant_object& vo, const char* name, const optional<M>& v )const
{
if( v.valid() )
vo(name,*v);
vo(name, variant( *v, _max_depth ));
}
template<typename M>
void add( mutable_variant_object& vo, const char* name, const M& v )const
{ vo(name,v); }
{ vo(name, variant( v, _max_depth )); }
mutable_variant_object& vo;
const T& val;
const uint32_t _max_depth;
};
template<typename T>
class from_variant_visitor
{
public:
from_variant_visitor( const variant_object& _vo, T& v )
:vo(_vo),val(v){}
from_variant_visitor( const variant_object& _vo, T& v, uint32_t max_depth )
:vo(_vo),val(v),_max_depth(max_depth - 1) {
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
}
template<typename Member, class Class, Member (Class::*member)>
void operator()( const char* name )const
{
auto itr = vo.find(name);
if( itr != vo.end() )
from_variant( itr->value(), val.*member );
from_variant( itr->value(), val.*member, _max_depth );
}
const variant_object& vo;
T& val;
const uint32_t _max_depth;
};
template<typename IsReflected=fc::false_type>
struct if_enum
template<typename IsEnum=fc::false_type>
struct if_enum
{
template<typename T>
static inline void to_variant( const T& v, fc::variant& vo )
{
template<typename T>
static inline void to_variant( const T& v, fc::variant& vo, uint32_t max_depth )
{
mutable_variant_object mvo;
fc::reflector<T>::visit( to_variant_visitor<T>( mvo, v ) );
fc::reflector<T>::visit( to_variant_visitor<T>( mvo, v, max_depth ) );
vo = fc::move(mvo);
}
template<typename T>
static inline void from_variant( const fc::variant& v, T& o )
{
}
template<typename T>
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth )
{
const variant_object& vo = v.get_object();
fc::reflector<T>::visit( from_variant_visitor<T>( vo, o ) );
}
fc::reflector<T>::visit( from_variant_visitor<T>( vo, o, max_depth ) );
}
};
template<>
struct if_enum<fc::true_type>
{
template<typename T>
static inline void to_variant( const T& o, fc::variant& v )
static inline void to_variant( const T& o, fc::variant& v, uint32_t max_depth = 1 )
{
v = fc::reflector<T>::to_fc_string(o);
}
template<typename T>
static inline void from_variant( const fc::variant& v, T& o )
static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth = 1 )
{
if( v.is_string() )
o = fc::reflector<T>::from_string( v.get_string().c_str() );
@ -95,15 +101,14 @@ namespace fc
template<typename T>
void to_variant( const T& o, variant& v )
void to_variant( const T& o, variant& v, uint32_t max_depth )
{
if_enum<typename fc::reflector<T>::is_enum>::to_variant( o, v );
if_enum<typename fc::reflector<T>::is_enum>::to_variant( o, v, max_depth );
}
template<typename T>
void from_variant( const variant& v, T& o )
void from_variant( const variant& v, T& o, uint32_t max_depth )
{
if_enum<typename fc::reflector<T>::is_enum>::from_variant( v, o );
if_enum<typename fc::reflector<T>::is_enum>::from_variant( v, o, max_depth );
}
}

View file

@ -8,7 +8,6 @@
#include <functional>
#include <utility>
#include <fc/signals.hpp>
//#include <fc/rpc/json_connection.hpp>
namespace fc {
class api_connection;
@ -37,31 +36,34 @@ namespace fc {
return [=]( Args... args ) { return f( a0, args... ); };
}
template<typename R>
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 )
{
return f();
}
template<typename R, typename Arg0, typename ... Args>
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
{
FC_ASSERT( a0 != e );
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >() ), a0+1, e );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >( max_depth - 1 ) ), a0+1, e, max_depth - 1 );
}
template<typename R, typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )
std::function<variant(const fc::variants&, uint32_t)> to_generic( const std::function<R(Args...)>& f )
{
return [=]( const variants& args ) {
return variant( call_generic( f, args.begin(), args.end() ) );
return [=]( const variants& args, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
return variant( call_generic( f, args.begin(), args.end(), max_depth - 1 ), max_depth - 1 );
};
}
template<typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )
std::function<variant(const fc::variants&, uint32_t)> to_generic( const std::function<void(Args...)>& f )
{
return [=]( const variants& args ) {
call_generic( f, args.begin(), args.end() );
return [=]( const variants& args, uint32_t max_depth ) {
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
call_generic( f, args.begin(), args.end(), max_depth - 1 );
return variant();
};
}
@ -139,31 +141,34 @@ namespace fc {
}
template<typename R>
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )const
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 )const
{
return f();
}
template<typename R, typename Signature, typename ... Args>
R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
{
FC_ASSERT( a0 != e, "too few arguments passed to method" );
detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() );
return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), a0+1, e );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>(1) );
return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), a0+1, e, max_depth - 1 );
}
template<typename R, typename Signature, typename ... Args>
R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
{
FC_ASSERT( a0 != e, "too few arguments passed to method" );
detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>() );
return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), a0+1, e );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
detail::callback_functor<Signature> arg0( get_connection(), a0->as<uint64_t>(1) );
return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), a0+1, e, max_depth - 1 );
}
template<typename R, typename Arg0, typename ... Args>
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth )
{
FC_ASSERT( a0 != e, "too few arguments passed to method" );
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >() ), a0+1, e );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >( max_depth - 1 ) ), a0+1, e, max_depth - 1 );
}
struct api_visitor
@ -207,7 +212,7 @@ namespace fc {
class api_connection : public std::enable_shared_from_this<fc::api_connection>
{
public:
api_connection(){}
api_connection(uint32_t max_depth):_max_conversion_depth(max_depth){}
virtual ~api_connection(){};
@ -232,12 +237,12 @@ namespace fc {
variant receive_callback( uint64_t callback_id, const variants& args = variants() )const
{
FC_ASSERT( _local_callbacks.size() > callback_id );
return _local_callbacks[callback_id]( args );
return _local_callbacks[callback_id]( args, _max_conversion_depth );
}
void receive_notice( uint64_t callback_id, const variants& args = variants() )const
{
FC_ASSERT( _local_callbacks.size() > callback_id );
_local_callbacks[callback_id]( args );
_local_callbacks[callback_id]( args, _max_conversion_depth );
}
template<typename Interface>
@ -262,10 +267,11 @@ namespace fc {
std::vector<std::string> get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); }
fc::signal<void()> closed;
const uint32_t _max_conversion_depth; // for nested structures, json, variant etc.
private:
std::vector< std::unique_ptr<generic_api> > _local_apis;
std::map< uint64_t, api_id_type > _handle_to_id;
std::vector< std::function<variant(const variants&)> > _local_callbacks;
std::vector< std::unique_ptr<generic_api> > _local_apis;
std::map< uint64_t, api_id_type > _handle_to_id;
std::vector< std::function<variant(const variants&, uint32_t)> > _local_callbacks;
struct api_visitor
@ -281,15 +287,16 @@ namespace fc {
api_visitor() = delete;
template<typename Result>
static Result from_variant( const variant& v, Result*, const std::shared_ptr<fc::api_connection>& )
static Result from_variant( const variant& v, Result*, const std::shared_ptr<fc::api_connection>&, uint32_t max_depth )
{
return v.as<Result>();
return v.as<Result>( max_depth );
}
template<typename ResultInterface>
static fc::api<ResultInterface> from_variant( const variant& v,
fc::api<ResultInterface>* /*used for template deduction*/,
const std::shared_ptr<fc::api_connection>& con
const std::shared_ptr<fc::api_connection>& con,
uint32_t max_depth = 1
)
{
return con->get_remote_api<ResultInterface>( v.as_uint64() );
@ -298,7 +305,8 @@ namespace fc {
static fc::api_ptr from_variant(
const variant& v,
fc::api_ptr* /* used for template deduction */,
const std::shared_ptr<fc::api_connection>& con
const std::shared_ptr<fc::api_connection>& con,
uint32_t max_depth = 1
)
{
if( v.is_null() )
@ -307,9 +315,9 @@ namespace fc {
}
template<typename T>
static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>&, const T& v )
static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>& con, const T& v )
{
return fc::variant(v);
return fc::variant( v, con->_max_conversion_depth );
}
template<typename Signature>
@ -325,7 +333,7 @@ namespace fc {
auto api_id = _api_id;
memb = [con,api_id,name]( Args... args ) {
auto var_result = con->send_call( api_id, name, { convert_callbacks(con,args)...} );
return from_variant( var_result, (Result*)nullptr, con );
return from_variant( var_result, (Result*)nullptr, con, con->_max_conversion_depth );
};
}
template<typename... Args>
@ -343,6 +351,9 @@ namespace fc {
class local_api_connection : public api_connection
{
public:
local_api_connection( uint32_t max_depth ) : api_connection(max_depth){}
~local_api_connection(){}
/** makes calls to the remote server */
virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) override
{
@ -389,7 +400,7 @@ namespace fc {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
auto api_result = gapi->call_generic( f, args.begin(), args.end() );
auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
return con->register_api( api_result );
};
}
@ -403,7 +414,7 @@ namespace fc {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
auto api_result = gapi->call_generic( f, args.begin(), args.end() );
auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
if( api_result )
return con->register_api( *api_result );
return variant();
@ -420,7 +431,7 @@ namespace fc {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
auto api_result = gapi->call_generic( f, args.begin(), args.end() );
auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth );
if( !api_result )
return variant();
return api_result->register_api( *con );
@ -430,18 +441,24 @@ namespace fc {
template<typename R, typename ... Args>
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
{
auto con = _api_con.lock();
FC_ASSERT( con, "not connected" );
uint32_t max_depth = con->_max_conversion_depth;
generic_api* gapi = &_api;
return [f,gapi]( const variants& args ) {
return variant( gapi->call_generic( f, args.begin(), args.end() ) );
return [f,gapi,max_depth]( const variants& args ) {
return variant( gapi->call_generic( f, args.begin(), args.end(), max_depth ), max_depth );
};
}
template<typename ... Args>
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
{
auto con = _api_con.lock();
FC_ASSERT( con, "not connected" );
uint32_t max_depth = con->_max_conversion_depth;
generic_api* gapi = &_api;
return [f,gapi]( const variants& args ) {
gapi->call_generic( f, args.begin(), args.end() );
return [f,gapi,max_depth]( const variants& args ) {
gapi->call_generic( f, args.begin(), args.end(), max_depth );
return variant();
};
}

View file

@ -16,6 +16,7 @@ namespace fc { namespace rpc {
class cli : public api_connection
{
public:
cli( uint32_t max_depth ) : api_connection(max_depth) {}
~cli();
virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() );

View file

@ -11,7 +11,7 @@ namespace fc { namespace rpc {
class http_api_connection : public api_connection
{
public:
http_api_connection();
http_api_connection(uint32_t max_conversion_depth);
~http_api_connection();
virtual variant send_call(

View file

@ -21,7 +21,7 @@ namespace fc { namespace rpc {
typedef std::function<variant(const variants&)> method;
typedef std::function<variant(const variant_object&)> named_param_method;
json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out );
json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth );
~json_connection();
/**
@ -303,7 +303,10 @@ namespace fc { namespace rpc {
/// Sending in a variant_object will be issued as named parameters
variant call( const fc::string& method, const variant_object& named_args );
///@}
protected:
const uint32_t _max_conversion_depth; // for nested structures, json, variant etc.
private:
std::unique_ptr<detail::json_connection_impl> my;
};

View file

@ -10,7 +10,7 @@ namespace fc { namespace rpc {
class websocket_api_connection : public api_connection
{
public:
websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection> &c );
websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection> &c, uint32_t max_conversion_depth );
~websocket_api_connection();
virtual variant send_call(

View file

@ -89,7 +89,7 @@ namespace fc {
template<typename T>
T& smart_ref<T>::operator = ( smart_ref<T>&& u ) {
if( &u == this ) return *impl;
if( impl ) delete impl;
delete impl;
impl = u.impl;
u.impl = nullptr;
return *impl;

View file

@ -344,42 +344,45 @@ struct visitor {
struct from_static_variant
{
variant& var;
from_static_variant( variant& dv ):var(dv){}
const uint32_t _max_depth;
from_static_variant( variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
typedef void result_type;
template<typename T> void operator()( const T& v )const
{
to_variant( v, var );
to_variant( v, var, _max_depth );
}
};
struct to_static_variant
{
const variant& var;
to_static_variant( const variant& dv ):var(dv){}
const uint32_t _max_depth;
to_static_variant( const variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){}
typedef void result_type;
template<typename T> void operator()( T& v )const
{
from_variant( var, v );
from_variant( var, v, _max_depth );
}
};
template<typename... T> void to_variant( const fc::static_variant<T...>& s, fc::variant& v )
template<typename... T> void to_variant( const fc::static_variant<T...>& s, fc::variant& v, uint32_t max_depth )
{
variant tmp;
FC_ASSERT( max_depth > 0 );
variants vars(2);
vars[0] = s.which();
s.visit( from_static_variant(vars[1]) );
s.visit( from_static_variant(vars[1], max_depth - 1) );
v = std::move(vars);
}
template<typename... T> void from_variant( const fc::variant& v, fc::static_variant<T...>& s )
template<typename... T> void from_variant( const fc::variant& v, fc::static_variant<T...>& s, uint32_t max_depth )
{
FC_ASSERT( max_depth > 0 );
auto ar = v.get_array();
if( ar.size() < 2 ) return;
s.set_which( ar[0].as_uint64() );
s.visit( to_static_variant(ar[1]) );
s.visit( to_static_variant(ar[1], max_depth - 1) );
}
template<typename... T> struct get_typename { static const char* name() { return typeid(static_variant<T...>).name(); } };

View file

@ -25,7 +25,7 @@ namespace fc
typedef fc::optional<fc::string> ostring;
class variant_object;
fc::string format_string( const fc::string&, const variant_object& );
fc::string format_string( const fc::string&, const variant_object&, uint32_t max_object_depth = 200 );
fc::string trim( const fc::string& );
fc::string to_lower( const fc::string& );
string trim_and_normalize_spaces( const string& s );

View file

@ -38,8 +38,8 @@ namespace fc {
inline microseconds days(int64_t d) { return hours(24*d); }
class variant;
void to_variant( const fc::microseconds&, fc::variant& );
void from_variant( const fc::variant& , fc::microseconds& );
void to_variant( const fc::microseconds&, fc::variant&, uint32_t max_depth = 1 );
void from_variant( const fc::variant&, fc::microseconds&, uint32_t max_depth = 1 );
class time_point {
public:

View file

@ -3,6 +3,7 @@
#include <stdint.h>
#include <string>
#include <fc/config.hpp>
#include <fc/exception/exception.hpp>
#include <fc/crypto/city.hpp>
@ -120,15 +121,15 @@ namespace fc
class variant;
void to_variant( const uint128& var, variant& vo );
void from_variant( const variant& var, uint128& vo );
void to_variant( const uint128& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, uint128& vo, uint32_t max_depth = 1 );
namespace raw
{
template<typename Stream>
inline void pack( Stream& s, const uint128& u ) { s.write( (char*)&u, sizeof(u) ); }
inline void pack( Stream& s, const uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.write( (char*)&u, sizeof(u) ); }
template<typename Stream>
inline void unpack( Stream& s, uint128& u ) { s.read( (char*)&u, sizeof(u) ); }
inline void unpack( Stream& s, uint128& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { s.read( (char*)&u, sizeof(u) ); }
}
size_t city_hash_size_t(const char *buf, size_t len);

View file

@ -17,6 +17,17 @@
#include <fc/smart_ref_fwd.hpp>
#include <boost/multi_index_container_fwd.hpp>
#ifdef FC_ASSERT
#define _FC_ASSERT(...) FC_ASSERT( __VA_ARGS__ )
#else
// poor man's FC_ASSERT, want to avoid recursive inclusion of exception.hpp
namespace fc
{
void throw_assertion_failure( const std::string& message );
}
#define _FC_ASSERT( cond, msg ) { if( !(cond) ) { fc::throw_assertion_failure( #cond ": " msg ); } }
#endif
namespace fc
{
/**
@ -27,8 +38,8 @@ namespace fc
* for your Serializable_type
*
* @code
* void to_variant( const Serializable_type& e, variant& v );
* void from_variant( const variant& e, Serializable_type& ll );
* void to_variant( const Serializable_type& e, variant& v, uint32_t max_depth );
* void from_variant( const variant& e, Serializable_type& ll, uint32_t max_depth );
* @endcode
*/
@ -44,117 +55,120 @@ namespace fc
struct blob { std::vector<char> data; };
void to_variant( const blob& var, variant& vo );
void from_variant( const variant& var, blob& vo );
void to_variant( const blob& var, variant& vo, uint32_t max_depth = 1);
void from_variant( const variant& var, blob& vo, uint32_t max_depth = 1 );
template<typename T, typename... Args> void to_variant( const boost::multi_index_container<T,Args...>& s, variant& v );
template<typename T, typename... Args> void from_variant( const variant& v, boost::multi_index_container<T,Args...>& s );
template<typename T, typename... Args> void to_variant( const boost::multi_index_container<T,Args...>& s, variant& v, uint32_t max_depth );
template<typename T, typename... Args> void from_variant( const variant& v, boost::multi_index_container<T,Args...>& s, uint32_t max_depth );
template<typename T> void to_variant( const smart_ref<T>& s, variant& v );
template<typename T> void from_variant( const variant& v, smart_ref<T>& s );
template<typename T> void to_variant( const safe<T>& s, variant& v );
template<typename T> void from_variant( const variant& v, safe<T>& s );
template<typename T> void to_variant( const std::unique_ptr<T>& s, variant& v );
template<typename T> void from_variant( const variant& v, std::unique_ptr<T>& s );
template<typename T> void to_variant( const smart_ref<T>& s, variant& v, uint32_t max_depth );
template<typename T> void from_variant( const variant& v, smart_ref<T>& s, uint32_t max_depth );
template<typename T> void to_variant( const safe<T>& s, variant& v, uint32_t max_depth );
template<typename T> void from_variant( const variant& v, safe<T>& s, uint32_t max_depth );
template<typename T> void to_variant( const std::unique_ptr<T>& s, variant& v, uint32_t max_depth );
template<typename T> void from_variant( const variant& v, std::unique_ptr<T>& s, uint32_t max_depth );
template<typename... T> void to_variant( const static_variant<T...>& s, variant& v );
template<typename... T> void from_variant( const variant& v, static_variant<T...>& s );
template<typename... T> void to_variant( const static_variant<T...>& s, variant& v, uint32_t max_depth );
template<typename... T> void from_variant( const variant& v, static_variant<T...>& s, uint32_t max_depth );
void to_variant( const uint8_t& var, variant& vo );
void from_variant( const variant& var, uint8_t& vo );
void to_variant( const int8_t& var, variant& vo );
void from_variant( const variant& var, int8_t& vo );
void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth = 1 );
void to_variant( const int8_t& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, int8_t& vo, uint32_t max_depth = 1 );
void to_variant( const uint16_t& var, variant& vo );
void from_variant( const variant& var, uint16_t& vo );
void to_variant( const int16_t& var, variant& vo );
void from_variant( const variant& var, int16_t& vo );
void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth = 1 );
void to_variant( const int16_t& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, int16_t& vo, uint32_t max_depth = 1 );
void to_variant( const uint32_t& var, variant& vo );
void from_variant( const variant& var, uint32_t& vo );
void to_variant( const int32_t& var, variant& vo );
void from_variant( const variant& var, int32_t& vo );
void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth = 1 );
void to_variant( const int32_t& var, variant& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, int32_t& vo, uint32_t max_depth = 1 );
void to_variant( const variant_object& var, variant& vo );
void from_variant( const variant& var, variant_object& vo );
void to_variant( const mutable_variant_object& var, variant& vo );
void from_variant( const variant& var, mutable_variant_object& vo );
void to_variant( const std::vector<char>& var, variant& vo );
void from_variant( const variant& var, std::vector<char>& vo );
void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth = 1 );
void to_variant( const int64_t& var, variant& vo, uint32_t max_depth = 1 );
void to_variant( const variant_object& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, variant_object& vo, uint32_t max_depth );
void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth );
void to_variant( const std::vector<char>& var, variant& vo, uint32_t max_depth = 1 );
void from_variant( const variant& var, std::vector<char>& vo, uint32_t max_depth = 1 );
template<typename K, typename T>
void to_variant( const std::unordered_map<K,T>& var, variant& vo );
void to_variant( const std::unordered_map<K,T>& var, variant& vo, uint32_t max_depth );
template<typename K, typename T>
void from_variant( const variant& var, std::unordered_map<K,T>& vo );
void from_variant( const variant& var, std::unordered_map<K,T>& vo, uint32_t max_depth );
template<typename K, typename... T>
void to_variant( const fc::flat_map<K,T...>& var, variant& vo );
void to_variant( const fc::flat_map<K,T...>& var, variant& vo, uint32_t max_depth );
template<typename K, typename T, typename... A>
void from_variant(const variant& var, flat_map<K, T, A...>& vo);
void from_variant(const variant& var, flat_map<K, T, A...>& vo, uint32_t max_depth );
template<typename K, typename T, typename C>
void to_variant( const std::map<K,T, C>& var, variant& vo );
void to_variant( const std::map<K,T, C>& var, variant& vo, uint32_t max_depth );
template<typename K, typename T, typename C>
void from_variant( const variant& var, std::map<K,T,C>& vo );
void from_variant( const variant& var, std::map<K,T,C>& vo, uint32_t max_depth );
template<typename K, typename T>
void to_variant( const std::multimap<K,T>& var, variant& vo );
void to_variant( const std::multimap<K,T>& var, variant& vo, uint32_t max_depth );
template<typename K, typename T>
void from_variant( const variant& var, std::multimap<K,T>& vo );
void from_variant( const variant& var, std::multimap<K,T>& vo, uint32_t max_depth );
template<typename T>
void to_variant( const std::unordered_set<T>& var, variant& vo );
void to_variant( const std::unordered_set<T>& var, variant& vo, uint32_t max_depth );
template<typename T>
void from_variant( const variant& var, std::unordered_set<T>& vo );
void from_variant( const variant& var, std::unordered_set<T>& vo, uint32_t max_depth );
template<typename T>
void to_variant( const std::deque<T>& var, variant& vo );
void to_variant( const std::deque<T>& var, variant& vo, uint32_t max_depth );
template<typename T>
void from_variant( const variant& var, std::deque<T>& vo );
void from_variant( const variant& var, std::deque<T>& vo, uint32_t max_depth );
template<typename T>
void to_variant( const fc::flat_set<T>& var, variant& vo );
void to_variant( const fc::flat_set<T>& var, variant& vo, uint32_t max_depth );
template<typename T>
void from_variant( const variant& var, fc::flat_set<T>& vo );
void from_variant( const variant& var, fc::flat_set<T>& vo, uint32_t max_depth );
template<typename T>
void to_variant( const std::set<T>& var, variant& vo );
void to_variant( const std::set<T>& var, variant& vo, uint32_t max_depth );
template<typename T>
void from_variant( const variant& var, std::set<T>& vo );
void from_variant( const variant& var, std::set<T>& vo, uint32_t max_depth );
void to_variant( const time_point& var, variant& vo );
void from_variant( const variant& var, time_point& vo );
void to_variant( const time_point& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, time_point& vo, uint32_t max_depth );
void to_variant( const time_point_sec& var, variant& vo );
void from_variant( const variant& var, time_point_sec& vo );
void to_variant( const time_point_sec& var, variant& vo, uint32_t max_depth );
void from_variant( const variant& var, time_point_sec& vo, uint32_t max_depth );
void to_variant( const microseconds& input_microseconds, variant& output_variant );
void from_variant( const variant& input_variant, microseconds& output_microseconds );
void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth );
void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth );
#ifdef __APPLE__
void to_variant( size_t s, variant& v );
void to_variant( size_t s, variant& v, uint32_t max_depth = 1 );
#elif defined(_MSC_VER)
void to_variant( unsigned long s, variant& v);
void to_variant( unsigned long s, variant& v, uint32_t max_depth = 1 );
#elif !defined(_MSC_VER)
void to_variant( long long int s, variant& v );
void to_variant( unsigned long long int s, variant& v );
void to_variant( long long int s, variant& v, uint32_t max_depth = 1 );
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth = 1 );
#endif
void to_variant( const std::string& s, variant& v );
void to_variant( const std::string& s, variant& v, uint32_t max_depth = 1 );
template<typename T>
void to_variant( const std::shared_ptr<T>& var, variant& vo );
void to_variant( const std::shared_ptr<T>& var, variant& vo, uint32_t max_depth );
template<typename T>
void from_variant( const variant& var, std::shared_ptr<T>& vo );
void from_variant( const variant& var, std::shared_ptr<T>& vo, uint32_t max_depth );
typedef std::vector<variant> variants;
template<typename A, typename B>
void to_variant( const std::pair<A,B>& t, variant& v );
void to_variant( const std::pair<A,B>& t, variant& v, uint32_t max_depth );
template<typename A, typename B>
void from_variant( const variant& v, std::pair<A,B>& p );
void from_variant( const variant& v, std::pair<A,B>& p, uint32_t max_depth );
/**
* @brief stores null, int64, uint64, double, bool, string, std::vector<variant>,
@ -184,31 +198,31 @@ namespace fc
/// Constructs a null_type variant
variant();
/// Constructs a null_type variant
variant( nullptr_t );
variant( nullptr_t, uint32_t max_depth = 1 );
/// @param str - UTF8 string
variant( const char* str );
variant( char* str );
variant( wchar_t* str );
variant( const wchar_t* str );
variant( float val );
variant( uint8_t val );
variant( int8_t val );
variant( uint16_t val );
variant( int16_t val );
variant( uint32_t val );
variant( int32_t val );
variant( uint64_t val );
variant( int64_t val );
variant( double val );
variant( bool val );
variant( blob val );
variant( fc::string val );
variant( variant_object );
variant( mutable_variant_object );
variant( variants );
variant( const variant& );
variant( variant&& );
variant( const char* str, uint32_t max_depth = 1 );
variant( char* str, uint32_t max_depth = 1 );
variant( wchar_t* str, uint32_t max_depth = 1 );
variant( const wchar_t* str, uint32_t max_depth = 1 );
variant( float val, uint32_t max_depth = 1 );
variant( uint8_t val, uint32_t max_depth = 1 );
variant( int8_t val, uint32_t max_depth = 1 );
variant( uint16_t val, uint32_t max_depth = 1 );
variant( int16_t val, uint32_t max_depth = 1 );
variant( uint32_t val, uint32_t max_depth = 1 );
variant( int32_t val, uint32_t max_depth = 1 );
variant( uint64_t val, uint32_t max_depth = 1 );
variant( int64_t val, uint32_t max_depth = 1 );
variant( double val, uint32_t max_depth = 1 );
variant( bool val, uint32_t max_depth = 1 );
variant( blob val, uint32_t max_depth = 1 );
variant( fc::string val, uint32_t max_depth = 1 );
variant( variant_object, uint32_t max_depth = 1 );
variant( mutable_variant_object, uint32_t max_depth = 1 );
variant( variants, uint32_t max_depth = 1 );
variant( const variant&, uint32_t max_depth = 1 );
variant( variant&&, uint32_t max_depth = 1 );
~variant();
/**
@ -292,7 +306,7 @@ namespace fc
* following method to implement conversion from variant to T.
*
* <code>
* void from_variant( const Variant& var, T& val )
* void from_variant( const Variant& var, T& val, uint32_t max_depth )
* </code>
*
* The above form is not always convienant, so the this templated
@ -300,17 +314,17 @@ namespace fc
* types.
*/
template<typename T>
T as()const
T as( uint32_t max_depth )const
{
T tmp;
from_variant( *this, tmp );
from_variant( *this, tmp, max_depth );
return tmp;
}
template<typename T>
void as( T& v )const
void as( T& v, uint32_t max_depth )const
{
from_variant( *this, v );
from_variant( *this, v, max_depth );
}
variant& operator=( variant&& v );
@ -323,14 +337,15 @@ namespace fc
}
template<typename T>
variant( const optional<T>& v )
variant( const optional<T>& v, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
memset( this, 0, sizeof(*this) );
if( v.valid() ) *this = variant(*v);
if( v.valid() ) *this = variant( *v, max_depth - 1 );
}
template<typename T>
explicit variant( const T& val );
variant( const T& val, uint32_t max_depth );
void clear();
@ -342,200 +357,213 @@ namespace fc
typedef optional<variant> ovariant;
/** @ingroup Serializable */
void from_variant( const variant& var, string& vo );
void from_variant( const variant& var, string& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, variants& vo );
void from_variant( const variant& var, variant& vo );
void from_variant( const variant& var, variants& vo, uint32_t max_depth );
void from_variant( const variant& var, variant& vo, uint32_t max_depth );
/** @ingroup Serializable */
void from_variant( const variant& var, int64_t& vo );
void from_variant( const variant& var, int64_t& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, uint64_t& vo );
void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, bool& vo );
void from_variant( const variant& var, bool& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, double& vo );
void from_variant( const variant& var, double& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, float& vo );
/** @ingroup Serializable */
void from_variant( const variant& var, int32_t& vo );
/** @ingroup Serializable */
void from_variant( const variant& var, uint32_t& vo );
void from_variant( const variant& var, float& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
template<typename T>
void from_variant( const variant& var, optional<T>& vo )
void from_variant( const variant& var, optional<T>& vo, uint32_t max_depth )
{
if( var.is_null() ) vo = optional<T>();
else
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
vo = T();
from_variant( var, *vo );
from_variant( var, *vo, max_depth - 1 );
}
}
template<typename T>
void to_variant( const std::unordered_set<T>& var, variant& vo )
void to_variant( const std::unordered_set<T>& var, variant& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = variant(*itr);
for( const auto& item : var )
vars[i++] = variant( item, max_depth - 1 );
vo = vars;
}
template<typename T>
void from_variant( const variant& var, std::unordered_set<T>& vo )
void from_variant( const variant& var, std::unordered_set<T>& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
vo.clear();
vo.reserve( vars.size() );
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as<T>() );
for( const auto& item : vars )
vo.insert( item.as<T>( max_depth - 1 ) );
}
template<typename K, typename T>
void to_variant( const std::unordered_map<K, T>& var, variant& vo )
void to_variant( const std::unordered_map<K, T>& var, variant& vo, uint32_t max_depth )
{
std::vector< variant > vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = fc::variant(*itr);
vo = vars;
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector< variant > vars(var.size());
size_t i = 0;
for( const auto& key_value : var )
vars[i++] = fc::variant( key_value, max_depth - 1 );
vo = vars;
}
template<typename K, typename T>
void from_variant( const variant& var, std::unordered_map<K, T>& vo )
void from_variant( const variant& var, std::unordered_map<K, T>& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
vo.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as< std::pair<K,T> >() );
vo.reserve( vars.size() );
for( const auto& item : vars )
vo.insert( item.as< std::pair<K,T> >( max_depth - 1 ) );
}
template<typename K, typename T, typename C>
void to_variant( const std::map<K, T, C>& var, variant& vo )
void to_variant( const std::map<K, T, C>& var, variant& vo, uint32_t max_depth )
{
std::vector< variant > vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = fc::variant(*itr);
vo = vars;
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector< variant > vars(var.size());
size_t i = 0;
for( const auto& key_value : var )
vars[i++] = fc::variant( key_value, max_depth - 1 );
vo = vars;
}
template<typename K, typename T, typename C>
void from_variant( const variant& var, std::map<K, T, C>& vo )
void from_variant( const variant& var, std::map<K, T, C>& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
vo.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as< std::pair<K,T> >() );
for( auto item : vars )
vo.insert( item.as< std::pair<K,T> >( max_depth - 1 ) );
}
template<typename K, typename T>
void to_variant( const std::multimap<K, T>& var, variant& vo )
void to_variant( const std::multimap<K, T>& var, variant& vo, uint32_t max_depth )
{
std::vector< variant > vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = fc::variant(*itr);
vo = vars;
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector< variant > vars(var.size());
size_t i = 0;
for( const auto& key_value : var )
vars[i++] = fc::variant( key_value, max_depth - 1 );
vo = vars;
}
template<typename K, typename T>
void from_variant( const variant& var, std::multimap<K, T>& vo )
void from_variant( const variant& var, std::multimap<K, T>& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
vo.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as< std::pair<K,T> >() );
for( auto item : vars )
vo.insert( item.as< std::pair<K,T> >( max_depth - 1 ) );
}
template<typename T>
void to_variant( const std::set<T>& var, variant& vo )
void to_variant( const std::set<T>& var, variant& vo, uint32_t max_depth )
{
std::vector<variant> vars(var.size());
size_t i = 0;
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
vars[i] = variant(*itr);
vo = vars;
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars(var.size());
size_t i = 0;
for( const auto& item : var )
vars[i++] = fc::variant( item, max_depth - 1 );
vo = vars;
}
template<typename T>
void from_variant( const variant& var, std::set<T>& vo )
void from_variant( const variant& var, std::set<T>& vo, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
vo.clear();
//vo.reserve( vars.size() );
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
vo.insert( itr->as<T>() );
for( const auto& item : vars )
vo.insert( item.as<T>( max_depth - 1 ) );
}
/** @ingroup Serializable */
template<typename T>
void from_variant( const variant& var, std::deque<T>& tmp )
void from_variant( const variant& var, std::deque<T>& dest, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
tmp.clear();
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
tmp.push_back( itr->as<T>() );
dest.clear();
dest.resize( vars.size() );
for( const auto& item : vars )
dest.push_back( item.as<T>( max_depth - 1 ) );
}
/** @ingroup Serializable */
template<typename T>
void to_variant( const std::deque<T>& t, variant& v )
void to_variant( const std::deque<T>& src, variant& v, uint32_t max_depth )
{
std::vector<variant> vars(t.size());
for( size_t i = 0; i < t.size(); ++i )
vars[i] = variant(t[i]);
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars(src.size());
for( size_t i = 0; i < src.size(); ++i )
vars[i] = variant( src[i], max_depth - 1 );
v = std::move(vars);
}
/** @ingroup Serializable */
template<typename T>
void from_variant( const variant& var, std::vector<T>& tmp )
void from_variant( const variant& var, std::vector<T>& dest, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = var.get_array();
tmp.clear();
tmp.reserve( vars.size() );
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
tmp.push_back( itr->as<T>() );
dest.clear();
dest.reserve( vars.size() );
for( const auto& item : vars )
dest.push_back( item.as<T>( max_depth - 1 ) );
}
/** @ingroup Serializable */
template<typename T>
void to_variant( const std::vector<T>& t, variant& v )
void to_variant( const std::vector<T>& t, variant& v, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars(t.size());
for( size_t i = 0; i < t.size(); ++i )
vars[i] = variant(t[i]);
v = std::move(vars);
for( size_t i = 0; i < t.size(); ++i )
vars[i] = variant( t[i], max_depth - 1 );
v = std::move(vars);
}
/** @ingroup Serializable */
template<typename A, typename B>
void to_variant( const std::pair<A,B>& t, variant& v )
void to_variant( const std::pair<A,B>& t, variant& v, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars(2);
vars[0] = variant(t.first);
vars[1] = variant(t.second);
v = vars;
vars[0] = variant( t.first, max_depth - 1 );
vars[1] = variant( t.second, max_depth - 1 );
v = vars;
}
template<typename A, typename B>
void from_variant( const variant& v, std::pair<A,B>& p )
void from_variant( const variant& v, std::pair<A,B>& p, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = v.get_array();
if( vars.size() > 0 )
p.first = vars[0].as<A>();
p.first = vars[0].as<A>( max_depth - 1 );
if( vars.size() > 1 )
p.second = vars[1].as<B>();
p.second = vars[1].as<B>( max_depth - 1 );
}
template<typename T>
variant::variant( const T& val )
variant::variant( const T& val, uint32_t max_depth )
{
memset( this, 0, sizeof(*this) );
to_variant( val, *this );
to_variant( val, *this, max_depth );
}
#ifdef __APPLE__
inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); }
inline void to_variant( size_t s, variant& v, uint32_t max_depth = 1 ) { v = variant(uint64_t(s)); }
#endif
#ifdef _MSC_VER
@ -543,68 +571,90 @@ namespace fc
#endif
template<typename T>
void to_variant( const std::shared_ptr<T>& var, variant& vo )
void to_variant( const std::shared_ptr<T>& var, variant& vo, uint32_t max_depth )
{
if( var ) to_variant( *var, vo );
if( var )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
to_variant( *var, vo, max_depth - 1 );
}
else vo = nullptr;
}
template<typename T>
void from_variant( const variant& var, std::shared_ptr<T>& vo )
void from_variant( const variant& var, std::shared_ptr<T>& vo, uint32_t max_depth )
{
if( var.is_null() ) vo = nullptr;
else if( vo ) from_variant( var, *vo );
else {
vo = std::make_shared<T>();
from_variant( var, *vo );
else
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
if( !vo ) vo = std::make_shared<T>();
from_variant( var, *vo, max_depth - 1 );
}
}
template<typename T>
void to_variant( const std::unique_ptr<T>& var, variant& vo )
void to_variant( const std::unique_ptr<T>& var, variant& vo, uint32_t max_depth )
{
if( var ) to_variant( *var, vo );
if( var )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
to_variant( *var, vo, max_depth - 1 );
}
else vo = nullptr;
}
template<typename T>
void from_variant( const variant& var, std::unique_ptr<T>& vo )
void from_variant( const variant& var, std::unique_ptr<T>& vo, uint32_t max_depth )
{
if( var.is_null() ) vo.reset();
else if( vo ) from_variant( var, *vo );
else {
vo.reset( new T() );
from_variant( var, *vo );
else
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
if( !vo ) vo.reset( new T() );
from_variant( var, *vo, max_depth - 1 );
}
}
template<typename T>
void to_variant( const safe<T>& s, variant& v ) { v = s.value; }
template<typename T>
void from_variant( const variant& v, safe<T>& s ) { s.value = v.as_uint64(); }
template<typename T>
void to_variant( const smart_ref<T>& s, variant& v ) { v = *s; }
template<typename T>
void from_variant( const variant& v, smart_ref<T>& s ) { from_variant( v, *s ); }
template<typename T, typename... Args> void to_variant( const boost::multi_index_container<T,Args...>& c, variant& v )
{
std::vector<variant> vars;
vars.reserve( c.size() );
for( const auto& item : c )
vars.emplace_back( variant(item) );
v = std::move(vars);
void to_variant( const safe<T>& s, variant& v, uint32_t max_depth ) {
to_variant( s.value, v, max_depth );
}
template<typename T, typename... Args> void from_variant( const variant& v, boost::multi_index_container<T,Args...>& c )
template<typename T>
void from_variant( const variant& v, safe<T>& s, uint32_t max_depth ) {
s.value = v.as<T>( max_depth );
}
template<typename T>
void to_variant( const smart_ref<T>& s, variant& v, uint32_t max_depth ) {
to_variant( *s, v, max_depth );
}
template<typename T>
void from_variant( const variant& v, smart_ref<T>& s, uint32_t max_depth ) {
from_variant( v, *s, max_depth );
}
template<typename T, typename... Args>
void to_variant( const boost::multi_index_container<T,Args...>& c, variant& v, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
std::vector<variant> vars;
vars.reserve( c.size() );
for( const auto& item : c )
vars.emplace_back( variant( item, max_depth - 1 ) );
v = std::move(vars);
}
template<typename T, typename... Args>
void from_variant( const variant& v, boost::multi_index_container<T,Args...>& c, uint32_t max_depth )
{
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
const variants& vars = v.get_array();
c.clear();
for( const auto& item : vars )
c.insert( item.as<T>() );
c.insert( item.as<T>( max_depth - 1 ) );
}
variant operator + ( const variant& a, const variant& b );

View file

@ -90,9 +90,9 @@ namespace fc
friend class mutable_variant_object;
};
/** @ingroup Serializable */
void to_variant( const variant_object& var, variant& vo );
void to_variant( const variant_object& var, variant& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, variant_object& vo );
void from_variant( const variant& var, variant_object& vo, uint32_t max_depth = 1 );
/**
@ -169,11 +169,12 @@ namespace fc
*
* @return *this;
*/
mutable_variant_object& operator()( string key, variant var );
mutable_variant_object& operator()( string key, variant var, uint32_t max_depth = 1 );
template<typename T>
mutable_variant_object& operator()( string key, T&& var )
mutable_variant_object& operator()( string key, T&& var, uint32_t max_depth )
{
set(std::move(key), variant( fc::forward<T>(var) ) );
_FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
set( std::move(key), variant( fc::forward<T>(var), max_depth - 1 ) );
return *this;
}
/**
@ -216,9 +217,27 @@ namespace fc
std::unique_ptr< std::vector< entry > > _key_value;
friend class variant_object;
};
class limited_mutable_variant_object : public mutable_variant_object
{
public:
limited_mutable_variant_object( uint32_t max_depth );
template<typename T>
limited_mutable_variant_object& operator()( string key, T&& var )
{
set( std::move(key), variant( fc::forward<T>(var), _max_depth ) );
return *this;
}
limited_mutable_variant_object& operator()( const variant_object& vo );
private:
const uint32_t _max_depth;
};
/** @ingroup Serializable */
void to_variant( const mutable_variant_object& var, variant& vo );
void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth = 1 );
/** @ingroup Serializable */
void from_variant( const variant& var, mutable_variant_object& vo );
void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth = 1 );
} // namespace fc

View file

@ -128,14 +128,14 @@ namespace fc {
}
bigint bigint::operator / ( const bigint& a ) const {
BN_CTX* ctx = BN_CTX_new();
bigint tmp;//(*this);
bigint tmp;
BN_div( tmp.n, NULL, n, a.n, ctx );
BN_CTX_free(ctx);
return tmp;
}
bigint bigint::operator % ( const bigint& a ) const {
BN_CTX* ctx = BN_CTX_new();
bigint tmp;//(*this);
bigint tmp;
BN_mod( tmp.n, n, a.n, ctx );
BN_CTX_free(ctx);
return tmp;
@ -143,7 +143,7 @@ namespace fc {
bigint bigint::operator /= ( const bigint& a ) {
BN_CTX* ctx = BN_CTX_new();
bigint tmp;//*this);
bigint tmp;
BN_div( tmp.n, NULL, n, a.n, ctx );
fc_swap( tmp.n, n );
BN_CTX_free(ctx);
@ -188,6 +188,8 @@ namespace fc {
bigint& bigint::operator = ( bigint&& a ) {
if( &a == this )
return *this;
fc_swap( a.n, n );
return *this;
}
@ -208,14 +210,14 @@ namespace fc {
}
/** encodes the big int as base64 string, or a number */
void to_variant( const bigint& bi, variant& v )
void to_variant( const bigint& bi, variant& v, uint32_t max_depth )
{
std::vector<char> ve = bi;
v = fc::variant(base64_encode((unsigned char*)ve.data(),ve.size()));
}
/** decodes the big int as base64 string, or a number */
void from_variant( const variant& v, bigint& bi )
void from_variant( const variant& v, bigint& bi, uint32_t max_depth )
{
if( v.is_numeric() ) bi = bigint( static_cast<unsigned long>(v.as_uint64()) );
else

View file

@ -381,27 +381,27 @@ namespace fc { namespace ecc {
}
}
void to_variant( const ecc::private_key& var, variant& vo )
void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth )
{
vo = var.get_secret();
to_variant( var.get_secret(), vo, max_depth );
}
void from_variant( const variant& var, ecc::private_key& vo )
void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth )
{
fc::sha256 sec;
from_variant( var, sec );
from_variant( var, sec, max_depth );
vo = ecc::private_key::regenerate(sec);
}
void to_variant( const ecc::public_key& var, variant& vo )
void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth )
{
vo = var.serialize();
to_variant( var.serialize(), vo, max_depth );
}
void from_variant( const variant& var, ecc::public_key& vo )
void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth )
{
ecc::public_key_data dat;
from_variant( var, dat );
from_variant( var, dat, max_depth );
vo = ecc::public_key(dat);
}

View file

@ -81,13 +81,13 @@ namespace fc {
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
}
void to_variant( const md5& bi, variant& v )
void to_variant( const md5& bi, variant& v, uint32_t max_depth )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
v = fc::variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), max_depth );
}
void from_variant( const variant& v, md5& bi )
void from_variant( const variant& v, md5& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >();
std::vector<char> ve = v.as< std::vector<char> >(max_depth);
if( ve.size() )
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
else

View file

@ -338,28 +338,28 @@ namespace fc {
}
/** encodes the big int as base64 string, or a number */
void to_variant( const public_key& bi, variant& v )
void to_variant( const public_key& bi, variant& v, uint32_t max_depth )
{
v = bi.serialize();
}
/** decodes the big int as base64 string, or a number */
void from_variant( const variant& v, public_key& bi )
void from_variant( const variant& v, public_key& bi, uint32_t max_depth )
{
bi = public_key( v.as<std::vector<char> >() );
bi = public_key( v.as<std::vector<char> >(max_depth) );
}
/** encodes the big int as base64 string, or a number */
void to_variant( const private_key& bi, variant& v )
void to_variant( const private_key& bi, variant& v, uint32_t max_depth )
{
v = bi.serialize();
}
/** decodes the big int as base64 string, or a number */
void from_variant( const variant& v, private_key& bi )
void from_variant( const variant& v, private_key& bi, uint32_t max_depth )
{
bi = private_key( v.as<std::vector<char> >() );
bi = private_key( v.as<std::vector<char> >(max_depth) );
}
} // fc

View file

@ -26,7 +26,8 @@ ripemd160::operator string()const { return str(); }
char* ripemd160::data()const { return (char*)&_hash[0]; }
struct ripemd160::encoder::impl {
class ripemd160::encoder::impl {
public:
impl()
{
memset( (char*)&ctx, 0, sizeof(ctx) );
@ -98,19 +99,16 @@ bool operator == ( const ripemd160& h1, const ripemd160& h2 ) {
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
}
void to_variant( const ripemd160& bi, variant& v )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
}
void from_variant( const variant& v, ripemd160& bi )
{
std::vector<char> ve = v.as< std::vector<char> >();
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
else
memset( &bi, char(0), sizeof(bi) );
void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth )
{
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth );
}
void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >( max_depth );
memset( &bi, char(0), sizeof(bi) );
if( ve.size() )
memcpy( &bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
} // fc

View file

@ -83,19 +83,16 @@ bool operator == ( const sha1& h1, const sha1& h2 ) {
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
}
void to_variant( const sha1& bi, variant& v )
void to_variant( const sha1& bi, variant& v, uint32_t max_depth )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth );
}
void from_variant( const variant& v, sha1& bi )
void from_variant( const variant& v, sha1& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >();
std::vector<char> ve = v.as< std::vector<char> >( max_depth );
memset( &bi, char(0), sizeof(bi) );
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
else
memset( &bi, char(0), sizeof(bi) );
memcpy( &bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
} // fc

View file

@ -60,7 +60,7 @@ namespace fc {
sha224 operator ^ ( const sha224& h1, const sha224& h2 ) {
sha224 result;
for( uint32_t i = 0; i < 7; ++i )
result._hash[i] = h1._hash[i] ^ h2._hash[i];
result._hash[i] = h1._hash[i] ^ h2._hash[i];
return result;
}
bool operator >= ( const sha224& h1, const sha224& h2 ) {
@ -79,19 +79,16 @@ namespace fc {
return memcmp( h1._hash, h2._hash, sizeof(sha224) ) == 0;
}
void to_variant( const sha224& bi, variant& v )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
}
void from_variant( const variant& v, sha224& bi )
{
std::vector<char> ve = v.as< std::vector<char> >();
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
else
memset( &bi, char(0), sizeof(bi) );
void to_variant( const sha224& bi, variant& v, uint32_t max_depth )
{
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth );
}
void from_variant( const variant& v, sha224& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >( max_depth );
memset( &bi, char(0), sizeof(bi) );
if( ve.size() )
memcpy( &bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
template<>

View file

@ -148,7 +148,6 @@ namespace fc {
}
else
(*this) = (*this) << (nzbits - 0x18);
return;
}
double sha256::inverse_approx_log_32_double( uint32_t x )
@ -194,19 +193,16 @@ namespace fc {
return lzbits;
}
void to_variant( const sha256& bi, variant& v )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
}
void from_variant( const variant& v, sha256& bi )
{
std::vector<char> ve = v.as< std::vector<char> >();
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
else
memset( &bi, char(0), sizeof(bi) );
void to_variant( const sha256& bi, variant& v, uint32_t max_depth )
{
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth );
}
void from_variant( const variant& v, sha256& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >( max_depth );
memset( &bi, char(0), sizeof(bi) );
if( ve.size() )
memcpy( &bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
uint64_t hash64(const char* buf, size_t len)

View file

@ -85,19 +85,16 @@ namespace fc {
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
}
void to_variant( const sha512& bi, variant& v )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
}
void from_variant( const variant& v, sha512& bi )
{
std::vector<char> ve = v.as< std::vector<char> >();
if( ve.size() )
{
memcpy(&bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
else
memset( &bi, char(0), sizeof(bi) );
void to_variant( const sha512& bi, variant& v, uint32_t max_depth )
{
to_variant( std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth );
}
void from_variant( const variant& v, sha512& bi, uint32_t max_depth )
{
std::vector<char> ve = v.as< std::vector<char> >( max_depth );
memset( &bi, char(0), sizeof(bi) );
if( ve.size() )
memcpy( &bi, ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
}
template<>

View file

@ -123,19 +123,25 @@ namespace fc
exception::~exception(){}
void to_variant( const exception& e, variant& v )
void to_variant( const exception& e, variant& v, uint32_t max_depth )
{
v = mutable_variant_object( "code", e.code() )
( "name", e.name() )
( "message", e.what() )
( "stack", e.get_log() );
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
variant v_log;
to_variant( e.get_log(), v_log, max_depth - 1 );
mutable_variant_object tmp;
tmp( "code", e.code() )
( "name", e.name() )
( "message", e.what() )
( "stack", v_log );
v = variant( tmp, max_depth );
}
void from_variant( const variant& v, exception& ll )
void from_variant( const variant& v, exception& ll, uint32_t max_depth )
{
FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" );
auto obj = v.get_object();
if( obj.contains( "stack" ) )
ll.my->_elog = obj["stack"].as<log_messages>();
ll.my->_elog = obj["stack"].as<log_messages>( max_depth - 1 );
if( obj.contains( "code" ) )
ll.my->_code = obj["code"].as_int64();
if( obj.contains( "name" ) )
@ -161,8 +167,15 @@ namespace fc
ss << variant(my->_code).as_string() <<" " << my->_name << ": " <<my->_what<<"\n";
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); )
{
ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n";
ss << " " << json::to_string( itr->get_data() )<<"\n";
ss << itr->get_message() <<"\n";
try
{
ss << " " << json::to_string( itr->get_data() )<<"\n";
}
catch( const fc::assert_exception& e )
{
ss << "ERROR: Failed to convert log data to string!\n";
}
ss << " " << itr->get_context().to_string();
++itr;
if( itr != my->_elog.end() ) ss<<"\n";
@ -181,7 +194,6 @@ namespace fc
{
if( itr->get_format().size() )
ss << " " << fc::format_string( itr->get_format(), itr->get_data() );
// ss << " " << itr->get_context().to_string() <<"\n";
}
return ss.str();
}
@ -244,6 +256,11 @@ namespace fc
return *this;
}
void throw_assertion_failure( const std::string& message )
{
FC_THROW_EXCEPTION( fc::assert_exception, message );
}
void record_assert_trip(
const char* filename,
uint32_t lineno,
@ -256,10 +273,16 @@ namespace fc
("source_lineno", lineno)
("expr", expr)
;
std::cout
<< "FC_ASSERT triggered: "
<< fc::json::to_string( assert_trip_info ) << "\n";
return;
try
{
std::cout
<< "FC_ASSERT triggered: "
<< fc::json::to_string( assert_trip_info ) << "\n";
}
catch( const fc::assert_exception& e )
{ // this should never happen. assert_trip_info is flat.
std::cout << "ERROR: Failed to convert info to string?!\n";
}
}
bool enable_record_assert_trip = false;

View file

@ -27,19 +27,15 @@
namespace fc {
// when converting to and from a variant, store utf-8 in the variant
void to_variant( const fc::path& path_to_convert, variant& variant_output )
void to_variant( const fc::path& path_to_convert, variant& variant_output, uint32_t max_depth )
{
std::wstring wide_string = path_to_convert.generic_wstring();
std::string utf8_string;
fc::encodeUtf8(wide_string, &utf8_string);
variant_output = utf8_string;
//std::string path = t.to_native_ansi_path();
//std::replace(path.begin(), path.end(), '\\', '/');
//v = path;
}
void from_variant( const fc::variant& variant_to_convert, fc::path& path_output )
void from_variant( const fc::variant& variant_to_convert, fc::path& path_output, uint32_t max_depth )
{
std::wstring wide_string;
fc::decodeUtf8(variant_to_convert.as_string(), &wide_string);

View file

@ -5,7 +5,7 @@
#include <fc/io/fstream.hpp>
#include <fc/io/sstream.hpp>
#include <fc/log/logger.hpp>
//#include <utfcpp/utf8.h>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <sstream>
@ -15,22 +15,30 @@
namespace fc
{
// forward declarations of provided functions
template<typename T, json::parse_type parser_type> variant variant_from_stream( T& in );
template<typename T, json::parse_type parser_type> variant variant_from_stream( T& in, uint32_t max_depth );
template<typename T> char parseEscape( T& in );
template<typename T> fc::string stringFromStream( T& in );
template<typename T> bool skip_white_space( T& in );
template<typename T> fc::string stringFromToken( T& in );
template<typename T, json::parse_type parser_type> variant_object objectFromStream( T& in );
template<typename T, json::parse_type parser_type> variants arrayFromStream( T& in );
template<typename T> variant_object objectFromStreamBase( T& in, std::function<std::string(T&)>& get_key, std::function<variant(T&)>& get_value );
template<typename T, json::parse_type parser_type> variant_object objectFromStream( T& in, uint32_t max_depth );
template<typename T> variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value );
template<typename T, json::parse_type parser_type> variants arrayFromStream( T& in, uint32_t max_depth );
template<typename T, json::parse_type parser_type> variant number_from_stream( T& in );
template<typename T> variant token_from_stream( T& in );
void escape_string( const string& str, ostream& os );
template<typename T> void to_stream( T& os, const variants& a, json::output_formatting format );
template<typename T> void to_stream( T& os, const variant_object& o, json::output_formatting format );
template<typename T> void to_stream( T& os, const variant& v, json::output_formatting format );
template<typename T> void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth );
template<typename T> void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth );
template<typename T> void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth );
fc::string pretty_print( const fc::string& v, uint8_t indent );
}
#if __cplusplus > 201402L
#define FALLTHROUGH [[fallthrough]];
#else
#define FALLTHROUGH
#endif
#include <fc/io/json_relaxed.hpp>
namespace fc
@ -167,8 +175,8 @@ namespace fc
("token", token.str() ) );
}
template<typename T, json::parse_type parser_type>
variant_object objectFromStream( T& in )
template<typename T>
variant_object objectFromStreamBase( T& in, std::function<std::string(T&)>& get_key, std::function<variant(T&)>& get_value )
{
mutable_variant_object obj;
try
@ -179,7 +187,6 @@ namespace fc
"Expected '{', but read '${char}'",
("char",string(&c, &c + 1)) );
in.get();
skip_white_space(in);
while( in.peek() != '}' )
{
if( in.peek() == ',' )
@ -188,7 +195,7 @@ namespace fc
continue;
}
if( skip_white_space(in) ) continue;
string key = stringFromStream( in );
string key = get_key( in );
skip_white_space(in);
if( in.peek() != ':' )
{
@ -196,10 +203,9 @@ namespace fc
("key", key) );
}
in.get();
auto val = variant_from_stream<T, parser_type>( in );
auto val = get_value( in );
obj(std::move(key),std::move(val));
skip_white_space(in);
}
if( in.peek() == '}' )
{
@ -219,7 +225,15 @@ namespace fc
}
template<typename T, json::parse_type parser_type>
variants arrayFromStream( T& in )
variant_object objectFromStream( T& in, uint32_t max_depth )
{
std::function<std::string(T&)> get_key = []( T& in ){ return stringFromStream( in ); };
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return variant_from_stream<T, parser_type>( in, max_depth ); };
return objectFromStreamBase<T>( in, get_key, get_value );
}
template<typename T>
variants arrayFromStreamBase( T& in, std::function<variant(T&)>& get_value )
{
variants ar;
try
@ -227,7 +241,6 @@ namespace fc
if( in.peek() != '[' )
FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" );
in.get();
skip_white_space(in);
while( in.peek() != ']' )
{
@ -237,8 +250,7 @@ namespace fc
continue;
}
if( skip_white_space(in) ) continue;
ar.push_back( variant_from_stream<T, parser_type>(in) );
skip_white_space(in);
ar.push_back( get_value(in) );
}
if( in.peek() != ']' )
FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}",
@ -250,6 +262,13 @@ namespace fc
return ar;
}
template<typename T, json::parse_type parser_type>
variants arrayFromStream( T& in, uint32_t max_depth )
{
std::function<variant(T&)> get_value = [max_depth]( T& in ){ return variant_from_stream<T, parser_type>( in, max_depth ); };
return arrayFromStreamBase<T>( in, get_value );
}
template<typename T, json::parse_type parser_type>
variant number_from_stream( T& in )
{
@ -276,6 +295,7 @@ namespace fc
if (dot)
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse a number with two decimal places");
dot = true;
FALLTHROUGH
case '0':
case '1':
case '2':
@ -299,16 +319,20 @@ namespace fc
}
}
catch (fc::eof_exception&)
{
{ // EOF ends the loop
}
catch (const std::ios_base::failure&)
{
{ // read error ends the loop
}
fc::string str = ss.str();
if (str == "-." || str == ".") // check the obviously wrong things we could have encountered
if (str == "-." || str == "." || str == "-") // check the obviously wrong things we could have encountered
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse token \"${token}\" as a JSON numeric constant", ("token", str));
if( dot )
return parser_type == json::legacy_parser_with_string_doubles ? variant(str) : variant(to_double(str));
return
#ifdef WITH_EXOTIC_JSON_PARSERS
parser_type == json::legacy_parser_with_string_doubles ? variant(str) :
#endif
variant(to_double(str));
if( neg )
return to_int64(str);
return to_uint64(str);
@ -379,132 +403,77 @@ namespace fc
// make out ("falfe")
// A strict JSON parser would signal this as an error, but we
// will just treat the malformed token as an un-quoted string.
return str + stringFromToken(in);;
return str + stringFromToken(in);
}
}
}
template<typename T, json::parse_type parser_type>
variant variant_from_stream( T& in )
variant variant_from_stream( T& in, uint32_t max_depth )
{
if( max_depth == 0 )
FC_THROW_EXCEPTION( parse_error_exception, "Too many nested items in JSON input!" );
skip_white_space(in);
variant var;
while( signed char c = in.peek() )
signed char c = in.peek();
switch( c )
{
switch( c )
{
case ' ':
case '\t':
case '\n':
case '\r':
in.get();
continue;
case '"':
return stringFromStream( in );
case '{':
return objectFromStream<T, parser_type>( in );
case '[':
return arrayFromStream<T, parser_type>( in );
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return number_from_stream<T, parser_type>( in );
// null, true, false, or 'warning' / string
case 'n':
case 't':
case 'f':
return token_from_stream( in );
case 0x04: // ^D end of transmission
case EOF:
case 0:
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
default:
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
("c", c)("s", stringFromToken(in)) );
}
case '"':
return stringFromStream( in );
case '{':
return objectFromStream<T, parser_type>( in, max_depth - 1 );
case '[':
return arrayFromStream<T, parser_type>( in, max_depth - 1 );
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return number_from_stream<T, parser_type>( in );
// null, true, false, or 'warning' / string
case 'n':
case 't':
case 'f':
return token_from_stream( in );
case 0x04: // ^D end of transmission
case EOF:
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
case 0:
if( parser_type == fc::json::broken_nul_parser )
return variant();
FALLTHROUGH
default:
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"",
("c", c)("s", stringFromToken(in)) );
}
return variant();
}
}
/** the purpose of this check is to verify that we will not get a stack overflow in the recursive descent parser */
void check_string_depth( const string& utf8_str )
{
int32_t open_object = 0;
int32_t open_array = 0;
for( auto c : utf8_str )
{
switch( c )
{
case '{': open_object++; break;
case '}': open_object--; break;
case '[': open_array++; break;
case ']': open_array--; break;
default: break;
}
FC_ASSERT( open_object < 100 && open_array < 100, "object graph too deep", ("object depth",open_object)("array depth", open_array) );
}
}
variant json::from_string( const std::string& utf8_str, parse_type ptype )
variant json::from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
{ try {
check_string_depth( utf8_str );
fc::stringstream in( utf8_str );
//in.exceptions( std::ifstream::eofbit );
switch( ptype )
{
case legacy_parser:
return variant_from_stream<fc::stringstream, legacy_parser>( in );
case legacy_parser_with_string_doubles:
return variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
case strict_parser:
return json_relaxed::variant_from_stream<fc::stringstream, true>( in );
case relaxed_parser:
return json_relaxed::variant_from_stream<fc::stringstream, false>( in );
default:
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
}
fc::istream_ptr in( new fc::stringstream( utf8_str ) );
fc::buffered_istream bin( in );
return from_stream( bin, ptype, max_depth );
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) }
variants json::variants_from_string( const std::string& utf8_str, parse_type ptype )
{ try {
check_string_depth( utf8_str );
variants json::variants_from_string( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
{
variants result;
fc::stringstream in( utf8_str );
//in.exceptions( std::ifstream::eofbit );
try {
fc::stringstream in( utf8_str );
while( true )
{
// result.push_back( variant_from_stream( in ));
result.push_back(json_relaxed::variant_from_stream<fc::stringstream, false>( in ));
}
} catch ( const fc::eof_exception& ){}
return result;
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) ) }
/*
void toUTF8( const char str, ostream& os )
{
// validate str == valid utf8
utf8::replace_invalid( &str, &str + 1, ostream_iterator<char>(os) );
result.push_back(json_relaxed::variant_from_stream<fc::stringstream, false>( in, max_depth ));
} catch ( const fc::eof_exception& ) {
return result;
} FC_RETHROW_EXCEPTIONS( warn, "", ("str",utf8_str) )
}
void toUTF8( const wchar_t c, ostream& os )
{
utf8::utf16to8( &c, (&c)+1, ostream_iterator<char>(os) );
}
*/
/**
* Convert '\t', '\a', '\n', '\\' and '"' to "\t\a\n\\\""
*
@ -574,7 +543,6 @@ namespace fc
default:
os << *itr;
//toUTF8( *itr, os );
}
}
os << '"';
@ -586,14 +554,14 @@ namespace fc
}
template<typename T>
void to_stream( T& os, const variants& a, json::output_formatting format )
void to_stream( T& os, const variants& a, json::output_formatting format, uint32_t max_depth )
{
os << '[';
auto itr = a.begin();
while( itr != a.end() )
{
to_stream( os, *itr, format );
to_stream( os, *itr, format, max_depth );
++itr;
if( itr != a.end() )
os << ',';
@ -601,7 +569,7 @@ namespace fc
os << ']';
}
template<typename T>
void to_stream( T& os, const variant_object& o, json::output_formatting format )
void to_stream( T& os, const variant_object& o, json::output_formatting format, uint32_t max_depth )
{
os << '{';
auto itr = o.begin();
@ -610,7 +578,7 @@ namespace fc
{
escape_string( itr->key(), os );
os << ':';
to_stream( os, itr->value(), format );
to_stream( os, itr->value(), format, max_depth );
++itr;
if( itr != o.end() )
os << ',';
@ -619,35 +587,28 @@ namespace fc
}
template<typename T>
void to_stream( T& os, const variant& v, json::output_formatting format )
void to_stream( T& os, const variant& v, json::output_formatting format, uint32_t max_depth )
{
FC_ASSERT( max_depth > 0, "Too many nested objects!" );
switch( v.get_type() )
{
case variant::null_type:
os << "null";
return;
case variant::int64_type:
{
int64_t i = v.as_int64();
if( format == json::stringify_large_ints_and_doubles &&
i > 0xffffffff )
( v.as_int64() > INT32_MAX || v.as_int64() < INT32_MIN ) )
os << '"'<<v.as_string()<<'"';
else
os << i;
os << v.as_int64();
return;
}
case variant::uint64_type:
{
uint64_t i = v.as_uint64();
if( format == json::stringify_large_ints_and_doubles &&
i > 0xffffffff )
v.as_uint64() > 0xffffffff )
os << '"'<<v.as_string()<<'"';
else
os << i;
os << v.as_uint64();
return;
}
case variant::double_type:
if (format == json::stringify_large_ints_and_doubles)
os << '"'<<v.as_string()<<'"';
@ -664,24 +625,20 @@ namespace fc
escape_string( v.as_string(), os );
return;
case variant::array_type:
{
const variants& a = v.get_array();
to_stream( os, a, format );
to_stream( os, v.get_array(), format, max_depth - 1 );
return;
}
case variant::object_type:
{
const variant_object& o = v.get_object();
to_stream(os, o, format );
to_stream(os, v.get_object(), format, max_depth - 1 );
return;
}
default:
FC_THROW_EXCEPTION( fc::invalid_arg_exception, "Unsupported variant type: " + v.get_type() );
}
}
fc::string json::to_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
fc::string json::to_string( const variant& v, output_formatting format, uint32_t max_depth )
{
fc::stringstream ss;
fc::to_stream( ss, v, format );
fc::to_stream( ss, v, format, max_depth );
return ss.str();
}
@ -761,7 +718,7 @@ namespace fc
//If we're in quotes and see a \n, just print it literally but unset the escape flag.
if( quote && escape )
escape = false;
//No break; fall through to default case
FALLTHROUGH
default:
if( first ) {
ss<<'\n';
@ -776,100 +733,75 @@ namespace fc
fc::string json::to_pretty_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
fc::string json::to_pretty_string( const variant& v, output_formatting format, uint32_t max_depth )
{
return pretty_print(to_string(v, format), 2);
return pretty_print(to_string(v, format, max_depth), 2);
}
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty, output_formatting format /* = stringify_large_ints_and_doubles */ )
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty, output_formatting format, uint32_t max_depth )
{
if( pretty )
{
auto str = json::to_pretty_string( v, format );
auto str = json::to_pretty_string( v, format, max_depth );
fc::ofstream o(fi);
o.write( str.c_str(), str.size() );
}
else
{
fc::ofstream o(fi);
fc::to_stream( o, v, format );
fc::to_stream( o, v, format, max_depth );
}
}
variant json::from_file( const fc::path& p, parse_type ptype )
variant json::from_file( const fc::path& p, parse_type ptype, uint32_t max_depth )
{
//auto tmp = std::make_shared<fc::ifstream>( p, ifstream::binary );
//auto tmp = std::make_shared<std::ifstream>( p.generic_string().c_str(), std::ios::binary );
//buffered_istream bi( tmp );
boost::filesystem::ifstream bi( p, std::ios::binary );
switch( ptype )
{
case legacy_parser:
return variant_from_stream<boost::filesystem::ifstream, legacy_parser>( bi );
case legacy_parser_with_string_doubles:
return variant_from_stream<boost::filesystem::ifstream, legacy_parser_with_string_doubles>( bi );
case strict_parser:
return json_relaxed::variant_from_stream<boost::filesystem::ifstream, true>( bi );
case relaxed_parser:
return json_relaxed::variant_from_stream<boost::filesystem::ifstream, false>( bi );
default:
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
}
fc::istream_ptr in( new fc::ifstream( p ) );
fc::buffered_istream bin( in );
return from_stream( bin, ptype, max_depth );
}
variant json::from_stream( buffered_istream& in, parse_type ptype )
variant json::from_stream( buffered_istream& in, parse_type ptype, uint32_t max_depth )
{
switch( ptype )
{
case legacy_parser:
return variant_from_stream<fc::buffered_istream, legacy_parser>( in );
return variant_from_stream<fc::buffered_istream, legacy_parser>( in, max_depth );
#ifdef WITH_EXOTIC_JSON_PARSERS
case legacy_parser_with_string_doubles:
return variant_from_stream<fc::buffered_istream, legacy_parser_with_string_doubles>( in );
return variant_from_stream<fc::buffered_istream, legacy_parser_with_string_doubles>( in, max_depth );
case strict_parser:
return json_relaxed::variant_from_stream<buffered_istream, true>( in );
return json_relaxed::variant_from_stream<buffered_istream, true>( in, max_depth );
case relaxed_parser:
return json_relaxed::variant_from_stream<buffered_istream, false>( in );
return json_relaxed::variant_from_stream<buffered_istream, false>( in, max_depth );
#endif
case broken_nul_parser:
return variant_from_stream<fc::buffered_istream, broken_nul_parser>( in, max_depth );
default:
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
}
}
ostream& json::to_stream( ostream& out, const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
ostream& json::to_stream( ostream& out, const variant& v, output_formatting format, uint32_t max_depth )
{
fc::to_stream( out, v, format );
fc::to_stream( out, v, format, max_depth );
return out;
}
ostream& json::to_stream( ostream& out, const variants& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
ostream& json::to_stream( ostream& out, const variants& v, output_formatting format, uint32_t max_depth )
{
fc::to_stream( out, v, format );
fc::to_stream( out, v, format, max_depth );
return out;
}
ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format, uint32_t max_depth )
{
fc::to_stream( out, v, format );
fc::to_stream( out, v, format, max_depth );
return out;
}
bool json::is_valid( const std::string& utf8_str, parse_type ptype )
bool json::is_valid( const std::string& utf8_str, parse_type ptype, uint32_t max_depth )
{
if( utf8_str.size() == 0 ) return false;
fc::stringstream in( utf8_str );
switch( ptype )
{
case legacy_parser:
variant_from_stream<fc::stringstream, legacy_parser>( in );
break;
case legacy_parser_with_string_doubles:
variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
break;
case strict_parser:
json_relaxed::variant_from_stream<fc::stringstream, true>( in );
break;
case relaxed_parser:
json_relaxed::variant_from_stream<fc::stringstream, false>( in );
break;
default:
FC_ASSERT( false, "Unknown JSON parser type {ptype}", ("ptype", ptype) );
}
try { in.peek(); } catch ( const eof_exception& e ) { return true; }
fc::istream_ptr in( new fc::stringstream( utf8_str ) );
fc::buffered_istream bin( in );
from_stream( bin, ptype, max_depth );
try { bin.peek(); } catch ( const eof_exception& e ) { return true; }
return false;
}

View file

@ -3,8 +3,8 @@
namespace fc
{
void to_variant( const signed_int& var, variant& vo ) { vo = var.value; }
void from_variant( const variant& var, signed_int& vo ) { vo.value = static_cast<int32_t>(var.as_int64()); }
void to_variant( const unsigned_int& var, variant& vo ) { vo = var.value; }
void from_variant( const variant& var, unsigned_int& vo ) { vo.value = static_cast<uint32_t>(var.as_uint64()); }
void to_variant( const signed_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; }
void from_variant( const variant& var, signed_int& vo, uint32_t max_depth ) { vo.value = static_cast<int32_t>(var.as_int64()); }
void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; }
void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth ) { vo.value = static_cast<uint32_t>(var.as_uint64()); }
}

View file

@ -31,7 +31,7 @@ namespace fc {
console_appender::console_appender( const variant& args )
:my(new impl)
{
configure( args.as<config>() );
configure( args.as<config>( FC_MAX_LOG_OBJECT_DEPTH ) );
}
console_appender::console_appender( const config& cfg )
@ -89,12 +89,9 @@ namespace fc {
}
void console_appender::log( const log_message& m ) {
//fc::string message = fc::format_string( m.get_format(), m.get_data() );
//fc::variant lmsg(m);
FILE* out = stream::std_error ? stderr : stdout;
//fc::string fmt_str = fc::format_string( cfg.format, mutable_variant_object(m.get_context())( "message", message) );
std::stringstream file_line;
file_line << m.get_context().get_file() <<":"<<m.get_context().get_line_number() <<" ";
@ -117,8 +114,8 @@ namespace fc {
line << std::setw( 20 ) << std::left << m.get_context().get_method().substr(p,20).c_str() <<" ";
}
line << "] ";
fc::string message = fc::format_string( m.get_format(), m.get_data() );
line << message;//.c_str();
fc::string message = fc::format_string( m.get_format(), m.get_data(), my->cfg.max_object_depth );
line << message;
fc::unique_lock<boost::mutex> lock(log_mutex());
@ -141,7 +138,7 @@ namespace fc {
#endif
if( text.size() )
fprintf( out, "%s", text.c_str() ); //fmt_str.c_str() );
fprintf( out, "%s", text.c_str() );
#ifdef WIN32
if (my->console_handle != INVALID_HANDLE_VALUE)

View file

@ -172,7 +172,7 @@ namespace fc {
{}
file_appender::file_appender( const variant& args ) :
my( new impl( args.as<config>() ) )
my( new impl( args.as<config>( FC_MAX_LOG_OBJECT_DEPTH ) ) )
{
try
{
@ -218,13 +218,9 @@ namespace fc {
}
line << "] ";
fc::string message = fc::format_string( m.get_format(), m.get_data() );
fc::string message = fc::format_string( m.get_format(), m.get_data(), my->cfg.max_object_depth );
line << message.c_str();
//fc::variant lmsg(m);
// fc::string fmt_str = fc::format_string( my->cfg.format, mutable_variant_object(m.get_context())( "message", message) );
{
fc::scoped_lock<boost::mutex> lock( my->slock );
my->out << line.str() << "\t\t\t" << m.get_context().get_file() << ":" << m.get_context().get_line_number() << "\n";

View file

@ -38,7 +38,7 @@ namespace fc
};
gelf_appender::gelf_appender(const variant& args) :
my(new impl(args.as<config>()))
my( new impl( args.as<config>( FC_MAX_LOG_OBJECT_DEPTH ) ) )
{
try
{
@ -94,7 +94,7 @@ namespace fc
mutable_variant_object gelf_message;
gelf_message["version"] = "1.1";
gelf_message["host"] = my->cfg.host;
gelf_message["short_message"] = format_string(message.get_format(), message.get_data());
gelf_message["short_message"] = format_string( message.get_format(), message.get_data(), my->cfg.max_object_depth );
gelf_message["timestamp"] = context.get_timestamp().time_since_epoch().count() / 1000000.;
@ -128,8 +128,15 @@ namespace fc
if (!context.get_task_name().empty())
gelf_message["_task_name"] = context.get_task_name();
string gelf_message_as_string = json::to_string(gelf_message);
//unsigned uncompressed_size = gelf_message_as_string.size();
string gelf_message_as_string;
try
{
gelf_message_as_string = json::to_string(gelf_message);
}
catch( const fc::assert_exception& e )
{
gelf_message_as_string = "{\"level\":3,\"short_message\":\"ERROR while generating log message\"}";
}
gelf_message_as_string = zlib_compress(gelf_message_as_string);
// graylog2 expects the zlib header to be 0x78 0x9c

View file

@ -58,11 +58,11 @@ namespace fc
my->task_name = current_task_desc ? current_task_desc : "?unnamed?";
}
log_context::log_context( const variant& v )
log_context::log_context( const variant& v, uint32_t max_depth )
:my( std::make_shared<detail::log_context_impl>() )
{
auto obj = v.get_object();
my->level = obj["level"].as<log_level>();
my->level = obj["level"].as<log_level>(max_depth);
my->file = obj["file"].as_string();
my->line = obj["line"].as_uint64();
my->method = obj["method"].as_string();
@ -70,9 +70,9 @@ namespace fc
my->thread_name = obj["thread_name"].as_string();
if (obj.contains("task_name"))
my->task_name = obj["task_name"].as_string();
my->timestamp = obj["timestamp"].as<time_point>();
my->timestamp = obj["timestamp"].as<time_point>(max_depth);
if( obj.contains( "context" ) )
my->context = obj["context"].as<string>();
my->context = obj["context"].as<string>(max_depth);
}
fc::string log_context::to_string()const
@ -91,26 +91,26 @@ namespace fc
log_context::~log_context(){}
void to_variant( const log_context& l, variant& v )
void to_variant( const log_context& l, variant& v, uint32_t max_depth )
{
v = l.to_variant();
v = l.to_variant(max_depth);
}
void from_variant( const variant& l, log_context& c )
void from_variant( const variant& l, log_context& c, uint32_t max_depth )
{
c = log_context(l);
c = log_context(l, max_depth);
}
void from_variant( const variant& l, log_message& c )
void from_variant( const variant& l, log_message& c, uint32_t max_depth )
{
c = log_message(l);
c = log_message(l, max_depth);
}
void to_variant( const log_message& m, variant& v )
void to_variant( const log_message& m, variant& v, uint32_t max_depth )
{
v = m.to_variant();
v = m.to_variant( max_depth );
}
void to_variant( log_level e, variant& v )
void to_variant( log_level e, variant& v, uint32_t max_depth )
{
switch( e )
{
@ -134,7 +134,7 @@ namespace fc
return;
}
}
void from_variant( const variant& v, log_level& e )
void from_variant( const variant& v, log_level& e, uint32_t max_depth )
{
try
{
@ -163,16 +163,16 @@ namespace fc
string log_context::get_context()const { return my->context; }
variant log_context::to_variant()const
variant log_context::to_variant(uint32_t max_depth)const
{
mutable_variant_object o;
o( "level", variant(my->level) )
o( "level", variant(my->level, max_depth) )
( "file", my->file )
( "line", my->line )
( "method", my->method )
( "hostname", my->hostname )
( "thread_name", my->thread_name )
( "timestamp", variant(my->timestamp) );
( "timestamp", variant(my->timestamp, max_depth) );
if( my->context.size() )
o( "context", my->context );
@ -191,22 +191,23 @@ namespace fc
my->args = std::move(args);
}
log_message::log_message( const variant& v )
:my( std::make_shared<detail::log_message_impl>( log_context( v.get_object()["context"] ) ) )
log_message::log_message( const variant& v, uint32_t max_depth )
:my( std::make_shared<detail::log_message_impl>( log_context( v.get_object()["context"], max_depth ) ) )
{
my->format = v.get_object()["format"].as_string();
my->args = v.get_object()["data"].get_object();
}
variant log_message::to_variant()const
variant log_message::to_variant(uint32_t max_depth)const
{
return mutable_variant_object( "context", my->context )
return limited_mutable_variant_object(max_depth)
( "context", my->context )
( "format", my->format )
( "data", my->args );
}
log_context log_message::get_context()const { return my->context; }
string log_message::get_format()const { return my->format; }
log_context log_message::get_context()const { return my->context; }
string log_message::get_format()const { return my->format; }
variant_object log_message::get_data()const { return my->args; }
string log_message::get_message()const

View file

@ -27,7 +27,6 @@ namespace fc {
get_logger_map().clear();
get_appender_map().clear();
//slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() );
for( size_t i = 0; i < cfg.appenders.size(); ++i ) {
appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args );
// TODO... process enabled

View file

@ -137,20 +137,20 @@ namespace fc { namespace ip {
} // namespace ip
void to_variant( const ip::endpoint& var, variant& vo )
void to_variant( const ip::endpoint& var, variant& vo, uint32_t max_depth )
{
vo = fc::string(var);
}
void from_variant( const variant& var, ip::endpoint& vo )
void from_variant( const variant& var, ip::endpoint& vo, uint32_t max_depth )
{
vo = ip::endpoint::from_string(var.as_string());
}
void to_variant( const ip::address& var, variant& vo )
void to_variant( const ip::address& var, variant& vo, uint32_t max_depth )
{
vo = fc::string(var);
}
void from_variant( const variant& var, ip::address& vo )
void from_variant( const variant& var, ip::address& vo, uint32_t max_depth )
{
vo = ip::address(var.as_string());
}

View file

@ -89,11 +89,11 @@ namespace fc
};
}
void to_variant( const url& u, fc::variant& v )
void to_variant( const url& u, fc::variant& v, uint32_t max_depth )
{
v = fc::string(u);
}
void from_variant( const fc::variant& v, url& u )
void from_variant( const fc::variant& v, url& u, uint32_t max_depth )
{
u = url( v.as_string() );
}

View file

@ -118,11 +118,11 @@ namespace fc
return result;
}
void to_variant( const real128& var, variant& vo )
void to_variant( const real128& var, variant& vo, uint32_t max_depth )
{
vo = std::string(var);
}
void from_variant( const variant& var, real128& vo )
void from_variant( const variant& var, real128& vo, uint32_t max_depth )
{
vo = real128(var.as_string());
}

View file

@ -7,7 +7,8 @@ http_api_connection::~http_api_connection()
{
}
http_api_connection::http_api_connection()
http_api_connection::http_api_connection(uint32_t max_depth)
:api_connection(max_depth)
{
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
{
@ -88,25 +89,27 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht
{
resp.add_header( "Content-Type", "application/json" );
std::string req_body( req.body.begin(), req.body.end() );
auto var = fc::json::from_string( req_body );
auto var = fc::json::from_string( req_body, fc::json::legacy_parser, _max_conversion_depth );
const auto& var_obj = var.get_object();
if( var_obj.contains( "method" ) )
{
auto call = var.as<fc::rpc::request>();
auto call = var.as<fc::rpc::request>(_max_conversion_depth);
try
{
try
{
auto result = _rpc_state.local_call( call.method, call.params );
resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) );
fc::variant result( _rpc_state.local_call( call.method, call.params ), _max_conversion_depth );
resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, result ), _max_conversion_depth),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
resp_status = http::reply::OK;
}
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) );
}
catch ( const fc::exception& e )
{
resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) );
resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e, _max_conversion_depth)} ), _max_conversion_depth),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
resp_status = http::reply::InternalServerError;
}
}

View file

@ -14,8 +14,8 @@ namespace fc { namespace rpc {
class json_connection_impl
{
public:
json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out )
:_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"){}
json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out, uint32_t max_depth )
:_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"),_max_depth(max_depth){}
fc::buffered_istream_ptr _in;
fc::buffered_ostream_ptr _out;
@ -33,6 +33,7 @@ namespace fc { namespace rpc {
std::function<void(fc::exception_ptr)> _on_close;
logger _logger;
uint32_t _max_depth;
void send_result( variant id, variant result )
{
@ -40,9 +41,9 @@ namespace fc { namespace rpc {
{
fc::scoped_lock<fc::mutex> lock(_write_mutex);
*_out << "{\"id\":";
json::to_stream( *_out, id );
json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth );
*_out << ",\"result\":";
json::to_stream( *_out, result);
json::to_stream( *_out, result, json::stringify_large_ints_and_doubles, _max_depth );
*_out << "}\n";
_out->flush();
}
@ -54,11 +55,11 @@ namespace fc { namespace rpc {
{
fc::scoped_lock<fc::mutex> lock(_write_mutex);
*_out << "{\"id\":";
json::to_stream( *_out, id );
json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth );
*_out << ",\"error\":{\"message\":";
json::to_stream( *_out, fc::string(e.what()) );
*_out <<",\"code\":0,\"data\":";
json::to_stream( *_out, variant(e));
json::to_stream( *_out, variant(e, _max_depth), json::stringify_large_ints_and_doubles, _max_depth );
*_out << "}}\n";
_out->flush();
}
@ -165,10 +166,7 @@ namespace fc { namespace rpc {
auto err = e->value().get_object();
auto data = err.find( "data" );
if( data != err.end() )
{
//wlog( "exception: ${except}", ("except", data->value() ) );
await->second->set_exception( data->value().as<exception>().dynamic_copy_exception() );
}
await->second->set_exception( data->value().as<exception>(_max_depth).dynamic_copy_exception() );
else
await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",e->value()) ) ) );
}
@ -207,7 +205,7 @@ namespace fc { namespace rpc {
fc::string line;
while( !_done.canceled() )
{
variant v = json::from_stream(*_in);
variant v = json::from_stream( *_in, json::legacy_parser, _max_depth );
///ilog( "input: ${in}", ("in", v ) );
//wlog( "recv: ${line}", ("line", line) );
_handle_message_future = fc::async([=](){ handle_message(v.get_object()); }, "json_connection handle_message");
@ -242,8 +240,8 @@ namespace fc { namespace rpc {
};
}//namespace detail
json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out )
:my( new detail::json_connection_impl(fc::move(in),fc::move(out)) )
json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth )
:_max_conversion_depth(max_depth),my( new detail::json_connection_impl(fc::move(in),fc::move(out),max_depth) )
{}
json_connection::~json_connection()

View file

@ -7,8 +7,8 @@ websocket_api_connection::~websocket_api_connection()
{
}
websocket_api_connection::websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection>& c )
: _connection(c)
websocket_api_connection::websocket_api_connection( const std::shared_ptr<fc::http::websocket_connection>& c, uint32_t max_depth )
: api_connection(max_depth),_connection(c)
{
FC_ASSERT( c );
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
@ -61,7 +61,8 @@ variant websocket_api_connection::send_call(
if( _connection )
{
auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } );
_connection->send_message( fc::json::to_string(request) );
_connection->send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
return _rpc_state.wait_for_response( *request.id );
}
return variant();
@ -74,7 +75,8 @@ variant websocket_api_connection::send_callback(
if( _connection )
{
auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } );
_connection->send_message( fc::json::to_string(request) );
_connection->send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
return _rpc_state.wait_for_response( *request.id );
}
return variant();
@ -87,7 +89,8 @@ void websocket_api_connection::send_notice(
if( _connection )
{
fc::rpc::request req{ optional<uint64_t>(), "notice", {callback_id, std::move(args)}};
_connection->send_message( fc::json::to_string(req) );
_connection->send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) );
}
}
@ -97,12 +100,12 @@ std::string websocket_api_connection::on_message(
{
try
{
auto var = fc::json::from_string(message);
auto var = fc::json::from_string(message, fc::json::legacy_parser, _max_conversion_depth);
const auto& var_obj = var.get_object();
if( var_obj.contains( "method" ) )
{
auto call = var.as<fc::rpc::request>();
auto call = var.as<fc::rpc::request>(_max_conversion_depth);
exception_ptr optexcept;
try
{
@ -125,7 +128,7 @@ std::string websocket_api_connection::on_message(
if( call.id )
{
auto reply = fc::json::to_string( response( *call.id, result, "2.0" ) );
auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
if( send_message && _connection )
_connection->send_message( reply );
return reply;
@ -142,7 +145,8 @@ std::string websocket_api_connection::on_message(
}
if( optexcept ) {
auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept)}, "2.0" ) );
auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ),
fc::json::stringify_large_ints_and_doubles, _max_conversion_depth );
if( send_message && _connection )
_connection->send_message( reply );
@ -151,7 +155,7 @@ std::string websocket_api_connection::on_message(
}
else
{
auto reply = var.as<fc::rpc::response>();
auto reply = var.as<fc::rpc::response>(_max_conversion_depth);
_rpc_state.handle_reply( reply );
}
}

View file

@ -2,6 +2,8 @@
#include <fc/utility.hpp>
#include <fc/fwd_impl.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/json.hpp>
#include <fc/io/sstream.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
@ -256,6 +258,60 @@ namespace fc {
}
}
string format_string( const string& format, const variant_object& args, uint32_t max_object_depth )
{
stringstream ss;
size_t prev = 0;
auto next = format.find( '$' );
while( prev < format.size() )
{
ss << format.substr( prev, next == string::npos ? string::npos : next - prev );
// if we got to the end, return it.
if( next == size_t(string::npos) || next == format.size() )
return ss.str();
// if we are not at the end, then update the start
prev = next + 1;
if( format[prev] == '{' )
{
// if the next char is a open, then find close
next = format.find( '}', prev );
// if we found close...
if( next != string::npos )
{
// the key is between prev and next
string key = format.substr( prev+1, (next-prev-1) );
auto val = args.find( key );
if( val != args.end() )
{
if( val->value().is_object() || val->value().is_array() )
{
try
{
ss << json::to_string( val->value(), json::stringify_large_ints_and_doubles, max_object_depth );
}
catch( const fc::assert_exception& e )
{
ss << "[\"ERROR_WHILE_CONVERTING_VALUE_TO_STRING\"]";
}
}
else
ss << val->value().as_string();
}
else
ss << "${"<<key<<"}";
prev = next + 1;
}
}
else
ss << format[next];
next = format.find( '$', prev );
}
return ss.str();
}
} // namespace fc

View file

@ -54,16 +54,16 @@ namespace fc {
return time_point( time_point_sec::from_iso_string( s ) );
} FC_RETHROW_EXCEPTIONS( warn, "unable to convert ISO-formatted string to fc::time_point" ) }
void to_variant( const fc::time_point& t, variant& v ) {
v = fc::string( t );
void to_variant( const fc::time_point& t, variant& v, uint32_t max_depth ) {
to_variant( fc::string( t ), v, max_depth );
}
void from_variant( const fc::variant& v, fc::time_point& t ) {
void from_variant( const fc::variant& v, fc::time_point& t, uint32_t max_depth ) {
t = fc::time_point::from_iso_string( v.as_string() );
}
void to_variant( const fc::time_point_sec& t, variant& v ) {
v = fc::string( t );
void to_variant( const fc::time_point_sec& t, variant& v, uint32_t max_depth ) {
to_variant( fc::string( t ), v, max_depth );
}
void from_variant( const fc::variant& v, fc::time_point_sec& t ) {
void from_variant( const fc::variant& v, fc::time_point_sec& t, uint32_t max_depth ) {
t = fc::time_point_sec::from_iso_string( v.as_string() );
}
@ -134,11 +134,11 @@ namespace fc {
return get_approximate_relative_time_string(time_point_sec(event_time), time_point_sec(relative_to_time), ago);
}
void to_variant( const microseconds& input_microseconds, variant& output_variant )
void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth )
{
output_variant = input_microseconds.count();
}
void from_variant( const variant& input_variant, microseconds& output_microseconds )
void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth )
{
output_microseconds = microseconds(input_variant.as_int64());
}

View file

@ -13,7 +13,7 @@ namespace fc
template <typename T>
static void divide(const T &numerator, const T &denominator, T &quotient, T &remainder)
{
static const int bits = sizeof(T) * 8;//CHAR_BIT;
static const int bits = sizeof(T) * 8;
if(denominator == 0) {
throw std::domain_error("divide by zero");
@ -228,22 +228,6 @@ namespace fc
self /= other;
hi = static_cast<uint64_t>(self >> 64);
lo = static_cast<uint64_t>((self << 64 ) >> 64);
/*
uint128 remainder;
divide(*this, b, *this, remainder ); //, *this);
if( tmp.hi != hi || tmp.lo != lo ) {
std::cerr << tmp.hi << " " << hi <<"\n";
std::cerr << tmp.lo << " " << lo << "\n";
exit(1);
}
*/
/*
const auto& b128 = std::reinterpret_cast<const m128&>(b);
auto& this128 = std::reinterpret_cast<m128&>(*this);
this128 /= b128;
*/
return *this;
}
@ -344,8 +328,6 @@ namespace fc
result_hi = uint128( y[3], y[2] );
result_lo = uint128( y[1], y[0] );
return;
}
static uint8_t _popcount_64( uint64_t x )
@ -374,8 +356,14 @@ namespace fc
return _popcount_64( lo ) + _popcount_64( hi );
}
void to_variant( const uint128& var, variant& vo ) { vo = std::string(var); }
void from_variant( const variant& var, uint128& vo ){ vo = uint128(var.as_string()); }
void to_variant( const uint128& var, variant& vo, uint32_t max_depth )
{
vo = std::string(var);
}
void from_variant( const variant& var, uint128& vo, uint32_t max_depth )
{
vo = uint128(var.as_string());
}
} // namespace fc

View file

@ -27,140 +27,139 @@ variant::variant()
set_variant_type( this, null_type );
}
variant::variant( fc::nullptr_t )
variant::variant( fc::nullptr_t, uint32_t max_depth )
{
set_variant_type( this, null_type );
}
variant::variant( uint8_t val )
variant::variant( uint8_t val, uint32_t max_depth )
{
*reinterpret_cast<uint64_t*>(this) = val;
set_variant_type( this, uint64_type );
}
variant::variant( int8_t val )
variant::variant( int8_t val, uint32_t max_depth )
{
*reinterpret_cast<int64_t*>(this) = val;
set_variant_type( this, int64_type );
}
variant::variant( uint16_t val )
variant::variant( uint16_t val, uint32_t max_depth )
{
*reinterpret_cast<uint64_t*>(this) = val;
set_variant_type( this, uint64_type );
}
variant::variant( int16_t val )
variant::variant( int16_t val, uint32_t max_depth )
{
*reinterpret_cast<int64_t*>(this) = val;
set_variant_type( this, int64_type );
}
variant::variant( uint32_t val )
variant::variant( uint32_t val, uint32_t max_depth )
{
*reinterpret_cast<uint64_t*>(this) = val;
set_variant_type( this, uint64_type );
}
variant::variant( int32_t val )
variant::variant( int32_t val, uint32_t max_depth )
{
*reinterpret_cast<int64_t*>(this) = val;
set_variant_type( this, int64_type );
}
variant::variant( uint64_t val )
variant::variant( uint64_t val, uint32_t max_depth )
{
*reinterpret_cast<uint64_t*>(this) = val;
set_variant_type( this, uint64_type );
}
variant::variant( int64_t val )
variant::variant( int64_t val, uint32_t max_depth )
{
*reinterpret_cast<int64_t*>(this) = val;
set_variant_type( this, int64_type );
}
variant::variant( float val )
variant::variant( float val, uint32_t max_depth )
{
*reinterpret_cast<double*>(this) = val;
set_variant_type( this, double_type );
}
variant::variant( double val )
variant::variant( double val, uint32_t max_depth )
{
*reinterpret_cast<double*>(this) = val;
set_variant_type( this, double_type );
}
variant::variant( bool val )
variant::variant( bool val, uint32_t max_depth )
{
*reinterpret_cast<bool*>(this) = val;
set_variant_type( this, bool_type );
}
variant::variant( char* str )
variant::variant( char* str, uint32_t max_depth )
{
*reinterpret_cast<string**>(this) = new string( str );
set_variant_type( this, string_type );
}
variant::variant( const char* str )
variant::variant( const char* str, uint32_t max_depth )
{
*reinterpret_cast<string**>(this) = new string( str );
set_variant_type( this, string_type );
}
// TODO: do a proper conversion to utf8
variant::variant( wchar_t* str )
variant::variant( wchar_t* str, uint32_t max_depth )
{
size_t len = wcslen(str);
boost::scoped_array<char> buffer(new char[len]);
for (unsigned i = 0; i < len; ++i)
buffer[i] = (char)str[i];
buffer[i] = (char)str[i];
*reinterpret_cast<string**>(this) = new string(buffer.get(), len);
set_variant_type( this, string_type );
}
// TODO: do a proper conversion to utf8
variant::variant( const wchar_t* str )
variant::variant( const wchar_t* str, uint32_t max_depth )
{
size_t len = wcslen(str);
boost::scoped_array<char> buffer(new char[len]);
for (unsigned i = 0; i < len; ++i)
buffer[i] = (char)str[i];
buffer[i] = (char)str[i];
*reinterpret_cast<string**>(this) = new string(buffer.get(), len);
set_variant_type( this, string_type );
}
variant::variant( fc::string val )
variant::variant( fc::string val, uint32_t max_depth )
{
*reinterpret_cast<string**>(this) = new string( fc::move(val) );
set_variant_type( this, string_type );
}
variant::variant( blob val )
variant::variant( blob val, uint32_t max_depth )
{
*reinterpret_cast<blob**>(this) = new blob( fc::move(val) );
set_variant_type( this, blob_type );
}
variant::variant( variant_object obj)
variant::variant( variant_object obj, uint32_t max_depth )
{
*reinterpret_cast<variant_object**>(this) = new variant_object(fc::move(obj));
*reinterpret_cast<variant_object**>(this) = new variant_object(fc::move(obj));
set_variant_type(this, object_type );
}
variant::variant( mutable_variant_object obj)
variant::variant( mutable_variant_object obj, uint32_t max_depth )
{
*reinterpret_cast<variant_object**>(this) = new variant_object(fc::move(obj));
*reinterpret_cast<variant_object**>(this) = new variant_object(fc::move(obj));
set_variant_type(this, object_type );
}
variant::variant( variants arr )
variant::variant( variants arr, uint32_t max_depth )
{
*reinterpret_cast<variants**>(this) = new variants(fc::move(arr));
set_variant_type(this, array_type );
}
typedef const variant_object* const_variant_object_ptr;
typedef const variants* const_variants_ptr;
typedef const blob* const_blob_ptr;
@ -185,7 +184,7 @@ void variant::clear()
set_variant_type( this, null_type );
}
variant::variant( const variant& v )
variant::variant( const variant& v, uint32_t max_depth )
{
switch( v.get_type() )
{
@ -209,7 +208,7 @@ variant::variant( const variant& v )
}
}
variant::variant( variant&& v )
variant::variant( variant&& v, uint32_t max_depth )
{
memcpy( this, &v, sizeof(v) );
set_variant_type( &v, null_type );
@ -575,88 +574,85 @@ const variant_object& variant::get_object()const
FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) );
}
void from_variant( const variant& var, variants& vo )
void from_variant( const variant& var, variants& vo, uint32_t max_depth )
{
vo = var.get_array();
}
//void from_variant( const variant& var, variant_object& vo )
//{
// vo = var.get_object();
//}
void from_variant( const variant& var, variant& vo, uint32_t max_depth ) { vo = var; }
void from_variant( const variant& var, variant& vo ) { vo = var; }
void to_variant( const uint8_t& var, variant& vo ) { vo = uint64_t(var); }
void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
// TODO: warn on overflow?
void from_variant( const variant& var, uint8_t& vo ){ vo = static_cast<uint8_t>(var.as_uint64()); }
void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth ){ vo = static_cast<uint8_t>(var.as_uint64()); }
void to_variant( const int8_t& var, variant& vo ) { vo = int64_t(var); }
void to_variant( const int8_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
// TODO: warn on overflow?
void from_variant( const variant& var, int8_t& vo ){ vo = static_cast<int8_t>(var.as_int64()); }
void from_variant( const variant& var, int8_t& vo, uint32_t max_depth ) { vo = static_cast<int8_t>(var.as_int64()); }
void to_variant( const uint16_t& var, variant& vo ) { vo = uint64_t(var); }
void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
// TODO: warn on overflow?
void from_variant( const variant& var, uint16_t& vo ){ vo = static_cast<uint16_t>(var.as_uint64()); }
void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth ){ vo = static_cast<uint16_t>(var.as_uint64()); }
void to_variant( const int16_t& var, variant& vo ) { vo = int64_t(var); }
void to_variant( const int16_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
// TODO: warn on overflow?
void from_variant( const variant& var, int16_t& vo ){ vo = static_cast<int16_t>(var.as_int64()); }
void from_variant( const variant& var, int16_t& vo, uint32_t max_depth ){ vo = static_cast<int16_t>(var.as_int64()); }
void to_variant( const uint32_t& var, variant& vo ) { vo = uint64_t(var); }
void from_variant( const variant& var, uint32_t& vo )
void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); }
void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth )
{
vo = static_cast<uint32_t>(var.as_uint64());
}
void to_variant( const int32_t& var, variant& vo ) { vo = int64_t(var); }
void from_variant( const variant& var, int32_t& vo )
void to_variant( const int32_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); }
void from_variant( const variant& var,int32_t& vo, uint32_t max_depth )
{
vo = static_cast<int32_t>(var.as_int64());
}
void from_variant( const variant& var, int64_t& vo )
void to_variant( const int64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
void from_variant( const variant& var, int64_t& vo, uint32_t max_depth )
{
vo = var.as_int64();
}
void from_variant( const variant& var, uint64_t& vo )
void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth ) { vo = var; }
void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth )
{
vo = var.as_uint64();
}
void from_variant( const variant& var, bool& vo )
void from_variant( const variant& var, bool& vo, uint32_t max_depth )
{
vo = var.as_bool();
}
void from_variant( const variant& var, double& vo )
void from_variant( const variant& var, double& vo, uint32_t max_depth )
{
vo = var.as_double();
}
void from_variant( const variant& var, float& vo )
void from_variant( const variant& var, float& vo, uint32_t max_depth )
{
vo = static_cast<float>(var.as_double());
}
void to_variant( const std::string& s, variant& v )
void to_variant( const std::string& s, variant& v, uint32_t max_depth )
{
v = variant( fc::string(s) );
v = variant( fc::string(s), max_depth );
}
void from_variant( const variant& var, string& vo )
void from_variant( const variant& var, string& vo, uint32_t max_depth )
{
vo = var.as_string();
}
void to_variant( const std::vector<char>& var, variant& vo )
void to_variant( const std::vector<char>& var, variant& vo, uint32_t max_depth )
{
if( var.size() )
vo = variant(to_hex(var.data(),var.size()));
else vo = "";
}
void from_variant( const variant& var, std::vector<char>& vo )
void from_variant( const variant& var, std::vector<char>& vo, uint32_t max_depth )
{
auto str = var.as_string();
vo.resize( str.size() / 2 );
@ -665,75 +661,13 @@ void from_variant( const variant& var, std::vector<char>& vo )
size_t r = from_hex( str, vo.data(), vo.size() );
FC_ASSERT( r == vo.size() );
}
// std::string b64 = base64_decode( var.as_string() );
// vo = std::vector<char>( b64.c_str(), b64.c_str() + b64.size() );
}
string format_string( const string& format, const variant_object& args )
{
stringstream ss;
size_t prev = 0;
auto next = format.find( '$' );
while( prev != size_t(string::npos) && prev < size_t(format.size()) )
{
ss << format.substr( prev, size_t(next-prev) );
// if we got to the end, return it.
if( next == size_t(string::npos) )
return ss.str();
// if we are not at the end, then update the start
prev = next + 1;
if( format[prev] == '{' )
{
// if the next char is a open, then find close
next = format.find( '}', prev );
// if we found close...
if( next != size_t(string::npos) )
{
// the key is between prev and next
string key = format.substr( prev+1, (next-prev-1) );
auto val = args.find( key );
if( val != args.end() )
{
if( val->value().is_object() || val->value().is_array() )
{
ss << json::to_string( val->value() );
}
else
{
ss << val->value().as_string();
}
}
else
{
ss << "${"<<key<<"}";
}
prev = next + 1;
// find the next $
next = format.find( '$', prev );
}
else
{
// we didn't find it.. continue to while...
}
}
else
{
ss << format[prev];
++prev;
next = format.find( '$', prev );
}
}
return ss.str();
}
#ifdef __APPLE__
#elif !defined(_MSC_VER)
void to_variant( long long int s, variant& v ) { v = variant( int64_t(s) ); }
void to_variant( unsigned long long int s, variant& v ) { v = variant( uint64_t(s)); }
#endif
#ifdef __APPLE__
#elif !defined(_MSC_VER)
void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); }
void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); }
#endif
variant operator == ( const variant& a, const variant& b )
{

View file

@ -103,7 +103,6 @@ namespace fc
variant_object::variant_object( string key, variant val )
: _key_value(std::make_shared<std::vector<entry>>())
{
//_key_value->push_back(entry(fc::move(key), fc::move(val)));
_key_value->emplace_back(entry(fc::move(key), fc::move(val)));
}
@ -163,12 +162,12 @@ namespace fc
return *this;
}
void to_variant( const variant_object& var, variant& vo )
void to_variant( const variant_object& var, variant& vo, uint32_t max_depth )
{
vo = variant(var);
}
void from_variant( const variant& var, variant_object& vo )
void from_variant( const variant& var, variant_object& vo, uint32_t max_depth )
{
vo = var.get_object();
}
@ -344,7 +343,7 @@ namespace fc
/** Appends \a key and \a var without checking for duplicates, designed to
* simplify construction of dictionaries using (key,val)(key2,val2) syntax
*/
mutable_variant_object& mutable_variant_object::operator()( string key, variant var )
mutable_variant_object& mutable_variant_object::operator()( string key, variant var, uint32_t max_depth )
{
_key_value->push_back( entry( fc::move(key), fc::move(var) ) );
return *this;
@ -366,12 +365,24 @@ namespace fc
return *this;
}
void to_variant( const mutable_variant_object& var, variant& vo )
limited_mutable_variant_object::limited_mutable_variant_object( uint32_t m )
: mutable_variant_object(), _max_depth(m - 1)
{
FC_ASSERT( m > 0, "Recursion depth exceeded!" );
}
limited_mutable_variant_object& limited_mutable_variant_object::operator()( const variant_object& vo )
{
mutable_variant_object::operator()( vo );
return *this;
}
void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth )
{
vo = variant(var);
}
void from_variant( const variant& var, mutable_variant_object& vo )
void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth )
{
vo = var.get_object();
}

View file

@ -46,11 +46,14 @@ add_executable( all_tests all_tests.cpp
crypto/dh_test.cpp
crypto/rand_test.cpp
crypto/sha_tests.cpp
io/json_tests.cpp
io/stream_tests.cpp
network/http/websocket_test.cpp
thread/task_cancel.cpp
thread/thread_tests.cpp
bloom_test.cpp
real128_test.cpp
serialization_test.cpp
utf8_test.cpp
)
target_link_libraries( all_tests fc )

View file

@ -52,6 +52,8 @@ class variant_calculator
using namespace fc::http;
using namespace fc::rpc;
#define MAX_DEPTH 10
int main( int argc, char** argv )
{
try {
@ -59,7 +61,7 @@ int main( int argc, char** argv )
fc::http::websocket_server server;
server.on_connection([&]( const websocket_connection_ptr& c ){
auto wsc = std::make_shared<websocket_api_connection>(c);
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
auto login = std::make_shared<login_api>();
login->calc = calc_api;
wsc->register_api(fc::api<login_api>(login));
@ -74,7 +76,7 @@ int main( int argc, char** argv )
try {
fc::http::websocket_client client;
auto con = client.connect( "ws://localhost:8090" );
auto apic = std::make_shared<websocket_api_connection>(con);
auto apic = std::make_shared<websocket_api_connection>(con, MAX_DEPTH);
auto remote_login_api = apic->get_remote_api<login_api>();
auto remote_calc = remote_login_api->get_calc();
remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } );
@ -167,8 +169,8 @@ int main( int argc, char** argv )
fc::api<login_api> napi(&napi_impl);
auto client_side = std::make_shared<local_api_connection>();
auto server_side = std::make_shared<local_api_connection>();
auto client_side = std::make_shared<local_api_connection>(MAX_DEPTH);
auto server_side = std::make_shared<local_api_connection>(MAX_DEPTH);
server_side->set_remote_connection( client_side );
client_side->set_remote_connection( server_side );

View file

@ -65,8 +65,8 @@ void test_big( const std::string& expected ) {
H hash2( expected );
fc::variant v;
to_variant( hash2, v );
from_variant( v, hash );
to_variant( hash2, v, 5 );
from_variant( v, hash, 5 );
BOOST_CHECK( hash == hash2 );
H hash3( expected.substr(15) + "000000000000000" );

376
tests/io/json_tests.cpp Normal file
View file

@ -0,0 +1,376 @@
#include <boost/test/unit_test.hpp>
#include <fc/variant.hpp>
#include <fc/variant_object.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/buffered_iostream.hpp>
#include <fc/io/fstream.hpp>
#include <fc/io/iostream.hpp>
#include <fc/io/json.hpp>
#include <fc/io/sstream.hpp>
#include <fstream>
BOOST_AUTO_TEST_SUITE(json_tests)
static void replace_some( std::string& str )
{
for( size_t i = 0; i < str.length(); i++ )
if( str[i] == '\1' ) str[i] = '\0';
else if( str[i] == '\'' ) str[i] = '"';
}
static void test_fail_string( const std::string& str )
{
try {
fc::json::from_string( str );
BOOST_FAIL( "json::from_string('" + str + "') failed" );
} catch( const fc::parse_error_exception& ) { // ignore, ok
} catch( const fc::eof_exception& ) { // ignore, ok
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_string failed")(str) )
}
static void test_fail_stream( const std::string& str )
{
fc::temp_file file( fc::temp_directory_path(), true );
{
std::fstream init( file.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( str.c_str(), str.length() );
init.close();
}
try {
fc::istream_ptr in( new fc::ifstream( file.path() ) );
fc::buffered_istream bin( in );
fc::json::from_stream( bin );
BOOST_FAIL( "json::from_stream('" + str + "') failed using ifstream" );
} catch( const fc::parse_error_exception& ) { // ignore, ok
} catch( const fc::eof_exception& ) { // ignore, ok
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_stream failed using ifstream")(str) )
try {
fc::istream_ptr in( new fc::stringstream( str ) );
fc::buffered_istream bin( in );
fc::json::from_stream( bin );
BOOST_FAIL( "json::from_stream('" + str + "') failed using stringstream" );
} catch( const fc::parse_error_exception& ) { // ignore, ok
} catch( const fc::eof_exception& ) { // ignore, ok
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_stream failed using stringstream")(str) )
}
static void test_fail_file( const std::string& str )
{
fc::temp_file file( fc::temp_directory_path(), true );
{
std::fstream init( file.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( str.c_str(), str.length() );
init.close();
}
try {
fc::json::from_file( file.path() );
BOOST_FAIL( "json::from_file('" + str + "') failed using" );
} catch( const fc::parse_error_exception& ) { // ignore, ok
} catch( const fc::eof_exception& ) { // ignore, ok
} FC_CAPTURE_LOG_AND_RETHROW( ("json::from_file failed")(str) )
}
BOOST_AUTO_TEST_CASE(imbalanced_test)
{
std::string open40("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[");
std::string close40("]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
std::string open80 = open40 + open40;
std::string close80 = close40 + close40;
std::vector<std::string> tests
{ // for easier handling and better readability, in the following test
// strings ' is used instead of " and \1 instead of \0
"",
"{",
"{'",
"{'}",
"{'a'",
"{'a':",
"{'a':5",
"[",
"['",
"[']",
"[ 13",
"' end",
"{ 13: }",
"\1",
"{\1",
"{\1}",
"{'\1",
"{'\1}",
"{'a'\1",
"{'a'\1}",
"{'a': \1",
"{'a': \1}",
"[\1",
"[\1]",
"['\1",
"['\1]",
"[ 13\1",
"[ 13\1]",
"' end\1",
open80 + "'" + close80 + close80 + "'," + open80 + open80
+ close80 + close80 + close80
};
for( std::string test : tests )
{
replace_some( test );
test_fail_string( test );
test_fail_stream( test );
test_fail_file( test );
}
}
static bool equal( const fc::variant& a, const fc::variant& b )
{
auto a_type = a.get_type();
auto b_type = b.get_type();
if( a_type == fc::variant::type_id::int64_type && a.as<int64_t>(1) > 0 )
a_type = fc::variant::type_id::uint64_type;
if( b_type == fc::variant::type_id::int64_type && b.as<int64_t>(1) > 0 )
b_type = fc::variant::type_id::uint64_type;
if( a_type != b_type )
{
if( ( a_type == fc::variant::type_id::double_type
&& b_type == fc::variant::type_id::string_type )
|| ( a_type == fc::variant::type_id::string_type
&& b_type == fc::variant::type_id::double_type ) )
return a.as<double>(1) == b.as<double>(1);
return false;
}
switch( a_type )
{
case fc::variant::type_id::null_type: return true;
case fc::variant::type_id::int64_type: return a.as<int64_t>(1) == b.as<int64_t>(1);
case fc::variant::type_id::uint64_type: return a.as<uint64_t>(1) == b.as<uint64_t>(1);
case fc::variant::type_id::double_type: return a.as<double>(1) == b.as<double>(1);
case fc::variant::type_id::bool_type: return a.as<bool>(1) == b.as<bool>(1);
case fc::variant::type_id::string_type: return a.as<std::string>(1) == b.as<std::string>(1);
case fc::variant::type_id::array_type:
if( a.get_array().size() != b.get_array().size() ) return false;
else
{
std::vector<fc::variant>::const_iterator b_it = b.get_array().begin();
for( const auto& a_it : a.get_array() )
{
if( !equal( a_it, *b_it ) ) return false;
b_it++;
}
}
return true;
case fc::variant::type_id::object_type:
if( a.get_object().size() != b.get_object().size() ) return false;
for( const auto& a_it : a.get_object() )
{
const auto& b_obj = b.get_object().find( a_it.key() );
if( b_obj == b.get_object().end() || !equal( a_it.value(), b_obj->value() ) ) return false;
}
return true;
case fc::variant::type_id::blob_type:
default:
FC_THROW_EXCEPTION( fc::invalid_arg_exception, "Unsupported variant type: " + a.get_type() );
}
}
static void test_recursive( const fc::variant& v )
{ try {
const std::string json = fc::json::to_string( v );
BOOST_CHECK( fc::json::is_valid( json ) );
BOOST_CHECK( !fc::json::is_valid( json + " " ) );
const std::string pretty = fc::json::to_pretty_string( v );
BOOST_CHECK( fc::json::is_valid( pretty ) );
BOOST_CHECK( !fc::json::is_valid( pretty + " " ) );
fc::temp_file file( fc::temp_directory_path(), true );
fc::json::save_to_file( v, file.path(), false );
fc::variants list = fc::json::variants_from_string( json );
BOOST_CHECK_EQUAL( 1, list.size() );
BOOST_CHECK( equal( v, list[0] ) );
list = fc::json::variants_from_string( pretty );
BOOST_CHECK_EQUAL( 1, list.size() );
BOOST_CHECK( equal( v, list[0] ) );
BOOST_CHECK( equal( v, fc::json::from_string( json + " " ) ) );
BOOST_CHECK( equal( v, fc::json::from_string( pretty + " " ) ) );
BOOST_CHECK( equal( v, fc::json::from_file( file.path() ) ) );
if( v.get_type() == fc::variant::type_id::array_type )
for( const auto& item : v.get_array() )
test_recursive( item );
else if( v.get_type() == fc::variant::type_id::object_type )
for( const auto& item : v.get_object() )
test_recursive( item.value() );
} FC_CAPTURE_LOG_AND_RETHROW( (v) ) }
BOOST_AUTO_TEST_CASE(structured_test)
{
fc::variant_object v_empty_obj;
fc::variants v_empty_array;
fc::variant v_null;
fc::variant v_true( true );
fc::variant v_false( false );
fc::variant v_empty_str( "" );
fc::variant v_str( "false" );
fc::variant v_int8_1( (int8_t) 1 );
fc::variant v_int8_2( (int8_t) -2 );
fc::variant v_uint8_1( (int8_t) 1 );
fc::variant v_int16_1( (int16_t) 1 );
fc::variant v_int16_2( (int16_t) -2 );
fc::variant v_uint16_1( (int16_t) 1 );
fc::variant v_int32_1( (int32_t) 1 );
fc::variant v_int32_2( (int32_t) -2 );
fc::variant v_uint32_1( (int32_t) 1 );
fc::variant v_int64_1( (int8_t) 1 );
fc::variant v_int64_2( (int8_t) -2 );
fc::variant v_uint64_1( (int8_t) 1 );
fc::variant v_float_1( 0.0f );
fc::variant v_float_2( -2.0f );
fc::variant v_double_1( 0.0d );
fc::variant v_double_2( -2.0d );
fc::variants v_small_array
{
v_empty_obj,
v_empty_array,
v_null,
v_true,
v_false,
v_empty_str
};
fc::mutable_variant_object v_small_obj;
v_small_obj( "", v_empty_str )
( "1", v_empty_array )
( "2", v_null )
( "a", v_true )
( "b", v_false )
( "x", v_small_array )
( "y", v_empty_obj );
fc::variants v_big_array
{
v_empty_obj,
v_empty_array,
v_null,
v_true,
v_false,
v_empty_str,
v_str,
v_int8_1,
v_int8_2,
v_uint8_1,
v_int16_1,
v_int16_2,
v_uint16_1,
v_int32_1,
v_int32_2,
v_uint32_1,
v_int64_1,
v_int64_2,
v_uint64_1,
v_float_1,
v_float_2,
v_double_1,
v_double_2,
v_small_array,
v_small_obj
};
fc::mutable_variant_object v_big_obj;
v_big_obj( "v_empty_obj", v_empty_obj )
( "v_empty_array", v_empty_array )
( "v_null", v_null )
( "v_true", v_true )
( "v_false", v_false )
( "v_empty_str", v_empty_str )
( "v_str", v_str )
( "v_int8_1", v_int8_1 )
( "v_int8_2", v_int8_2 )
( "v_uint8_1", v_uint8_1 )
( "v_int16_1", v_int16_1 )
( "v_int16_2", v_int16_2 )
( "v_uint16_1", v_uint16_1 )
( "v_int32_1", v_int32_1 )
( "v_int32_2", v_int32_2 )
( "v_uint32_1", v_uint32_1 )
( "v_int64_1", v_int64_1 )
( "v_int64_2", v_int64_2 )
( "v_uint64_1", v_uint64_1 )
( "v_float_1", v_float_1 )
( "v_float_2", v_float_2 )
( "v_double_1", v_double_1 )
( "v_double_2", v_double_2 )
( "v_small_array", v_small_array )
( "v_small_obj", v_small_obj );
v_big_array.push_back( v_big_obj );
test_recursive( v_big_array );
}
BOOST_AUTO_TEST_CASE(precision_test)
{
BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( int64_t(0x100000000LL) ) ) );
BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( int64_t(-0x100000000LL) ) ) );
std::string half = fc::json::to_string( fc::variant( 0.5 ) );
BOOST_CHECK_EQUAL( '"', half.front() );
BOOST_CHECK_EQUAL( '"', half.back() );
half = half.substr( 1, half.length() - 2 );
while( '0' == half.back() ) half.erase( half.length() - 1, 1 );
BOOST_CHECK_EQUAL( "0.5", half );
}
BOOST_AUTO_TEST_CASE(recursion_test)
{
std::string ten_levels = "[[[[[[[[[[]]]]]]]]]]";
fc::variant nested = fc::json::from_string( ten_levels );
BOOST_CHECK_THROW( fc::json::from_string( ten_levels, fc::json::legacy_parser, 9 ), fc::parse_error_exception );
std::string back = fc::json::to_string( nested );
BOOST_CHECK_EQUAL( ten_levels, back );
BOOST_CHECK_THROW( fc::json::to_string( nested, fc::json::stringify_large_ints_and_doubles, 9 ), fc::assert_exception );
}
BOOST_AUTO_TEST_CASE(rethrow_test)
{
fc::variants biggie;
for( int i = 0; i < 250; i++ )
{
fc::variant tmp( std::move(biggie) );
biggie.reserve(1);
biggie.push_back( std::move(tmp) );
}
auto test_r = [&biggie](){
try {
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
} FC_RETHROW_EXCEPTIONS( warn, "Argh! ${biggie}", ("biggie",biggie) ) };
BOOST_CHECK_THROW( test_r(), fc::unknown_host_exception );
auto test_lr = [&biggie](){
try {
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
} FC_LOG_AND_RETHROW() };
BOOST_CHECK_THROW( test_lr(), fc::unknown_host_exception );
auto test_clr = [&biggie](){
try {
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
} FC_CAPTURE_LOG_AND_RETHROW( (biggie) ) };
BOOST_CHECK_THROW( test_clr(), fc::unknown_host_exception );
auto test_cl = [&biggie](){
try {
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
} FC_CAPTURE_AND_LOG( (biggie) ) };
test_cl();
auto test_cr = [&biggie](){
try {
FC_THROW_EXCEPTION( fc::unknown_host_exception, "WTF?" );
} FC_CAPTURE_AND_RETHROW( (biggie) ) };
BOOST_CHECK_THROW( test_cr(), fc::unknown_host_exception );
}
BOOST_AUTO_TEST_SUITE_END()

178
tests/io/stream_tests.cpp Normal file
View file

@ -0,0 +1,178 @@
#include <boost/test/unit_test.hpp>
#include <fc/filesystem.hpp>
#include <fc/exception/exception.hpp>
#include <fc/io/buffered_iostream.hpp>
#include <fc/io/fstream.hpp>
#include <fc/io/sstream.hpp>
#include <fstream>
BOOST_AUTO_TEST_SUITE(stream_tests)
BOOST_AUTO_TEST_CASE(stringstream_test)
{
const fc::string constant( "Hello", 6 ); // includes trailing \0
fc::string writable( "World" );
fc::stringstream in1( constant );
fc::stringstream in2( writable );
fc::stringstream out;
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
*buf = 'w';
in2.writesome( buf, 1, 0 );
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 3, out.writesome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 'l', in1.peek() );
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 4, 0 ) );
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
BOOST_CHECK_EQUAL( 2, out.writesome( buf, 2, 0 ) );
*buf = ' ';
out.writesome( buf, 1, 0 );
BOOST_CHECK_THROW( in1.readsome( buf, 3, 0 ), fc::eof_exception );
BOOST_CHECK_EQUAL( 5, in2.readsome( buf, 6, 0 ) );
BOOST_CHECK_EQUAL( 5, out.writesome( buf, 5, 0 ) );
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
BOOST_CHECK_EQUAL( "Hello world", out.str() );
BOOST_CHECK_THROW( in1.peek(), fc::eof_exception );
BOOST_CHECK( in1.eof() );
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
// BOOST_CHECK( in2.eof() ); // fails, apparently readsome doesn't set eof
}
BOOST_AUTO_TEST_CASE(buffered_stringstream_test)
{
const fc::string constant( "Hello", 6 ); // includes trailing \0
fc::string writable( "World" );
fc::istream_ptr in1( new fc::stringstream( constant ) );
std::shared_ptr<fc::stringstream> in2( new fc::stringstream( writable ) );
std::shared_ptr<fc::stringstream> out1( new fc::stringstream() );
fc::buffered_istream bin1( in1 );
fc::buffered_istream bin2( in2 );
fc::buffered_ostream bout( out1 );
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
*buf = 'w';
in2->writesome( buf, 1, 0 );
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 3, bout.writesome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 'l', bin1.peek() );
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 4, 0 ) );
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
BOOST_CHECK_EQUAL( 2, bout.writesome( buf, 2, 0 ) );
*buf = ' ';
bout.writesome( buf, 1, 0 );
BOOST_CHECK_THROW( bin1.readsome( buf, 3, 0 ), fc::eof_exception );
BOOST_CHECK_EQUAL( 5, bin2.readsome( buf, 6, 0 ) );
BOOST_CHECK_EQUAL( 5, bout.writesome( buf, 5, 0 ) );
BOOST_CHECK_THROW( bin2.readsome( buf, 3, 0 ), fc::eof_exception );
bout.flush();
BOOST_CHECK_EQUAL( "Hello world", out1->str() );
}
BOOST_AUTO_TEST_CASE(fstream_test)
{
fc::temp_file inf1( fc::temp_directory_path(), true );
fc::temp_file inf2( fc::temp_directory_path(), true );
fc::temp_file outf( fc::temp_directory_path(), true );
{
std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( "Hello", 6 ); // includes trailing \0
init.close();
init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( "world", 5 );
init.close();
init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.close();
}
fc::ifstream in1( inf1.path() );
fc::ifstream in2( inf2.path() );
fc::ofstream out( outf.path() );
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 3, out.writesome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 3, in1.readsome( buf, 4, 0 ) );
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
BOOST_CHECK_EQUAL( 2, out.writesome( buf, 2, 0 ) );
*buf = ' ';
out.writesome( buf, 1, 0 );
BOOST_CHECK_THROW( in1.readsome( buf, 3, 0 ), fc::eof_exception );
BOOST_CHECK_EQUAL( 5, in2.readsome( buf, 6, 0 ) );
BOOST_CHECK_EQUAL( 5, out.writesome( buf, 5, 0 ) );
BOOST_CHECK_THROW( in2.readsome( buf, 3, 0 ), fc::eof_exception );
{
out.flush();
std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in );
BOOST_CHECK_EQUAL( 11, test.readsome( (&(*buf)), 11 ) );
BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) );
BOOST_CHECK_EQUAL( 0, test.readsome( (&(*buf)), 11 ) );
test.close();
}
BOOST_CHECK( in1.eof() );
BOOST_CHECK( in2.eof() );
}
BOOST_AUTO_TEST_CASE(buffered_fstream_test)
{
fc::temp_file inf1( fc::temp_directory_path(), true );
fc::temp_file inf2( fc::temp_directory_path(), true );
fc::temp_file outf( fc::temp_directory_path(), true );
{
std::fstream init( inf1.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( "Hello", 6 ); // includes trailing \0
init.close();
init.open( inf2.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.write( "world", 5 );
init.close();
init.open( outf.path().to_native_ansi_path(), std::fstream::out | std::fstream::trunc );
init.close();
}
fc::istream_ptr in1( new fc::ifstream( inf1.path() ) );
fc::istream_ptr in2( new fc::ifstream( inf2.path() ) );
fc::ostream_ptr out( new fc::ofstream( outf.path() ) );
fc::buffered_istream bin1( in1 );
fc::buffered_istream bin2( in2 );
fc::buffered_ostream bout( out );
std::shared_ptr<char> buf( new char[15], [](char* p){ delete[] p; } );
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 3, bout.writesome( buf, 3, 0 ) );
BOOST_CHECK_EQUAL( 'l', bin1.peek() );
BOOST_CHECK_EQUAL( 3, bin1.readsome( buf, 4, 0 ) );
BOOST_CHECK_EQUAL( '\0', (&(*buf))[2] );
BOOST_CHECK_EQUAL( 2, bout.writesome( buf, 2, 0 ) );
*buf = ' ';
bout.writesome( buf, 1, 0 );
BOOST_CHECK_THROW( bin1.readsome( buf, 3, 0 ), fc::eof_exception );
BOOST_CHECK_EQUAL( 5, bin2.readsome( buf, 6, 0 ) );
BOOST_CHECK_EQUAL( 5, bout.writesome( buf, 5, 0 ) );
BOOST_CHECK_THROW( bin2.readsome( buf, 3, 0 ), fc::eof_exception );
{
bout.flush();
std::fstream test( outf.path().to_native_ansi_path(), std::fstream::in );
BOOST_CHECK_EQUAL( 11, test.readsome( (&(*buf)), 11 ) );
BOOST_CHECK_EQUAL( "Hello world", std::string( (&(*buf)), 11 ) );
BOOST_CHECK_EQUAL( 0, test.readsome( (&(*buf)), 11 ) );
test.close();
}
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -64,6 +64,10 @@ BOOST_AUTO_TEST_CASE(websocket_test)
BOOST_FAIL("expected assertion failure");
} catch (const fc::assert_exception& e) {
std::cerr << e.to_string() << "\n";
} catch (const fc::exception& e) {
BOOST_FAIL("Unexpected exception: " + e.to_string());
} catch (const std::exception& e) {
BOOST_FAIL("Unexpected exception: " + std::string(e.what()));
}
}

View file

@ -0,0 +1,108 @@
#include <boost/test/unit_test.hpp>
#include <fc/log/logger.hpp>
#include <fc/container/flat.hpp>
#include <fc/io/raw.hpp>
namespace fc { namespace test {
struct item;
inline bool operator < ( const item& a, const item& b );
inline bool operator == ( const item& a, const item& b );
struct item_wrapper
{
item_wrapper() {}
item_wrapper(item&& it) { v.reserve(1); v.insert( it ); }
boost::container::flat_set<struct item> v;
};
inline bool operator < ( const item_wrapper& a, const item_wrapper& b );
inline bool operator == ( const item_wrapper& a, const item_wrapper& b );
struct item
{
item(int32_t lvl = 0) : level(lvl) {}
item(item_wrapper&& wp, int32_t lvl = 0) : level(lvl), w(wp) {}
int32_t level;
item_wrapper w;
};
inline bool operator == ( const item& a, const item& b )
{ return ( std::tie( a.level, a.w ) == std::tie( b.level, b.w ) ); }
inline bool operator < ( const item& a, const item& b )
{ return ( std::tie( a.level, a.w ) < std::tie( b.level, b.w ) ); }
inline bool operator == ( const item_wrapper& a, const item_wrapper& b )
{ return ( std::tie( a.v ) == std::tie( b.v ) ); }
inline bool operator < ( const item_wrapper& a, const item_wrapper& b )
{ return ( std::tie( a.v ) < std::tie( b.v ) ); }
} }
FC_REFLECT( fc::test::item_wrapper, (v) );
FC_REFLECT( fc::test::item, (level)(w) );
BOOST_AUTO_TEST_SUITE(fc_serialization)
BOOST_AUTO_TEST_CASE( nested_objects_test )
{ try {
auto create_nested_object = []( uint32_t level )
{
ilog( "Creating nested object with ${lv} level(s)", ("lv",level) );
fc::test::item nested;
for( uint32_t i = 1; i <= level; i++ )
{
if( i % 100 == 0 )
ilog( "Creating level ${lv}", ("lv",i) );
fc::test::item_wrapper wp( std::move(nested) );
nested = fc::test::item( std::move(wp), i );
}
return nested;
};
// 100 levels, should be allowed
{
auto nested = create_nested_object( 100 );
std::stringstream ss;
BOOST_TEST_MESSAGE( "About to pack." );
fc::raw::pack( ss, nested );
BOOST_TEST_MESSAGE( "About to unpack." );
fc::test::item unpacked;
fc::raw::unpack( ss, unpacked );
BOOST_CHECK( unpacked == nested );
}
// 150 levels, by default packing will fail
{
auto nested = create_nested_object( 150 );
std::stringstream ss;
BOOST_TEST_MESSAGE( "About to pack." );
BOOST_CHECK_THROW( fc::raw::pack( ss, nested ), fc::assert_exception );
}
// 150 levels and allow packing, unpacking will fail
{
auto nested = create_nested_object( 150 );
std::stringstream ss;
BOOST_TEST_MESSAGE( "About to pack." );
fc::raw::pack( ss, nested, 1500 );
BOOST_TEST_MESSAGE( "About to unpack." );
fc::test::item unpacked;
BOOST_CHECK_THROW( fc::raw::unpack( ss, unpacked ), fc::assert_exception );
}
} FC_CAPTURE_LOG_AND_RETHROW ( (0) ) }
BOOST_AUTO_TEST_SUITE_END()