// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include #pragma once namespace anki { /// @addtogroup util_file /// @{ #define _ANKI_SIMPLE_TYPE (std::is_integral::value || std::is_floating_point::value || std::is_enum::value) /// Serialize functor. Used to add serialization code to classes that you can't add a serialize() method. template class SerializeFunctor { public: template void operator()(const T& x, TSerializer& serializer) { x.serialize(serializer); } }; /// Deserialize functor. Used to add deserialization code to classes that you can't add a serialize() method. template class DeserializeFunctor { public: template void operator()(T& x, TDeserializer& deserializer) { x.deserialize(deserializer); } }; /// Specialization for WeakArray. template class SerializeFunctor> { public: template void operator()(const WeakArray& x, TSerializer& serializer) { const TSize size = x.getSize(); serializer.doDynamicArray("m_array", 0, (x.getSize()) ? &x[0] : nullptr, size); serializer.doValue("m_size", sizeof(void*), size); } }; /// Specialization for WeakArray. template class DeserializeFunctor> { public: template void operator()(WeakArray& x, TDeserializer& deserializer) { TSize size; deserializer.doValue("m_size", sizeof(void*), size); T* arr = nullptr; if(size > 0) { deserializer.doDynamicArray("m_array", 0, arr, size); } x = WeakArray(arr, size); } }; /// Serializes to binary files. class BinarySerializer { public: BinarySerializer() = default; BinarySerializer(const BinarySerializer&) = delete; // Non-copyable BinarySerializer& operator=(const BinarySerializer&) = delete; // Non-copyable /// Serialize a class. /// @param x What to serialize. /// @param tmpAllocator A temp allocator for some memory needed. /// @param file The file to populate. template ANKI_USE_RESULT Error serialize(const T& x, GenericMemoryPoolAllocator tmpAllocator, File& file) { const Error err = serializeInternal(x, tmpAllocator, file); if(err) { ANKI_UTIL_LOGE("There was a serialization error"); } return err; } /// Write a single value. Can't call this directly. template void doValue(CString varName, PtrSize memberOffset, const T& x) { doArray(varName, memberOffset, &x, 1); } /// Write an array of complex values. Can't call this directly. template void doArray(CString varName, PtrSize memberOffset, const T* arr, PtrSize size) { if(!m_err) { m_err = doArrayComplexType(arr, size, memberOffset); } } /// Write an array of int or float types. Can't call this directly. template void doArray(CString varName, PtrSize memberOffset, const T* arr, PtrSize size) { // Do nothing, it's already copied } /// Write a pointer. Can't call this directly. template void doPointer(CString varName, PtrSize memberOffset, const T* ptr) { doDynamicArray(varName, memberOffset, ptr, (ptr) ? 1 : 0); } /// Write a dynamic array of complex types. Can't call this directly. template void doDynamicArray(CString varName, PtrSize memberOffset, const T* arr, PtrSize size) { if(!m_err) { m_err = doDynamicArrayComplexType(arr, size, memberOffset); } } /// Write a dynamic array of int and float values. Can't call this directly. template void doDynamicArray(CString varName, PtrSize memberOffset, const T* arr, PtrSize size) { if(!m_err) { m_err = doDynamicArrayBasicType(arr, size * sizeof(T), alignof(T), memberOffset); } } private: class PointerInfo { public: PtrSize m_filePos; ///< Pointer location inside the file. PtrSize m_value; ///< Where it points to. It's an offset after the header. }; File* m_file = nullptr; PtrSize m_eofPos; ///< A logical end of the file. Used for allocations. PtrSize m_beginOfDataFilePos; ///< Where the data are located in the file. GenericMemoryPoolAllocator m_alloc; DynamicArray m_pointerFilePositions; ///< Array of file positions that contain pointers. DynamicArray m_structureFilePos; Error m_err = Error::NONE; template ANKI_USE_RESULT Error doArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset); template ANKI_USE_RESULT Error doDynamicArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset); ANKI_USE_RESULT Error doDynamicArrayBasicType(const void* arr, PtrSize size, U32 alignment, PtrSize memberOffset); template ANKI_USE_RESULT Error serializeInternal(const T& x, GenericMemoryPoolAllocator tmpAllocator, File& file); void check() { ANKI_ASSERT(m_file && "Can't call this function"); ANKI_ASSERT(m_file->tell() <= m_eofPos); } template static void checkStruct() { static_assert(!std::is_polymorphic::value, "Only PODs are supported in this serializer"); static_assert(alignof(T) <= ANKI_SAFE_ALIGNMENT, "Alignments can't exceed ANKI_SAFE_ALIGNMENT"); } }; /// Deserializes binary files. class BinaryDeserializer { public: BinaryDeserializer() = default; BinaryDeserializer(const BinaryDeserializer&) = delete; // Non-copyable BinaryDeserializer& operator=(const BinaryDeserializer&) = delete; // Non-copyable /// Serialize a class. /// @param x The struct to read. /// @param allocator The allocator to use to allocate the new structures. /// @param file The file to read from. template static ANKI_USE_RESULT Error deserialize(T*& x, GenericMemoryPoolAllocator allocator, File& file); /// Read a single value. Can't call this directly. template void doValue(CString varName, PtrSize memberOffset, T& x) { // Do nothing } /// Read an array. Can't call this directly. template void doArray(CString varName, PtrSize memberOffset, T* arr, PtrSize size) { // Do nothing } /// Read a pointer. Can't call this directly. template void doPointer(CString varName, PtrSize memberOffset, T* ptr) { // Do nothing } /// Read a dynamic array of complex types. Can't call this directly. template void doDynamicArray(CString varName, PtrSize memberOffset, T* arr, PtrSize size) { // Do nothing } }; /// @} #undef _ANKI_SIMPLE_TYPE } // end namespace anki #include