]> Dogcows Code - chaz/yoink/blob - src/stlplus/persistence/persistent_contexts.cpp
archiving support for releases
[chaz/yoink] / src / stlplus / persistence / persistent_contexts.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
7
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "persistent_contexts.hpp"
10 #include "persistent.hpp"
11 #include <map>
12 #include <string>
13 #include <stdio.h>
14
15 namespace stlplus
16 {
17
18
19 ////////////////////////////////////////////////////////////////////////////////
20 // File format version
21
22 // This relates to the layout of basic types - if I change the file layout of,
23 // say, int or vector, then this will change
24
25 // Early versions of the persistence routines did not have this - they are no longer supported
26 // - Change from version 1 to 2: changed the persistent representation of inf
27
28 unsigned char PersistentVersion = 2;
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // avoid creating dependencies on other libraries
32
33 static std::string to_string(int number)
34 {
35 // use sprintf in a very controlled way that cannot overrun
36 char* buffer = new char[50];
37 sprintf(buffer, "%i", number);
38 std::string result = buffer;
39 delete buffer;
40 return result;
41 }
42
43 static bool little_endian(void)
44 {
45 // TODO - find a compile-time way of doing this
46 int sample = 1;
47 char* sample_bytes = (char*)&sample;
48 return sample_bytes[0] != 0;
49 }
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // dump context classes
53 ////////////////////////////////////////////////////////////////////////////////
54
55 class dump_context_body
56 {
57 public:
58 typedef std::map<const void*,unsigned> magic_map;
59 typedef std::map<std::string,dump_context::callback_data> callback_map;
60 typedef std::map<std::string,unsigned> interface_map;
61
62 unsigned m_max_key;
63 unsigned char m_version;
64 bool m_little_endian;
65 std::ostream* m_device;
66 magic_map m_pointers;
67 callback_map m_callbacks;
68 interface_map m_interfaces;
69
70 dump_context_body(std::ostream& device, unsigned char version) throw(persistent_dump_failed) :
71 m_max_key(0), m_version(version), m_little_endian(stlplus::little_endian()), m_device(&device)
72 {
73 // write the version number as a single byte
74 put(version);
75 // map a null pointer onto magic number zero
76 m_pointers[0] = 0;
77 // test whether the version number is supported
78 if (m_version != 1 && m_version != 2)
79 throw persistent_dump_failed(std::string("wrong version: ") + to_string(m_version));
80 }
81
82 void put(unsigned char data) throw(persistent_dump_failed)
83 {
84 if (!m_device->put(data))
85 throw persistent_dump_failed(std::string("output device error"));
86 }
87
88 const std::ostream& device(void) const
89 {
90 return *m_device;
91 }
92
93 unsigned char version(void) const
94 {
95 return m_version;
96 }
97
98 bool little_endian(void) const
99 {
100 return m_little_endian;
101 }
102
103 std::pair<bool,unsigned> pointer_map(const void* const pointer)
104 {
105 magic_map::iterator found = m_pointers.find(pointer);
106 if (found == m_pointers.end())
107 {
108 // add a new mapping
109 unsigned magic = m_pointers.size();
110 m_pointers[pointer] = magic;
111 return std::pair<bool,unsigned>(false,magic);
112 }
113 // return the old mapping
114 return std::pair<bool,unsigned>(true,found->second);
115 }
116
117 unsigned register_callback(const std::type_info& info, dump_context::dump_callback callback)
118 {
119 std::string key = info.name();
120 unsigned data = ++m_max_key;
121 m_callbacks[key] = std::make_pair(data,callback);
122 return data;
123 }
124
125 bool is_callback(const std::type_info& info) const
126 {
127 return m_callbacks.find(info.name()) != m_callbacks.end();
128 }
129
130 dump_context::callback_data lookup_callback(const std::type_info& info) const throw(persistent_illegal_type)
131 {
132 std::string key = info.name();
133 callback_map::const_iterator found = m_callbacks.find(key);
134 if (found == m_callbacks.end())
135 throw persistent_illegal_type(key);
136 return found->second;
137 }
138
139 unsigned register_interface(const std::type_info& info)
140 {
141 std::string key = info.name();
142 unsigned data = ++m_max_key;
143 m_interfaces[key] = data;
144 return data;
145 }
146
147 bool is_interface(const std::type_info& info) const
148 {
149 return m_interfaces.find(info.name()) != m_interfaces.end();
150 }
151
152 unsigned lookup_interface(const std::type_info& info) const throw(persistent_illegal_type)
153 {
154 std::string key = info.name();
155 interface_map::const_iterator found = m_interfaces.find(key);
156 if (found == m_interfaces.end())
157 throw persistent_illegal_type(key);
158 return found->second;
159 }
160 };
161
162 ////////////////////////////////////////////////////////////////////////////////
163
164 dump_context::dump_context(std::ostream& device, unsigned char version) throw(persistent_dump_failed) : m_body(0)
165 {
166 m_body = new dump_context_body(device,version);
167 }
168
169 dump_context::~dump_context(void)
170 {
171 delete m_body;
172 }
173
174 void dump_context::put(unsigned char data) throw(persistent_dump_failed)
175 {
176 m_body->put(data);
177 }
178
179 const std::ostream& dump_context::device(void) const
180 {
181 return m_body->device();
182 }
183
184 unsigned char dump_context::version(void) const
185 {
186 return m_body->version();
187 }
188
189 bool dump_context::little_endian(void) const
190 {
191 return m_body->little_endian();
192 }
193
194 std::pair<bool,unsigned> dump_context::pointer_map(const void* const pointer)
195 {
196 return m_body->pointer_map(pointer);
197 }
198
199 unsigned dump_context::register_callback(const std::type_info& info, dump_context::dump_callback callback)
200 {
201 return m_body->register_callback(info,callback);
202 }
203
204 bool dump_context::is_callback(const std::type_info& info) const
205 {
206 return m_body->is_callback(info);
207 }
208
209 dump_context::callback_data dump_context::lookup_callback(const std::type_info& info) const throw(persistent_illegal_type)
210 {
211 return m_body->lookup_callback(info);
212 }
213
214 unsigned dump_context::register_interface(const std::type_info& info)
215 {
216 return m_body->register_interface(info);
217 }
218
219 bool dump_context::is_interface(const std::type_info& info) const
220 {
221 return m_body->is_interface(info);
222 }
223
224 unsigned dump_context::lookup_interface(const std::type_info& info) const throw(persistent_illegal_type)
225 {
226 return m_body->lookup_interface(info);
227 }
228
229 void dump_context::register_all(dump_context::installer installer)
230 {
231 if (installer) installer(*this);
232 }
233
234 ////////////////////////////////////////////////////////////////////////////////
235 // restore context classes
236 ////////////////////////////////////////////////////////////////////////////////
237
238 class restore_context_body
239 {
240 public:
241 typedef persistent* persistent_ptr;
242 typedef std::map<unsigned,void*> magic_map;
243 typedef std::map<unsigned,restore_context::callback_data> callback_map;
244 typedef std::map<unsigned,persistent_ptr> interface_map;
245
246 unsigned m_max_key;
247 unsigned char m_version;
248 bool m_little_endian;
249 std::istream* m_device;
250 magic_map m_pointers;
251 callback_map m_callbacks;
252 interface_map m_interfaces;
253
254 restore_context_body(std::istream& device) throw(persistent_restore_failed) :
255 m_max_key(0), m_little_endian(stlplus::little_endian()), m_device(&device)
256 {
257 // map a null pointer onto magic number zero
258 m_pointers[0] = 0;
259 // get the dump version and see if we support it
260 m_version = (unsigned char)get();
261 if (m_version != 1 && m_version != 2)
262 throw persistent_restore_failed(std::string("wrong version: ") + to_string(m_version));
263 }
264
265 ~restore_context_body(void)
266 {
267 // need to delete all interfaces
268 // I used to use smart_ptr_clone for storing them but I want to disconnect as many dependencies as possible
269 for (unsigned i = 0; i < m_interfaces.size(); i++)
270 delete m_interfaces[i];
271 }
272
273 const std::istream& device(void) const
274 {
275 return *m_device;
276 }
277
278 unsigned char version(void) const
279 {
280 return m_version;
281 }
282
283 bool little_endian(void) const
284 {
285 return m_little_endian;
286 }
287
288 int get(void) throw(persistent_restore_failed)
289 {
290 int result = m_device->get();
291 if (!m_device->good())
292 throw persistent_restore_failed(std::string("device error or premature end of file"));
293 return result;
294 }
295
296 std::pair<bool,void*> pointer_map(unsigned magic)
297 {
298 magic_map::iterator found = m_pointers.find(magic);
299 if (found == m_pointers.end())
300 {
301 // this magic number has never been seen before
302 return std::pair<bool,void*>(false,0);
303 }
304 return std::pair<bool,void*>(true,found->second);
305 }
306
307 void pointer_add(unsigned magic, void* new_pointer)
308 {
309 m_pointers[magic] = new_pointer;
310 }
311
312 unsigned register_callback(restore_context::create_callback create, restore_context::restore_callback restore)
313 {
314 unsigned key = ++m_max_key;
315 m_callbacks[key] = std::make_pair(create,restore);
316 return key;
317 }
318
319 bool is_callback(unsigned key) const
320 {
321 return m_callbacks.find(key) != m_callbacks.end();
322 }
323
324 restore_context::callback_data lookup_callback(unsigned key) const throw(persistent_illegal_type)
325 {
326 callback_map::const_iterator found = m_callbacks.find(key);
327 if (found == m_callbacks.end())
328 throw persistent_illegal_type(key);
329 return found->second;
330 }
331
332 unsigned register_interface(persistent* sample)
333 {
334 unsigned key = ++m_max_key;
335 m_interfaces[key] = sample;
336 return key;
337 }
338
339 bool is_interface(unsigned key) const
340 {
341 return m_interfaces.find(key) != m_interfaces.end();
342 }
343
344 persistent* lookup_interface(unsigned key) const throw(persistent_illegal_type)
345 {
346 interface_map::const_iterator found = m_interfaces.find(key);
347 if (found == m_interfaces.end())
348 throw persistent_illegal_type(key);
349 return found->second;
350 }
351 };
352
353 ////////////////////////////////////////////////////////////////////////////////
354
355 restore_context::restore_context(std::istream& device) throw(persistent_restore_failed) :
356 m_body(0)
357 {
358 m_body = new restore_context_body(device);
359 }
360
361 restore_context::~restore_context(void)
362 {
363 delete m_body;
364 }
365
366 const std::istream& restore_context::device(void) const
367 {
368 return m_body->device();
369 }
370
371 unsigned char restore_context::version(void) const
372 {
373 return m_body->version();
374 }
375
376 bool restore_context::little_endian(void) const
377 {
378 return m_body->little_endian();
379 }
380
381 int restore_context::get(void) throw(persistent_restore_failed)
382 {
383 return m_body->get();
384 }
385
386 std::pair<bool,void*> restore_context::pointer_map(unsigned magic)
387 {
388 return m_body->pointer_map(magic);
389 }
390
391 void restore_context::pointer_add(unsigned magic, void* new_pointer)
392 {
393 m_body->pointer_add(magic,new_pointer);
394 }
395
396 unsigned restore_context::register_callback(restore_context::create_callback create, restore_context::restore_callback restore)
397 {
398 return m_body->register_callback(create,restore);
399 }
400
401 bool restore_context::is_callback(unsigned key) const
402 {
403 return m_body->is_callback(key);
404 }
405
406 restore_context::callback_data restore_context::lookup_callback(unsigned key) const throw(persistent_illegal_type)
407 {
408 return m_body->lookup_callback(key);
409 }
410
411 unsigned restore_context::register_interface(persistent* sample)
412 {
413 return m_body->register_interface(sample);
414 }
415
416 bool restore_context::is_interface(unsigned key) const
417 {
418 return m_body->is_interface(key);
419 }
420
421 persistent* restore_context::lookup_interface(unsigned key) const throw(persistent_illegal_type)
422 {
423 return m_body->lookup_interface(key);
424 }
425
426 void restore_context::register_all(restore_context::installer installer)
427 {
428 if (installer) installer(*this);
429 }
430
431 ////////////////////////////////////////////////////////////////////////////////
432
433 } // end namespace stlplus
434
This page took 0.047616 seconds and 4 git commands to generate.