dd7c59ad2b2e545693822ca9209f206d8c3050bb
[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 #define RADIANT_DLLEXPORT __stdcall
30 #else
31 #define RADIANT_DLLEXPORT
32 #endif
33
34
35 class Module
36 {
37 public:
38   virtual void capture() = 0;
39   virtual void release() = 0;
40   virtual void* getTable() = 0;
41 };
42
43 inline void* Module_getTable(Module& module)
44 {
45   return module.getTable();
46 }
47
48 class TextOutputStream;
49 class DebugMessageHandler;
50
51 class ModuleServer
52 {
53 public:
54   class Visitor
55   {
56   public:
57     virtual void visit(const char* name, Module& module) const = 0;
58   };
59
60   virtual void setError(bool error) = 0;
61   virtual bool getError() const = 0;
62
63   virtual TextOutputStream& getOutputStream() = 0;
64   virtual TextOutputStream& getErrorStream() = 0;
65   virtual DebugMessageHandler& getDebugMessageHandler() = 0;
66
67   virtual void registerModule(const char* type, int version, const char* name, Module& module) = 0;
68   virtual Module* findModule(const char* type, int version, const char* name) const = 0;
69   virtual void foreachModule(const char* type, int version, const Visitor& visitor) = 0;
70 };
71
72 class ModuleServerHolder
73 {
74   ModuleServer* m_server;
75 public:
76   ModuleServerHolder()
77     : m_server(0)
78   {
79   }
80   void set(ModuleServer& server)
81   {
82     m_server = &server;
83   }
84   ModuleServer& get()
85   {
86     return *m_server;
87   }
88 };
89
90 typedef Static<ModuleServerHolder> GlobalModuleServer;
91
92 inline ModuleServer& globalModuleServer()
93 {
94   return GlobalModuleServer::instance().get();
95 }
96
97
98 inline void initialiseModule(ModuleServer& server)
99 {
100   GlobalErrorStream::instance().setOutputStream(server.getErrorStream());
101   GlobalOutputStream::instance().setOutputStream(server.getOutputStream());
102   GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler());
103   GlobalModuleServer::instance().set(server);
104 }
105
106
107
108 template<typename Type>
109 class Modules
110 {
111 public:
112   class Visitor
113   {
114   public:
115     virtual void visit(const char* name, const Type& table) const = 0;
116   };
117
118   virtual Type* findModule(const char* name) = 0;
119   virtual void foreachModule(const Visitor& visitor) = 0;
120 };
121
122 #include "debugging/debugging.h"
123
124 template<typename Type>
125 class ModuleRef
126 {
127   Module* m_module;
128   Type* m_table;
129 public:
130   ModuleRef(const char* name) : m_table(0)
131   {
132     if(!globalModuleServer().getError())
133     {
134       m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name);
135       if(m_module == 0)
136       {
137         globalModuleServer().setError(true);
138         globalErrorStream() << "ModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n";
139       }
140       else
141       {
142         m_module->capture();
143         if(!globalModuleServer().getError())
144         {
145           m_table = static_cast<Type*>(m_module->getTable());
146         }
147       }
148     }
149   }
150   ~ModuleRef()
151   {
152     if(m_module != 0)
153     {
154       m_module->release();
155     }
156   }
157   Type* getTable()
158   {
159 #if defined(_DEBUG)
160     ASSERT_MESSAGE(m_table != 0, "ModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised");
161 #endif
162     return m_table;
163   }
164 };
165
166 template<typename Type>
167 class SingletonModuleRef
168 {
169   Module* m_module;
170   Type* m_table;
171 public:
172
173   SingletonModuleRef()
174     : m_module(0), m_table(0)
175   {
176   }
177
178   bool initialised() const
179   {
180     return m_module != 0;
181   }
182
183   void initialise(const char* name)
184   {
185     m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name);
186     if(m_module == 0)
187     {
188       globalModuleServer().setError(true);
189       globalErrorStream() << "SingletonModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n";
190     }
191   }
192
193   Type* getTable()
194   {
195 #if defined(_DEBUG)
196     ASSERT_MESSAGE(m_table != 0, "SingletonModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised");
197 #endif
198     return m_table;
199   }
200   void capture()
201   {
202     if(initialised())
203     {
204       m_module->capture();
205       m_table = static_cast<Type*>(m_module->getTable());
206     }
207   }
208   void release()
209   {
210     if(initialised())
211     {
212       m_module->release();
213     }
214   }
215 };
216
217 template<typename Type>
218 class GlobalModule
219 {
220   static SingletonModuleRef<Type> m_instance;
221 public:
222   static SingletonModuleRef<Type>& instance()
223   {
224     return m_instance;
225   }
226   static Type& getTable()
227   {
228     return *m_instance.getTable();
229   }
230 };
231
232 template<class Type>
233 SingletonModuleRef<Type> GlobalModule<Type>::m_instance;
234
235
236 template<typename Type>
237 class GlobalModuleRef
238 {
239 public:
240   GlobalModuleRef(const char* name = "*")
241   {
242     if(!globalModuleServer().getError())
243     {
244       GlobalModule<Type>::instance().initialise(name);
245     }
246     GlobalModule<Type>::instance().capture();
247   }
248   ~GlobalModuleRef()
249   {
250     GlobalModule<Type>::instance().release();
251   }
252   Type& getTable()
253   {
254     return GlobalModule<Type>::getTable();
255   }
256 };
257
258 #endif