ObjectStreamOut.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/ObjectStream/ObjectStreamOut.h>
  5. #include <Jolt/ObjectStream/ObjectStreamTextOut.h>
  6. #include <Jolt/ObjectStream/ObjectStreamBinaryOut.h>
  7. #include <Jolt/ObjectStream/SerializableAttribute.h>
  8. #include <Jolt/ObjectStream/TypeDeclarations.h>
  9. JPH_NAMESPACE_BEGIN
  10. ObjectStreamOut::ObjectStreamOut(ostream &inStream) :
  11. mStream(inStream)
  12. {
  13. // Add all primitives to the class set
  14. #define JPH_DECLARE_PRIMITIVE(name) mClassSet.insert(JPH_RTTI(name));
  15. #include <Jolt/ObjectStream/ObjectStreamTypes.h>
  16. }
  17. ObjectStreamOut *ObjectStreamOut::Open(EStreamType inType, ostream &inStream)
  18. {
  19. switch (inType)
  20. {
  21. case EStreamType::Text: return new ObjectStreamTextOut(inStream);
  22. case EStreamType::Binary: return new ObjectStreamBinaryOut(inStream);
  23. default: JPH_ASSERT(false);
  24. }
  25. return nullptr;
  26. }
  27. bool ObjectStreamOut::Write(const void *inObject, const RTTI *inRTTI)
  28. {
  29. // Assign a new identifier to the object and write it
  30. mIdentifierMap.try_emplace(inObject, mNextIdentifier, inRTTI);
  31. mNextIdentifier++;
  32. WriteObject(inObject);
  33. // Write all linked objects
  34. while (!mObjectQueue.empty() && !mStream.fail())
  35. {
  36. const void *linked_object = mObjectQueue.front();
  37. WriteObject(linked_object);
  38. mObjectQueue.pop();
  39. }
  40. return !mStream.fail();
  41. }
  42. void ObjectStreamOut::WriteObject(const void *inObject)
  43. {
  44. // Find object identifier
  45. IdentifierMap::iterator i = mIdentifierMap.find(inObject);
  46. JPH_ASSERT(i != mIdentifierMap.end());
  47. // Write class description and associated descriptions
  48. QueueRTTI(i->second.mRTTI);
  49. while (!mClassQueue.empty() && !mStream.fail())
  50. {
  51. WriteRTTI(mClassQueue.front());
  52. mClassQueue.pop();
  53. }
  54. HintNextItem();
  55. HintNextItem();
  56. // Write object header.
  57. WriteDataType(EDataType::Object);
  58. WriteName(i->second.mRTTI->GetName());
  59. WriteIdentifier(i->second.mIdentifier);
  60. // Write attribute data
  61. WriteClassData(i->second.mRTTI, inObject);
  62. }
  63. void ObjectStreamOut::QueueRTTI(const RTTI *inRTTI)
  64. {
  65. ClassSet::const_iterator i = mClassSet.find(inRTTI);
  66. if (i == mClassSet.end())
  67. {
  68. mClassSet.insert(inRTTI);
  69. mClassQueue.push(inRTTI);
  70. }
  71. }
  72. void ObjectStreamOut::WriteRTTI(const RTTI *inRTTI)
  73. {
  74. HintNextItem();
  75. HintNextItem();
  76. // Write class header. E.g. in text mode: "class <name> <attr-count>"
  77. WriteDataType(EDataType::Declare);
  78. WriteName(inRTTI->GetName());
  79. WriteCount(inRTTI->GetAttributeCount());
  80. // Write class attribute info
  81. HintIndentUp();
  82. for (int attr_index = 0; attr_index < inRTTI->GetAttributeCount(); ++attr_index)
  83. {
  84. // Get attribute
  85. const SerializableAttribute *attr = DynamicCast<SerializableAttribute, RTTIAttribute>(inRTTI->GetAttribute(attr_index));
  86. if (attr == nullptr)
  87. continue;
  88. // Write definition of attribute class if undefined
  89. const RTTI *rtti = attr->GetMemberPrimitiveType();
  90. if (rtti != nullptr)
  91. QueueRTTI(rtti);
  92. HintNextItem();
  93. // Write attribute information.
  94. WriteName(attr->GetName());
  95. attr->WriteDataType(*this);
  96. }
  97. HintIndentDown();
  98. }
  99. void ObjectStreamOut::WriteClassData(const RTTI *inRTTI, const void *inInstance)
  100. {
  101. JPH_ASSERT(inInstance);
  102. // Write attributes
  103. HintIndentUp();
  104. for (int attr_index = 0; attr_index < inRTTI->GetAttributeCount(); ++attr_index)
  105. {
  106. // Get attribute
  107. const SerializableAttribute *attr = DynamicCast<SerializableAttribute, RTTIAttribute>(inRTTI->GetAttribute(attr_index));
  108. if (attr == nullptr)
  109. continue;
  110. attr->WriteData(*this, inInstance);
  111. }
  112. HintIndentDown();
  113. }
  114. void ObjectStreamOut::WritePointerData(const RTTI *inRTTI, const void *inPointer)
  115. {
  116. Identifier identifier;
  117. if (inPointer)
  118. {
  119. // Check if this object has an identifier
  120. IdentifierMap::iterator i = mIdentifierMap.find(inPointer);
  121. if (i != mIdentifierMap.end())
  122. {
  123. // Object already has an identifier
  124. identifier = i->second.mIdentifier;
  125. }
  126. else
  127. {
  128. // Assign a new identifier to this object and queue it for serialization
  129. identifier = mNextIdentifier++;
  130. mIdentifierMap.try_emplace(inPointer, identifier, inRTTI);
  131. mObjectQueue.push(inPointer);
  132. }
  133. }
  134. else
  135. {
  136. // Write nullptr pointer
  137. identifier = sNullIdentifier;
  138. }
  139. // Write the identifier
  140. HintNextItem();
  141. WriteIdentifier(identifier);
  142. }
  143. // Define macro to declare functions for a specific primitive type
  144. #define JPH_DECLARE_PRIMITIVE(name) \
  145. void OSWriteDataType(ObjectStreamOut &ioStream, name *) \
  146. { \
  147. ioStream.WriteDataType(ObjectStream::EDataType::T_##name); \
  148. } \
  149. void OSWriteData(ObjectStreamOut &ioStream, const name &inPrimitive) \
  150. { \
  151. ioStream.HintNextItem(); \
  152. ioStream.WritePrimitiveData(inPrimitive); \
  153. }
  154. // This file uses the JPH_DECLARE_PRIMITIVE macro to define all types
  155. #include <Jolt/ObjectStream/ObjectStreamTypes.h>
  156. JPH_NAMESPACE_END