Subversion Repositories gelsvn

Rev

Rev 56 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 56 Rev 67
1
#ifndef __RESOURCE_MANAGER_H
1
#ifndef __RESOURCE_MANAGER_H
2
#define __RESOURCE_MANAGER_H
2
#define __RESOURCE_MANAGER_H
3
 
3
 
4
#include <cassert>
4
#include <cassert>
5
#include <string>
5
#include <string>
6
#include <list>
6
#include <list>
7
#include <typeinfo>
7
#include <typeinfo>
8
 
8
 
9
#define CLEAN_SHUTDOWN 1
9
#define CLEAN_SHUTDOWN 1
10
 
10
 
11
namespace Util
11
namespace Util
12
{
12
{
13
 
13
 
14
	typedef unsigned char FlagByte;
14
	typedef unsigned char FlagByte;
15
	const FlagByte REMOVE_WHEN_UNUSED = 0x01;
15
	const FlagByte REMOVE_WHEN_UNUSED = 0x01;
16
	const FlagByte STATIC_RESOURCE    = 0x02;
16
	const FlagByte STATIC_RESOURCE    = 0x02;
17
 
17
 
18
	/** This class template represents a resource record. There is a pointer to 
18
	/** This class template represents a resource record. There is a pointer to 
19
			the actual resource (of type RES) and a usage counter which should never
19
			the actual resource (of type RES) and a usage counter which should never
20
			be less than 0. */
20
			be less than 0. */
21
	template<class RES>
21
	template<class RES>
22
	class ResourceRecord
22
	class ResourceRecord
23
	{
23
	{
24
		/// Name of the resource (const)
24
		/// Name of the resource (const)
25
    const std::string name;
25
    const std::string name;
26
 
26
 
27
		/// A pointer to the resource (the pointer not the pointee is const)
27
		/// A pointer to the resource (the pointer not the pointee is const)
28
		RES * const res;
28
		RES * const res;
29
		
29
		
30
		/// Usage counter.
30
		/// Usage counter.
31
		int usage;
31
		int usage;
32
 
32
 
33
		/// Flags
33
		/// Flags
34
		FlagByte flags;
34
		FlagByte flags;
35
 
35
 
36
	public:
36
	public:
37
	
37
	
38
		/// Construct a null record.
38
		/// Construct a null record.
39
		ResourceRecord(): res(0), usage(0), flags(0) {}
39
		ResourceRecord(): res(0), usage(0), flags(0) {}
40
 
40
 
41
		/// Construct a resource record with a name and a pointer.
41
		/// Construct a resource record with a name and a pointer.
42
		ResourceRecord(const std::string& _name, RES* _res, bool static_res=false): 
42
		ResourceRecord(const std::string& _name, RES* _res, bool static_res=false): 
43
			name(_name), 
43
			name(_name), 
44
			res(_res), 
44
			res(_res), 
45
			usage(0), 
45
			usage(0), 
46
			flags(static_res ? STATIC_RESOURCE : 0) 
46
			flags(static_res ? STATIC_RESOURCE : 0) 
47
		{
47
		{
48
			assert(res != 0);
48
			assert(res != 0);
49
		}
49
		}
50
 
50
 
51
		~ResourceRecord() 
51
		~ResourceRecord() 
52
		{
52
		{
53
#if CLEAN_SHUTDOWN
53
#if CLEAN_SHUTDOWN
54
			assert(usage==0);		
54
			assert(usage==0);		
55
#endif
55
#endif
56
		}
56
		}
57
	
57
	
58
		void erase_resource()
58
		void erase_resource()
59
		{
59
		{
60
			assert(usage==0);
60
			assert(usage==0);
61
			if(!(flags&STATIC_RESOURCE)) 
61
			if(!(flags&STATIC_RESOURCE)) 
62
				{
62
				{
63
					delete res;
63
					delete res;
64
				}
64
				}
65
		}
65
		}
66
 
66
 
67
		/// Increment the usage counter
67
		/// Increment the usage counter
68
		void increment_usage() 
68
		void increment_usage() 
69
		{
69
		{
70
			assert(usage>=0);
70
			assert(usage>=0);
71
			++usage;
71
			++usage;
72
		}
72
		}
73
 
73
 
74
		/// Decrement the usage counter. assert that counter is >0
74
		/// Decrement the usage counter. assert that counter is >0
75
		void decrement_usage() 
75
		void decrement_usage() 
76
		{
76
		{
77
			assert(usage>0);
77
			assert(usage>0);
78
			--usage;
78
			--usage;
79
		}
79
		}
80
 
80
 
81
		/// Return the usage count (mostly for debugging)
81
		/// Return the usage count (mostly for debugging)
82
		int get_usage() const { return usage; }
82
		int get_usage() const { return usage; }
83
 
83
 
84
		/// Get the name of a resource
84
		/// Get the name of a resource
85
		const std::string& get_name() const {return name;}
85
		const std::string& get_name() const {return name;}
86
 
86
 
87
		/// Get a pointer to the resource (const pointer)
87
		/// Get a pointer to the resource (const pointer)
88
		RES * const get_ptr() 
88
		RES * const get_ptr() 
89
		{
89
		{
90
			return res;
90
			return res;
91
		}
91
		}
92
 
92
 
93
		/// Get a resource pointer (const pointer and pointee)
93
		/// Get a resource pointer (const pointer and pointee)
94
		const RES * const get_ptr() const 
94
		const RES * const get_ptr() const 
95
		{
95
		{
96
			return res;
96
			return res;
97
		}
97
		}
98
 
98
 
99
		void remove_when_unused() 
99
		void remove_when_unused() 
100
		{
100
		{
101
/* 			assert(!(flags&STATIC_RESOURCE)); */
101
/* 			assert(!(flags&STATIC_RESOURCE)); */
102
/* 			if(!(flags&STATIC_RESOURCE)) */
102
/* 			if(!(flags&STATIC_RESOURCE)) */
103
				flags = flags|REMOVE_WHEN_UNUSED;
103
				flags = flags|REMOVE_WHEN_UNUSED;
104
		}
104
		}
105
 
105
 
106
		FlagByte get_flags() const { return flags;}
106
		FlagByte get_flags() const { return flags;}
107
	
107
	
108
	};
108
	};
109
 
109
 
110
 
110
 
111
	template<class RES> class ResourceManager;
111
	template<class RES> class ResourceManager;
112
 
112
 
113
 
113
 
114
	/** The ResourcePtr class template is a template for a reference
114
	/** The ResourcePtr class template is a template for a reference
115
			counted resource pointer. It is a smart pointer that actually points
115
			counted resource pointer. It is a smart pointer that actually points
116
			to a ResourceRecord and not to the actual resource. Since the record
116
			to a ResourceRecord and not to the actual resource. Since the record
117
			contains a reference count, we can increase the reference count when
117
			contains a reference count, we can increase the reference count when
118
			the pointer is copied and decrease it in the destructor. Only the
118
			the pointer is copied and decrease it in the destructor. Only the
119
			ResourceManager can create ResourcePtr's directly from a raw
119
			ResourceManager can create ResourcePtr's directly from a raw
120
			ResourceRecord. */
120
			ResourceRecord. */
121
	template<class RES>
121
	template<class RES>
122
	class ResourcePtr
122
	class ResourcePtr
123
	{
123
	{
124
		typedef ResourceRecord<RES> RR;
124
		typedef ResourceRecord<RES> RR;
125
		typedef std::list<RR> RRList;
125
		typedef std::list<RR> RRList;
126
		typedef typename RRList::iterator RRListIter;
126
		typedef typename RRList::iterator RRListIter;
127
 
127
 
128
		friend class ResourceManager<RES>;
128
		friend class ResourceManager<RES>;
129
 
129
 
130
	private:
130
	private:
131
		RRListIter rr;
131
		RRListIter rr;
132
		RES* res;
132
		RES* res;
133
	
133
	
134
		/** Explicit constructor with value. The constructor can only be called
134
		/** Explicit constructor with value. The constructor can only be called
135
				by a friend, i.e. the resource manager. */
135
				by a friend, i.e. the resource manager. */
136
		explicit ResourcePtr(const RRListIter& _rr): rr(_rr), res(0)
136
		explicit ResourcePtr(const RRListIter& _rr): rr(_rr), res(0)
137
		{
137
		{
138
			if(rr != 0)
138
			if(rr != 0)
139
				{
139
				{
140
					rr->increment_usage();
140
					rr->increment_usage();
141
					res = rr->get_ptr();
141
					res = rr->get_ptr();
142
				}
142
				}
143
		}
143
		}
144
 
144
 
145
		void decrement_usage();
145
		void decrement_usage();
146
	
146
	
147
	public:
147
	public:
148
	
148
	
149
		ResourcePtr(): rr(0), res(0) {}
149
		ResourcePtr(): rr(0), res(0) {}
150
	
150
	
151
		ResourcePtr(const ResourcePtr& r2): rr(r2.rr), res(0)
151
		ResourcePtr(const ResourcePtr& r2): rr(r2.rr), res(0)
152
		{
152
		{
153
			if(rr != 0)
153
			if(rr != 0)
154
				{
154
				{
155
					rr->increment_usage();
155
					rr->increment_usage();
156
					res = rr->get_ptr();
156
					res = rr->get_ptr();
157
				}
157
				}
158
		}
158
		}
159
 
159
 
160
		const ResourcePtr& operator=(const ResourcePtr& r2) 
160
		const ResourcePtr& operator=(const ResourcePtr& r2) 
161
		{
161
		{
162
			// Guard against self-assignment
162
			// Guard against self-assignment
163
			if (r2.rr != this->rr)
163
			if (r2.rr != this->rr)
164
				{
164
				{
165
					if(rr != 0)	decrement_usage();
165
					if(rr != 0)	decrement_usage();
166
 
166
 
167
					rr  = r2.rr;
167
					rr  = r2.rr;
168
					res = 0;
168
					res = 0;
169
 
169
 
170
					if(rr != 0)
170
					if(rr != 0)
171
						{
171
						{
172
							res = rr->get_ptr();
172
							res = rr->get_ptr();
173
							rr->increment_usage();
173
							rr->increment_usage();
174
						}
174
						}
175
				}
175
				}
176
			return *this;
176
			return *this;
177
		}
177
		}
178
 
178
 
179
		~ResourcePtr() {decrement_usage();}
179
		~ResourcePtr() {decrement_usage();}
180
 
180
 
181
		RES& operator*() const 
181
		RES& operator*() const 
182
		{
182
		{
183
			assert(rr != 0);
183
			assert(rr != 0);
184
			assert(res != 0);
184
			assert(res != 0);
185
			return *res;
185
			return *res;
186
		}
186
		}
187
 
187
 
188
		RES* const operator->() const 
188
		RES* const operator->() const 
189
		{
189
		{
190
			assert(rr != 0);
190
			assert(rr != 0);
191
			assert(res !=0);
191
			assert(res !=0);
192
			return res;
192
			return res;
193
		}
193
		}
194
 
194
 
195
		RES* const get_raw_ptr() const 
195
		RES* const get_raw_ptr() const 
196
		{
196
		{
197
			assert(rr != 0);
197
			assert(rr != 0);
198
			assert(res != 0);
198
			assert(res != 0);
199
			return res;
199
			return res;
200
		}
200
		}
201
 
201
 
202
		int usage() const
202
		int usage() const
203
		{
203
		{
204
			if(rr != 0)
204
			if(rr != 0)
205
				return rr->get_usage();
205
				return rr->get_usage();
206
			return -1;
206
			return -1;
207
		}
207
		}
208
 
208
 
209
		bool is_valid() const {return rr != 0;}
209
		bool is_valid() const {return rr != 0;}
210
 
210
 
211
		void relinquish_resource()
211
		void relinquish_resource()
212
		{
212
		{
213
			ResourcePtr p;
213
			ResourcePtr p;
214
			*this = p;
214
			*this = p;
215
		}
215
		}
216
 
216
 
217
		/** Calling this function sets the REMOVE_WHEN_UNUSED flag. If this 
217
		/** Calling this function sets the REMOVE_WHEN_UNUSED flag. If this 
218
				flag is set, the resource record is removed from the manager */
218
				flag is set, the resource record is removed from the manager */
219
		void remove_when_unused() {	rr->remove_when_unused(); }
219
		void remove_when_unused() {	rr->remove_when_unused(); }
220
	};
220
	};
221
 
221
 
222
 
222
 
223
	/** The ResourceManager is a singleton, and it uses Scott Meyers construct
223
	/** The ResourceManager is a singleton, and it uses Scott Meyers construct
224
			on first use idiom, i.e. the static function get_instance() will
224
			on first use idiom, i.e. the static function get_instance() will
225
			construct it when first called. There may be a problem with this
225
			construct it when first called. There may be a problem with this
226
			idion if resources depend on each other. However, that is only
226
			idion if resources depend on each other. However, that is only
227
			when the program shuts down.  See modern C++ design by
227
			when the program shuts down.  See modern C++ design by
228
			Alexandrescu for more information.
228
			Alexandrescu for more information.
229
 
229
 
230
			I'll try to make everything in this class private and accessed
230
			I'll try to make everything in this class private and accessed
231
			by a simple interface of friend functions.
231
			by a simple interface of friend functions.
232
 
232
 
233
	*/
233
	*/
234
 
234
 
235
	template<class RES>
235
	template<class RES>
236
	class ResourceManager
236
	class ResourceManager
237
	{
237
	{
238
		typedef ResourceRecord<RES> RR;
238
		typedef ResourceRecord<RES> RR;
239
		typedef std::list<RR> RRList;
239
		typedef std::list<RR> RRList;
240
		typedef typename RRList::iterator RRListIter;
240
		typedef typename RRList::iterator RRListIter;
241
		RRList resources;
241
		RRList resources;
242
	
242
	
243
		ResourceManager(): resources(0) {}
243
		ResourceManager(): resources(0) {}
244
		ResourceManager(const ResourceManager&);
244
		ResourceManager(const ResourceManager&);
245
		ResourceManager& operator=(const ResourceManager&);
245
		ResourceManager& operator=(const ResourceManager&);
246
 
246
 
247
	public:
247
	public:
248
 
248
 
249
 
249
 
250
		~ResourceManager()
250
		~ResourceManager()
251
		{
251
		{
252
#if CLEAN_SHUTDOWN
252
#if CLEAN_SHUTDOWN
253
			RRListIter i = resources.begin(); 
253
			RRListIter i = resources.begin(); 
254
			while(i != resources.end())
254
			while(i != resources.end())
255
				{
255
				{
256
					if(i->get_usage()==0)
256
					if(i->get_usage()==0)
257
						{
257
						{
258
							RRListIter tmp = i;
258
							RRListIter tmp = i;
259
							++i;
259
							++i;
260
							erase_resource(tmp);
260
							erase_resource(tmp);
261
						}
261
						}
262
					else
262
					else
263
						{
263
						{
264
							std::cout << "Warning, ResourceManager:\n\n"
264
							std::cout << "Warning, ResourceManager:\n\n"
265
												<< (typeid(this).name())
265
												<< (typeid(this).name())
266
												<< "\n\nis shutting down, and resource \n\n" 
266
												<< "\n\nis shutting down, and resource \n\n" 
267
												<< i->get_name() << "\n\nhas usage: " << i->get_usage()
267
												<< i->get_name() << "\n\nhas usage: " << i->get_usage()
268
												<< std::endl;
268
												<< std::endl;
269
							std::cout <<
269
							std::cout <<
270
 								"In other words, this resource is not unused at this\n"
270
 								"In other words, this resource is not unused at this\n"
271
								"point. That is unfortunate because then it cannot\n"
271
								"point. That is unfortunate because then it cannot\n"
272
								"be deleted (since it might be used by some other\n"
272
								"be deleted (since it might be used by some other\n"
273
								"part of the program during shutdown). Please ensure\n"
273
								"part of the program during shutdown). Please ensure\n"
274
								"that all resources are unused at program\n"
274
								"that all resources are unused at program\n"
275
								"termination. If you use a global ResourcePtr, this is\n"
275
								"termination. If you use a global ResourcePtr, this is\n"
276
								"done by calling relinquish_resource just before\n"
276
								"done by calling relinquish_resource just before\n"
277
								"exiting.\n"
277
								"exiting.\n"
278
												<< std::endl;
278
												<< std::endl;
279
							++i;
279
							++i;
280
						}
280
						}
281
				}
281
				}
282
#endif
282
#endif
283
		}
283
		}
284
 
284
 
285
		int get_no_resources() const
285
		int get_no_resources() const
286
		{
286
		{
287
			return resources.size();
287
			return resources.size();
288
		}
288
		}
289
 
289
 
290
		static ResourceManager& get_instance() 
290
		static ResourceManager& get_instance() 
291
		{
291
		{
292
			static ResourceManager instance;
292
			static ResourceManager instance;
293
			return instance;
293
			return instance;
294
		}
294
		}
295
 
295
 
296
		void erase_resource(RRListIter iter)
296
		void erase_resource(RRListIter iter)
297
		{
297
		{
298
			iter->erase_resource();
298
			iter->erase_resource();
299
			resources.erase(iter);
299
			resources.erase(iter);
300
		}
300
		}
301
 
301
 
302
		/** Find a resource and return a ResourcePtr to it. Returns the 
302
		/** Find a resource and return a ResourcePtr to it. Returns the 
303
				0 ResourcePtr if no string found. */
303
				0 ResourcePtr if no string found. */
304
		ResourcePtr<RES> get_resource_ptr(const std::string& str)
304
		ResourcePtr<RES> get_resource_ptr(const std::string& str)
305
		{
305
		{
306
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
306
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
307
				if((*i).get_name() == str) 
307
				if((*i).get_name() == str) 
308
					return ResourcePtr<RES>(i);
308
					return ResourcePtr<RES>(i);
309
			return ResourcePtr<RES>(0);
309
			return ResourcePtr<RES>(0);
310
		}
310
		}
311
 
311
 
312
		/** Add a resource with name passed as first argument and a pointer
312
		/** Add a resource with name passed as first argument and a pointer
313
				passed as 2nd argument. A ResourcePtr to the just inserted
313
				passed as 2nd argument. A ResourcePtr to the just inserted
314
				element is returned. */
314
				element is returned. */
315
		ResourcePtr<RES> register_resource(const std::string& str, 
315
		ResourcePtr<RES> register_resource(const std::string& str, 
316
																			 RES* res, bool static_resource)
316
																			 RES* res, bool static_resource)
317
		{
317
		{
318
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
318
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
319
				if(i->get_name() == str)
319
				if(i->get_name() == str)
320
					return (ResourcePtr<RES>(0));
320
					return (ResourcePtr<RES>(0));
321
 
321
 
322
			resources.push_front(RR(str, res, static_resource));
322
			resources.push_front(RR(str, res, static_resource));
323
			ResourcePtr<RES> ptr = ResourcePtr<RES>(resources.begin());
323
			ResourcePtr<RES> ptr = ResourcePtr<RES>(resources.begin());
324
			return ptr;
324
			return ptr;
325
		}
325
		}
326
 
326
 
327
/*		friend class ResourcePtr<RES>;
327
/*		friend class ResourcePtr<RES>;
328
		friend int get_no_resources<RES>();
328
		friend int get_no_resources<RES>();
329
		friend ResourcePtr<RES> get_resource_ptr<RES>(const std::string& str); 
329
		friend ResourcePtr<RES> get_resource_ptr<RES>(const std::string& str); 
330
		friend ResourcePtr<RES> register_static_resource<RES>(const std::string&,
330
		friend ResourcePtr<RES> register_static_resource<RES>(const std::string&,
331
																													RES*); 
331
																													RES*); 
332
		friend ResourcePtr<RES> register_dynamic_resource<RES>(const std::string&,
332
		friend ResourcePtr<RES> register_dynamic_resource<RES>(const std::string&,
333
																													 RES*);*/ 
333
																													 RES*);*/ 
334
	};
334
	};
335
 
335
 
336
	template<class RES>
336
	template<class RES>
337
	inline void ResourcePtr<RES>::decrement_usage()
337
	inline void ResourcePtr<RES>::decrement_usage()
338
	{
338
	{
339
		assert( (rr == 0) || (res != 0));
339
		assert( (rr == 0) || (res != 0));
340
		if(rr != 0)
340
		if(rr != 0)
341
			{
341
			{
342
				rr->decrement_usage();
342
				rr->decrement_usage();
343
				if(rr->get_usage() == 0 && (rr->get_flags()&REMOVE_WHEN_UNUSED))
343
				if(rr->get_usage() == 0 && (rr->get_flags()&REMOVE_WHEN_UNUSED))
344
					{
344
					{
345
						ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
345
						ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
346
						man.erase_resource(rr);
346
						man.erase_resource(rr);
347
					}
347
					}
348
			}
348
			}
349
	}
349
	}
350
 
350
 
351
	template<class RES>
351
	template<class RES>
352
	inline int get_no_resources()
352
	inline int get_no_resources()
353
	{
353
	{
354
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
354
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
355
		return man.get_no_resources();
355
		return man.get_no_resources();
356
	}
356
	}
357
 
357
 
358
	template<class RES>
358
	template<class RES>
359
	inline ResourcePtr<RES> get_resource_ptr(const std::string& str)
359
	inline ResourcePtr<RES> get_resource_ptr(const std::string& str)
360
	{
360
	{
361
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
361
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
362
		return man.get_resource_ptr(str);
362
		return man.get_resource_ptr(str);
363
	}
363
	}
364
 
364
 
365
	template<class RES>
365
	template<class RES>
366
	inline ResourcePtr<RES> register_dynamic_resource(const std::string& str,RES* res)
366
	inline ResourcePtr<RES> register_dynamic_resource(const std::string& str,RES* res)
367
	{
367
	{
368
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
368
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
369
		ResourcePtr<RES> ptr = man.register_resource(str, res, false);
369
		ResourcePtr<RES> ptr = man.register_resource(str, res, false);
370
		return ptr;
370
		return ptr;
371
	}
371
	}
372
 
372
 
373
	template<class RES>
373
	template<class RES>
374
	inline ResourcePtr<RES> register_static_resource(const std::string& str,RES* res)
374
	inline ResourcePtr<RES> register_static_resource(const std::string& str,RES* res)
375
	{
375
	{
376
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
376
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
377
		ResourcePtr<RES> ptr = man.register_resource(str, res, true);
377
		ResourcePtr<RES> ptr = man.register_resource(str, res, true);
378
		return ptr;
378
		return ptr;
379
	}
379
	}
380
 
380
 
381
}
381
}
382
 
382
 
383
 
383
 
384
#endif
384
#endif
385
 
385