1 ////////////////////////////////////////////////////////////////////////////////
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
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "persistent_contexts.hpp"
10 #include "persistent.hpp"
19 ////////////////////////////////////////////////////////////////////////////////
20 // File format version
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
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
28 unsigned char PersistentVersion
= 2;
30 ////////////////////////////////////////////////////////////////////////////////
31 // avoid creating dependencies on other libraries
33 static std::string
to_string(int number
)
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
;
43 static bool little_endian(void)
45 // TODO - find a compile-time way of doing this
47 char* sample_bytes
= (char*)&sample
;
48 return sample_bytes
[0] != 0;
51 ////////////////////////////////////////////////////////////////////////////////
52 // dump context classes
53 ////////////////////////////////////////////////////////////////////////////////
55 class dump_context_body
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
;
63 unsigned char m_version
;
65 std::ostream
* m_device
;
67 callback_map m_callbacks
;
68 interface_map m_interfaces
;
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
)
73 // write the version number as a single byte
75 // map a null pointer onto magic number zero
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
));
82 void put(unsigned char data
) throw(persistent_dump_failed
)
84 if (!m_device
->put(data
))
85 throw persistent_dump_failed(std::string("output device error"));
88 const std::ostream
& device(void) const
93 unsigned char version(void) const
98 bool little_endian(void) const
100 return m_little_endian
;
103 std::pair
<bool,unsigned> pointer_map(const void* const pointer
)
105 magic_map::iterator found
= m_pointers
.find(pointer
);
106 if (found
== m_pointers
.end())
109 unsigned magic
= m_pointers
.size();
110 m_pointers
[pointer
] = magic
;
111 return std::pair
<bool,unsigned>(false,magic
);
113 // return the old mapping
114 return std::pair
<bool,unsigned>(true,found
->second
);
117 unsigned register_callback(const std::type_info
& info
, dump_context::dump_callback callback
)
119 std::string key
= info
.name();
120 unsigned data
= ++m_max_key
;
121 m_callbacks
[key
] = std::make_pair(data
,callback
);
125 bool is_callback(const std::type_info
& info
) const
127 return m_callbacks
.find(info
.name()) != m_callbacks
.end();
130 dump_context::callback_data
lookup_callback(const std::type_info
& info
) const throw(persistent_illegal_type
)
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
;
139 unsigned register_interface(const std::type_info
& info
)
141 std::string key
= info
.name();
142 unsigned data
= ++m_max_key
;
143 m_interfaces
[key
] = data
;
147 bool is_interface(const std::type_info
& info
) const
149 return m_interfaces
.find(info
.name()) != m_interfaces
.end();
152 unsigned lookup_interface(const std::type_info
& info
) const throw(persistent_illegal_type
)
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
;
162 ////////////////////////////////////////////////////////////////////////////////
164 dump_context::dump_context(std::ostream
& device
, unsigned char version
) throw(persistent_dump_failed
) : m_body(0)
166 m_body
= new dump_context_body(device
,version
);
169 dump_context::~dump_context(void)
174 void dump_context::put(unsigned char data
) throw(persistent_dump_failed
)
179 const std::ostream
& dump_context::device(void) const
181 return m_body
->device();
184 unsigned char dump_context::version(void) const
186 return m_body
->version();
189 bool dump_context::little_endian(void) const
191 return m_body
->little_endian();
194 std::pair
<bool,unsigned> dump_context::pointer_map(const void* const pointer
)
196 return m_body
->pointer_map(pointer
);
199 unsigned dump_context::register_callback(const std::type_info
& info
, dump_context::dump_callback callback
)
201 return m_body
->register_callback(info
,callback
);
204 bool dump_context::is_callback(const std::type_info
& info
) const
206 return m_body
->is_callback(info
);
209 dump_context::callback_data
dump_context::lookup_callback(const std::type_info
& info
) const throw(persistent_illegal_type
)
211 return m_body
->lookup_callback(info
);
214 unsigned dump_context::register_interface(const std::type_info
& info
)
216 return m_body
->register_interface(info
);
219 bool dump_context::is_interface(const std::type_info
& info
) const
221 return m_body
->is_interface(info
);
224 unsigned dump_context::lookup_interface(const std::type_info
& info
) const throw(persistent_illegal_type
)
226 return m_body
->lookup_interface(info
);
229 void dump_context::register_all(dump_context::installer installer
)
231 if (installer
) installer(*this);
234 ////////////////////////////////////////////////////////////////////////////////
235 // restore context classes
236 ////////////////////////////////////////////////////////////////////////////////
238 class restore_context_body
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
;
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
;
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
)
257 // map a null pointer onto magic number zero
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
));
265 ~restore_context_body(void)
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
];
273 const std::istream
& device(void) const
278 unsigned char version(void) const
283 bool little_endian(void) const
285 return m_little_endian
;
288 int get(void) throw(persistent_restore_failed
)
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"));
296 std::pair
<bool,void*> pointer_map(unsigned magic
)
298 magic_map::iterator found
= m_pointers
.find(magic
);
299 if (found
== m_pointers
.end())
301 // this magic number has never been seen before
302 return std::pair
<bool,void*>(false,0);
304 return std::pair
<bool,void*>(true,found
->second
);
307 void pointer_add(unsigned magic
, void* new_pointer
)
309 m_pointers
[magic
] = new_pointer
;
312 unsigned register_callback(restore_context::create_callback create
, restore_context::restore_callback restore
)
314 unsigned key
= ++m_max_key
;
315 m_callbacks
[key
] = std::make_pair(create
,restore
);
319 bool is_callback(unsigned key
) const
321 return m_callbacks
.find(key
) != m_callbacks
.end();
324 restore_context::callback_data
lookup_callback(unsigned key
) const throw(persistent_illegal_type
)
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
;
332 unsigned register_interface(persistent
* sample
)
334 unsigned key
= ++m_max_key
;
335 m_interfaces
[key
] = sample
;
339 bool is_interface(unsigned key
) const
341 return m_interfaces
.find(key
) != m_interfaces
.end();
344 persistent
* lookup_interface(unsigned key
) const throw(persistent_illegal_type
)
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
;
353 ////////////////////////////////////////////////////////////////////////////////
355 restore_context::restore_context(std::istream
& device
) throw(persistent_restore_failed
) :
358 m_body
= new restore_context_body(device
);
361 restore_context::~restore_context(void)
366 const std::istream
& restore_context::device(void) const
368 return m_body
->device();
371 unsigned char restore_context::version(void) const
373 return m_body
->version();
376 bool restore_context::little_endian(void) const
378 return m_body
->little_endian();
381 int restore_context::get(void) throw(persistent_restore_failed
)
383 return m_body
->get();
386 std::pair
<bool,void*> restore_context::pointer_map(unsigned magic
)
388 return m_body
->pointer_map(magic
);
391 void restore_context::pointer_add(unsigned magic
, void* new_pointer
)
393 m_body
->pointer_add(magic
,new_pointer
);
396 unsigned restore_context::register_callback(restore_context::create_callback create
, restore_context::restore_callback restore
)
398 return m_body
->register_callback(create
,restore
);
401 bool restore_context::is_callback(unsigned key
) const
403 return m_body
->is_callback(key
);
406 restore_context::callback_data
restore_context::lookup_callback(unsigned key
) const throw(persistent_illegal_type
)
408 return m_body
->lookup_callback(key
);
411 unsigned restore_context::register_interface(persistent
* sample
)
413 return m_body
->register_interface(sample
);
416 bool restore_context::is_interface(unsigned key
) const
418 return m_body
->is_interface(key
);
421 persistent
* restore_context::lookup_interface(unsigned key
) const throw(persistent_illegal_type
)
423 return m_body
->lookup_interface(key
);
426 void restore_context::register_all(restore_context::installer installer
)
428 if (installer
) installer(*this);
431 ////////////////////////////////////////////////////////////////////////////////
433 } // end namespace stlplus