diff options
Diffstat (limited to 'src/stable/sharedcore.h')
-rw-r--r-- | src/stable/sharedcore.h | 193 |
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 | |||
16 | namespace 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 | ||