BitShares-Core  6.1.0
BitShares blockchain implementation and command-line interface software
object_id.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #pragma once
26 #include <fc/io/varint.hpp>
27 
28 namespace graphene { namespace db {
29 
31  {
32  static constexpr uint8_t instance_bits = 48;
33  static constexpr uint8_t type_and_instance_bits = 56;
34  static constexpr uint64_t one_byte_mask = 0x00ff;
35  static constexpr uint64_t max_instance = 0x0000ffffffffffff;
36 
37  object_id_type() = default;
38  object_id_type( uint8_t s, uint8_t t, uint64_t i ){ reset( s, t, i ); }
39 
40  void reset( uint8_t s, uint8_t t, uint64_t i )
41  {
42  FC_ASSERT( i >> instance_bits == 0, "instance overflow", ("instance",i) );
43  number = ( (uint64_t(s) << type_and_instance_bits) | (uint64_t(t) << instance_bits) ) | i;
44  }
45 
46  uint8_t space()const { return number >> type_and_instance_bits; }
47  uint8_t type()const { return (number >> instance_bits) & one_byte_mask; }
48  uint16_t space_type()const { return number >> instance_bits; }
49  uint64_t instance()const { return number & max_instance; }
50  bool is_null()const { return 0 == number; }
51  explicit operator uint64_t()const { return number; }
52 
53  friend bool operator == ( const object_id_type& a, const object_id_type& b ) { return a.number == b.number; }
54  friend bool operator != ( const object_id_type& a, const object_id_type& b ) { return a.number != b.number; }
55  friend bool operator < ( const object_id_type& a, const object_id_type& b ) { return a.number < b.number; }
56  friend bool operator > ( const object_id_type& a, const object_id_type& b ) { return a.number > b.number; }
57 
58  object_id_type& operator++() { ++number; return *this; }
59 
60  friend object_id_type operator+(const object_id_type& a, int64_t delta ) {
61  return object_id_type( a.space(), a.type(), a.instance() + delta );
62  }
63  friend size_t hash_value( const object_id_type& v ) { return std::hash<uint64_t>()(v.number); }
64 
65  template< typename T >
66  bool is() const
67  {
68  return space_type() == T::space_type;
69  }
70 
71 
72  template< typename T >
73  T as() const
74  {
75  return T( *this );
76  }
77 
78  explicit operator std::string() const
79  {
80  return fc::to_string(space()) + "." + fc::to_string(type()) + "." + fc::to_string(instance());
81  }
82 
83  uint64_t number = 0;
84  };
85 
86  class object;
87  class object_database;
88 
90  template<typename ObjectID>
91  struct object_downcast { using type = object; };
92  // This macro specializes the above template for a specific xyz_object type
93 #define MAP_OBJECT_ID_TO_TYPE(OBJECT) \
94  namespace graphene { namespace db { \
95  template<> \
96  struct object_downcast<const graphene::db::object_id<OBJECT::space_id, \
97  OBJECT::type_id>&> { using type = OBJECT; }; \
98  } }
99  template<typename ObjectID>
101 
102  template<uint8_t SpaceID, uint8_t TypeID>
103  struct object_id
104  {
105  static constexpr uint8_t type_bits = 8;
106  static constexpr uint8_t instance_bits = 48;
107  static constexpr uint64_t max_instance = 0x0000ffffffffffff;
108 
109  static constexpr uint8_t space_id = SpaceID;
110  static constexpr uint8_t type_id = TypeID;
111 
112  static constexpr uint16_t space_type = uint16_t(uint16_t(space_id) << type_bits) | uint16_t(type_id);
113 
114  static constexpr object_id max()
115  {
116  return object_id( max_instance );
117  }
118 
119  object_id() = default;
120  explicit object_id( const fc::unsigned_int& i ):instance(i)
121  {
122  validate();
123  }
124  explicit object_id( uint64_t i ):instance(i)
125  {
126  validate();
127  }
128  explicit object_id( const object_id_type& id ):instance(id.instance())
129  {
130  // Won't overflow, but need to check space and type
131  FC_ASSERT( id.is<std::remove_reference_t<decltype(*this)>>(), "space or type mismatch" );
132  }
133 
134  void validate()const
135  {
136  FC_ASSERT( (instance.value >> instance_bits) == 0, "instance overflow", ("instance",instance) );
137  }
138 
140  {
141  *this = object_id(o);
142  return *this;
143  }
144 
145  friend object_id operator+(const object_id& a, int64_t delta )
146  { return object_id( uint64_t(a.instance.value+delta) ); }
147 
148  explicit operator object_id_type()const { return object_id_type( SpaceID, TypeID, instance.value ); }
149  explicit operator uint64_t()const { return object_id_type( *this ).number; }
150 
151  template<typename DB>
152  auto operator()(const DB& db)const -> const decltype(db.get(*this))& { return db.get(*this); }
153 
154  friend bool operator == ( const object_id& a, const object_id& b ) { return a.instance == b.instance; }
155  friend bool operator != ( const object_id& a, const object_id& b ) { return a.instance != b.instance; }
156  friend bool operator == ( const object_id_type& a, const object_id& b ) { return a == object_id_type(b); }
157  friend bool operator != ( const object_id_type& a, const object_id& b ) { return a != object_id_type(b); }
158  friend bool operator == ( const object_id& a, const object_id_type& b ) { return object_id_type(a) == b; }
159  friend bool operator != ( const object_id& a, const object_id_type& b ) { return object_id_type(a) != b; }
160  friend bool operator == ( const object_id& a, const fc::unsigned_int& b ) { return a.instance == b; }
161  friend bool operator != ( const object_id& a, const fc::unsigned_int& b ) { return a.instance != b; }
162  friend bool operator == ( const fc::unsigned_int& a, const object_id& b ) { return a == b.instance; }
163  friend bool operator != ( const fc::unsigned_int& a, const object_id& b ) { return a != b.instance; }
164 
165  friend bool operator < ( const object_id& a, const object_id& b )
166  { return a.instance.value < b.instance.value; }
167  friend bool operator > ( const object_id& a, const object_id& b )
168  { return a.instance.value > b.instance.value; }
169 
170  friend size_t hash_value( const object_id& v ) { return std::hash<uint64_t>()(v.instance.value); }
171 
172  explicit operator std::string() const
173  {
174  return fc::to_string(space_id) + "." + fc::to_string(type_id) + "." + fc::to_string(instance.value);
175  }
176 
177  fc::unsigned_int instance; // default is 0
178  };
179 
180 } } // graphene::db
181 
183 
184 // REFLECT object_id manually because it has 2 template params
185 namespace fc {
186 template<uint8_t SpaceID, uint8_t TypeID>
187 struct get_typename<graphene::db::object_id<SpaceID,TypeID>>
188 {
189  static const char* name() {
190  return typeid(get_typename).name();
191  static std::string _str = string("graphene::db::object_id<") + fc::to_string(SpaceID) + ":"
192  + fc::to_string(TypeID) + ">";
193  return _str.c_str();
194  }
195 };
196 
197 template<uint8_t SpaceID, uint8_t TypeID>
198 struct reflector<graphene::db::object_id<SpaceID,TypeID> >
199 {
201  using is_defined = std::true_type;
207  local_member_count = 1,
208  total_member_count = 1
209  };
210  template<typename Visitor>
211  static inline void visit( const Visitor& visitor )
212  {
213  using member_type = decltype(((type*)nullptr)->instance);
214  visitor.TEMPLATE operator()<member_type,type,&type::instance>( "instance" );
215  }
216 };
217 namespace member_names {
218 template<uint8_t S, uint8_t T>
219 struct member_name<graphene::db::object_id<S,T>, 0> { static constexpr const char* value = "instance"; };
220 }
221 
222 
223  inline void to_variant( const graphene::db::object_id_type& var, fc::variant& vo, uint32_t max_depth = 1 )
224  {
225  vo = std::string( var );
226  }
227 
228  inline void from_variant( const fc::variant& var, graphene::db::object_id_type& vo, uint32_t max_depth = 1 )
229  { try {
230  const auto& s = var.get_string();
231  auto first_dot = s.find('.');
232  FC_ASSERT( first_dot != std::string::npos, "Missing the first dot" );
233  FC_ASSERT( first_dot != 0, "Missing the space part" );
234  auto second_dot = s.find('.',first_dot+1);
235  FC_ASSERT( second_dot != std::string::npos, "Missing the second dot" );
236  FC_ASSERT( second_dot != first_dot+1, "Missing the type part" );
237  auto space_id = fc::to_uint64( s.substr( 0, first_dot ) );
238  FC_ASSERT( space_id <= graphene::db::object_id_type::one_byte_mask, "space overflow" );
239  auto type_id = fc::to_uint64( s.substr( first_dot+1, (second_dot-first_dot)-1 ) );
240  FC_ASSERT( type_id <= graphene::db::object_id_type::one_byte_mask, "type overflow");
241  auto instance = fc::to_uint64(s.substr( second_dot+1 ));
242  vo.reset( static_cast<uint8_t>(space_id), static_cast<uint8_t>(type_id), instance );
243  } FC_CAPTURE_AND_RETHROW( (var) ) }
244  template<uint8_t SpaceID, uint8_t TypeID>
245  void to_variant( const graphene::db::object_id<SpaceID,TypeID>& var, fc::variant& vo, uint32_t max_depth = 1 )
246  {
247  vo = std::string( var );
248  }
249  template<uint8_t SpaceID, uint8_t TypeID>
250  void from_variant( const fc::variant& var, graphene::db::object_id<SpaceID,TypeID>& vo, uint32_t max_depth = 1 )
251  { try {
252  const auto& s = var.get_string();
253  auto first_dot = s.find('.');
254  FC_ASSERT( first_dot != std::string::npos, "Missing the first dot" );
255  FC_ASSERT( first_dot != 0, "Missing the space part" );
256  auto second_dot = s.find('.',first_dot+1);
257  FC_ASSERT( second_dot != std::string::npos, "Missing the second dot" );
258  FC_ASSERT( second_dot != first_dot+1, "Missing the type part" );
259  FC_ASSERT( fc::to_uint64( s.substr( 0, first_dot ) ) == SpaceID &&
260  fc::to_uint64( s.substr( first_dot+1, (second_dot-first_dot)-1 ) ) == TypeID,
261  "Space.Type.0 (${SpaceID}.${TypeID}.0) doesn't match expected value ${var}",
262  ("TypeID",TypeID)("SpaceID",SpaceID)("var",var) );
263  graphene::db::object_id<SpaceID,TypeID> tmp { fc::to_uint64(s.substr( second_dot+1 )) };
264  vo = tmp;
265  } FC_CAPTURE_AND_RETHROW( (var) ) }
266 
267 } // namespace fc
268 
269 namespace std {
270  template <> struct hash<graphene::db::object_id_type>
271  {
273  {
274  return std::hash<uint64_t>()(x.number);
275  }
276  };
277 }
friend object_id operator+(const object_id &a, int64_t delta)
Definition: object_id.hpp:145
object_id & operator=(const object_id_type &o)
Definition: object_id.hpp:139
object_id(const object_id_type &id)
Definition: object_id.hpp:128
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition: reflect.hpp:388
auto operator()(const DB &db) const -> const decltype(db.get(*this))&
Definition: object_id.hpp:152
friend bool operator>(const object_id_type &a, const object_id_type &b)
Definition: object_id.hpp:56
Definition: api.cpp:48
friend object_id_type operator+(const object_id_type &a, int64_t delta)
Definition: object_id.hpp:60
fc::unsigned_int instance
Definition: object_id.hpp:177
uint64_t instance() const
Definition: object_id.hpp:49
void reset(uint8_t s, uint8_t t, uint64_t i)
Definition: object_id.hpp:40
friend bool operator==(const object_id_type &a, const object_id_type &b)
Definition: object_id.hpp:53
static constexpr uint64_t max_instance
Definition: object_id.hpp:35
void to_variant(const graphene::db::object_id< SpaceID, TypeID > &var, fc::variant &vo, uint32_t max_depth=1)
Definition: object_id.hpp:245
This template is used to downcast a generic object type to a specific xyz_object type.
Definition: object_id.hpp:91
defines visit functions for T Unless this is specialized, visit() will not be defined for T...
Definition: reflect.hpp:25
object_id(const fc::unsigned_int &i)
Definition: object_id.hpp:120
maintains a set of indexed objects that can be modified with multi-level rollback support ...
friend size_t hash_value(const object_id &v)
Definition: object_id.hpp:170
object_id_type(uint8_t s, uint8_t t, uint64_t i)
Definition: object_id.hpp:38
void from_variant(const fc::variant &var, graphene::db::object_id< SpaceID, TypeID > &vo, uint32_t max_depth=1)
Definition: object_id.hpp:250
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:479
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
static constexpr uint8_t instance_bits
Definition: object_id.hpp:32
uint64_t to_uint64(const std::string &)
Definition: string.cpp:47
The actual list type.
Definition: typelist.hpp:17
Defines exception&#39;s used by fc.
uint16_t space_type() const
Definition: object_id.hpp:48
typename object_downcast< ObjectID >::type object_downcast_t
Definition: object_id.hpp:100
std::string to_string(double)
Definition: string.cpp:73
static constexpr uint64_t one_byte_mask
Definition: object_id.hpp:34
Definition: api.hpp:15
friend bool operator<(const object_id_type &a, const object_id_type &b)
Definition: object_id.hpp:55
uint64_t value
Definition: varint.hpp:17
const std::string & get_string() const
Definition: variant.cpp:575
friend bool operator!=(const object_id_type &a, const object_id_type &b)
Definition: object_id.hpp:54
base for all database objects
Definition: object.hpp:61
static constexpr uint8_t type_and_instance_bits
Definition: object_id.hpp:33
friend size_t hash_value(const object_id_type &v)
Definition: object_id.hpp:63
size_t operator()(const graphene::db::object_id_type &x) const
Definition: object_id.hpp:272
static constexpr object_id max()
Definition: object_id.hpp:114
object_id_type & operator++()
Definition: object_id.hpp:58
A template which stores the name of the native member at a given index in a given class...
Definition: reflect.hpp:28