Skip to content

Instantly share code, notes, and snippets.

@mortennobel
Last active July 3, 2018 14:46
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mortennobel/6327279 to your computer and use it in GitHub Desktop.
Save mortennobel/6327279 to your computer and use it in GitHub Desktop.
C++11 Observer Version 2
//
// Event.h
//
// Created by Morten Nobel-Jørgensen on 8/18/13.
// Copyright (c) 2013 morten. All rights reserved.
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause)
#pragma once
#include <iostream>
#include <functional>
#include "EventListener.h"
#include <vector>
#include <utility>
class AbstractEvent{
public:
virtual bool removeListener(int id) = 0;
};
template <typename E>
class Event : public AbstractEvent{
public:
EventListener<E> createListener(std::function<void (E)> listener){
listeners.emplace_back(listener, eventListenerId);
eventListenerId++;
return EventListener<E>(this, eventListenerId-1);
}
void registerSyncValue(SyncValue<E>& syncValue){
if (syncValue.listenerId > -1){
removeListener(syncValue.listenerId);
}
std::function<void (E)> updateFunction = [&](E e){
syncValue.value = e;
};
listeners.emplace_back(updateFunction, eventListenerId, 0);
syncValue.listenerId = eventListenerId;
syncValue.ae = this;
eventListenerId++;
}
void notifyListeners(E e){
for (auto & l : listeners){
l.first(e);
}
}
bool removeListener(int id){
auto iter = listeners.begin();
while (iter != listeners.end()){
if (iter->second == id){
listeners.erase(iter);
return true;
}
iter++;
}
return false;
}
protected:
std::vector<std::pair<std::function<void (E)>, int>> listeners;
friend class EventListener<E>;
int eventListenerId = 0;
};
//
// EventListener.cpp
//
// Created by Morten Nobel-Jørgensen on 8/18/13.
// Copyright (c) 2013 morten. All rights reserved.
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause)
#include "EventListener.h"
#include "Event.h"
AbstractEventListener::AbstractEventListener(AbstractEvent *ae, int listenerId)
:ae(ae), listenerId(listenerId){
}
AbstractEventListener::~AbstractEventListener(){
destroyListener();
}
void AbstractEventListener::destroyListener(){
if (ae){
ae->removeListener(listenerId);
}
}
//
// EventListener.h
//
// Created by Morten Nobel-Jørgensen on 8/18/13.
// Copyright (c) 2013 morten. All rights reserved.
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause)
#pragma once
#include <iostream>
class AbstractEvent;
class AbstractEventListener{
public:
AbstractEventListener(){};
AbstractEventListener(AbstractEvent *ae, int listenerId);
AbstractEventListener(const AbstractEventListener&) = delete;
AbstractEventListener& operator=( const AbstractEventListener& rhs ) = delete;
virtual ~AbstractEventListener();
friend class AbstractEvent;
protected:
void destroyListener();
int listenerId = -1;
AbstractEvent *ae = nullptr;
};
template <typename E>
class Event;
template <typename E>
class EventListener : public AbstractEventListener {
public:
EventListener(){
}
EventListener(Event<E> *e, int listenerId)
:AbstractEventListener(e, listenerId)
{
}
EventListener(const EventListener&) = delete;
EventListener& operator=( const EventListener& rhs ) = delete;
EventListener(EventListener&& other){
listenerId = other.listenerId;
ae = other.ae;
other.ae = nullptr;
}
EventListener& operator=( EventListener&& rhs ) {
if (this != &rhs){
destroyListener();
listenerId = rhs.listenerId;
ae = rhs.ae;
rhs.ae = nullptr;
}
return *this;
};
friend class Event<E>;
};
template <typename E>
class SyncValue : public AbstractEventListener {
public:
SyncValue(){
}
E& getValue(){
return value;
}
SyncValue(const SyncValue&) = delete;
SyncValue& operator=( const SyncValue& rhs ) = delete;
SyncValue(SyncValue&& other){
listenerId = other.listenerId;
ae = other.ae;
value = std::move(other.value);
other.ae = nullptr;
}
SyncValue& operator=( SyncValue&& rhs ) {
if (this != &rhs){
destroyListener();
listenerId = rhs.listenerId;
ae = rhs.ae;
value = std::move(rhs.value);
rhs.ae = nullptr;
}
return *this;
};
friend class Event<E>;
private:
E value;
};
//
// main.cpp
// Observer pattern in C++11
//
// Created by Morten Nobel-Jørgensen on 8/18/13.
// Copyright (c) 2012 Morten Nobel-Joergensen. All rights reserved.
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause)
#include <iostream>
#include <iostream>
#include <functional>
#include <vector>
#include <map>
#include <string>
#include <utility>
#include "Event.h"
#include "EventListener.h"
using namespace std;
class Foo {
public:
Foo(){
}
Event<int> event;
void setValue(int i){
value = i;
event.notifyListeners(i);
}
private:
int value;
};
class Moo {
public:
Moo(Foo *f) {
f->event.registerSyncValue(syncVal);
eventListener = f->event.createListener([](int v){
cout<<"Value is "<<v<<endl;
});
}
SyncValue<int> syncVal;
private:
EventListener<int> eventListener;
};
int main(int argc, const char * argv[])
{
Foo f;
{
Moo m(&f);
f.setValue(123);
cout << "synched value " << m.syncVal.getValue()<<endl;;
f.setValue(12);
cout << "synched value " << m.syncVal.getValue()<<endl;;
}
f.setValue(1234);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment