#pragma once #include "BsScriptEnginePrerequisites.h" #include "BsIReflectable.h" #include namespace BansheeEngine { /** * @brief Contains key and value data used for serializing a managed dictionary. */ struct BS_SCR_BE_EXPORT ManagedSerializableDictionaryKeyValue : public IReflectable { ManagedSerializableDictionaryKeyValue() {} ManagedSerializableDictionaryKeyValue(const ManagedSerializableFieldDataPtr& key, const ManagedSerializableFieldDataPtr& value); ManagedSerializableFieldDataPtr key; ManagedSerializableFieldDataPtr value; /************************************************************************/ /* RTTI */ /************************************************************************/ public: friend class ManagedSerializableDictionaryKeyValueRTTI; static RTTITypeBase* getRTTIStatic(); virtual RTTITypeBase* getRTTI() const override; }; /** * @brief Allows access to an underlying managed dictionary, or a cached version of that dictionary that * can be serialized/deserialized. * * @note This class can be in two states: * - Linked - When the object has a link to a managed object. This is the default * state when a new instance of ManagedSerializableObject is created. * Any operations during this state will operate directly on the linked * managed object. * - Serialized - When the object has no link to the managed object but instead just * contains cached object and field data that may be used for initializing * a managed object. Any operations during this state will operate * only on the cached internal data. * You can transfer between these states by calling serialize(linked->serialized) & * deserialize (serialized->linked). * */ class BS_SCR_BE_EXPORT ManagedSerializableDictionary : public IReflectable { private: struct ConstructPrivately {}; /** * @brief Generates a hash value for field data. */ struct BS_SCR_BE_EXPORT Hash { inline size_t operator()(const ManagedSerializableFieldDataPtr& x) const; }; /** * @brief Compares two field data objects. */ struct BS_SCR_BE_EXPORT Equals { inline bool operator()(const ManagedSerializableFieldDataPtr& a, const ManagedSerializableFieldDataPtr& b) const; }; public: typedef UnorderedMap CachedEntriesMap; /** * @brief Helper class that enumerates over all entires in a managed dictionary. Operates on * managed object if the parent dictionary is in linked state, or on cached data otherwise. */ class Enumerator { public: /** * @brief Constructs a new enumerator for the provided managed object. * * @param instance Managed instance of type System.Collections.Generic.Dictionary. * @param parent Serializable parent of the managed instance. */ Enumerator(MonoObject* instance, const ManagedSerializableDictionary* parent); /** * @brief Returns the wrapped key data at the current enumerator position. * Only valid to call this if enumerator is valid (i.e. last call to * ::moveNext returned true). */ ManagedSerializableFieldDataPtr getKey() const; /** * @brief Returns the wrapped value data at the current enumerator position. * Only valid to call this if enumerator is valid (i.e. last call to * ::moveNext returned true). */ ManagedSerializableFieldDataPtr getValue() const; /** * @brief Moves the enumerator to the next position. Initially enumerator is * at an invalid position and must be called at least once before accesing * its data. * * @return Returns if the enumerator is at valid position. When the enumerator returns * false it means there are no more elements to enumerate. */ bool moveNext(); private: MonoObject* mInstance; MonoObject* mCurrent; CachedEntriesMap::const_iterator mCachedIter; bool mIteratorInitialized; const ManagedSerializableDictionary* mParent; }; public: ManagedSerializableDictionary(const ConstructPrivately& dummy, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo, MonoObject* managedInstance); ManagedSerializableDictionary(const ConstructPrivately& dummy); /** * @brief Returns the internal managed instance of the dictionary. This will return null if * the object is in serialized mode. */ MonoObject* getManagedInstance() const { return mManagedInstance; } /** * @brief Returns the type information for the internal dictionary. */ ManagedSerializableTypeInfoDictionaryPtr getTypeInfo() const { return mDictionaryTypeInfo; } /** * @brief Returns the dictionary value at the specified key. If the key doesn't exist * the default value for the type is returned. Operates on managed object if in * linked state, or on cached data otherwise. * * @param key Wrapper around the key data at which to retrieve the value. * * @return A wrapper around the value in the dictionary at the specified key. */ ManagedSerializableFieldDataPtr getFieldData(const ManagedSerializableFieldDataPtr& key); /** * @brief Sets the dictionary value at the specified key. Operates on managed object if in * linked state, or on cached data otherwise. * * @param key Wrapper around the key data at which to set the value. * @param val Wrapper around the value to set at the specified key. */ void setFieldData(const ManagedSerializableFieldDataPtr& key, const ManagedSerializableFieldDataPtr& val); /** * @brief Deletes the key/value pair at the specified key. If the key doesn't exist * this operation does nothing. Operates on managed object if in linked state, * or on cached data otherwise. * * @param key Wrapper around the key data at which to delete the value. */ void removeFieldData(const ManagedSerializableFieldDataPtr& key); /** * @brief Checks if the dictionary contains the specified key. Operates on managed object * if in linked state, or on cached data otherwise. * * @param key Wrapper around the key data which to check. */ bool contains(const ManagedSerializableFieldDataPtr& key) const; /** * @brief Returns an enumerator object that allows you to iterate over * all key/value pairs in the dictionary. */ Enumerator getEnumerator() const; /** * @brief Serializes the internal managed object into a set of cached data that can be saved * in memory/disk and can be deserialized later. Does nothing if object is already is * serialized mode. When in serialized mode the reference to the managed instance will be lost. */ void serialize(); /** * @brief Deserializes a set of cached data into a managed object. This action may fail in case the cached * data contains a type that no longer exists. You may check if it completely successfully if ::getManagedInstance * returns non-null after. * * This action transfers the object into linked mode. All further operations will operate directly on the managed instance * and the cached data will be cleared. If you call this method on an already linked object the old object will be * replaced and initialized with empty data (since cached data does not exist). */ void deserialize(); /** * @brief Creates a managed serializable dictionary that references an existing managed dictionary. Created object will be in linked mode. * * @param managedInstance Constructed managed instance of the dictionary to link with. Its type must correspond with the provided type info. * @param typeInfo Type information for the dictionary and its key/value pair. */ static ManagedSerializableDictionaryPtr createFromExisting(MonoObject* managedInstance, const ManagedSerializableTypeInfoDictionaryPtr& typeInfo); /** * @brief Creates a managed serializable dictionary that creates and references a brand new managed dictionary instance. * * @param typeInfo Type of the dictionary to create. */ static ManagedSerializableDictionaryPtr createNew(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo); /** * @brief Creates a managed dictionary instance. * * @param typeInfo Type of the dictionary to create. */ static MonoObject* createManagedInstance(const ManagedSerializableTypeInfoDictionaryPtr& typeInfo); protected: /** * @brief Retrieves needed Mono types and methods. Should be called * before performing any operations with the managed object. */ void initMonoObjects(MonoClass* dictionaryClass); MonoObject* mManagedInstance; MonoMethod* mAddMethod; MonoMethod* mRemoveMethod; MonoMethod* mTryGetValueMethod; MonoMethod* mContainsKeyMethod; MonoMethod* mGetEnumerator; MonoMethod* mEnumMoveNext; MonoProperty* mEnumCurrentProp; MonoProperty* mKeyProp; MonoProperty* mValueProp; ManagedSerializableTypeInfoDictionaryPtr mDictionaryTypeInfo; CachedEntriesMap mCachedEntries; /************************************************************************/ /* RTTI */ /************************************************************************/ /** * @brief Creates an empty and uninitialized object used for serialization purposes. */ static ManagedSerializableDictionaryPtr createEmpty(); public: friend class ManagedSerializableDictionaryRTTI; static RTTITypeBase* getRTTIStatic(); virtual RTTITypeBase* getRTTI() const override; }; }