ztsdb
cow_ptr.hpp
1 // (C) 2016 Leonardo Silvestri
2 //
3 // This file is part of ztsdb.
4 //
5 // ztsdb is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // ztsdb is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with ztsdb. If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 #ifndef COW_PTR_HPP
20 #define COW_PTR_HPP
21 
22 
23 #include <memory>
24 
25 namespace arr {
26 
27  const unsigned NOFLAGS = 0x00;
28  const unsigned REF = 0x01;
29  const unsigned LOCKED = 0x02;
30  const unsigned CONSTREF = 0x04;
31  const unsigned TMP = 0x08;
32  const unsigned LAST = 0x10;
33 
41  template<typename T>
42  struct cow_ptr {
43 
44  cow_ptr(unsigned flags_p, T* t)
45  : flags(flags_p), p(t), count(std::make_shared<long>(1)) { }
46  cow_ptr(unsigned flags_p, std::shared_ptr<T> tp)
47  : flags(flags_p), p(tp), count(std::make_shared<long>(1)) { }
48 
49  // LLL: to be complete we need a constructor that can construct
50  // from a class derived from T
51 
52  // const dereferencing
53  const T* operator->() const {
54  return p.get();
55  }
56  const T& operator*() const {
57  return *p.get();
58  }
59 
60  // non-const dereferencing
61  T* operator->() {
62  if (isConst()) {
63  throw std::range_error("cannot modify const object");
64  }
65  //std::cout << "->deref: use_count(): " << use_count() << std::endl;
66  if (*count > 1) {
67  if (flags & LOCKED) {
68  throw std::range_error("cannot copy locked object");
69  }
70  //std::cout << "->deref: making copy" << std::endl;
71  p = std::make_shared<T>(*p); // call T's copy constructor
72  --*count;
73  count = std::make_shared<long>(1);
74  }
75  return p.get();
76  }
77  T& operator*() {
78  //std::cout << "*deref: use_count(): " << use_count() << std::endl;
79  if (isConst()) {
80  throw std::range_error("cannot modify const object");
81  }
82  if (*count > 1) {
83  if (flags & LOCKED) {
84  throw std::range_error("cannot copy locked object");
85  }
86  //std::cout << "*deref: making copy" << std::endl;
87  p = std::make_shared<T>(*p); // call T's copy constructor
88  --*count;
89  count = std::make_shared<long>(1);
90  }
91  return *p.get();
92  }
93 
96  T* get() { return p.get(); }
99  const T* get() const { return p.get(); }
100 
101  cow_ptr& operator=(const cow_ptr<T>& o) {
102  // should not allow copying of CONST ? and LAST? LLL
103  p = o.p;
104  flags = o.flags & ~LAST;
105  count = o.count;
106  if (!(flags & CONSTREF))
107  ++*count;
108  return *this;
109  }
110 
111  cow_ptr(const cow_ptr& o)
112  : flags(o.flags & ~LAST), p(o.p), count(o.count) { ++*count; }
113 
114  bool isRef() const { return flags & REF; }
115  bool isLocked() const { return flags & LOCKED; }
116  bool isConst() const { return flags & CONSTREF; }
117  bool isTmp() const { return flags & TMP; }
118  bool isLast() const { return flags & LAST; }
119 
120  void setTmp() { flags |= TMP; --*count; }
121  void setRef() { flags |= REF; }
122  void setLock() { flags |= LOCKED; }
123  void setConst() { flags |= CONSTREF; }
124  void setLast() {
125  flags |= LAST; --*count;
126  }
127 
128  void resetTmp() { flags &= ~TMP; }
129  void resetLock() { flags &= ~LOCKED; }
130  void resetRef() { flags &= ~REF; }
131 
132  unsigned getFlags() const { return flags; }
133 
134  long use_count() const { return *count; }
135 
136  ~cow_ptr() {
137  if (!isLast() && !isTmp()) {
138  --*count;
139  }
140  }
141 
142  private:
143  unsigned flags;
144  std::shared_ptr<T> p;
145  std::shared_ptr<long> count;
146  };
147 
148 
149  template <typename T, typename... Args>
150  inline cow_ptr<T> make_cow(unsigned flags, Args&&... args)
151  {
152  return cow_ptr<T>(flags, new T(std::forward<Args>(args)...));
153  }
154 
155 }
156 
157 
158 #endif
arr::cow_ptr::get
T * get()
Definition: cow_ptr.hpp:96
arr::cow_ptr
Definition: cow_ptr.hpp:42
arr::cow_ptr::get
const T * get() const
Definition: cow_ptr.hpp:99
arr
Contains the classes and functions that implement a multidimentional array type.
Definition: allocator.hpp:29