├── .gitignore ├── Makefile ├── LICENSE ├── README.md ├── main.cpp ├── NotificationCenter.cpp └── NotificationCenter.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | notification_center_example 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ -std=c++0x -Wall -Werror 2 | BUILD_DIR=./build 3 | 4 | default: notification_center_example 5 | 6 | NotificationCenter.o: NotificationCenter.cpp NotificationCenter.hpp 7 | $(CXX) -c $^ 8 | 9 | main.o: main.cpp NotificationCenter.hpp 10 | $(CXX) -c $^ 11 | 12 | notification_center_example: NotificationCenter.o main.o 13 | $(CXX) $^ -o $@ 14 | rm -f NotificationCenter.o 15 | rm -f main.o 16 | rm -f NotificationCenter.hpp.gch 17 | ./notification_center_example 18 | 19 | clean: 20 | rm -f notification_center_example 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jonathan Goodman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CPP-NotificationCenter 2 | 3 | A C++ API inspired by Cocoa's NSNotificationCenter API. 4 | 5 | ## Usage 6 | 7 | Using NotificationCenter is simple. In order to use the default center, simply use the static method `NotificationCenter::defaultNotificationCenter()` like so: 8 | ```C++ 9 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Hello world!\n");}, "My Observer"); 10 | ``` 11 | NotificationCenter is intended to be included directly in your projects, as such no library (dynamic or static) is provided. 12 | 13 | ### Supported Compilers 14 | NotificationCenter requires a compiler that supports the following C++11 APIs: 15 | ```C++ 16 | std::mutex 17 | std::function 18 | std::bind 19 | std::shared_ptr 20 | ``` 21 | It has been tested on the following compilers (as of December 15th, 2013): 22 | 23 | Compiler Name | Version | Pass/Fail | Notes 24 | --- | --- | --- | --- 25 | Clang | 3.3 | Pass | N/A 26 | MSVC | 2013 | Pass | N/A 27 | 28 | ### Adding Observers 29 | 30 | Adding observers is a simple porcess. Simply invoke the method `NotificationCenter::addObserver` on your NotificationCenter passing in a function pointer and string for the notification that this observer should respond to. A couple of examples of how to do this are: 31 | 32 | ```C++ 33 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Hello world!\n");}, "My Observer"); 34 | NotificationCenter::defaultNotificationCenter()->addObserver(helloWorldFunc, "My Observer"); 35 | Foo myFoo; 36 | NotificationCenter::defaultNotificationCenter()->addObserver(std::bind(&Foo::func, myFoo), "My Observer"); 37 | ``` 38 | 39 | Currently, only `void(void)` function signatures are supported. 40 | 41 | ### Posting Notifications 42 | Posting notifications can be done with `NotificationCenter::postNotification`, like so: 43 | 44 | ```C++ 45 | NotificationCenter::defaultNotificationCenter()->postNotification("My Observer"); 46 | ``` 47 | 48 | ### Avoiding Unnecessary Lookups 49 | Notifications can be posted and modified by either string or iterator. Posting or modifying by string incurs a string lookup, which depending on the application may not be ideal. For these situations, the best option when using NotificationCenter is to post and modify by iterator. An example of how to do this is: 50 | ```C++ 51 | NotificationCenter::notification_itr_t notiItr = NotificationCenter::defaultNotificationCenter()->getNotificationIterator("My Observer"); 52 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("I'm being posted by an iterator!\n");}, notiItr); 53 | NotificationCenter::defaultNotificationCenter()->postNotification(notiItr); 54 | ``` 55 | `NotificationCenter::addObserver`, `NotificationCenter::removeObserver`, `NotificationCenter::removeAllObservers`, and `NotificationCenter::postNotification` all support notification iterators in overloaded methods. 56 | 57 | ### Multiple NotificationCenters 58 | You can also use more than one instance of NotificationCenter. Although a default notification center is provided, you can also create your own notification centers for whatever purpose you may require them for. 59 | 60 | ### Example Program 61 | The included example program shows you the basics of how to use NotificationCenter. It's not intended to be sophisticated by any means, just to showcase the basics. 62 | 63 | ### Future 64 | As it stands, NotificationCenter is currently limited in that it only supports callbacks with the signature of `void(void)`. In the future, NotificationCenter may have support for additional function signatures either by making NotificationCenter a template, or by allowing one to specify arbitrary data in a similar way to NSNotification's userInfo parameter. 65 | 66 | ### Bugs 67 | I don't expect this to work flawlessly for all applications, and thread safety isn't something that I've tested particularly well. If you find issues, feel free to file a bug. If you wish to contribute, simply fork this repository and make a pull request. 68 | 69 | ## License 70 | NotificationCenter is licensed under the MIT license. 71 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * main.cpp 3 | * Notification Center CPP 4 | * 5 | * Created by Jonathan Goodman on 11/23/13. 6 | * Copyright (c) 2013 Jonathan Goodman. All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | #include "NotificationCenter.hpp" 29 | 30 | class Foo { 31 | 32 | public: 33 | void func() 34 | { 35 | printf("Hello std::bind!\n"); 36 | } 37 | }; 38 | 39 | void runNotification() 40 | { 41 | auto i1 = NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 1);}, "Poster"); 42 | auto i2 = NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 2);}, "Poster"); 43 | auto i3 = NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 3);}, "Poster"); 44 | auto i4 = NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 4);}, "Poster"); 45 | auto i5 = NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 5);}, "Poster"); 46 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 6);}, "Poster"); 47 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 7);}, "Poster"); 48 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Recieved notification %d!\n", 8);}, "Poster"); 49 | 50 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 51 | 52 | printf("============\n"); 53 | 54 | NotificationCenter::defaultNotificationCenter()->removeObserver("Poster", i1); 55 | 56 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 57 | 58 | printf("============\n"); 59 | 60 | NotificationCenter::defaultNotificationCenter()->removeObserver("Poster", i2); 61 | 62 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 63 | 64 | printf("============\n"); 65 | 66 | NotificationCenter::defaultNotificationCenter()->removeObserver("Poster", i3); 67 | 68 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 69 | 70 | printf("============\n"); 71 | 72 | NotificationCenter::defaultNotificationCenter()->removeObserver("Poster", i4); 73 | 74 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 75 | 76 | printf("============\n"); 77 | 78 | NotificationCenter::defaultNotificationCenter()->removeObserver("Poster", i5); 79 | 80 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 81 | 82 | printf("============\n"); 83 | 84 | NotificationCenter::defaultNotificationCenter()->removeAllObservers("Poster"); 85 | 86 | NotificationCenter::defaultNotificationCenter()->postNotification("Poster"); 87 | 88 | printf("============\n"); 89 | 90 | NotificationCenter::defaultNotificationCenter()->addObserver([=]{printf("Called by iterator!\n");}, "Second Poster"); 91 | NotificationCenter::notification_const_itr_t itr = NotificationCenter::defaultNotificationCenter()->getNotificationIterator("Second Poster"); 92 | NotificationCenter::defaultNotificationCenter()->postNotification(itr); 93 | printf("============\n"); 94 | 95 | Foo myFoo; 96 | 97 | NotificationCenter::defaultNotificationCenter()->addObserver(std::bind(&Foo::func, myFoo), "Second Poster"); 98 | NotificationCenter::defaultNotificationCenter()->postNotification("Second Poster"); 99 | 100 | } 101 | 102 | int main(int argc, const char * argv[]) 103 | { 104 | runNotification(); 105 | 106 | return 0; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /NotificationCenter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * NotificationCenter.cpp 3 | * Notification Center CPP 4 | * 5 | * Created by Jonathan Goodman on 11/23/13. 6 | * Copyright (c) 2013 Jonathan Goodman. All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | #include "NotificationCenter.hpp" 27 | 28 | std::shared_ptr NotificationCenter::_defaultCenter = nullptr; 29 | 30 | NotificationCenter::observer_const_itr_t NotificationCenter::addObserver(std::function method, const std::string& name) 31 | { 32 | std::lock_guard lock(_mutex); 33 | NotificationObserver n; 34 | n.callback = method; 35 | _observers[name].push_back(n); 36 | return --_observers[name].end(); 37 | } 38 | 39 | NotificationCenter::observer_const_itr_t NotificationCenter::addObserver(std::function method, notification_itr_t ¬ification) 40 | { 41 | std::lock_guard lock(_mutex); 42 | NotificationCenter::observer_const_itr_t retVal = notification->second.end(); 43 | if (notification != _observers.end()) 44 | { 45 | NotificationObserver n; 46 | n.callback = method; 47 | notification->second.push_back(n); 48 | retVal = --notification->second.end(); 49 | } 50 | return retVal; 51 | } 52 | 53 | void NotificationCenter::removeObserver(const std::string& name, observer_const_itr_t& observer) 54 | { 55 | std::lock_guard lock(_mutex); 56 | notification_itr_t i = _observers.find(name); 57 | if (i != _observers.end()) 58 | { 59 | i->second.erase(observer); 60 | } 61 | } 62 | 63 | void NotificationCenter::removeObserver(notification_itr_t& notification, observer_const_itr_t& observer) 64 | { 65 | std::lock_guard lock(_mutex); 66 | if (notification != _observers.end()) 67 | { 68 | notification->second.erase(observer); 69 | } 70 | } 71 | 72 | void NotificationCenter::removeAllObservers(const std::string& name) 73 | { 74 | std::lock_guard lock(_mutex); 75 | _observers.erase(name); 76 | } 77 | 78 | void NotificationCenter::removeAllObservers(notification_itr_t& notification) 79 | { 80 | std::lock_guard lock(_mutex); 81 | if (notification != _observers.end()) 82 | { 83 | _observers.erase(notification); 84 | } 85 | } 86 | 87 | bool NotificationCenter::postNotification(const std::string& notification) const 88 | { 89 | std::lock_guard lock(_mutex); 90 | notification_const_itr_t i = _observers.find(notification); 91 | if (i != _observers.end()) 92 | { 93 | const std::list& notiList = i->second; 94 | for (observer_const_itr_t ia = notiList.begin(); ia != notiList.end(); ia++) 95 | { 96 | ia->callback(); 97 | } 98 | return true; 99 | } 100 | else 101 | { 102 | printf("WARNING: Notification \"%s\" does not exist.\n", notification.data()); 103 | return false; 104 | } 105 | } 106 | 107 | bool NotificationCenter::postNotification(NotificationCenter::notification_const_itr_t& notification) const 108 | { 109 | std::lock_guard lock(_mutex); 110 | if (notification != _observers.end()) 111 | { 112 | const std::list& notiList = notification->second; 113 | for (observer_const_itr_t i = notiList.begin(); i != notiList.end(); i++) 114 | { 115 | i->callback(); 116 | } 117 | return true; 118 | } 119 | else 120 | { 121 | printf("WARNING: Notification \"%s\" does not exist.\n", notification->first.data()); 122 | return false; 123 | } 124 | } 125 | 126 | NotificationCenter::notification_itr_t NotificationCenter::getNotificationIterator(const std::string& notification) 127 | { 128 | notification_itr_t retVal; 129 | if (_observers.find(notification) != _observers.end()) 130 | { 131 | retVal = _observers.find(notification); 132 | } 133 | 134 | return retVal; 135 | } 136 | 137 | std::shared_ptr NotificationCenter::defaultNotificationCenter() 138 | { 139 | static std::mutex mutex; 140 | std::lock_guard lock(mutex); 141 | if (!_defaultCenter) 142 | { 143 | _defaultCenter = std::shared_ptr(new NotificationCenter); 144 | } 145 | 146 | return _defaultCenter; 147 | } 148 | -------------------------------------------------------------------------------- /NotificationCenter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * NotificationCenter.hpp 3 | * Notification Center CPP 4 | * 5 | * Created by Jonathan Goodman on 11/23/13. 6 | * Copyright (c) 2013 Jonathan Goodman. All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #ifndef __Notification_Center_CPP__NotificationCenter__ 28 | #define __Notification_Center_CPP__NotificationCenter__ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | struct NotificationObserver { 40 | std::function callback; 41 | }; 42 | 43 | class NotificationCenter { 44 | static std::shared_ptr _defaultCenter; 45 | std::map > _observers; 46 | mutable std::mutex _mutex; 47 | public: 48 | 49 | typedef std::map >::const_iterator notification_const_itr_t; 50 | typedef std::map >::iterator notification_itr_t; 51 | typedef std::list::const_iterator observer_const_itr_t; 52 | typedef std::list::iterator observer_itr_t; 53 | 54 | /** 55 | * This method adds a function callback as an observer to a named notification. 56 | * @param method the function callback. Accepts void(void) methods or lambdas. 57 | * @param name the name of the notification you wish to observe. 58 | */ 59 | observer_const_itr_t addObserver(std::function method, const std::string& name); 60 | 61 | /** 62 | * This method adds a function callback as an observer to a given notification. 63 | * @param method the function callback. Accepts void(void) methods or lambdas. 64 | * @param name the name of the notification you wish to observe. 65 | */ 66 | observer_const_itr_t addObserver(std::function method, notification_itr_t& notification); 67 | 68 | /** 69 | * This method removes an observer by iterator. 70 | * @param name the name of the notification you wish to remove a given observer from. 71 | * @param observer the iterator to the observer you wish to remove. 72 | */ 73 | void removeObserver(const std::string& name, observer_const_itr_t& observer); 74 | 75 | /** 76 | * This method removes an observer by iterator. 77 | * @param notification the iterator of the notification you wish to remove a given observer from. 78 | * @param observer the iterator to the observer you wish to remove. 79 | */ 80 | void removeObserver(notification_itr_t& notification, observer_const_itr_t& observer); 81 | 82 | /** 83 | * This method removes all observers from a given notification, removing the notification from being tracked outright. 84 | * @param name the name of the notification you wish to remove. 85 | */ 86 | void removeAllObservers(const std::string& name); 87 | 88 | /** 89 | * This method removes all observers from a given notification, removing the notification from being tracked outright. 90 | * @param notification the iterator of the notification you wish to remove. 91 | */ 92 | void removeAllObservers(notification_itr_t& notification); 93 | 94 | /** 95 | * This method posts a notification to a set of observers. 96 | * If successful, this function calls all callbacks associated with that notification and return true. If no such notification exists, this function will print a warning to the console and return false. 97 | * @param name the name of the notification you wish to post. 98 | */ 99 | bool postNotification(const std::string& notification) const; 100 | 101 | /** 102 | * This method posts a notification to a set of observers. 103 | * If successful, this function calls all callbacks associated with that notification and return true. If no such notification exists, this function will print a warning to the console and return false. 104 | * @param name the name of the notification you wish to post. 105 | */ 106 | bool postNotification(notification_const_itr_t& notification) const; 107 | 108 | /** 109 | * This method retrieves a notification iterator for a named notification. 110 | * The returned iterator may be used with the overloaded variants of postNotification, removeAllObservers, removeObserver, and addObserver to avoid string lookups. 111 | * @param name the name of the notification you wish to post. 112 | */ 113 | notification_itr_t getNotificationIterator(const std::string& notification); 114 | 115 | /** 116 | * This method returns the default global notification center. You may alternatively create your own notification center without using the default notification center. 117 | */ 118 | static std::shared_ptr defaultNotificationCenter(); 119 | }; 120 | 121 | #endif /* defined(__Notification_Center_CPP__NotificationCenter__) */ 122 | --------------------------------------------------------------------------------