1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ 2 3 // creg - Code compoment registration system 4 5 #ifndef _CREG_H 6 #define _CREG_H 7 8 #include <vector> 9 #include <string> 10 #include <boost/shared_ptr.hpp> 11 12 #include "ISerializer.h" 13 #include "System/Sync/SyncedPrimitive.h" 14 15 16 namespace creg { 17 18 class IType; 19 class Class; 20 class ClassBinder; 21 22 typedef unsigned int uint; 23 24 // Fundamental/basic types 25 enum BasicTypeID 26 { 27 crInt, crUInt, 28 crShort, crUShort, 29 crChar, crUChar, 30 crInt64, crUInt64, 31 crFloat, 32 crDouble, 33 crBool, 34 #if defined(SYNCDEBUG) || defined(SYNCCHECK) 35 crSyncedSint, crSyncedUint, 36 crSyncedSshort, crSyncedUshort, 37 crSyncedSchar, crSyncedUchar, 38 crSyncedFloat, 39 crSyncedDouble, 40 crSyncedBool, 41 #endif 42 }; 43 44 class IType 45 { 46 public: 47 // Type interface can go here... 48 virtual ~IType(); 49 50 virtual void Serialize(ISerializer* s, void* instance) = 0; 51 virtual std::string GetName() = 0; 52 virtual size_t GetSize() = 0; 53 54 static boost::shared_ptr<IType> CreateBasicType(BasicTypeID t); 55 static boost::shared_ptr<IType> CreateStringType(); 56 static boost::shared_ptr<IType> CreateObjInstanceType(Class* objectType); 57 static boost::shared_ptr<IType> CreateEnumeratedType(size_t size); 58 }; 59 60 class IMemberRegistrator 61 { 62 public: 63 virtual ~IMemberRegistrator(); 64 virtual void RegisterMembers(Class* cls) = 0; 65 }; 66 67 enum ClassFlags { 68 CF_None = 0, 69 CF_Abstract = 4, 70 CF_Synced = 8, 71 }; 72 73 struct _DummyStruct {}; 74 75 /** Class member flags to use with CR_MEMBER_SETFLAG */ 76 enum ClassMemberFlag { 77 CM_NoSerialize = 1, /// Make the serializers skip the member 78 CM_Config = 2, // Exposed in config 79 }; 80 81 /** 82 * Stores class bindings such as constructor/destructor 83 */ 84 class ClassBinder 85 { 86 public: 87 ClassBinder(const char* className, unsigned int cf, ClassBinder* base, 88 IMemberRegistrator** mreg, int instanceSize, int instanceAlignment, bool hasVTable, 89 void (*constructorProc)(void* instance), 90 void (*destructorProc)(void* instance)); 91 92 Class* class_; 93 ClassBinder* base; 94 ClassFlags flags; 95 IMemberRegistrator** memberRegistrator; 96 const char* name; 97 int size; // size of an instance in bytes 98 int alignment; 99 bool hasVTable; 100 101 void (*constructor)(void* instance); 102 /** 103 * Needed for classes without virtual destructor. 104 * (classes/structs declared with CR_DECLARE_STRUCT) 105 */ 106 void (*destructor)(void* instance); 107 108 ClassBinder* nextBinder; 109 }; 110 111 class System 112 { 113 public: 114 /// Return the global list of classes GetClasses()115 static const std::vector<Class*>& GetClasses() { return classes; } 116 117 /** 118 * Initialization of creg, collects all the classes and initializes 119 * metadata. 120 */ 121 static void InitializeClasses(); 122 123 /// Shutdown of creg 124 static void FreeClasses(); 125 126 /// Find a class by name 127 static Class* GetClass(const std::string& name); 128 129 static void AddClassBinder(ClassBinder* cb); 130 131 protected: 132 static ClassBinder* binderList; 133 static std::vector<Class*> classes; 134 }; 135 136 /** 137 * Represents a C++ class or struct, declared with 138 * CR_DECLARE or CR_DECLARE_STRUCT. 139 */ 140 class Class 141 { 142 public: 143 struct Member 144 { 145 const char* name; 146 boost::shared_ptr<IType> type; 147 unsigned int offset; 148 int alignment; 149 int flags; // combination of ClassMemberFlag's 150 }; 151 152 Class(); 153 ~Class(); 154 155 /// Returns true if this class is equal to or derived from other 156 bool IsSubclassOf(Class* other) const; 157 void DeleteInstance(void* inst); 158 /// Allocate an instance of the class 159 void* CreateInstance(); 160 /// Calculate a checksum from the class metadata 161 void CalculateChecksum(unsigned int& checksum); 162 bool AddMember(const char* name, boost::shared_ptr<IType> type, unsigned int offset, int alignment); 163 bool AddMember(const char* name, IType* type, unsigned int offset, int alignment); 164 void SetMemberFlag(const char* name, ClassMemberFlag f); 165 Member* FindMember(const char* name); 166 167 void BeginFlag(ClassMemberFlag flag); 168 void EndFlag(ClassMemberFlag flag); 169 170 void SetFlag(ClassFlags flag); 171 IsAbstract()172 bool IsAbstract() const { return (binder->flags & CF_Abstract) != 0; } 173 174 /// Returns all concrete classes that implement this class 175 std::vector<Class*> GetImplementations(); 176 177 std::vector <Member*> members; 178 /// all classes that derive from this class 179 std::vector <Class*> derivedClasses; 180 ClassBinder* binder; 181 std::string name; 182 int size; 183 int alignment; 184 Class* base; 185 void (_DummyStruct::*serializeProc)(ISerializer& s); 186 void (_DummyStruct::*postLoadProc)(); 187 188 friend class ClassBinder; 189 }; 190 191 // ------------------------------------------------------------------- 192 // Container Type templates 193 // ------------------------------------------------------------------- 194 195 // vector,deque container 196 template<typename T> 197 class DynamicArrayType : public IType 198 { 199 public: 200 typedef typename T::iterator iterator; 201 typedef typename T::value_type ElemT; 202 203 boost::shared_ptr<IType> elemType; 204 DynamicArrayType(boost::shared_ptr<IType> et)205 DynamicArrayType(boost::shared_ptr<IType> et) 206 : elemType(et) {} ~DynamicArrayType()207 ~DynamicArrayType() {} 208 Serialize(ISerializer * s,void * inst)209 void Serialize(ISerializer* s, void* inst) { 210 T& ct = *(T*)inst; 211 if (s->IsWriting()) { 212 int size = (int)ct.size(); 213 s->SerializeInt(&size, sizeof(int)); 214 for (int a = 0; a < size; a++) { 215 elemType->Serialize(s, &ct[a]); 216 } 217 } else { 218 int size; 219 s->SerializeInt(&size, sizeof(int)); 220 ct.resize(size); 221 for (int a = 0; a < size; a++) { 222 elemType->Serialize(s, &ct[a]); 223 } 224 } 225 } GetName()226 std::string GetName() { return elemType->GetName() + "[]"; } GetSize()227 size_t GetSize() { return sizeof(T); } 228 }; 229 230 class StaticArrayBaseType : public IType 231 { 232 public: 233 boost::shared_ptr<IType> elemType; 234 int size, elemSize; 235 StaticArrayBaseType(boost::shared_ptr<IType> et,int Size,int ElemSize)236 StaticArrayBaseType(boost::shared_ptr<IType> et, int Size, int ElemSize) 237 : elemType(et), size(Size), elemSize(ElemSize) {} ~StaticArrayBaseType()238 ~StaticArrayBaseType() {} 239 240 std::string GetName(); GetSize()241 size_t GetSize() { return size * elemSize; } 242 }; 243 244 template<typename T, int Size> 245 class StaticArrayType : public StaticArrayBaseType 246 { 247 public: 248 typedef T ArrayType[Size]; StaticArrayType(boost::shared_ptr<IType> et)249 StaticArrayType(boost::shared_ptr<IType> et) 250 : StaticArrayBaseType(et, Size, sizeof(ArrayType)/Size) {} Serialize(ISerializer * s,void * instance)251 void Serialize(ISerializer* s, void* instance) 252 { 253 T* array = (T*)instance; 254 for (int a = 0; a < Size; a++) 255 elemType->Serialize(s, &array[a]); 256 } 257 }; 258 259 template<typename T> 260 class BitArrayType : public IType 261 { 262 public: 263 boost::shared_ptr<IType> elemType; 264 BitArrayType(boost::shared_ptr<IType> et)265 BitArrayType(boost::shared_ptr<IType> et) 266 : elemType(et) {} ~BitArrayType()267 ~BitArrayType() {} 268 Serialize(ISerializer * s,void * inst)269 void Serialize(ISerializer* s, void* inst) { 270 T* ct = (T*)inst; 271 if (s->IsWriting()) { 272 int size = (int)ct->size(); 273 s->SerializeInt(&size, sizeof(int)); 274 for (int a = 0; a < size; a++) { 275 bool b = (*ct)[a]; 276 elemType->Serialize(s, &b); 277 } 278 } else { 279 int size; 280 s->SerializeInt(&size, sizeof(int)); 281 ct->resize(size); 282 for (int a = 0; a < size; a++) { 283 bool b; 284 elemType->Serialize(s, &b); 285 (*ct)[a] = b; 286 } 287 } 288 } GetName()289 std::string GetName() { return elemType->GetName() + "[]"; } GetSize()290 size_t GetSize() { return sizeof(T); } 291 }; 292 293 class EmptyType : public IType 294 { 295 public: 296 int size; EmptyType(int Size)297 EmptyType(int Size) {size=Size;} ~EmptyType()298 ~EmptyType() {} 299 Serialize(ISerializer * s,void * instance)300 void Serialize(ISerializer* s, void* instance) 301 { 302 for (int a=0;a<size;a++) { 303 char c=0; 304 s->Serialize(&c,1); 305 } 306 } GetName()307 std::string GetName() 308 { 309 return "void"; 310 } GetSize()311 size_t GetSize() { return 0; /* size*/ } //FIXME used by CR_RESERVED(), ignored by now 312 }; 313 314 class IgnoredType : public IType 315 { 316 public: 317 int size; IgnoredType(int Size)318 IgnoredType(int Size) {size=Size;} ~IgnoredType()319 ~IgnoredType() {} 320 Serialize(ISerializer * s,void * instance)321 void Serialize(ISerializer* s, void* instance) 322 { 323 for (int a=0;a<size;a++) { 324 char c=0; 325 s->Serialize(&c,1); 326 } 327 } GetName()328 std::string GetName() 329 { 330 return "ignored"; 331 } GetSize()332 size_t GetSize() { return size; } 333 }; 334 } 335 336 #include "TypeDeduction.h" 337 338 339 //FIXME: defined cause gcc4.8 still doesn't support c++11's offsetof for non-static members 340 #define offsetof_creg(type, member) (std::size_t)(((char*)&null->member) - ((char*)null)) 341 342 343 namespace creg { 344 345 /** @def CR_DECLARE 346 * Add the definitions for creg binding to the class 347 * this should be put within the class definition 348 */ 349 #define CR_DECLARE(TCls) public: \ 350 static creg::ClassBinder binder; \ 351 typedef TCls MyType; \ 352 static creg::IMemberRegistrator* memberRegistrator; \ 353 static void _ConstructInstance(void* d); \ 354 static void _DestructInstance(void* d); \ 355 friend struct TCls##MemberRegistrator; \ 356 inline static creg::Class* StaticClass() { return binder.class_; } \ 357 virtual creg::Class* GetClass() const; \ 358 static const bool hasVTable = true; 359 360 /** @def CR_DECLARE_STRUCT 361 * Use this to declare a structure 362 * this should be put in the class definition, instead of CR_DECLARE 363 * For creg, the only difference between a class and a structure is having a 364 * vtable or not. 365 */ 366 #define CR_DECLARE_STRUCT(TStr) public: \ 367 static creg::ClassBinder binder; \ 368 typedef TStr MyType; \ 369 static creg::IMemberRegistrator* memberRegistrator; \ 370 static void _ConstructInstance(void* d); \ 371 static void _DestructInstance(void* d); \ 372 friend struct TStr##MemberRegistrator; \ 373 inline static creg::Class* StaticClass() { return binder.class_; } \ 374 creg::Class* GetClass() const; \ 375 static const bool hasVTable = false; 376 377 /** @def CR_DECLARE_SUB 378 * Use this to declare a sub class. This should be put in the class definition 379 * of the superclass, alongside CR_DECLARE(CSuperClass) (or CR_DECLARE_STRUCT). 380 */ 381 #define CR_DECLARE_SUB(cl) \ 382 struct cl##MemberRegistrator; 383 384 /** @def CR_BIND_DERIVED 385 * Bind a derived class declared with CR_DECLARE to creg 386 * Should be used in the source file 387 * @param TCls class to bind 388 * @param TBase base class of TCls 389 * @param ctor_args constructor arguments 390 */ 391 #define CR_BIND_DERIVED(TCls, TBase, ctor_args) \ 392 creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 393 creg::Class* TCls::GetClass() const { return binder.class_; } \ 394 void TCls::_ConstructInstance(void* d) { new(d) MyType ctor_args; } \ 395 void TCls::_DestructInstance(void* d) { ((MyType*)d)->~MyType(); } \ 396 creg::ClassBinder TCls::binder(#TCls, 0, &TBase::binder, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, TCls::_ConstructInstance, TCls::_DestructInstance); 397 398 /** @def CR_BIND_DERIVED_SUB 399 * Bind a derived class inside another class to creg 400 * Should be used in the source file 401 * @param TSuper class that contains the class to register 402 * @param TCls subclass to bind 403 * @param TBase base class of TCls 404 * @param ctor_args constructor arguments 405 */ 406 #define CR_BIND_DERIVED_SUB(TSuper, TCls, TBase, ctor_args) \ 407 creg::IMemberRegistrator* TSuper::TCls::memberRegistrator=0; \ 408 creg::Class* TSuper::TCls::GetClass() const { return binder.class_; } \ 409 void TSuper::TCls::_ConstructInstance(void* d) { new(d) TCls ctor_args; } \ 410 void TSuper::TCls::_DestructInstance(void* d) { ((TCls*)d)->~TCls(); } \ 411 creg::ClassBinder TSuper::TCls::binder(#TSuper "::" #TCls, 0, &TBase::binder, &TSuper::TCls::memberRegistrator, sizeof(TSuper::TCls), alignof(TCls), TCls::hasVTable, TSuper::TCls::_ConstructInstance, TSuper::TCls::_DestructInstance); 412 413 /** @def CR_BIND 414 * Bind a class not derived from CObject 415 * should be used in the source file 416 * @param TCls class to bind 417 * @param ctor_args constructor arguments 418 */ 419 #define CR_BIND(TCls, ctor_args) \ 420 creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 421 creg::Class* TCls::GetClass() const { return binder.class_; } \ 422 void TCls::_ConstructInstance(void* d) { new(d) MyType ctor_args; } \ 423 void TCls::_DestructInstance(void* d) { ((MyType*)d)->~MyType(); } \ 424 creg::ClassBinder TCls::binder(#TCls, 0, 0, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, TCls::_ConstructInstance, TCls::_DestructInstance); 425 426 #ifdef __clang__ 427 // LLVM/Clang expects a different order 428 #define CR_BIND_TEMPLATE(TCls, ctor_args) \ 429 template<> creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 430 template<> void TCls::_ConstructInstance(void* d) { new(d) MyType ctor_args; } \ 431 template<> void TCls::_DestructInstance(void* d) { ((MyType*)d)->~MyType(); } \ 432 template<> creg::ClassBinder TCls::binder(#TCls, 0, 0, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, TCls::_ConstructInstance, TCls::_DestructInstance); \ 433 template<> creg::Class* TCls::GetClass() const { return binder.class_; } 434 #else 435 #define CR_BIND_TEMPLATE(TCls, ctor_args) \ 436 template<> creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 437 template<> creg::Class* TCls::GetClass() const { return binder.class_; } \ 438 template<> void TCls::_ConstructInstance(void* d) { new(d) MyType ctor_args; } \ 439 template<> void TCls::_DestructInstance(void* d) { ((MyType*)d)->~MyType(); } \ 440 template<> creg::ClassBinder TCls::binder(#TCls, 0, 0, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, TCls::_ConstructInstance, TCls::_DestructInstance); 441 #endif 442 443 /** @def CR_BIND_DERIVED_INTERFACE 444 * Bind an abstract derived class 445 * should be used in the source file 446 * @param TCls abstract class to bind 447 * @param TBase base class of TCls 448 */ 449 #define CR_BIND_DERIVED_INTERFACE(TCls, TBase) \ 450 creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 451 creg::Class* TCls::GetClass() const { return binder.class_; } \ 452 creg::ClassBinder TCls::binder(#TCls, (unsigned int)creg::CF_Abstract, &TBase::binder, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, 0, 0); 453 454 /** @def CR_BIND_INTERFACE 455 * Bind an abstract class 456 * should be used in the source file 457 * This simply does not register a constructor to creg, so you can bind 458 * non-abstract class as abstract classes as well. 459 * @param TCls abstract class to bind 460 */ 461 #define CR_BIND_INTERFACE(TCls) \ 462 creg::IMemberRegistrator* TCls::memberRegistrator=0; \ 463 creg::Class* TCls::GetClass() const { return binder.class_; } \ 464 creg::ClassBinder TCls::binder(#TCls, (unsigned int)creg::CF_Abstract, 0, &TCls::memberRegistrator, sizeof(TCls), alignof(TCls), TCls::hasVTable, 0, 0); 465 466 /** @def CR_REG_METADATA 467 * Binds the class metadata to the class itself 468 * should be used in the source file 469 * @param TClass class to register the info to 470 * @param Members the metadata of the class\n 471 * should consist of a series of single expression of metadata macros\n 472 * for example: (CR_MEMBER(a),CR_POSTLOAD(PostLoadCallback)) 473 * @see CR_MEMBER 474 * @see CR_ENUM_MEMBER 475 * @see CR_SERIALIZER 476 * @see CR_POSTLOAD 477 * @see CR_MEMBER_SETFLAG 478 */ 479 #define CR_REG_METADATA(TClass, Members) \ 480 struct TClass##MemberRegistrator : creg::IMemberRegistrator {\ 481 typedef TClass Type; \ 482 TClass##MemberRegistrator() { \ 483 Type::memberRegistrator=this; \ 484 } \ 485 void RegisterMembers(creg::Class* class_) { \ 486 Type* null=nullptr; \ 487 (void)null; /*suppress compiler warning if this isn't used*/ \ 488 Members; } \ 489 } static TClass##mreg; 490 491 /** @def CR_REG_METADATA_SUB 492 * Just like CR_REG_METADATA, but for a subclass. 493 * @see CR_REG_METADATA 494 */ 495 #define CR_REG_METADATA_SUB(TSuperClass, TSubClass, Members) \ 496 struct TSuperClass::TSubClass##MemberRegistrator : creg::IMemberRegistrator {\ 497 typedef TSuperClass::TSubClass Type; \ 498 TSubClass##MemberRegistrator() { \ 499 Type::memberRegistrator=this; \ 500 } \ 501 void RegisterMembers(creg::Class* class_) { \ 502 Type* null=nullptr; \ 503 (void)null; \ 504 Members; } \ 505 } static TSuperClass##TSubClass##mreg; 506 507 /** @def CR_MEMBER 508 * Registers a class/struct member variable, of a type that is: 509 * - a struct registered with CR_DECLARE_STRUCT/CR_BIND_STRUCT 510 * - a class registered with CR_DECLARE/CR_BIND* 511 * - an int,short,char,long,double,float or bool, or any of the unsigned 512 * variants of those 513 * - a std::set/multiset included with STL_Set.h 514 * - a std::list included with STL_List.h 515 * - a std::deque included with STL_Deque.h 516 * - a std::map/multimap included with STL_Map.h 517 * - a std::vector 518 * - a std::string 519 * - an array 520 * - a pointer/reference to a creg registered struct or class instance 521 * For enumerated type members, @see CR_ENUM_MEMBER 522 */ 523 #define CR_MEMBER(Member) \ 524 class_->AddMember( #Member, creg::GetType(null->Member), offsetof_creg(Type, Member), alignof(decltype(Type::Member))) 525 526 /** @def CR_ENUM_MEMBER 527 * Registers a class/struct member variable with an enumerated type 528 */ 529 #define CR_ENUM_MEMBER(Member) \ 530 class_->AddMember( #Member, creg::IType::CreateEnumeratedType(sizeof(Type::Member)), offsetof_creg(Type, Member), alignof(decltype(Type::Member))) 531 532 /** @def CR_IGNORED 533 * Registers a member variable that isn't saved/loaded 534 */ 535 #define CR_IGNORED(Member) \ 536 class_->AddMember( #Member, new creg::IgnoredType(sizeof(Type::Member)), offsetof_creg(Type, Member), alignof(decltype(Type::Member))) 537 538 539 /** @def CR_MEMBER_UN 540 * Registers a member variable that is unsynced. 541 * It may be saved depending on the purpose. 542 * Currently works as CR_IGNORED. 543 */ 544 #define CR_MEMBER_UN(Member) \ 545 CR_IGNORED( Member ) 546 547 548 /** @def CR_RESERVED 549 * @author Victor Muraviev 550 * Registers a unused space for compatibility 551 * Size = 1: 552 * - char, synced char, bool, synced bool 553 * - pointer 554 * - enum 555 * Size = 2: 556 * - short, synced short 557 * - enum 558 * Size = 4: 559 * - int, synced int, long, synced long, float, synced float 560 * - std::set/multiset 561 * - std::list 562 * - std::deque 563 * - std::map/multimap 564 * - std::vector 565 * - std::string 566 * - enum 567 * Size = 8: 568 * - double, synced double 569 */ 570 #define CR_RESERVED(Size) \ 571 class_->AddMember("Reserved", new creg::EmptyType(Size), 0, 0) 572 573 /** @def CR_SETFLAG 574 * Set a flag for a class/struct. 575 * @param Flag the class flag @see ClassFlag 576 */ 577 #define CR_SETFLAG(Flag) \ 578 class_->SetFlag(creg::Flag) 579 580 /** @def CR_MEMBER_SETFLAG 581 * Set a flag for a class/struct member 582 * This should come after the CR_MEMBER or CR_ENUM_MEMBER for the member 583 * @param Member the class member variable 584 * @param Flag the class member flag @see ClassMemberFlag 585 * @see ClassMemberFlag 586 */ 587 #define CR_MEMBER_SETFLAG(Member, Flag) \ 588 class_->SetMemberFlag(#Member, creg::Flag) 589 590 #define CR_MEMBER_BEGINFLAG(Flag) \ 591 class_->BeginFlag(creg::Flag) 592 593 #define CR_MEMBER_ENDFLAG(Flag) \ 594 class_->EndFlag(creg::Flag) 595 596 /** @def CR_SERIALIZER 597 * Registers a custom serialization method for the class/struct 598 * this function will be called when an instance is serialized. 599 * There can only be one serialize method per class/struct. 600 * On serialization, the registered members will be serialized first, 601 * and then this function will be called if specified 602 * 603 * @param SerializeFunc the serialize method, should be a member function of the 604 * class 605 */ 606 #define CR_SERIALIZER(SerializeFunc) \ 607 (class_->serializeProc = (void(creg::_DummyStruct::*)(creg::ISerializer&))&Type::SerializeFunc) 608 609 /** @def CR_POSTLOAD 610 * Registers a custom post-loading method for the class/struct 611 * this function will be called during package loading when all serialization is 612 * finished. 613 * There can only be one postload method per class/struct 614 */ 615 #define CR_POSTLOAD(PostLoadFunc) \ 616 (class_->postLoadProc = (void(creg::_DummyStruct::*)())&Type::PostLoadFunc) 617 } 618 619 #endif // _CREG_H 620