ObjectStreamOut.cpp 4.8 KB

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