| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Util/File.h>
- #include <AnKi/Util/WeakArray.h>
- #pragma once
- namespace anki {
- /// @addtogroup util_file
- /// @{
- #define _ANKI_SIMPLE_TYPE (std::is_integral<T>::value || std::is_floating_point<T>::value || std::is_enum<T>::value)
- /// Serialize functor. Used to add serialization code to classes that you can't add a serialize() method.
- template<typename T>
- class SerializeFunctor
- {
- public:
- template<typename TSerializer>
- 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<typename T>
- class DeserializeFunctor
- {
- public:
- template<typename TDeserializer>
- void operator()(T& x, TDeserializer& deserializer)
- {
- x.deserialize(deserializer);
- }
- };
- /// Specialization for WeakArray.
- template<typename T, typename TSize>
- class SerializeFunctor<WeakArray<T, TSize>>
- {
- public:
- template<typename TSerializer>
- void operator()(const WeakArray<T, TSize>& 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<typename T, typename TSize>
- class DeserializeFunctor<WeakArray<T, TSize>>
- {
- public:
- template<typename TDeserializer>
- void operator()(WeakArray<T, TSize>& 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<T, TSize>(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 file The file to populate.
- template<typename T>
- Error serialize(const T& x, BaseMemoryPool& tmpPool, File& file)
- {
- const Error err = serializeInternal(x, tmpPool, file);
- if(err)
- {
- ANKI_UTIL_LOGE("There was a serialization error");
- }
- return err;
- }
- /// Write a single value. Can't call this directly.
- template<typename T>
- 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<typename T>
- void doArray([[maybe_unused]] CString varName, PtrSize memberOffset, const T* arr, PtrSize size) requires(!_ANKI_SIMPLE_TYPE)
- {
- if(!m_err)
- {
- m_err = doArrayComplexType(arr, size, memberOffset);
- }
- }
- /// Write an array of int or float types. Can't call this directly.
- template<typename T>
- void doArray([[maybe_unused]] CString varName, [[maybe_unused]] PtrSize memberOffset, [[maybe_unused]] const T* arr,
- [[maybe_unused]] PtrSize size) requires(_ANKI_SIMPLE_TYPE)
- {
- // Do nothing, it's already copied
- }
- /// Write a pointer. Can't call this directly.
- template<typename T>
- 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<typename T>
- void doDynamicArray([[maybe_unused]] CString varName, PtrSize memberOffset, const T* arr, PtrSize size) requires(!_ANKI_SIMPLE_TYPE)
- {
- if(!m_err)
- {
- m_err = doDynamicArrayComplexType(arr, size, memberOffset);
- }
- }
- /// Write a dynamic array of int and float values. Can't call this directly.
- template<typename T>
- void doDynamicArray([[maybe_unused]] CString varName, PtrSize memberOffset, const T* arr, PtrSize size) requires(_ANKI_SIMPLE_TYPE)
- {
- 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.
- };
- using Pool = MemoryPoolPtrWrapper<BaseMemoryPool>;
- 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.
- Pool m_pool;
- DynamicArray<PointerInfo, Pool> m_pointerFilePositions; ///< Array of file positions that contain pointers.
- DynamicArray<PtrSize, Pool> m_structureFilePos;
- Error m_err = Error::kNone;
- template<typename T>
- Error doArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset);
- template<typename T>
- Error doDynamicArrayComplexType(const T* arr, PtrSize size, PtrSize memberOffset);
- Error doDynamicArrayBasicType(const void* arr, PtrSize size, U32 alignment, PtrSize memberOffset);
- template<typename T>
- Error serializeInternal(const T& x, BaseMemoryPool& tmpPool, File& file);
- void check()
- {
- ANKI_ASSERT(m_file && "Can't call this function");
- ANKI_ASSERT(m_file->tell() <= m_eofPos);
- }
- template<typename T>
- static void checkStruct()
- {
- static_assert(!std::is_polymorphic<T>::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 pool The memory pool to use to allocate the new structures.
- /// @param file The file to read from.
- template<typename T, typename TFile>
- static Error deserialize(T*& x, BaseMemoryPool& pool, TFile& file);
- /// Read a single value. Can't call this directly.
- template<typename T>
- void doValue([[maybe_unused]] CString varName, [[maybe_unused]] PtrSize memberOffset, [[maybe_unused]] T& x)
- {
- // Do nothing
- }
- /// Read an array. Can't call this directly.
- template<typename T>
- void doArray([[maybe_unused]] CString varName, [[maybe_unused]] PtrSize memberOffset, [[maybe_unused]] T* arr, [[maybe_unused]] PtrSize size)
- {
- // Do nothing
- }
- /// Read a pointer. Can't call this directly.
- template<typename T>
- void doPointer([[maybe_unused]] CString varName, [[maybe_unused]] PtrSize memberOffset, [[maybe_unused]] T* ptr)
- {
- // Do nothing
- }
- /// Read a dynamic array of complex types. Can't call this directly.
- template<typename T>
- void doDynamicArray([[maybe_unused]] CString varName, [[maybe_unused]] PtrSize memberOffset, [[maybe_unused]] T* arr,
- [[maybe_unused]] PtrSize size)
- {
- // Do nothing
- }
- };
- /// @}
- #undef _ANKI_SIMPLE_TYPE
- } // end namespace anki
- #include <AnKi/Util/Serializer.inl.h>
|