#ifndef ICATALOGUE_H #define ICATALOGUE_H #include "model.h" #include #include #include #include namespace M { class ICatalogue : public M::Model { Q_OBJECT protected: class AbstractIndex; public: ICatalogue(const W::Address p_address, QObject* parent = 0); ~ICatalogue(); virtual uint64_t addElement(const W::Vocabulary& record); virtual void removeElement(uint64_t id); virtual W::Vocabulary* getElement(uint64_t id) = 0; virtual void modifyElement(uint64_t id, const W::Vocabulary& newValue) = 0; virtual uint64_t size() const = 0; virtual void clear(); virtual void addIndex(const W::String& fieldName, W::Object::objectType fieldType); const std::set& find(const W::String& indexName, const W::Object& value) const; std::set find(const W::Vocabulary& value) const; M::Model::ModelType getType() const override; static const M::Model::ModelType type = catalogue; void set(const W::Object & value) override; void set(W::Object * value) override; W::Handler* subscribeMember; handler(subscribeMember); static bool match(const W::Vocabulary& value, const W::Vocabulary& filter); static const std::set empty; signals: void countChange(uint64_t count); protected: virtual std::set getAll() const = 0; void h_subscribe(const W::Event & ev) override; handler(get); handler(add); handler(update); typedef std::map IndexMap; IndexMap indexes; private: uint64_t lastIndex; std::map activeChildren; void processAddElement(uint64_t id, const W::Vocabulary& value, SMap::const_iterator subscriberIterator, uint64_t socketId); uint64_t getInsertingNeighbour(const W::Vocabulary& params, const W::Vocabulary& record, uint64_t id, const std::set& allowed = empty) const; protected: class AbstractIndex { public: AbstractIndex(W::Object::objectType vt): valueType(vt) {} virtual ~AbstractIndex() {} virtual const std::set& find(const W::Object& value) const = 0; virtual void add(const W::Object& value, uint64_t id) = 0; virtual void remove(const W::Object & value, uint64_t id) = 0; virtual void clear() = 0; virtual W::Vector sort(const std::set& set, bool ascending) = 0; virtual uint64_t getNext(uint64_t id, const W::Object& value) = 0; virtual uint64_t getPrev(uint64_t id, const W::Object& value) = 0; W::Object::objectType valueType; protected: class TypeError : public Utils::Exception { public: TypeError(const std::string& name, const std::string& method, W::Object::objectType myType, W::Object::objectType valueType); std::string getMessage() const; private: std::string name; std::string method; W::Object::objectType myType; W::Object::objectType valueType; }; }; template class Index : public AbstractIndex { public: Index(); ~Index(); const std::set& find(const W::Object& value) const override; void add(const W::Object & value, uint64_t id) override; void remove(const W::Object & value, uint64_t id) override; void clear() override; W::Vector sort(const std::set & set, bool ascending) override; uint64_t getNext(uint64_t id, const W::Object& value) override; uint64_t getPrev(uint64_t id, const W::Object& value) override; private: typedef std::map> Map; Map values; }; }; template ICatalogue::Index::Index(): ICatalogue::AbstractIndex(T::type), values() { } template ICatalogue::Index::~Index() { } template const std::set & ICatalogue::Index::find(const W::Object& value) const { if (value.getType() != valueType) { throw new TypeError("Unknown", "find", valueType, value.getType()); //todo replace that unknown stuff, find a way to provide index name } const T& val = static_cast(value); typename std::map>::const_iterator itr = values.find(val); if (itr == values.end()) { return ICatalogue::empty; } else { return itr->second; } } template void ICatalogue::Index::add(const W::Object& value, uint64_t id) { if (value.getType() != valueType) { throw new TypeError("Unknown", "add", valueType, value.getType()); } const T& val = static_cast(value); typename std::map>::iterator itr = values.find(val); if (itr == values.end()) { itr = values.insert(std::make_pair(val, std::set())).first; } itr->second.insert(id); } template void ICatalogue::Index::remove(const W::Object& value, uint64_t id) { if (value.getType() != valueType) { throw new TypeError("Unknown", "remove", valueType, value.getType()); } const T& val = static_cast(value); typename std::map>::iterator itr = values.find(val); if (itr != values.end()) { std::set& set = itr->second; if (set.size() == 1) { values.erase(itr); } else { std::set::const_iterator hint = set.find(id); set.erase(hint); } } } template void ICatalogue::Index::clear() { values.clear(); } template W::Vector ICatalogue::Index::sort(const std::set & set, bool ascending) //TODO this needs an optimization { W::Vector res; std::set::const_iterator sEnd = set.end(); uint64_t size = set.size(); if (size == 0) { return res; } else if (size == 1) { res.push(W::Uint64(*(set.begin()))); return res; } if (ascending) { typename std::map>::const_iterator itr = values.begin(); typename std::map>::const_iterator end = values.end(); for (; itr != end; ++itr) { if (size == res.size()) { break; } const std::set& chunk = itr->second; std::set::const_iterator cItr = chunk.begin(); std::set::const_iterator cEnd = chunk.end(); for (; cItr != cEnd; ++cItr) { uint64_t id = *cItr; if (set.find(id) != sEnd) { res.push(W::Uint64(id)); } } } } else { typename std::map>::reverse_iterator itr = values.rbegin(); typename std::map>::reverse_iterator end = values.rend(); for (; itr != end; ++itr) { if (size == res.size()) { break; } const std::set& chunk = itr->second; std::set::const_iterator cItr = chunk.begin(); std::set::const_iterator cEnd = chunk.end(); for (; cItr != cEnd; ++cItr) { uint64_t id = *cItr; if (set.find(id) != sEnd) { res.push(W::Uint64(id)); } } } } return res; } template uint64_t ICatalogue::Index::getNext(uint64_t id, const W::Object& value) { if (value.getType() != valueType) { throw new TypeError("Unknown", "getNext", valueType, value.getType()); } const T& val = static_cast(value); typename std::map>::iterator itr = values.find(val); if (itr == values.end()) { throw 2; //this is not suppose to happen! } const std::set& set = itr->second; std::set::const_iterator sItr = set.find(id); if (sItr == set.end()) { throw 2; //not suppose to happen! } ++sItr; if (sItr == set.end()) { ++itr; bool found = false; while (itr != values.end()) { if (itr->second.size() != 0) { sItr = set.begin(); found = true; break; } ++itr; } if (!found) { return 0; } } return *sItr; } template uint64_t ICatalogue::Index::getPrev(uint64_t id, const W::Object& value) { if (value.getType() != valueType) { throw new TypeError("Unknown", "getPrev", valueType, value.getType()); } const T& val = static_cast(value); typename std::map>::iterator itr = values.find(val); if (itr == values.end()) { throw 2; //this is not suppose to happen! } const std::set& set = itr->second; std::set::const_iterator sItr = set.find(id); if (sItr == set.end()) { throw 2; //not suppose to happen! } if (sItr == set.begin()) { bool found = false; while (itr != values.begin()) { --itr; if (itr->second.size() != 0) { sItr = set.end(); --sItr; break; } } if (!found) { return 0; } } else { --sItr; } return *sItr; } } #endif // ICATALOGUE_H