| #ifndef _RIVE_IMPORT_STACK_HPP_ | |
| #define _RIVE_IMPORT_STACK_HPP_ | |
| #include "rive/status_code.hpp" | |
| #include <algorithm> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include <algorithm> | |
| #include <memory> | |
| namespace rive | |
| { | |
| class ImportStackObject | |
| { | |
| public: | |
| virtual ~ImportStackObject() {} | |
| virtual StatusCode resolve() { return StatusCode::Ok; } | |
| virtual bool readNullObject() { return false; } | |
| }; | |
| class ImportStack | |
| { | |
| public: | |
| template <typename T = ImportStackObject> T* latest(uint16_t coreType) | |
| { | |
| auto itr = m_latests.find(coreType); | |
| if (itr == m_latests.end()) | |
| { | |
| return nullptr; | |
| } | |
| return static_cast<T*>(itr->second.get()); | |
| } | |
| StatusCode makeLatest( | |
| uint16_t coreType, | |
| std::unique_ptr<ImportStackObject> object) | |
| { | |
| // Clean up the old object in the stack. | |
| auto itr = m_latests.find(coreType); | |
| if (itr != m_latests.end()) | |
| { | |
| auto stackObject = itr->second.get(); | |
| // Remove it from latests. | |
| auto lastAddedItr = std::find( | |
| m_lastAdded.begin(), | |
| m_lastAdded.end(), | |
| stackObject); | |
| if (lastAddedItr != m_lastAdded.end()) | |
| { | |
| m_lastAdded.erase(lastAddedItr); | |
| } | |
| StatusCode code = stackObject->resolve(); | |
| if (code != StatusCode::Ok) | |
| { | |
| m_latests.erase(coreType); | |
| return code; | |
| } | |
| } | |
| // Set the new one. | |
| if (object == nullptr) | |
| { | |
| m_latests.erase(coreType); | |
| } | |
| else | |
| { | |
| m_lastAdded.push_back(object.get()); | |
| m_latests[coreType] = std::move(object); | |
| } | |
| return StatusCode::Ok; | |
| } | |
| StatusCode resolve() | |
| { | |
| StatusCode returnCode = StatusCode::Ok; | |
| // Reverse iterate the last added import stack objects and resolve them. | |
| // If any don't resolve, capture the return code and stop resolving. | |
| for (auto itr = m_lastAdded.rbegin(); itr != m_lastAdded.rend(); itr++) | |
| { | |
| StatusCode code = (*itr)->resolve(); | |
| if (code != StatusCode::Ok) | |
| { | |
| returnCode = code; | |
| break; | |
| } | |
| } | |
| m_latests.clear(); | |
| m_lastAdded.clear(); | |
| return returnCode; | |
| } | |
| bool readNullObject() | |
| { | |
| for (auto itr = m_lastAdded.rbegin(); itr != m_lastAdded.rend(); itr++) | |
| { | |
| if ((*itr)->readNullObject()) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // The major/minor version of the file being imported. Objects can read | |
| // this during import() to gate behavior on the file format version. | |
| int majorVersion() const { return m_majorVersion; } | |
| int minorVersion() const { return m_minorVersion; } | |
| void version(int major, int minor) | |
| { | |
| m_majorVersion = major; | |
| m_minorVersion = minor; | |
| } | |
| private: | |
| std::unordered_map<uint16_t, std::unique_ptr<ImportStackObject>> m_latests; | |
| std::vector<ImportStackObject*> m_lastAdded; | |
| int m_majorVersion = 0; | |
| int m_minorVersion = 0; | |
| }; | |
| } // namespace rive | |
| #endif |