Subversion Repositories gelsvn

Rev

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

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