peerplays_migrated/libraries/db/include/graphene/db/object_id.hpp
2019-08-20 12:16:49 +02:00

222 lines
9 KiB
C++

/*
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#pragma once
#include <fc/exception/exception.hpp>
#include <fc/io/varint.hpp>
#include <memory>
#define GRAPHENE_DB_MAX_INSTANCE_ID (uint64_t(-1)>>16)
namespace graphene { namespace db {
using std::shared_ptr;
using std::unique_ptr;
using std::vector;
using fc::flat_map;
using fc::variant;
using fc::unsigned_int;
using fc::signed_int;
struct object_id_type
{
object_id_type( uint8_t s, uint8_t t, uint64_t i )
{
assert( i>>48 == 0 );
FC_ASSERT( i >> 48 == 0, "instance overflow", ("instance",i) );
number = (uint64_t(s)<<56) | (uint64_t(t)<<48) | i;
}
object_id_type(){ number = 0; }
uint8_t space()const { return number >> 56; }
uint8_t type()const { return number >> 48 & 0x00ff; }
uint16_t space_type()const { return number >> 48; }
uint64_t instance()const { return number & GRAPHENE_DB_MAX_INSTANCE_ID; }
bool is_null()const { return number == 0; }
explicit operator uint64_t()const { return number; }
friend bool operator == ( const object_id_type& a, const object_id_type& b ) { return a.number == b.number; }
friend bool operator != ( const object_id_type& a, const object_id_type& b ) { return a.number != b.number; }
friend bool operator < ( const object_id_type& a, const object_id_type& b ) { return a.number < b.number; }
friend bool operator > ( const object_id_type& a, const object_id_type& b ) { return a.number > b.number; }
object_id_type& operator++(int) { ++number; return *this; }
object_id_type& operator++() { ++number; return *this; }
friend object_id_type operator+(const object_id_type& a, int delta ) {
return object_id_type( a.space(), a.type(), a.instance() + delta );
}
friend object_id_type operator+(const object_id_type& a, int64_t delta ) {
return object_id_type( a.space(), a.type(), a.instance() + delta );
}
friend size_t hash_value( object_id_type v ) { return std::hash<uint64_t>()(v.number); }
template< typename T >
bool is() const
{
return (number >> 48) == ((T::space_id << 8) | (T::type_id));
}
template< typename T >
T as() const
{
FC_ASSERT( is<T>() );
return T( *this );
}
explicit operator std::string() const
{
return fc::to_string(space()) + "." + fc::to_string(type()) + "." + fc::to_string(instance());
}
uint64_t number;
};
class object;
class object_database;
template<uint8_t SpaceID, uint8_t TypeID, typename T = object>
struct object_id
{
typedef T type;
static const uint8_t space_id = SpaceID;
static const uint8_t type_id = TypeID;
object_id(){}
object_id( unsigned_int i ):instance(i){}
explicit object_id( uint64_t i ):instance(i)
{
FC_ASSERT( (i >> 48) == 0 );
}
object_id( object_id_type id ):instance(id.instance())
{
}
friend object_id operator+(const object_id a, int64_t delta ) { return object_id( uint64_t(a.instance.value+delta) ); }
friend object_id operator+(const object_id a, int delta ) { return object_id( uint64_t(a.instance.value+delta) ); }
operator object_id_type()const { return object_id_type( SpaceID, TypeID, instance.value ); }
explicit operator uint64_t()const { return object_id_type( *this ).number; }
template<typename DB>
const T& operator()(const DB& db)const { return db.get(*this); }
friend bool operator == ( const object_id& a, const object_id& b ) { return a.instance == b.instance; }
friend bool operator != ( const object_id& a, const object_id& b ) { return a.instance != b.instance; }
friend bool operator == ( const object_id_type& a, const object_id& b ) { return a == object_id_type(b); }
friend bool operator != ( const object_id_type& a, const object_id& b ) { return a != object_id_type(b); }
friend bool operator == ( const object_id& b, const object_id_type& a ) { return a == object_id_type(b); }
friend bool operator != ( const object_id& b, const object_id_type& a ) { return a != object_id_type(b); }
friend bool operator < ( const object_id& a, const object_id& b ) { return a.instance.value < b.instance.value; }
friend bool operator > ( const object_id& a, const object_id& b ) { return a.instance.value > b.instance.value; }
friend size_t hash_value( object_id v ) { return std::hash<uint64_t>()(v.instance.value); }
unsigned_int instance;
};
} } // graphene::db
FC_REFLECT( graphene::db::object_id_type, (number) )
// REFLECT object_id manually because it has 2 template params
namespace fc {
template<uint8_t SpaceID, uint8_t TypeID, typename T>
struct get_typename<graphene::db::object_id<SpaceID,TypeID,T>>
{
static const char* name() {
return typeid(get_typename).name();
static std::string _str = string("graphene::db::object_id<")+fc::to_string(SpaceID) + ":" + fc::to_string(TypeID)+">";
return _str.c_str();
}
};
template<uint8_t SpaceID, uint8_t TypeID, typename T>
struct reflector<graphene::db::object_id<SpaceID,TypeID,T> >
{
typedef graphene::db::object_id<SpaceID,TypeID,T> type;
typedef fc::true_type is_defined;
typedef fc::false_type is_enum;
enum member_count_enum {
local_member_count = 1,
total_member_count = 1
};
template<typename Visitor>
static inline void visit( const Visitor& visitor )
{
typedef decltype(((type*)nullptr)->instance) member_type;
visitor.TEMPLATE operator()<member_type,type,&type::instance>( "instance" );
}
};
inline void to_variant( const graphene::db::object_id_type& var, fc::variant& vo, uint32_t max_depth = 1 )
{
vo = std::string( var );
}
inline void from_variant( const fc::variant& var, graphene::db::object_id_type& vo, uint32_t max_depth = 1 )
{ try {
vo.number = 0;
const auto& s = var.get_string();
auto first_dot = s.find('.');
auto second_dot = s.find('.',first_dot+1);
FC_ASSERT( first_dot != second_dot );
FC_ASSERT( first_dot != 0 && first_dot != std::string::npos );
vo.number = fc::to_uint64(s.substr( second_dot+1 ));
FC_ASSERT( vo.number <= GRAPHENE_DB_MAX_INSTANCE_ID );
auto space_id = fc::to_uint64( s.substr( 0, first_dot ) );
FC_ASSERT( space_id <= 0xff );
auto type_id = fc::to_uint64( s.substr( first_dot+1, second_dot-first_dot-1 ) );
FC_ASSERT( type_id <= 0xff );
vo.number |= (space_id << 56) | (type_id << 48);
} FC_CAPTURE_AND_RETHROW( (var) ) }
template<uint8_t SpaceID, uint8_t TypeID, typename T>
void to_variant( const graphene::db::object_id<SpaceID,TypeID,T>& var, fc::variant& vo, uint32_t max_depth = 1 )
{
vo = fc::to_string(SpaceID) + "." + fc::to_string(TypeID) + "." + fc::to_string(var.instance.value);
}
template<uint8_t SpaceID, uint8_t TypeID, typename T>
void from_variant( const fc::variant& var, graphene::db::object_id<SpaceID,TypeID,T>& vo, uint32_t max_depth = 1 )
{ try {
const auto& s = var.get_string();
auto first_dot = s.find('.');
auto second_dot = s.find('.',first_dot+1);
FC_ASSERT( first_dot != second_dot );
FC_ASSERT( first_dot != 0 && first_dot != std::string::npos );
FC_ASSERT( fc::to_uint64( s.substr( 0, first_dot ) ) == SpaceID &&
fc::to_uint64( s.substr( first_dot+1, second_dot-first_dot-1 ) ) == TypeID,
"Space.Type.0 (${SpaceID}.${TypeID}.0) doesn't match expected value ${var}", ("TypeID",TypeID)("SpaceID",SpaceID)("var",var) );
vo.instance = fc::to_uint64(s.substr( second_dot+1 ));
} FC_CAPTURE_AND_RETHROW( (var) ) }
} // namespace fc
namespace std {
template <> struct hash<graphene::db::object_id_type>
{
size_t operator()(const graphene::db::object_id_type& x) const
{
return std::hash<uint64_t>()(x.number);
}
};
}