#ifndef oo_ObjSelector_H__ #define oo_ObjSelector_H__ #include "ObjBase.h" #include #include #include #include #include #include namespace meow{ /*! * @brief 利用register的概念, 達到runtime用string選擇要new的class * * @author cathook */ template //!< 讓程式可以有不只一個 \c ObjSelector class ObjSelector { private: struct Info { ObjSelector* parent_; ObjBase const* pointer_; bool autoDelete_; // Info(ObjSelector* parent, ObjBase const* ptr, bool autoDelete) { parent_ = parent; pointer_ = ptr; autoDelete_ = autoDelete; } ~Info() { if (autoDelete_) { delete pointer_; } if (parent_ != NULL) { parent_->me_.second = NULL; } } }; friend struct Info; typedef typename std::map Funcs; typedef typename std::map::iterator FuncsIterator; static Funcs& funcs() { static Funcs f; return f; } static Info* add(std::string name, ObjSelector* parent, ObjBase* ptr, bool autoDelete) { Info* info = new Info(parent, ptr, autoDelete); del(name); funcs()[name] = info; return info; } std::pair me_; public: /*! * @brief 新增(註冊) 一個Class (必須要繼承自 \c ObjBase) 並且給定其Name */ static void add(std::string name, ObjBase* obj, bool autoDelete) { add(name, NULL, obj, autoDelete); } /*! * @brief 新增(註冊) 一個Class (必須要繼承自 \c ObjBase) 並且默認type為name */ static void add(ObjBase* obj, bool autoDelete) { add(obj->type(), NULL, obj, autoDelete); } /*! * @brief 依照name刪除之前註冊過得Class */ static void del(std::string name) { if (funcs().find(name) != funcs().end()) { delete funcs()[name]; funcs().erase(name); } } /*! * @brief 取得之前註冊過得Class */ static ObjBase const* get(std::string name) { if (funcs().find(name) == funcs().end()) return NULL; return funcs()[name]->pointer_; } /*! * @brief 回傳一個之前註冊過得Class new出來的實體 */ static ObjBase* create(std::string name) { ObjBase const* ptr = get(name); if(ptr == NULL) return NULL; return ptr->create(); } /*! * @brief 利用type檢查是否有註冊過同種類的Class */ static bool exist(ObjBase* obj) { for (FuncsIterator it = funcs().begin(); it != funcs().end(); it++) { if (it->second->pointer_ == obj || (it->second->pointer_ != NULL && it->second->pointer_->type() == obj->type())) { return true; } } return false; } /*! * @brief 利用type尋找name */ static std::string name(ObjBase* obj) { for (FuncsIterator it = funcs().begin(); it != funcs().end(); it++) { if (it->second->pointer_ == obj || (it->second->pointer_ != NULL && it->second->pointer_->type() == obj->type())) { return it->first; } } return std::string(); } /*! * @brief 回傳所有註冊過的name */ static std::vector names() { std::vector ret; for (FuncsIterator it = funcs().begin(); it != funcs().end(); it++) ret.push_back(it->first); return ret; } /*! * @brief 宣告一個ObjSelector實體, 並且註冊一個 ObjBase */ ObjSelector(std::string name, ObjBase* obj, bool autoDelete) { me_.first = name; me_.second = add(me_.first, this, obj, autoDelete); } /*! * @brief 宣告一個ObjSelector實體, 並且註冊一個 ObjBase */ ObjSelector(ObjBase* obj, bool autoDelete) { me_.first = obj->type(); me_.second = add(me_.first, this, obj, autoDelete); } //! 解構子 ~ObjSelector() { if (me_.second != NULL) { del(me_.first); } } /*! * @brief 將一個物件寫到檔案裡(該物件必須要有註冊過) */ static bool write(FILE* f, bool binary, ObjBase* obj, unsigned int fg) { if (!exist(obj)) return false; char const* nme = name(obj).c_str(); size_t len = strlen(nme); if (binary) { if (fwrite(&len, sizeof(size_t ), 1, f) < 1) return false; if (fwrite(nme , sizeof(char ), len, f) < len) return false; if (fwrite(&fg , sizeof(unsigned int), 1, f) < 1) return false; } else { if (fprintf(f, "%s %u\n", nme, fg) < 2) return false; } return obj->write(f, binary, fg); } /*! * @brief 從檔案中讀取一個物件(該物件必須要有註冊過) */ static ObjBase* read(FILE* f, bool binary) { char name[2048]; size_t len; unsigned int fg; if (binary) { if (fread(&len, sizeof(size_t ), 1, f) < 1) return NULL; if (fread(name, sizeof(char ), len, f) < len) return NULL; if (fread(&fg , sizeof(unsigned int), 1, f) < 1) return NULL; name[len] = '\0'; } else { if (fscanf(f, "%s %u", name, &fg) < 2) return NULL; } ObjBase* ret = create(std::string(name)); if (ret != NULL && ret->read(f, binary, fg) == false) { delete ret; ret = NULL; } return ret; } }; static const size_t kGlobalSeletorID = 0; } #endif // oo_ObjSelector_H__