git-svn-id: svn://svn.icculus.org/netradiant/trunk@54 61c419a2-8eb2-4b30-bcec-8cead03...
[xonotic/netradiant.git] / include / modulesystem.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_MODULESYSTEM_H)
23 #define INCLUDED_MODULESYSTEM_H
24
25 #include "generic/static.h"
26 #include "debugging/debugging.h"
27
28 #if defined(WIN32)
29 #ifdef MINGW32
30 #define RADIANT_DLLEXPORT __declspec(dllexport)
31 #define RADIANT_DLLIMPORT __declspec(dllimport)
32 #else
33 #define RADIANT_DLLEXPORT __stdcall
34 #define RADIANT_DLLIMPORT __stdcall
35 #endif
36 #else
37 #define RADIANT_DLLEXPORT
38 #define RADIANT_DLLIMPORT
39 #endif
40
41
42 class Module
43 {
44 public:
45   virtual void capture() = 0;
46   virtual void release() = 0;
47   virtual void* getTable() = 0;
48 };
49
50 inline void* Module_getTable(Module& module)
51 {
52   return module.getTable();
53 }
54
55 class TextOutputStream;
56 class DebugMessageHandler;
57
58 class ModuleServer
59 {
60 public:
61   class Visitor
62   {
63   public:
64     virtual void visit(const char* name, Module& module) const = 0;
65   };
66
67   virtual void setError(bool error) = 0;
68   virtual bool getError() const = 0;
69
70   virtual TextOutputStream& getOutputStream() = 0;
71   virtual TextOutputStream& getErrorStream() = 0;
72   virtual DebugMessageHandler& getDebugMessageHandler() = 0;
73
74   virtual void registerModule(const char* type, int version, const char* name, Module& module) = 0;
75   virtual Module* findModule(const char* type, int version, const char* name) const = 0;
76   virtual void foreachModule(const char* type, int version, const Visitor& visitor) = 0;
77 };
78
79 class ModuleServerHolder
80 {
81   ModuleServer* m_server;
82 public:
83   ModuleServerHolder()
84     : m_server(0)
85   {
86   }
87   void set(ModuleServer& server)
88   {
89     m_server = &server;
90   }
91   ModuleServer& get()
92   {
93     return *m_server;
94   }
95 };
96
97 typedef Static<ModuleServerHolder> GlobalModuleServer;
98
99 inline ModuleServer& globalModuleServer()
100 {
101   return GlobalModuleServer::instance().get();
102 }
103
104
105 inline void initialiseModule(ModuleServer& server)
106 {
107   GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
108   GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
109   GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
110   GlobalModuleServer::instance().set(server);
111 }
112
113
114
115 template<typename Type>
116 class Modules
117 {
118 public:
119   class Visitor
120   {
121   public:
122     virtual void visit(const char* name, const Type& table) const = 0;
123   };
124
125   virtual Type* findModule(const char* name) = 0;
126   virtual void foreachModule(const Visitor& visitor) = 0;
127 };
128
129 #include "debugging/debugging.h"
130
131 template<typename Type>
132 class ModuleRef
133 {
134   Module* m_module;
135   Type* m_table;
136 public:
137   ModuleRef(const char* name) : m_table(0)
138   {
139     if(!globalModuleServer().getError())
140     {
141       m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name);
142       if(m_module == 0)
143       {
144         globalModuleServer().setError(true);
145         globalErrorStream() << "ModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n";
146       }
147       else
148       {
149         m_module->capture();
150         if(!globalModuleServer().getError())
151         {
152           m_table = static_cast<Type*>(m_module->getTable());
153         }
154       }
155     }
156   }
157   ~ModuleRef()
158   {
159     if(m_module != 0)
160     {
161       m_module->release();
162     }
163   }
164   Type* getTable()
165   {
166 #if defined(_DEBUG)
167     ASSERT_MESSAGE(m_table != 0, "ModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised");
168 #endif
169     return m_table;
170   }
171 };
172
173 template<typename Type>
174 class SingletonModuleRef
175 {
176   Module* m_module;
177   Type* m_table;
178 public:
179
180   SingletonModuleRef()
181     : m_module(0), m_table(0)
182   {
183   }
184
185   bool initialised() const
186   {
187     return m_module != 0;
188   }
189
190   void initialise(const char* name)
191   {
192     m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name);
193     if(m_module == 0)
194     {
195       globalModuleServer().setError(true);
196       globalErrorStream() << "SingletonModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n";
197     }
198   }
199
200   Type* getTable()
201   {
202 #if defined(_DEBUG)
203     ASSERT_MESSAGE(m_table != 0, "SingletonModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised");
204 #endif
205     return m_table;
206   }
207   void capture()
208   {
209     if(initialised())
210     {
211       m_module->capture();
212       m_table = static_cast<Type*>(m_module->getTable());
213     }
214   }
215   void release()
216   {
217     if(initialised())
218     {
219       m_module->release();
220     }
221   }
222 };
223
224 template<typename Type>
225 class GlobalModule
226 {
227   static SingletonModuleRef<Type> m_instance;
228 public:
229   static SingletonModuleRef<Type>& instance()
230   {
231     return m_instance;
232   }
233   static Type& getTable()
234   {
235     return *m_instance.getTable();
236   }
237 };
238
239 template<class Type>
240 SingletonModuleRef<Type> GlobalModule<Type>::m_instance;
241
242
243 template<typename Type>
244 class GlobalModuleRef
245 {
246 public:
247   GlobalModuleRef(const char* name = "*")
248   {
249     if(!globalModuleServer().getError())
250     {
251       GlobalModule<Type>::instance().initialise(name);
252     }
253     GlobalModule<Type>::instance().capture();
254   }
255   ~GlobalModuleRef()
256   {
257     GlobalModule<Type>::instance().release();
258   }
259   Type& getTable()
260   {
261     return GlobalModule<Type>::getTable();
262   }
263 };
264
265 #endif