ObjectStreamOut.cpp 4.0 KB

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