aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/Self.h
blob: 5a62984028a257467f547cb1ff40cb90d009b256 (plain) (tree)





































































































































































































































                                                                                              
#ifndef   Self_h__
#define   Self_h__

#include <cstdlib>

namespace meow {

/*!
 *@brief 具有copy on write, 且擁有比C++更靈活的reference機制
 *
 *使用上就是把所有成員變數包到一個class/structure裡, 送給Self \n
 *例如以下
 *@code{.cpp}
 * class A {
 * private:
 *   struct Myself {
 *     int data;
 *     Myself(){
 *       data = 0;
 *     }
 *     ~Myself() {
 *     }
 *     Myself copyFrom(Myself const& ms) const {
 *       data = ms.data;
 *     }
 *   };
 *   Self<Myself> const self;
 * public:
 *   A(): self(true) { // self(true) 表示要建立實體, 即struct Myself
 *   }
 *   A(A const& a): self(false) { // for std::swap
 *     copyFrom(a);
 *   }
 *   // A(A const& a); // disable 模糊用法, 與上者二選一
 *   A(A const& a, bool reference): self(false) {
 *     if (reference) {
 *       referenceFrom(a);
 *     } else {
 *       copyFrom(a);
 *     }
 *   }
 *   ~A() {
 *   }
 *   void setMemeber(int k) {
 *     self()->data = k;  // self()->?? 可以有write權限
 *   }
 *   int getMemember(int wh) const {
 *     return self->data; // self->?? 只有const
 *   }
 *   A referenceFrom(A const& a) {
 *     self.referenceFrom(a.self);
 *   }
 *   A copyFrom(A const& a) {
 *     self.copyFrom(a.self);
 *   }
 *   A& operator=(A const& b) { // for std::swap
 *     copyFrom(b);
 *   }
 *   A& operator=(A const& b); // 避免諢亂用法
 * };
 * @endcode
 *
 *@author cathook
 *
 *@warning \c Self 這個class會把\c operator= 給disable掉, 所以使用它當
 *         kernel的class預設的 \c operator= 都會無法使用
 */
template<class Data>
class Self {
private:
  class Body {
  private:
    struct Kernel {
      Data    data_;
      int  counter_;
      Kernel() {
        counter_ = 1;
      }
      Kernel(Data const& data) {
        counter_ = 1;
        data_.copyFrom(data);
      }
    };
    Kernel *pointer_;
    int     counter_;
  public:
    Body() {
      counter_ = 1;
      pointer_ = new Kernel;
    }
    Body(Body const& b) {
      counter_ = 1;
      pointer_ = b.pointer_;
      pointer_->counter_++;
    }
    ~Body() {
      pointer_->counter_--;
      if (pointer_->counter_ <= 0) {
        delete pointer_;
      }
    }
    int attatch() { return ++counter_; }
    int detatch() { return --counter_; }
    Data const* access() const { return &(pointer_->data_); }
    Data      * modify() {
      if (pointer_->counter_ > 1) {
        pointer_->counter_--;
        pointer_ = new Kernel(pointer_->data_);
      }
      return &(pointer_->data_);
    }
  };
  Body*  body_;
  
  void clear(Body* body) {
    if (body != NULL) {
      if (body->detatch() <= 0) {
        delete body;
      }
    }
  }
public:
  /*!
   *@brief constructor
   *
   *@param [in] create_body 是否要new一個實體資料 (如果constructor完, 馬上就要
   *                        \c copyFrom() , 或是 \c referenceFrom() 的話
   *                        不太需要 new一個實體, 否則基本上都要
   */
  Self(bool create_body) {
    body_ = (create_body ? new Body() : NULL);
  }
  
  //! @brief 不允許copy constructor
  Self(Self const& b);
  
  //! @brief 解構子
  ~Self() {
    clear(body_);
  }
  
  //! @brief 回傳指向 Data const 的指標
  Data const* operator->() const {
    return body_->access();
  }
  
  //! @brief 回傳指向 Data 的指標, 如有需要, 這邊會做資料的duplicate
  Data* operator->() {
    return body_->modify();
  }
  
  //! @brief 回傳非const型態的自己
  Self& operator()() const {
    return *((Self*)this);
  }
  
  /*!
   *@brief 將給定的 \c Self 的資料複製到自己這裡
   *
   *@param [in] s 給定的\c Self
   *@return 無
   *
   *@note 與reference的差別是, copy之後若該給定的 \c Self 有資料修改, 
   *      this 這邊 \b 不會 被改到
   */
  void copyFrom(Self const& s) {
    Body* old = body_;
    body_ = new Body(*(s.body_));
    clear(old);
  }
  
  /*!
   *@brief 將自己reference 到給定的 \c Self
   *
   *@param [in] s 給定的\c Self
   *@return 無
   *
   *@note 把reference想像成指標會比較容易思考, 譬如 \c a.referenceFrom(b)
   *      \c b.referenceFrom(c) 相當於 \b a指向b原本指的記憶體位置,
   *      \b b指向c原本指的記憶體位置 , 之後更動c時, 只有b會被牽連
   *      
   */
  void referenceFrom(Self const& s) {
    if (body_ != s.body_) {
      clear(body_);
      body_ = s.body_;
      body_->attatch();
    }
  }
  
  /*!
   * @brief 比對兩個 \c Self 是否指向同一個reference
   *
   * @param [in] s 另一個 \c Self
   * @return \c true/false 表示是否為同一個reference
   */
  bool same(Self const& s) const {
    return (body_ == s.body_);
  }
  
  /*!
   * @brief 比對兩個 \c Self 的內容是否一樣
   * 
   * @param [in] s 另一個 \c Self
   * @return \c true/false 表示兩個內容是否一樣
   *
   * @note 需要用到 Data的equal()
   */
  bool equal(Self const& s) const {
    if (same(s) || body_->access() == s.body_->access()) return true;
    return (body_->access()->equal(*(s.body_->access())));
  }
  
  /*!
   * @brief 以reference作為判斷依據的小於判斷
   *
   * @param [in] s 另一個 \c Self
   * @return \c true/false 表示自己是否小於另一個 \c Self
   */
  bool referenceLess(Self const& s) const {
    return (body_ < s.body_);
  }
  
  //! @brief 將 \c operator= 給disable掉
  void operator=(Self const& a);
};

} // meow

#endif // Self_h__