diff options
Diffstat (limited to 'src/sharedcore.h')
-rw-r--r-- | src/sharedcore.h | 77 |
1 files changed, 75 insertions, 2 deletions
diff --git a/src/sharedcore.h b/src/sharedcore.h index 5a44df9..1887ca2 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h | |||
@@ -15,10 +15,57 @@ | |||
15 | 15 | ||
16 | namespace Bu | 16 | namespace Bu |
17 | { | 17 | { |
18 | template<typename Core> | 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> | ||
19 | class SharedCore | 66 | class SharedCore |
20 | { | 67 | { |
21 | typedef class SharedCore<Core> _SharedType; | 68 | typedef class SharedCore<Shell, Core> _SharedType; |
22 | public: | 69 | public: |
23 | SharedCore() : | 70 | SharedCore() : |
24 | core( NULL ), | 71 | core( NULL ), |
@@ -54,6 +101,18 @@ namespace Bu | |||
54 | return *iRefCount; | 101 | return *iRefCount; |
55 | } | 102 | } |
56 | 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 | |||
57 | protected: | 116 | protected: |
58 | Core *core; | 117 | Core *core; |
59 | void _hardCopy() | 118 | void _hardCopy() |
@@ -68,6 +127,20 @@ namespace Bu | |||
68 | iRefCount = new int( 1 ); | 127 | iRefCount = new int( 1 ); |
69 | } | 128 | } |
70 | 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 | |||
71 | virtual Core *_allocateCore() | 144 | virtual Core *_allocateCore() |
72 | { | 145 | { |
73 | return new Core(); | 146 | return new Core(); |