X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fstlplus%2Fpersistence%2Fpersistent_contexts.cpp;fp=src%2Fstlplus%2Fpersistence%2Fpersistent_contexts.cpp;h=008fa9fba4eab6107e7e38f02dcf5183730a375c;hb=6b0a0d0efafe34d48ab344fca3b479553bd4e62c;hp=0000000000000000000000000000000000000000;hpb=85783316365181491a3e3c0c63659972477cebba;p=chaz%2Fyoink diff --git a/src/stlplus/persistence/persistent_contexts.cpp b/src/stlplus/persistence/persistent_contexts.cpp new file mode 100644 index 0000000..008fa9f --- /dev/null +++ b/src/stlplus/persistence/persistent_contexts.cpp @@ -0,0 +1,434 @@ +//////////////////////////////////////////////////////////////////////////////// + +// Author: Andy Rushton +// Copyright: (c) Southampton University 1999-2004 +// (c) Andy Rushton 2004-2009 +// License: BSD License, see ../docs/license.html + +//////////////////////////////////////////////////////////////////////////////// +#include "persistent_contexts.hpp" +#include "persistent.hpp" +#include +#include +#include + +namespace stlplus +{ + + + //////////////////////////////////////////////////////////////////////////////// + // File format version + + // This relates to the layout of basic types - if I change the file layout of, + // say, int or vector, then this will change + + // Early versions of the persistence routines did not have this - they are no longer supported + // - Change from version 1 to 2: changed the persistent representation of inf + + unsigned char PersistentVersion = 2; + + //////////////////////////////////////////////////////////////////////////////// + // avoid creating dependencies on other libraries + + static std::string to_string(int number) + { + // use sprintf in a very controlled way that cannot overrun + char* buffer = new char[50]; + sprintf(buffer, "%i", number); + std::string result = buffer; + delete buffer; + return result; + } + + static bool little_endian(void) + { + // TODO - find a compile-time way of doing this + int sample = 1; + char* sample_bytes = (char*)&sample; + return sample_bytes[0] != 0; + } + + //////////////////////////////////////////////////////////////////////////////// + // dump context classes + //////////////////////////////////////////////////////////////////////////////// + + class dump_context_body + { + public: + typedef std::map magic_map; + typedef std::map callback_map; + typedef std::map interface_map; + + unsigned m_max_key; + unsigned char m_version; + bool m_little_endian; + std::ostream* m_device; + magic_map m_pointers; + callback_map m_callbacks; + interface_map m_interfaces; + + dump_context_body(std::ostream& device, unsigned char version) throw(persistent_dump_failed) : + m_max_key(0), m_version(version), m_little_endian(stlplus::little_endian()), m_device(&device) + { + // write the version number as a single byte + put(version); + // map a null pointer onto magic number zero + m_pointers[0] = 0; + // test whether the version number is supported + if (m_version != 1 && m_version != 2) + throw persistent_dump_failed(std::string("wrong version: ") + to_string(m_version)); + } + + void put(unsigned char data) throw(persistent_dump_failed) + { + if (!m_device->put(data)) + throw persistent_dump_failed(std::string("output device error")); + } + + const std::ostream& device(void) const + { + return *m_device; + } + + unsigned char version(void) const + { + return m_version; + } + + bool little_endian(void) const + { + return m_little_endian; + } + + std::pair pointer_map(const void* const pointer) + { + magic_map::iterator found = m_pointers.find(pointer); + if (found == m_pointers.end()) + { + // add a new mapping + unsigned magic = m_pointers.size(); + m_pointers[pointer] = magic; + return std::pair(false,magic); + } + // return the old mapping + return std::pair(true,found->second); + } + + unsigned register_callback(const std::type_info& info, dump_context::dump_callback callback) + { + std::string key = info.name(); + unsigned data = ++m_max_key; + m_callbacks[key] = std::make_pair(data,callback); + return data; + } + + bool is_callback(const std::type_info& info) const + { + return m_callbacks.find(info.name()) != m_callbacks.end(); + } + + dump_context::callback_data lookup_callback(const std::type_info& info) const throw(persistent_illegal_type) + { + std::string key = info.name(); + callback_map::const_iterator found = m_callbacks.find(key); + if (found == m_callbacks.end()) + throw persistent_illegal_type(key); + return found->second; + } + + unsigned register_interface(const std::type_info& info) + { + std::string key = info.name(); + unsigned data = ++m_max_key; + m_interfaces[key] = data; + return data; + } + + bool is_interface(const std::type_info& info) const + { + return m_interfaces.find(info.name()) != m_interfaces.end(); + } + + unsigned lookup_interface(const std::type_info& info) const throw(persistent_illegal_type) + { + std::string key = info.name(); + interface_map::const_iterator found = m_interfaces.find(key); + if (found == m_interfaces.end()) + throw persistent_illegal_type(key); + return found->second; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + + dump_context::dump_context(std::ostream& device, unsigned char version) throw(persistent_dump_failed) : m_body(0) + { + m_body = new dump_context_body(device,version); + } + + dump_context::~dump_context(void) + { + delete m_body; + } + + void dump_context::put(unsigned char data) throw(persistent_dump_failed) + { + m_body->put(data); + } + + const std::ostream& dump_context::device(void) const + { + return m_body->device(); + } + + unsigned char dump_context::version(void) const + { + return m_body->version(); + } + + bool dump_context::little_endian(void) const + { + return m_body->little_endian(); + } + + std::pair dump_context::pointer_map(const void* const pointer) + { + return m_body->pointer_map(pointer); + } + + unsigned dump_context::register_callback(const std::type_info& info, dump_context::dump_callback callback) + { + return m_body->register_callback(info,callback); + } + + bool dump_context::is_callback(const std::type_info& info) const + { + return m_body->is_callback(info); + } + + dump_context::callback_data dump_context::lookup_callback(const std::type_info& info) const throw(persistent_illegal_type) + { + return m_body->lookup_callback(info); + } + + unsigned dump_context::register_interface(const std::type_info& info) + { + return m_body->register_interface(info); + } + + bool dump_context::is_interface(const std::type_info& info) const + { + return m_body->is_interface(info); + } + + unsigned dump_context::lookup_interface(const std::type_info& info) const throw(persistent_illegal_type) + { + return m_body->lookup_interface(info); + } + + void dump_context::register_all(dump_context::installer installer) + { + if (installer) installer(*this); + } + + //////////////////////////////////////////////////////////////////////////////// + // restore context classes + //////////////////////////////////////////////////////////////////////////////// + + class restore_context_body + { + public: + typedef persistent* persistent_ptr; + typedef std::map magic_map; + typedef std::map callback_map; + typedef std::map interface_map; + + unsigned m_max_key; + unsigned char m_version; + bool m_little_endian; + std::istream* m_device; + magic_map m_pointers; + callback_map m_callbacks; + interface_map m_interfaces; + + restore_context_body(std::istream& device) throw(persistent_restore_failed) : + m_max_key(0), m_little_endian(stlplus::little_endian()), m_device(&device) + { + // map a null pointer onto magic number zero + m_pointers[0] = 0; + // get the dump version and see if we support it + m_version = (unsigned char)get(); + if (m_version != 1 && m_version != 2) + throw persistent_restore_failed(std::string("wrong version: ") + to_string(m_version)); + } + + ~restore_context_body(void) + { + // need to delete all interfaces + // I used to use smart_ptr_clone for storing them but I want to disconnect as many dependencies as possible + for (unsigned i = 0; i < m_interfaces.size(); i++) + delete m_interfaces[i]; + } + + const std::istream& device(void) const + { + return *m_device; + } + + unsigned char version(void) const + { + return m_version; + } + + bool little_endian(void) const + { + return m_little_endian; + } + + int get(void) throw(persistent_restore_failed) + { + int result = m_device->get(); + if (!m_device->good()) + throw persistent_restore_failed(std::string("device error or premature end of file")); + return result; + } + + std::pair pointer_map(unsigned magic) + { + magic_map::iterator found = m_pointers.find(magic); + if (found == m_pointers.end()) + { + // this magic number has never been seen before + return std::pair(false,0); + } + return std::pair(true,found->second); + } + + void pointer_add(unsigned magic, void* new_pointer) + { + m_pointers[magic] = new_pointer; + } + + unsigned register_callback(restore_context::create_callback create, restore_context::restore_callback restore) + { + unsigned key = ++m_max_key; + m_callbacks[key] = std::make_pair(create,restore); + return key; + } + + bool is_callback(unsigned key) const + { + return m_callbacks.find(key) != m_callbacks.end(); + } + + restore_context::callback_data lookup_callback(unsigned key) const throw(persistent_illegal_type) + { + callback_map::const_iterator found = m_callbacks.find(key); + if (found == m_callbacks.end()) + throw persistent_illegal_type(key); + return found->second; + } + + unsigned register_interface(persistent* sample) + { + unsigned key = ++m_max_key; + m_interfaces[key] = sample; + return key; + } + + bool is_interface(unsigned key) const + { + return m_interfaces.find(key) != m_interfaces.end(); + } + + persistent* lookup_interface(unsigned key) const throw(persistent_illegal_type) + { + interface_map::const_iterator found = m_interfaces.find(key); + if (found == m_interfaces.end()) + throw persistent_illegal_type(key); + return found->second; + } + }; + + //////////////////////////////////////////////////////////////////////////////// + + restore_context::restore_context(std::istream& device) throw(persistent_restore_failed) : + m_body(0) + { + m_body = new restore_context_body(device); + } + + restore_context::~restore_context(void) + { + delete m_body; + } + + const std::istream& restore_context::device(void) const + { + return m_body->device(); + } + + unsigned char restore_context::version(void) const + { + return m_body->version(); + } + + bool restore_context::little_endian(void) const + { + return m_body->little_endian(); + } + + int restore_context::get(void) throw(persistent_restore_failed) + { + return m_body->get(); + } + + std::pair restore_context::pointer_map(unsigned magic) + { + return m_body->pointer_map(magic); + } + + void restore_context::pointer_add(unsigned magic, void* new_pointer) + { + m_body->pointer_add(magic,new_pointer); + } + + unsigned restore_context::register_callback(restore_context::create_callback create, restore_context::restore_callback restore) + { + return m_body->register_callback(create,restore); + } + + bool restore_context::is_callback(unsigned key) const + { + return m_body->is_callback(key); + } + + restore_context::callback_data restore_context::lookup_callback(unsigned key) const throw(persistent_illegal_type) + { + return m_body->lookup_callback(key); + } + + unsigned restore_context::register_interface(persistent* sample) + { + return m_body->register_interface(sample); + } + + bool restore_context::is_interface(unsigned key) const + { + return m_body->is_interface(key); + } + + persistent* restore_context::lookup_interface(unsigned key) const throw(persistent_illegal_type) + { + return m_body->lookup_interface(key); + } + + void restore_context::register_all(restore_context::installer installer) + { + if (installer) installer(*this); + } + + //////////////////////////////////////////////////////////////////////////////// + +} // end namespace stlplus +