// SPDX-FileCopyrightText: 2021 Jorrit Rouwe // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include namespace JPH { /// ObjectStreamOut contains all logic for writing an object to disk. It is the base /// class for the text and binary output streams (ObjectStreamTextOut and ObjectStreamBinaryOut). class ObjectStreamOut : public ObjectStream { private: struct ObjectInfo; public: /// Main function to write an object to a stream template static bool sWriteObject(ostream &inStream, ObjectStream::EStreamType inType, const T &inObject) { // Create the output stream bool result = false; ObjectStreamOut *stream = ObjectStreamOut::Open(inType, inStream); if (stream) { // Write the object to the stream result = stream->Write((void *)&inObject, GetRTTI(&inObject)); delete stream; } return result; } /// Main function to write an object to a file template static bool sWriteObject(const char *inFileName, ObjectStream::EStreamType inType, const T &inObject) { ofstream stream; stream.open(inFileName, ofstream::out | ofstream::trunc | ofstream::binary); if (!stream.is_open()) return false; return sWriteObject(stream, inType, inObject); } ////////////////////////////////////////////////////// // EVERYTHING BELOW THIS SHOULD NOT DIRECTLY BE CALLED ////////////////////////////////////////////////////// ///@name Serialization operations bool Write(const void *inObject, const RTTI *inRTTI); void WriteObject(const void *inObject); void QueueRTTI(const RTTI *inRTTI); void WriteRTTI(const RTTI *inRTTI); void WriteClassData(const RTTI *inRTTI, const void *inInstance); void WritePointerData(const RTTI *inRTTI, const void *inPointer); ///@name Output type specific operations virtual void WriteDataType(EDataType inType) = 0; virtual void WriteName(const char *inName) = 0; virtual void WriteIdentifier(Identifier inIdentifier) = 0; virtual void WriteCount(uint32 inCount) = 0; virtual void WritePrimitiveData(const uint8 &inPrimitive) = 0; virtual void WritePrimitiveData(const uint16 &inPrimitive) = 0; virtual void WritePrimitiveData(const int &inPrimitive) = 0; virtual void WritePrimitiveData(const uint32 &inPrimitive) = 0; virtual void WritePrimitiveData(const uint64 &inPrimitive) = 0; virtual void WritePrimitiveData(const float &inPrimitive) = 0; virtual void WritePrimitiveData(const bool &inPrimitive) = 0; virtual void WritePrimitiveData(const string &inPrimitive) = 0; virtual void WritePrimitiveData(const Float3 &inPrimitive) = 0; virtual void WritePrimitiveData(const Vec3 &inPrimitive) = 0; virtual void WritePrimitiveData(const Vec4 &inPrimitive) = 0; virtual void WritePrimitiveData(const Quat &inPrimitive) = 0; virtual void WritePrimitiveData(const Mat44 &inPrimitive) = 0; ///@name Layout hints (for text output) virtual void HintNextItem() { } virtual void HintIndentUp() { } virtual void HintIndentDown() { } protected: /// Static constructor static ObjectStreamOut * Open(EStreamType inType, ostream &inStream); /// Constructor explicit ObjectStreamOut(ostream &inStream); ostream & mStream; private: struct ObjectInfo { ObjectInfo() : mIdentifier(0), mRTTI(nullptr) { } ObjectInfo(Identifier inIdentifier, const RTTI *inRTTI) : mIdentifier(inIdentifier), mRTTI(inRTTI) { } Identifier mIdentifier; const RTTI * mRTTI; }; using IdentifierMap = unordered_map; using ClassSet = unordered_set; using ObjectQueue = queue; using ClassQueue = queue; Identifier mNextIdentifier; ///< Next free identifier for this stream IdentifierMap mIdentifierMap; ///< Links object pointer to an identifier ObjectQueue mObjectQueue; ///< Queue of objects to be written ClassSet mClassSet; ///< List of classes already written ClassQueue mClassQueue; ///< List of classes waiting to be written }; // Define macro to declare functions for a specific primitive type #define JPH_DECLARE_PRIMITIVE(name) \ void OSWriteDataType(ObjectStreamOut &ioStream, name *inNull); \ void OSWriteData(ObjectStreamOut &ioStream, const name &inPrimitive); // This file uses the JPH_DECLARE_PRIMITIVE macro to define all types #include // Define serialization templates for dynamic arrays template void OSWriteDataType(ObjectStreamOut &ioStream, vector *inNull) { ioStream.WriteDataType(ObjectStream::EDataType::Array); OSWriteDataType(ioStream, (T *)nullptr); } template void OSWriteData(ObjectStreamOut &ioStream, const vector &inArray) { // Write size of array ioStream.HintNextItem(); ioStream.WriteCount((uint32)inArray.size()); // Write data in array ioStream.HintIndentUp(); for (const T &v : inArray) OSWriteData(ioStream, v); ioStream.HintIndentDown(); } /// Define serialization templates for static arrays template void OSWriteDataType(ObjectStreamOut &ioStream, StaticArray *inNull) { ioStream.WriteDataType(ObjectStream::EDataType::Array); OSWriteDataType(ioStream, (T *)nullptr); } template void OSWriteData(ObjectStreamOut &ioStream, const StaticArray &inArray) { // Write size of array ioStream.HintNextItem(); ioStream.WriteCount(inArray.size()); // Write data in array ioStream.HintIndentUp(); for (const typename StaticArray::value_type &v : inArray) OSWriteData(ioStream, v); ioStream.HintIndentDown(); } /// Define serialization templates for C style arrays template void OSWriteDataType(ObjectStreamOut &ioStream, T (*inNull)[N]) { ioStream.WriteDataType(ObjectStream::EDataType::Array); OSWriteDataType(ioStream, (T *)nullptr); } template void OSWriteData(ObjectStreamOut &ioStream, const T (&inArray)[N]) { // Write size of array ioStream.HintNextItem(); ioStream.WriteCount((uint32)N); // Write data in array ioStream.HintIndentUp(); for (const T &v : inArray) OSWriteData(ioStream, v); ioStream.HintIndentDown(); } /// Define serialization templates for references template void OSWriteDataType(ObjectStreamOut &ioStream, Ref *inNull) { OSWriteDataType(ioStream, (T *)nullptr); } template void OSWriteData(ObjectStreamOut &ioStream, const Ref &inRef) { if (inRef != nullptr) ioStream.WritePointerData(GetRTTI(inRef.GetPtr()), inRef.GetPtr()); else ioStream.WritePointerData(nullptr, nullptr); } template void OSWriteDataType(ObjectStreamOut &ioStream, RefConst *inNull) { OSWriteDataType(ioStream, (T *)nullptr); } template void OSWriteData(ObjectStreamOut &ioStream, const RefConst &inRef) { if (inRef != nullptr) ioStream.WritePointerData(GetRTTI(inRef.GetPtr()), inRef.GetPtr()); else ioStream.WritePointerData(nullptr, nullptr); } } // JPH