diff --git a/include/filedat.hpp b/include/filedat.hpp index 16d4757..f6f13ec 100644 --- a/include/filedat.hpp +++ b/include/filedat.hpp @@ -188,14 +188,25 @@ namespace ztd inline void add(std::vector const& vec) { addToList(vec); } //! @brief Concatenate chunks of data /*! Effective only if the two chunks are of the same type\n - Map: combines two maps into a single map\n - List: combines into a single list\n + Map: Combines into a single map. Error on colliding keys\n + List: Append input list to current chunk\n String: Concatenate strings */ void concatenate(chunkdat const& chk); + //! @brief Merge chk into current chunk + /*! Merge is performed recursively\n + Map: combines into a single map. Colliding keys get merged\n + List: Append input list to current chunk\n + String: Error\n + @param overwrite In case of collisions or type mismatch, input overwrites current chunk + */ + void merge(chunkdat const& chk, bool overwrite=false); + + //! @brief Erase key from map void erase(const std::string& key); + //! @brief Erase index from list void erase(const unsigned int index); @@ -285,6 +296,10 @@ namespace ztd //! @brief substract inline chunkdat operator-(const chunkdat& a, const unsigned int b) { chunkdat ret(a); ret -= b; return ret; } + //! @brief Merge chunks + inline chunkdat merge(chunkdat a, chunkdat const& b, bool overwrite) { a.merge(b, overwrite); return a; } + + //! @brief File data object /*! Object for importing, reading, altering and writing of file data\n @@ -413,6 +428,7 @@ namespace ztd inline std::ostream& operator<<(std::ostream& stream, chunkdat const& a) { return stream << a.strval(); } inline std::ostream& operator<<(std::ostream& stream, filedat const& a) { return stream << a.strval(); } + void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin); //! @brief Print exception to console /*! diff --git a/src/filedat.cpp b/src/filedat.cpp index 794c882..d41e86a 100644 --- a/src/filedat.cpp +++ b/src/filedat.cpp @@ -252,7 +252,6 @@ std::pair _skip(const std::string& str) } -// TODO TODO TODO // value, rest, start of rest, start of value, delim found static std::tuple _getstrval(const std::string& str, const char delim=0, const char altdelim=0) { @@ -748,6 +747,57 @@ void ztd::chunkdat::concatenate(chunkdat const& chk) } } +// overwrite: chk replaces this when conflict +void ztd::chunkdat::merge(chunkdat const& chk, bool overwrite) +{ + if(this->type() == ztd::chunk_abstract::none) //nothing: copy + { + this->set(chk); + } + else if(this->type()==ztd::chunk_abstract::map && chk.type()==ztd::chunk_abstract::map) //map + { + ztd::chunk_map* ci = dynamic_cast(chk.getp()); + ztd::chunk_map* cc = dynamic_cast(m_achunk); + for(auto it: ci->values) // iterate keys + { + auto fi = cc->values.find(it.first); + if(fi == cc->values.end()) // new key + { + this->addToMap(it.first, *it.second); + } + else // key already present + { + fi->second->merge(*it.second, overwrite); // merge subchunks + } + } + //map merge + } + else if(this->type()==ztd::chunk_abstract::list && chk.type()==ztd::chunk_abstract::list) //list + { + ztd::chunk_list* ci = dynamic_cast(chk.getp()); + for(auto it : ci->list) + { + this->add(*it); + } + } + else if(this->type()==ztd::chunk_abstract::string && chk.type()==ztd::chunk_abstract::string) //string + { + ztd::chunk_string* cc = dynamic_cast(m_achunk); + if(overwrite) + cc->val = chk.str(); + else + throw ztd::format_error("Cannot merge string chunks", "", "", -1); + } + else + { + if(overwrite) + this->set(chk); + else + throw ztd::format_error("Cannot merge chunks of different types", "", "", -1); + } +} + + void ztd::chunkdat::erase(const std::string& key) { if(this->type()==ztd::chunk_abstract::map) @@ -867,7 +917,7 @@ ztd::chunkdat* ztd::chunkdat::subChunkPtr(std::string const& in) const ztd::chunk_map* dc = dynamic_cast(m_achunk); auto fi = dc->values.find(in); if(fi == dc->values.end()) //none found - return nullptr; + return nullptr; return fi->second; } else //not a chunk