Leviathan  0.8.0.0
Leviathan game engine
BaseNotifiableImpl.h
Go to the documentation of this file.
1 
4 // ------------------------------------ //
5 #pragma once
6 
7 #include "BaseNotifiable.h"
8 #include "BaseNotifier.h"
9 // ------------------------------------ //
10 template<class ParentType, class ChildType>
11 Leviathan::BaseNotifiable<ParentType, ChildType>::BaseNotifiable(ChildType* ourptr) : PointerToOurNotifiable(ourptr){
12 
13 }
14 
15 template<class ParentType, class ChildType>
17  GUARD_LOCK();
18 
19  // Last chance to unhook //
20  if(ConnectedToParents.size())
21  ReleaseParentHooks(guard);
22 }
23 // ------------------------------------ //
24 template<class ParentType, class ChildType>
26  // This needs a bit of trickery since the lock order must be parent, child so we may not lock ourselves
27 
28  while(!ConnectedToParents.empty()){
29 
30  // Get the parent and erase it from the vector, this should avoid problems during this
31  // object is unlocked
32  auto parentptr = *ConnectedToParents.begin();
33  ConnectedToParents.erase(ConnectedToParents.begin());
34 
35  guard.unlock();
36 
37  // Lock the parent //
38  GUARD_LOCK_OTHER_NAME(parentptr, guard2);
39 
40  // Now that the parent is locked we can re-lock ourselves //
41  guard.lock();
42 
43  parentptr->_OnUnhookNotifiable(guard2, this, guard);
44 
45  // Remove it //
46  _OnNotifierDisconnected(guard, parentptr->GetActualPointerToNotifierObject(), guard2);
47  }
48 }
49 // ------------------------------------ //
50 template<class ParentType, class ChildType>
52 
53  // Used to force the specific locking order //
54  BaseNotifier<ParentType, ChildType>* foundtarget = NULL;
55 
56  {
57  GUARD_LOCK();
58 
59  // Find child matching the provided id //
60  auto end = ConnectedToParents.end();
61  for(auto iter = ConnectedToParents.begin(); iter != end; ++iter){
62 
63  if(iter->GetID() == id){
64  // Found the target //
65  foundtarget = *iter;
66  }
67  }
68  }
69 
70  if(!foundtarget){
71  // Didn't find it //
72  return false;
73  }
74 
75  // Found a target, do the locking in the right order //
76 
77  GUARD_LOCK_OTHER_NAME(foundtarget, guard2);
78  GUARD_LOCK();
79 
80  return UnConnectFromNotifier(guard, foundtarget, guard2);
81 }
82 
83 template<class ParentType, class ChildType>
85  BaseNotifier<ParentType, ChildType>* specificnotifier, Lock &notifierlock)
86 {
87  VerifyLock(guard);
88 
89  // Remove from the list and call functions //
90  auto end = ConnectedToParents.end();
91  for(auto iter = ConnectedToParents.begin(); iter != end; ++iter){
92 
93  if(*iter == specificnotifier){
94  // Call unhook on the child //
95  (*iter)->_OnUnhookNotifiable(notifierlock, this, guard);
96 
97  // Remove it //
98  _OnNotifierDisconnected(guard, (*iter)->GetActualPointerToNotifierObject(),
99  notifierlock);
100 
101  ConnectedToParents.erase(iter);
102  return true;
103  }
104  }
105  return false;
106 }
107 
108 template<class ParentType, class ChildType>
111 {
112  // Lock the other first //
113  GUARD_LOCK_OTHER_NAME(owner, guard2);
114  GUARD_LOCK();
115 
116  // Check is it already connected //
117  if(IsConnectedTo(owner, guard)){
118 
119  return false;
120  }
121 
122  // Call hook on the parent //
123  owner->_OnHookNotifiable(guard2, this, guard);
124 
125  // Add to the list //
126  ConnectedToParents.push_back(owner);
127 
128  // Finally call the callback //
129  _OnNotifierConnected(guard, owner->GetActualPointerToNotifierObject(), guard2);
130 
131 
132  return true;
133 }
134 
135 template<class ParentType, class ChildType>
138 {
139  unlockable.unlock();
140 
141  // Lock the other first //
142  GUARD_LOCK_OTHER_NAME(owner, guard2);
143 
144  unlockable.lock();
145 
146  // Check is it already connected //
147  if(IsConnectedTo(owner, unlockable)){
148 
149  return false;
150  }
151 
152  // Call hook on the parent //
153  owner->_OnHookNotifiable(guard2, this, unlockable);
154 
155  // Add to the list //
156  ConnectedToParents.push_back(owner);
157 
158  // Finally call the callback //
159  _OnNotifierConnected(unlockable, owner->GetActualPointerToNotifierObject(), guard2);
160 
161  return true;
162 }
163 // ------------------------------------ //
164 template<class ParentType, class ChildType>
167 {
168  VerifyLock(guard);
169 
170  auto end = ConnectedToParents.end();
171  for(auto iter = ConnectedToParents.begin(); iter != end; ++iter){
172 
173  if(*iter == check)
174  return true;
175  }
176 
177  // Didn't find a match //
178  return false;
179 }
180 // ------------------------------------ //
181 template<class ParentType, class ChildType>
183  BaseNotifier<ParentType, ChildType>* parent, Lock &parentlock)
184 {
185 
186  // Add the object to the list of objects //
187  ConnectedToParents.push_back(parent);
188  _OnNotifierConnected(locked, parent->GetActualPointerToNotifierObject(), parentlock);
189 }
190 
191 template<class ParentType, class ChildType>
193  BaseNotifier<ParentType, ChildType>* parent, Lock &parentlock)
194 {
195 
196  // Remove from list //
197  auto end = ConnectedToParents.end();
198  for(auto iter = ConnectedToParents.begin(); iter != end; ++iter){
199 
200  if(*iter == parent){
201  // Remove it //
202  _OnNotifierDisconnected(locked, (*iter)->GetActualPointerToNotifierObject(),
203  parentlock);
204 
205  ConnectedToParents.erase(iter);
206  return;
207  }
208  }
209 }
210 // ------------------------------------ //
211 template<class ParentType, class ChildType>
213  Lock &guard, ParentType* parenttoremove, Lock &parentlock)
214 {
215 
216 }
217 
218 template<class ParentType, class ChildType>
220  Lock &guard, ParentType* parentadded, Lock &parentlock)
221 {
222 
223 }
224 // ------------------------------------ //
225 template<class ParentType, class ChildType>
227  return PointerToOurNotifiable;
228 }
229 // ------------------------------------ //
230 template<class ParentType, class ChildType>
232  // More trickery needed here to keep the locking order //
233  auto currentparent = *ConnectedToParents.begin();
234  auto actualptr = GetActualPointerToNotifiableObject();
235 
236  while(currentparent){
237 
238  // Now we need to unlock and the lock the parent //
239  guard.unlock();
240  {
241  GUARD_LOCK_OTHER_NAME(currentparent, guard2);
242 
243  // Now that the parent is locked we can re-lock ourselves //
244  guard.lock();
245 
246  // Notify now //
247  // TODO: add guard2 to this call
248  currentparent->OnNotified(guard2, actualptr, guard);
249 
250  }
251  // The current parent doesn't need to be locked while we change to a different parent //
252 
253  // Seek back to the current position //
254  auto end = ConnectedToParents.end();
255  for(auto iter = ConnectedToParents.begin(); iter != end; ){
256  // Check did we find the parent we are after, otherwise continue //
257  if(*iter == currentparent){
258  // The next parent will be the next target //
259  ++iter;
260 
261  currentparent = iter != ConnectedToParents.end() ? *iter: NULL;
262  break;
263 
264  } else {
265  ++iter;
266  }
267  }
268  }
269 }
270 
271 template<class ParentType, class ChildType>
273  ParentType* parent, Lock &parentlock)
274 {
275 
276 }
277 
278 
ChildType * GetActualPointerToNotifiableObject()
Gets the internal pointer to the actual object.
bool IsConnectedTo(BaseNotifier< ParentType, ChildType > *check, Lock &guard)
Actual implementation of this method.
#define GUARD_LOCK_OTHER_NAME(x, y)
Definition: ThreadSafe.h:127
BaseNotifiable(ChildType *ourptr)
void _OnHookNotifiable(Lock &guard, BaseNotifiable< ParentType, ChildType > *child, Lock &childlock)
ParentType * GetActualPointerToNotifierObject()
Gets the internal pointer to the actual object.
void _OnHookNotifier(Lock &locked, BaseNotifier< ParentType, ChildType > *parent, Lock &parentlock)
Called by parent to hook, and doesn&#39;t call the parent&#39;s functions.
virtual void NotifyAll(Lock &guard)
Notifies all the parents of this object about something.
void ReleaseParentHooks(Lock &guard)
Release function which releases all hooks.
virtual void _OnNotifierDisconnected(Lock &guard, ParentType *parentremoved, Lock &parentlock)
bool ConnectToNotifier(BaseNotifier< ParentType, ChildType > *owner)
Connects this to a notifier object calling all the needed functions.
void _OnUnhookNotifier(Lock &locked, BaseNotifier< ParentType, ChildType > *parent, Lock &parentlock)
Callback called by the parent, used to not to call the unhook again on the parent.
virtual void _OnNotifierConnected(Lock &guard, ParentType *parentadded, Lock &parentlock)
#define GUARD_LOCK()
Definition: ThreadSafe.h:111
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18
bool UnConnectFromNotifier(Lock &guard, BaseNotifier< ParentType, ChildType > *specificnotifier, Lock &notifierlock)
The actual implementation of UnConnectFromNotifier.
virtual void OnNotified(Lock &ownlock, ParentType *parent, Lock &parentlock)
Called when our parent notifies us about something.