Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/singleton/Scope.h @ 10407

Last change on this file since 10407 was 10407, checked in by landauf, 9 years ago

moved Scope and ScopedSingletonManager from util to core.
TODO I had to disable two tests in ScopeTest.cc because now that it runs in the core library, there are too many singletons which get loaded in graphics scope (with too many dependencies). this should be fixed

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30@file
31@ingroup SingletonScope
32@brief Declaration of the classes that are needed to use Scopes:
33orxonox::Scope, orxonox::ScopeListener, and orxonox::ScopeManager.
34
35@anchor Scope
36
37A virtual scope can be represented by an instance of class orxonox::Scope. orxonox::Scope<@a scope> is a template
38an its template argument defines the name of the virtual scope. See orxonox::ScopeID for an enumeration of the
39available values for @a scope. The orxonox::Scope object for a given @a scope can be activated or deactivated.
40Instances of orxonox::ScopeListener can register for a given @a scope and will get a notification if the
41corresponding orxonox::Scope object changes its state.
42
43To avoid multiple instances of orxonox::Scope<@a scope> in different libraries, each instance of orxonox::Scope
44registers in orxonox::ScopeManager, where they are linked statically in the core library.
45
46Scopes are usually used to control the creation and destruction of Singletons.
47
48@see orxonox::ScopedSingletonManager
49@see orxonox::Singleton
50*/
51
52#ifndef __Core_Scope_H__
53#define __Core_Scope_H__
54
55#include "core/CorePrereqs.h"
56
57#include <cassert>
58#include <map>
59#include <set>
60#include <loki/ScopeGuard.h>
61
62#include "util/Output.h"
63
64namespace orxonox
65{
66    /**
67        @brief The ScopeManager stores the variables of the Scope templates in a statically linked context.
68
69        If all Scope objects are managed by this class, they are statically linked in the core library.
70        Without this, a new instance of Scope<T> for each T would be created in every library of Orxonox,
71        which is of course not the desired behavior.
72
73        @see See @ref Scope "this description" for details about the interrelationship of Scope, ScopeListener, and ScopeManager.
74    */
75    class _CoreExport ScopeManager
76    {
77        template <ScopeID::Value scope>
78        friend class Scope;
79        friend class ScopeListener;
80
81        private:
82            static std::map<ScopeID::Value, int> instanceCounts_s;                  //!< Counts the number of active instances (>0 means active) for a scope
83            static std::map<ScopeID::Value, std::set<ScopeListener*> > listeners_s; //!< Stores all listeners for a scope
84    };
85
86    /**
87        @brief ScopeListeners register themselves in the corresponding Scope and wait for notifications.
88        Notifications are sent if a Scope is activated or deactivated.
89
90        @see See @ref Scope "this description" for details about the interrelationship of Scope, ScopeListener, and ScopeManager.
91    */
92    class _CoreExport ScopeListener
93    {
94        template <ScopeID::Value scope>
95        friend class Scope;
96
97        protected:
98            //! Constructor: Registers the instance.
99            ScopeListener(ScopeID::Value scope) : scope_(scope), bActivated_(false)
100                { ScopeManager::listeners_s[this->scope_].insert(this); }
101            //! Destructor: Unregisters the instance.
102            virtual ~ScopeListener()
103                { ScopeManager::listeners_s[this->scope_].erase(this); }
104
105            //! Gets called if the scope is activated
106            virtual void activated() = 0;
107            //! Gets called if the scope is deactivated
108            virtual void deactivated() = 0;
109
110        private:
111            ScopeID::Value scope_; //!< Store the scope to unregister on destruction
112            bool bActivated_;
113    };
114
115    /**
116        @brief A scope for a given template argument is either active or not.
117
118        Objects inheriting from a ScopeListener are registered in a list (different for each scope).
119        If the scope gets activated or deactivated, all objects in this list are notified.
120
121        @see See @ref Scope "this description" for details about the interrelationship of Scope, ScopeListener, and ScopeManager.
122    */
123    template <ScopeID::Value scope>
124    class Scope
125    {
126        public:
127            //! Constructor: Increases the instance counter and activates the scope if the count went from 0 to 1. Counts >1 don't change anything.
128            Scope()
129            {
130                orxout(internal_status) << "creating scope... (" << scope << ")" << endl;
131
132                try
133                {
134                    ScopeManager::instanceCounts_s[scope]++;
135                    assert(ScopeManager::instanceCounts_s[scope] > 0);
136                    if (ScopeManager::instanceCounts_s[scope] == 1)
137                    {
138                        Loki::ScopeGuard deactivator = Loki::MakeObjGuard(*this, &Scope::deactivateListeners);
139                        for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
140                        {
141                            (*it)->activated();
142                            (*(it++))->bActivated_ = true;
143                        }
144                        deactivator.Dismiss();
145                    }
146                }
147                catch (...)
148                {
149                    ScopeManager::instanceCounts_s[scope]--;
150                    throw;
151                }
152
153                orxout(internal_status) << "created scope (" << scope << ")" << endl;
154            }
155
156            //! Destructor: Decreases the instance counter and deactivates the scope if the count went from 1 to 0. Counts >0 don't change anything.
157            ~Scope()
158            {
159                orxout(internal_status) << "destroying scope... (" << scope << ")" << endl;
160
161                ScopeManager::instanceCounts_s[scope]--;
162
163                // This shouldn't happen but just to be sure: check if the count is positive
164                assert(ScopeManager::instanceCounts_s[scope] >= 0);
165                if (ScopeManager::instanceCounts_s[scope] < 0)
166                    ScopeManager::instanceCounts_s[scope] = 0;
167
168                if (ScopeManager::instanceCounts_s[scope] == 0)
169                    this->deactivateListeners();
170
171                orxout(internal_status) << "destroyed scope (" << scope << ")" << endl;
172            }
173
174            //! Deactivates the listeners of this scope in case the scope is destroyed or the construction fails.
175            void deactivateListeners()
176            {
177                for (typename std::set<ScopeListener*>::iterator it = ScopeManager::listeners_s[scope].begin(); it != ScopeManager::listeners_s[scope].end(); )
178                {
179                    if ((*it)->bActivated_)
180                    {
181                        try
182                            { (*it)->deactivated(); }
183                        catch (...)
184                            { orxout(internal_warning) << "ScopeListener::deactivated() failed! This MUST NOT happen, fix it!" << endl; }
185                        (*(it++))->bActivated_ = false;
186                    }
187                    else
188                        ++it;
189                }
190            }
191
192            //! Returns true if the scope is active.
193            static bool isActive()
194            {
195                return (ScopeManager::instanceCounts_s[scope] > 0);
196            }
197    };
198}
199
200#endif /* __Core_Scope_H__ */
Note: See TracBrowser for help on using the repository browser.