aboutsummaryrefslogtreecommitdiff
path: root/src/stable/sharedcore.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/sharedcore.h')
-rw-r--r--src/stable/sharedcore.h193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/stable/sharedcore.h b/src/stable/sharedcore.h
new file mode 100644
index 0000000..bf9395c
--- /dev/null
+++ b/src/stable/sharedcore.h
@@ -0,0 +1,193 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_SHARED_CORE_H
9#define BU_SHARED_CORE_H
10
11#include "bu/util.h"
12
13#include <stdio.h>
14#include <stdarg.h>
15
16namespace Bu
17{
18 /**
19 * A mechanism for creating classes that perform lazy copies. The concept
20 * behind this is that instead of copying a large object when it is assigned
21 * or passed into a copy constructor we simply copy a pointer internally.
22 * The assumption is that many times when an object is passed by value we
23 * don't really want to keep the object around, we want the recipient to
24 * take ownership without allocating a new object. This allows that to
25 * happen.
26 *
27 * When used properly this makes object copying essentially free (O(1),
28 * that is) and performs the actual copy when a user tries to modify the
29 * object.
30 *
31 * For example, lets look at something like the getKeys function in
32 * Bu::Hash. When this function is called it creates a Bu::List of
33 * appropriate type, fills it with keys, and returns it. This is a good
34 * way for this function to behave, there may be additional issues if the
35 * List object were allocated with new and not on the stack. However,
36 * returning the List at the end of the function could potentially take
37 * a very long time depending on the size of the list and the type of the
38 * key. In this case the getKeys function doesn't want ownership of the
39 * List object, and when it returns it, it's local copy will be destroyed.
40 *
41 * However, List inherits from SharedCore, which means that when it is
42 * returned all we do is copy a pointer to the "core" of the list, which
43 * is a very fast operatorion. For a brief moment, before anyone can do
44 * anything else, there are two objects referencing the core of that single
45 * list. However, the getKeys() function will destroy it's local copy
46 * before the calling function can use it's new copy. That means that by
47 * the time the calling function can use it's new List of keys it is the
48 * only one with a reference to the core, and no copy will need to happen.
49 *
50 * Using SharedCore on your own classes is fairly straight forward. There
51 * are only a couple of steps. First, break the class into two classes.
52 * Move every variable from the original class (generally everything that's
53 * private) into the new class. Then make the original class inherit from
54 * SharedCore. The SharedCore template takes 2 parameters, first is the
55 * class it's inheriting from, second is the new core class. Now, in your
56 * original class you will have one class variable, a pointer named core.
57 * All of your original variables will be accessable through core. The next
58 * step is to access everything you used to through core, and to find
59 * every function that may change data in the core. At the top of every
60 * function that may change data you want to call _hardCopy().
61 *
62 * That's more or less it. A more detailed guide will be written soon.
63 * @todo Write a guide for this.
64 */
65 template<typename Shell, typename Core>
66 class SharedCore
67 {
68 typedef class SharedCore<Shell, Core> _SharedType;
69 public:
70 SharedCore() :
71 core( NULL ),
72 iRefCount( NULL )
73 {
74 core = _allocateCore();
75 iRefCount = new int(1);
76 }
77
78 SharedCore( const _SharedType &rSrc ) :
79 core( NULL ),
80 iRefCount( NULL )
81 {
82 _softCopy( rSrc );
83 }
84
85 virtual ~SharedCore()
86 {
87 _deref();
88 }
89
90 SharedCore &operator=( const SharedCore &rhs )
91 {
92 if( core == rhs.core )
93 return *this;
94
95 _softCopy( rhs );
96 return *this;
97 }
98
99 int getRefCount() const
100 {
101 return *iRefCount;
102 }
103
104 Shell clone() const
105 {
106 Shell s( dynamic_cast<const Shell &>(*this) );
107 s._hardCopy();
108 return s;
109 }
110
111 bool isCoreShared( const Shell &rOther ) const
112 {
113 return rOther.core == core;
114 }
115
116 protected:
117 Core *core;
118 void _hardCopy()
119 {
120 if( !core || !iRefCount )
121 return;
122 if( (*iRefCount) == 1 )
123 return;
124 Core *copy = _copyCore( core );
125 _deref();
126 core = copy;
127 iRefCount = new int( 1 );
128 }
129
130 /**
131 * Reset core acts like a hard copy, except instead of providing a
132 * standalone copy of the shared core, it provides a brand new core.
133 *
134 * Very useful in functions used to reset the state of an object.
135 */
136 void _resetCore()
137 {
138 if( core )
139 _deref();
140 core = _allocateCore();
141 iRefCount = new int( 1 );
142 }
143
144 virtual Core *_allocateCore()
145 {
146 return new Core();
147 }
148
149 virtual Core *_copyCore( Core *pSrc )
150 {
151 return new Core( *pSrc );
152 }
153
154 virtual void _deallocateCore( Core *pSrc )
155 {
156 delete pSrc;
157 }
158
159 private:
160 void _deref()
161 {
162 if( (--(*iRefCount)) == 0 )
163 {
164 _deallocateCore( core );
165 delete iRefCount;
166 }
167 core = NULL;
168 iRefCount = NULL;
169 }
170
171 void _incRefCount()
172 {
173 if( iRefCount && core )
174 ++(*iRefCount);
175 }
176
177 void _softCopy( const _SharedType &rSrc )
178 {
179 if( core )
180 _deref();
181 core = rSrc.core;
182 iRefCount = rSrc.iRefCount;
183 _incRefCount();
184 }
185
186 int *iRefCount;
187 };
188};
189
190#undef fin
191#undef fout
192
193#endif