aboutsummaryrefslogtreecommitdiffstats
path: root/meowpp/Self.h
blob: 7de568bb4a718c25cd5b4a74c7d11609333f85d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#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 const& b): data(b.data) {  // 必要, copy constructor
 *     }
 *     ~Myself() {
 *     }
 *     bool operator==(Myself const& b) const { // 不一定需要(有用到equal()才要)
 *       return (data == b.data);
 *     }
 *   };
 *
 *   Self<Myself> const self;
 * public:
 *   A(): self() { }                                // 預設呼叫Myself()
 *   A(A const& a): self(a.self, COPY_FROM) { }     // 用Myself(b)做到copyFrom
 *   ~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);
 *   }
 * };
 * @endcode
 *
 * @author cathook
 *
 * @warning \c Self 這個class會把\c operator= 給disable掉, 所以使用它當
 *          kernel的class預設的 \c operator= 都會無法使用
 */
template<class Data>
class Self {
public:
  /*!
   * @brief 複製資料的方法
   */
  enum DuplicateType {
    COPY_FROM,          //!< 跟一般的複製一樣
    REFERENCE_FROM      //!< 參照, 執行完兩個Self會完全等效
  };
private:
  class Body {
  private:
    struct Kernel {
      Data    data_;
      int  counter_;

      Kernel(                ): data_(    ), counter_(1) { }
      Kernel(Data const& data): data_(data), counter_(1) { }
      ~Kernel() { }
    };

    Kernel* pointer_;
    int     counter_;
  public:
    Body(             ): pointer_(new Kernel( )), counter_(1) { }
    Body(Data const& d): pointer_(new Kernel(d)), counter_(1) { }
    Body(Body const& b): pointer_(b.pointer_   ), counter_(1) {
      ++pointer_->counter_;
    }
    ~Body() {
      clear();
    }
    Body& copyFrom(Body const& b) {
      clear();
      pointer_ = b.pointer_;
      ++(pointer_->counter_);
      return *this;
    }
    void clear() {
      --(pointer_->counter_);
      if (pointer_->counter_ <= 0) {
        delete pointer_;
      }
    }
    int attach() { return ++counter_; }
    int detach() { 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() {
    if (body_->detach() <= 0) {
      delete body_;
    }
  }
public:
  /*!
   *@brief constructor, 並宣告一個實體
   */
  Self(): body_(new Body()) {
  }

  /*!
   * @brief connstructor, 宣告一個實體, 其中該實體的constructor用copy
   *        constructor
   *
   * @param [in] d Inital data
   *
   */
  Self(Data const& d): body_(new Body(d)) {
  }

  /*!
   * @brief constructor, 使用給定的Self當作init value, 並且可以指定要用
   *         reference還是copy
   *
   * @param [in] b 給定的Self
   * @param [in] d 指定要用copy還是reference
   */
  Self(Self const& b, DuplicateType d) {
    switch(d) {
    case COPY_FROM:
      body_ = new Body(*b.body_);
      break;
    case REFERENCE_FROM:
      body_ = b.body_;
      body_->attach();
      break;
    }
  }

  //! @brief Disallow copy constructor
  Self(Self const& b);

  //! @brief 解構子
  ~Self() {
    clear();
  }

  //! @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 *this
   *
   * @note 與reference的差別是, copy之後若該給定的 \c Self 有資料修改,
   *       this 這邊 \b 不會 被改到
   */
  Self const& copyFrom(Self const& s) {
    if (body_->access() != s.body_->access()) {
      body_->copyFrom(*s.body_);
    }
    return *this;
  }

  /*!
   * @brief 將自己reference 到給定的 \c Self
   *
   * @param [in] s 給定的\c Self
   * @return *this
   *
   * @note 把reference想像成指標會比較容易思考, 譬如 \c a.referenceFrom(b)
   *       \c b.referenceFrom(c) 相當於 \b a指向b原本指的記憶體位置,
   *       \b b指向c原本指的記憶體位置 , 之後更動c時, 只有b會被牽連
   */
  Self const& referenceFrom(Self const& s) {
    if (body_ != s.body_) {
      clear();
      body_ = s.body_;
      body_->attach();
    }
    return *this;
  }

  /*!
   * @brief 依據給定DuplicateType選擇要呼叫copyFrom還是referenceFrom
   *
   * @param [in] s 給定的 \c Self
   * @param [in] t 給定的 \c DuplicateType
   * @return *this
   */
  Self const& duplicateFrom(Self const& s, DuplicateType t) {
    switch(t) {
    case COPY_FROM     : return      copyFrom(s);
    case REFERENCE_FROM: return referenceFrom(s);
    }
    return *this;
  }

  /*!
   * @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() == *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__