|
|
@@ -24,30 +24,60 @@ struct Observer
|
|
|
};
|
|
|
|
|
|
/// An over-qualified observer
|
|
|
-template<typename ObservingType, typename Value,
|
|
|
- void (ObservingType::*method)(Value)>
|
|
|
+template<typename ObservingClass, typename Value,
|
|
|
+ void (ObservingClass::*method)(Value)>
|
|
|
struct SuperObserver: Observer<Value>
|
|
|
{
|
|
|
- ObservingType* reveiver;
|
|
|
+ ObservingClass* receiver;
|
|
|
|
|
|
- SuperObserver(ObservingType* reveiver_)
|
|
|
- : reveiver(reveiver_)
|
|
|
- {}
|
|
|
+ SuperObserver(ObservingClass* receiver_)
|
|
|
+ : receiver(receiver_)
|
|
|
+ {
|
|
|
+ ANKI_ASSERT(receiver != nullptr);
|
|
|
+ }
|
|
|
|
|
|
void notify(Value x)
|
|
|
{
|
|
|
- (reveiver->*method)(x);
|
|
|
+ (receiver->*method)(x);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/// Basically a container of observers
|
|
|
-template<typename T>
|
|
|
+template<typename T, typename Alloc = Allocator<Observer<T>*>>
|
|
|
class Observable
|
|
|
{
|
|
|
public:
|
|
|
typedef T Value;
|
|
|
typedef Observer<Value> ObserverType;
|
|
|
- typedef PtrVector<ObserverType> Container;
|
|
|
+ typedef Vector<ObserverType*, Alloc> Container;
|
|
|
+
|
|
|
+ Observable(const Alloc& alloc = Alloc())
|
|
|
+ : observers(alloc)
|
|
|
+ {}
|
|
|
+
|
|
|
+ ~Observable()
|
|
|
+ {
|
|
|
+ Alloc alloc = observers.get_allocator();
|
|
|
+ for(ObserverType* x : observers)
|
|
|
+ {
|
|
|
+ alloc.destroy(x);
|
|
|
+ alloc.deallocate(x, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// XXX
|
|
|
+ template<typename Observer, typename... Args>
|
|
|
+ Observer* newObserver(Args&&... args)
|
|
|
+ {
|
|
|
+ typedef typename Alloc::template rebind<Observer>::other UberAlloc;
|
|
|
+
|
|
|
+ UberAlloc alloc(observers.get_allocator());
|
|
|
+
|
|
|
+ Observer* ptr = alloc.allocate(1);
|
|
|
+ alloc.construct(ptr, std::forward<Args>(args)...);
|
|
|
+
|
|
|
+ return ptr;
|
|
|
+ }
|
|
|
|
|
|
/// Add a new observer. The Observable takes ownership of the
|
|
|
/// pointer and its responsible of cleaning
|
|
|
@@ -59,10 +89,9 @@ public:
|
|
|
/// Notify all observers
|
|
|
void notifyAll(Value x)
|
|
|
{
|
|
|
- for(typename Container::iterator it = observers.begin();
|
|
|
- it != observers.end(); ++it)
|
|
|
+ for(ObserverType* obs : observers)
|
|
|
{
|
|
|
- (*it)->notify(x);
|
|
|
+ obs->notify(x);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -95,14 +124,18 @@ private:
|
|
|
/// ANKI_SLOT(updateZFar, const float&)
|
|
|
/// };
|
|
|
/// @endcode
|
|
|
-#define ANKI_SLOT(_name, _type) \
|
|
|
- typedef SuperObserver<ObservingType, _type, &ObservingType::_name> \
|
|
|
- Observing_##_name;
|
|
|
+#define ANKI_SLOT(_slot, _type) \
|
|
|
+ typedef SuperObserver<ObservingType, _type, &ObservingType::_slot> \
|
|
|
+ Observing_##_slot;
|
|
|
|
|
|
/// Define a signal
|
|
|
#define ANKI_SIGNAL(_type, _name) \
|
|
|
Observable<_type> _name;
|
|
|
|
|
|
+/// Define a signal with allocator
|
|
|
+#define ANKI_SIGNAL_ALLOCATOR(_Type, _name, _AllocType) \
|
|
|
+ Observable<_Type, _AllocType> _name;
|
|
|
+
|
|
|
/// It doesn't do anything. Its purpose is to make the code more understandable
|
|
|
#define ANKI_EMIT this->
|
|
|
|
|
|
@@ -110,8 +143,13 @@ private:
|
|
|
/// @note Use RemovePointer so you can be able to use the macro outside of the
|
|
|
/// _receiver body
|
|
|
#define ANKI_CONNECT(_sender, _signal, _receiver, _slot) \
|
|
|
- (_sender)->_signal.addNewObserver( new \
|
|
|
- RemovePointer<decltype(_receiver)>::Type::Observing_##_slot(_receiver))
|
|
|
+ do { \
|
|
|
+ auto observer = (_sender)->_signal.newObserver< \
|
|
|
+ RemovePointer<decltype(_receiver)>::Type::Observing_##_slot>( \
|
|
|
+ _receiver); \
|
|
|
+ (_sender)->_signal.addNewObserver(observer); \
|
|
|
+ } while(false);
|
|
|
+
|
|
|
/// @}
|
|
|
/// @}
|
|
|
|