diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index c84a1a2..730b18d 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -39,7 +39,7 @@ add_executable (xna WIN32 "content/manager.cpp" "content/reader.cpp" "csharp/binary.cpp" -"content/decstream.cpp" "content/lzx/decoder.cpp" "content/lzx/decoderstream.cpp" "content/typereadermanager.cpp" "csharp/object.cpp") +"content/decstream.cpp" "content/lzx/decoder.cpp" "content/lzx/decoderstream.cpp" "content/typereadermanager.cpp" "csharp/object.cpp" "csharp/type.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET xna PROPERTY CXX_STANDARD 20) diff --git a/framework/content/reader.cpp b/framework/content/reader.cpp index 160c74a..7f6a211 100644 --- a/framework/content/reader.cpp +++ b/framework/content/reader.cpp @@ -1,6 +1,7 @@ #include "reader.hpp" #include "manager.hpp" #include "lzx/decoderstream.hpp" +#include "typereadermanager.hpp" namespace xna { sptr ContentReader::Create(ContentManager* contentManager, Stream* input, String const& assetName) @@ -53,6 +54,6 @@ namespace xna { } Int ContentReader::ReadHeader() { - return Int(); + //typeReaders = ContentTypeReaderManager::ReadTypeManifest(this->Read7BitEncodedInt(), this); } } diff --git a/framework/content/typereadermanager.cpp b/framework/content/typereadermanager.cpp index f5148a5..636b7c5 100644 --- a/framework/content/typereadermanager.cpp +++ b/framework/content/typereadermanager.cpp @@ -34,10 +34,12 @@ namespace xna { return contentTypeReaderArray; } - sptr ContentTypeReaderManager::GetTypeReader(String const& targetType, sptr& contentReader, xna_error_ptr_arg) + sptr ContentTypeReaderManager::GetTypeReader(sptr const& targetType, sptr& contentReader, xna_error_ptr_arg) { - if (targetType.empty()) + if (!targetType) { + xna_error_apply(err, XnaErrorCode::ARGUMENT_IS_NULL); return nullptr; + } sptr typeReader = nullptr; @@ -57,10 +59,13 @@ namespace xna { { sptr reader = nullptr; - if (ContentTypeReaderManager::nameToReader.contains(readerTypeName) || !ContentTypeReaderManager::InstantiateTypeReader(readerTypeName, contentReader, reader)) { + if (ContentTypeReaderManager::nameToReader.contains(readerTypeName) || !ContentTypeReaderManager::InstantiateTypeReader(readerTypeName, contentReader, reader, err)) { return ContentTypeReaderManager::nameToReader[readerTypeName]; } + if (xna_error_haserros(err)) + return nullptr; + ContentTypeReaderManager::AddTypeReader(readerTypeName, contentReader, reader, err); if (xna_error_haserros(err)) return nullptr; @@ -70,15 +75,30 @@ namespace xna { return reader; } - bool ContentTypeReaderManager::InstantiateTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader) + bool ContentTypeReaderManager::InstantiateTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader, xna_error_ptr_arg) { - if (ContentTypeReaderManager::readerTypeToReader.contains(readerTypeName)) { - reader = ContentTypeReaderManager::readerTypeToReader[readerTypeName]; + sptr type = nullptr; + + std::map, sptr>::iterator it; + + for (it = readerTypeToReader.begin(); it != readerTypeToReader.end(); it++) { + if (it->first->FullName == readerTypeName) + type = it->first; + } + + if (!type) { + xna_error_apply(err, XnaErrorCode::INVALID_OPERATION); + return false; + } + + if (ContentTypeReaderManager::readerTypeToReader.contains(type)) { + reader = ContentTypeReaderManager::readerTypeToReader[type]; ContentTypeReaderManager::nameToReader.insert({ readerTypeName, reader }); return false; } - reader = ContentTypeReaderActivador::CreateInstance(readerTypeName); + reader = ContentTypeReaderActivador::CreateInstance(type, err); + return true; } void ContentTypeReaderManager::AddTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader, xna_error_ptr_arg) @@ -106,18 +126,7 @@ namespace xna { ContentTypeReaderManager::RollbackAddReader(ContentTypeReaderManager::targetTypeToReader, newTypeReader); ContentTypeReaderManager::RollbackAddReader(ContentTypeReaderManager::readerTypeToReader, newTypeReader); } - } - - void ContentTypeReaderManager::RollbackAddReader(std::map>& dictionary, sptr& reader) { - std::map>::iterator it; - - for (it = dictionary.begin(); it != dictionary.end(); it++) { - if (it->second == reader) { - dictionary.erase(it->first); - it = dictionary.begin(); - } - } - } + } void ContentTypeReaderManager::initMaps() { @@ -125,8 +134,10 @@ namespace xna { auto typeReader = New(); auto contentTypeReader = reinterpret_pointer_cast(typeReader); - targetTypeToReader.insert({ typeReader->TargetType(), contentTypeReader}); - readerTypeToReader.insert({ typeReader->GetType(), contentTypeReader}); + //targetTypeToReader.insert({ typeReader->TargetType(), contentTypeReader}); + //readerTypeToReader.insert({ typeReader->GetType(), contentTypeReader}); + targetTypeToReader.insert({ typeof(), contentTypeReader}); + readerTypeToReader.insert({ typeof(), contentTypeReader}); } } diff --git a/framework/content/typereadermanager.hpp b/framework/content/typereadermanager.hpp index 3e92bdc..784df69 100644 --- a/framework/content/typereadermanager.hpp +++ b/framework/content/typereadermanager.hpp @@ -1,56 +1,100 @@ #ifndef XNA_CONTENT_TYPEREADER_HPP #define XNA_CONTENT_TYPEREADER_HPP +#include "../csharp/type.hpp" #include "../default.hpp" -#include #include +#include namespace xna { - //ContentTypeReader - class ContentTypeReader { + //-------------------------------------------------------// + // ContentTypeReader // + //-------------------------------------------------------// + class ContentTypeReader : public Object { + public: + ContentTypeReader(){} + public: virtual Int TypeVersion() { return 0; } - virtual bool CanDeserializeIntoExistingObject() { return 0; } + virtual bool CanDeserializeIntoExistingObject() { return false; } virtual void Initialize(sptr& manager) {} - constexpr String TargetType() { return _targetType; } + sptr TargetType() { return _targetType; } - virtual String GetType() { return "ContentTypeReader"; } + virtual sptr GetType() const override { + auto type = New(); + type->FullName = "xna::ContentTypeReader"; + type->Namespace = "xna"; + type->IsClass = true; + return type; + } protected: - ContentTypeReader(String targetType) : _targetType(targetType) { + ContentTypeReader(sptr const& targetType) : _targetType(targetType) + { } virtual sptr Read(ContentReader input, sptr existingInstance) = 0; + public: + bool TargetIsValueType{ false }; + private: - String _targetType = "contentTypeReader"; + sptr _targetType = nullptr; }; - //ContentTypeReaderActivador + //-------------------------------------------------------// + // TypeComparator // + //-------------------------------------------------------// + struct TypeComparator + { + bool operator()(sptr t1, sptr t2) const + { + return t1->GetHashCode() < t2->GetHashCode(); + } + }; + + //-------------------------------------------------------// + // ContentTypeReaderActivador // + //-------------------------------------------------------// class ContentTypeReaderActivador { public: using Activador = sptr(*)(); - static sptr CreateInstance(String const& readerTypeName) { - if (!activators.contains(readerTypeName)) + static sptr CreateInstance(sptr const& type, xna_error_nullarg) { + if (!type) + { + xna_error_apply(err, XnaErrorCode::ARGUMENT_IS_NULL); + return nullptr; + } + + const auto hash = type->GetHashCode(); + + if (!activators.contains(hash)) return nullptr; - auto activador = activators[readerTypeName]; + auto activador = activators[hash]; if (!activador) return nullptr; return activador(); } - static void SetActivador(String const& readerTypeName, Activador activador) { - if (!activators.contains(readerTypeName)) - activators.insert({ readerTypeName, activador }); + static void SetActivador(sptr const& type, Activador activador, xna_error_nullarg) { + if (!type) { + xna_error_apply(err, XnaErrorCode::ARGUMENT_IS_NULL); + return; + } + + const auto hash = type->GetHashCode(); + + if (!activators.contains(hash)) + activators.insert({ hash, activador }); } private: - inline static std::map activators = - std::map(); + //inline static auto activators = std::map(); + inline static auto activators = std::map(); ContentTypeReaderActivador(); ContentTypeReaderActivador(ContentTypeReaderActivador&&); @@ -58,55 +102,87 @@ namespace xna { }; using PContentTypeReader = sptr; + using PType = sptr; - //ContentTypeReaderManager + //-------------------------------------------------------// + // ContentTypeReaderManager // + //-------------------------------------------------------// class ContentTypeReaderManager { public: static std::vector ReadTypeManifest(Int typeCount, sptr& contentReader, xna_error_nullarg); - static sptr GetTypeReader(String const& targetType, sptr& contentReader, xna_error_nullarg); + static sptr GetTypeReader(sptr const& targetType, sptr& contentReader, xna_error_nullarg); - inline sptr GetTypeReader(String const& targetType, xna_error_nullarg) { + inline sptr GetTypeReader(sptr const& targetType, xna_error_nullarg) { return ContentTypeReaderManager::GetTypeReader(targetType, this->contentReader, err); } - inline static bool ContainsTypeReader(String const& targetType) { + inline static bool ContainsTypeReader(sptr const& targetType) { return ContentTypeReaderManager::targetTypeToReader.contains(targetType); } private: ContentTypeReaderManager(sptr& contentReader); static sptr GetTypeReader(String const& readerTypeName, sptr& contentReader, std::vector& newTypeReaders, xna_error_nullarg); - static bool InstantiateTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader); + static bool InstantiateTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader, xna_error_nullarg); static void AddTypeReader(String const& readerTypeName, sptr& contentReader, sptr& reader, xna_error_nullarg); - static void RollbackAddReaders(std::vector>& newTypeReaders); - static void RollbackAddReader(std::map>& dictionary, sptr& reader); + static void RollbackAddReaders(std::vector>& newTypeReaders); + + static void RollbackAddReader(std::map& dictionary, sptr& reader) { + std::map>::iterator it; + + for (it = dictionary.begin(); it != dictionary.end(); it++) { + if (it->second == reader) { + dictionary.erase(it->first); + it = dictionary.begin(); + } + } + } + + static void RollbackAddReader(std::map& dictionary, sptr& reader) { + std::map>::iterator it; + + for (it = dictionary.begin(); it != dictionary.end(); it++) { + if (it->second == reader) { + dictionary.erase(it->first); + it = dictionary.begin(); + } + } + } private: sptr contentReader = nullptr; - inline static std::map nameToReader = std::map(); - inline static std::map targetTypeToReader = std::map(); - inline static std::map readerTypeToReader = std::map(); + inline static auto nameToReader = std::map(); + //inline static auto targetTypeToReader = std::map(); + //inline static auto readerTypeToReader = std::map(); + inline static auto targetTypeToReader = std::map(); + inline static auto readerTypeToReader = std::map(); static void initMaps(); }; - //ObjectReader + //-------------------------------------------------------// + // ObjectReader // + //-------------------------------------------------------// class ObjectReader : public ContentTypeReader { public: - ObjectReader() : ContentTypeReader("object"){ - ContentTypeReaderActivador::SetActivador("object", []() -> sptr { + ObjectReader() : ContentTypeReader(typeof(this)){ + ContentTypeReaderActivador::SetActivador(typeof(this), []() -> sptr { auto obj = New (); return reinterpret_pointer_cast(obj); }); } // Inherited via ContentTypeReader - sptr Read(ContentReader input, sptr existingInstance) override; + sptr Read(ContentReader input, sptr existingInstance) override; - String GetType() override { - return "ObjectReader"; + sptr GetType() const override{ + auto type = New(); + type->FullName = "xna::ObjectReader"; + type->Namespace = "xna"; + type->IsClass = true; + return type; } }; } diff --git a/framework/csharp/binary.hpp b/framework/csharp/binary.hpp index b06249c..9721817 100644 --- a/framework/csharp/binary.hpp +++ b/framework/csharp/binary.hpp @@ -43,6 +43,7 @@ namespace xna { bool m2BytesPerChar{ false }; + protected: Int InternalReadOneChar(xna_error_nullarg); void FillBuffer(Int numBytes, xna_error_nullarg); diff --git a/framework/csharp/object.cpp b/framework/csharp/object.cpp index 067c9ce..374dd51 100644 --- a/framework/csharp/object.cpp +++ b/framework/csharp/object.cpp @@ -2,12 +2,20 @@ #include "type.hpp" namespace xna { - sptr Object::GetType() + sptr Object::GetType() const { auto type = New(); - type->FullName = "Object"; + type->FullName = "xna::Object"; type->Namespace = "xna"; type->IsClass = true; return type; } + + size_t Object::GetHashCode() const + { + size_t seed = 0; + XnaHHashCombine(seed, this); + + return seed; + } } \ No newline at end of file diff --git a/framework/csharp/object.hpp b/framework/csharp/object.hpp index a83503c..9d30039 100644 --- a/framework/csharp/object.hpp +++ b/framework/csharp/object.hpp @@ -6,7 +6,8 @@ namespace xna { class Object { public: - virtual sptr GetType(); + virtual sptr GetType() const; + virtual size_t GetHashCode() const; }; } diff --git a/framework/csharp/type.cpp b/framework/csharp/type.cpp new file mode 100644 index 0000000..1f01559 --- /dev/null +++ b/framework/csharp/type.cpp @@ -0,0 +1,28 @@ +#include "type.hpp" + +namespace xna { + sptr Type::GetType() const + { + auto type = New(); + type->FullName = "xna::Type"; + type->Namespace = "xna"; + type->IsClass = true; + return type; + } + + size_t Type::GetHashCode() const + { + size_t seed = 0; + XnaHHashCombine(seed, Namespace); + XnaHHashCombine(seed, FullName); + XnaHHashCombine(seed, IsInterface); + XnaHHashCombine(seed, IsArray); + XnaHHashCombine(seed, IsPointer); + XnaHHashCombine(seed, IsClass); + XnaHHashCombine(seed, IsCOMObject); + XnaHHashCombine(seed, IsEnum); + XnaHHashCombine(seed, IsValueType); + + return seed; + } +} \ No newline at end of file diff --git a/framework/csharp/type.hpp b/framework/csharp/type.hpp index 3fba755..c75043e 100644 --- a/framework/csharp/type.hpp +++ b/framework/csharp/type.hpp @@ -5,7 +5,7 @@ #include "object.hpp" namespace xna { - class Type { + class Type : public Object { public: String Namespace; String FullName; @@ -16,13 +16,43 @@ namespace xna { bool IsCOMObject{ false }; bool IsEnum{ false }; bool IsValueType{ false }; - }; + + constexpr bool operator==(const Type& other) const + { + return Namespace == other.Namespace + && FullName == other.FullName + && IsInterface == other.IsInterface + && IsArray == other.IsArray + && IsPointer == other.IsPointer + && IsClass == other.IsClass + && IsCOMObject == other.IsCOMObject + && IsEnum == other.IsEnum + && IsValueType == other.IsValueType; + } + + virtual sptr GetType() const override; + virtual size_t GetHashCode() const; + + bool operator()(Type const& t1, Type const& t2) const { + return t1.GetHashCode() < t2.GetHashCode(); + } + }; template - inline sptr typeof(T const& obj) { - auto obj = reinterpret_cast(&obj); + inline sptr typeof() { + auto t = New(); + auto obj = reinterpret_pointer_cast(t); - if (!obj) + if (!obj) return nullptr; + + return obj->GetType(); + } + + template + inline sptr typeof(T const* object) { + auto obj = reinterpret_cast(object); + + if (!obj) return nullptr; return obj->GetType(); diff --git a/framework/helpers.hpp b/framework/helpers.hpp index aba54eb..afc396c 100644 --- a/framework/helpers.hpp +++ b/framework/helpers.hpp @@ -2,6 +2,7 @@ #define XNA_HELPERS_HPP #include +#include namespace xna { inline std::wstring XnaHToWString(const std::string& str) @@ -21,6 +22,12 @@ namespace xna { wcstombs_s(&size, &str[0], str.size() + 1, wstr.c_str(), wstr.size()); return str; } + + template + static constexpr void XnaHHashCombine(std::size_t& seed, const T& v) { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } } #endif \ No newline at end of file diff --git a/framework/xnaerror.hpp b/framework/xnaerror.hpp index 44b69d2..a89e32c 100644 --- a/framework/xnaerror.hpp +++ b/framework/xnaerror.hpp @@ -23,7 +23,7 @@ namespace xna { } inline bool xna_error_haserros(XnaErrorCode* source) { - return source != nullptr; + return source != nullptr && *source != XnaErrorCode::NONE; } #define xna_error_nullarg XnaErrorCode* err = nullptr