aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/oo/ObjSelector.h
blob: 7664a118d5743ee7eaa33d715c349ae3d67d5fc1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                            




                  
                  
                 

               























                                                                             
       

                                   
       








































































                                                                                              
       












                                                                         
       















































































                                                                          


                            
#ifndef   oo_ObjSelector_H__
#define   oo_ObjSelector_H__

#include "ObjBase.h"

#include <utility>
#include <vector>
#include <string>
#include <map>

#include <cstdlib>
#include <cstdio>

namespace meow{

/*!
 * @brief 利用register的概念, 達到runtime用string選擇要new的class
 *
 * @author cathook
 */
template<size_t id> //!< 讓程式可以有不只一個 \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<std::string, Info*>           Funcs;
  typedef typename std::map<std::string, Info*>::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<std::string, Info*> 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<std::string> names() {
    std::vector<std::string> 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__