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