libs/serialization/src/extended_type_info.cpp
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// extended_type_info.cpp: implementation for portable version of type_info
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#if (defined _MSC_VER) && (_MSC_VER == 1200)
# pragma warning (disable : 4786) // too long name, harmless warning
#endif
#include <algorithm>
#include <set>
#include <cassert>
#include <boost/config.hpp> // msvc needs this to suppress warning
#include <cstring>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{ using ::strcmp; }
#endif
#include <boost/detail/no_exceptions_support.hpp>
#define BOOST_SERIALIZATION_SOURCE
#include <boost/serialization/extended_type_info.hpp>
namespace boost {
namespace serialization {
// remove all registrations corresponding to a given type
void unregister_void_casts(extended_type_info *eti);
namespace detail {
// it turns out that at least one compiler (msvc 6.0) doesn't guarentee
// to destroy static objects in exactly the reverse sequence that they
// are constructed. To guarentee this, use a singleton pattern
// map for finding the unique global extended type entry for a given type
class tkmap {
struct type_info_compare
{
bool
operator()(const extended_type_info * lhs, const extended_type_info * rhs) const
{
assert(! lhs->is_destructing());
assert(! rhs->is_destructing());
return *lhs < *rhs;
}
};
// typedef std::multiset<const extended_type_info *, type_info_compare> type;
typedef std::set<const extended_type_info *, type_info_compare> type;
type m_map;
static tkmap * m_self;
tkmap(){}
static tkmap::type::iterator
lookup(const extended_type_info * eti){
return m_self->m_map.find(eti);
}
public:
~tkmap(){
m_self = NULL;
}
static void
insert(const extended_type_info * eti){
if(NULL == m_self){
static tkmap instance;
m_self = & instance;
}
// make sure that attempt at registration is done only once
assert(lookup(eti) == m_self->m_map.end());
m_self->m_map.insert(eti);
}
static const extended_type_info *
find(const extended_type_info * eti){
if(NULL == m_self)
return NULL;
tkmap::type::const_iterator it;
it = m_self->m_map.find(eti);
if(it == m_self->m_map.end())
return NULL;
return *it;
}
static void
purge(const extended_type_info * eti){
if(NULL == m_self)
return;
// note: the following can't be used as this function
// is called from a destructor of extended_type_info.
// This will generate an error on some machines - which
// makes sense be cause by this time the derived class data
// might be gone. Leave this in as a reminder not to do this
#if 0
tkmap::type::iterator it;
it = lookup(eti);
// it should be in there
assert(it != m_self->m_map.end());
m_self->m_map.erase(it);
#endif
tkmap::type::iterator i = m_self->m_map.begin();
tkmap::type::iterator k = m_self->m_map.end();
while(i != k){
// note that the erase might invalidate i so save it here
tkmap::type::iterator j = i++;
if(*j == eti)
m_self->m_map.erase(j);
}
}
};
tkmap * tkmap::m_self = NULL;
// map for finding the unique global extended type info entry given its GUID
class ktmap {
struct key_compare
{
bool
operator()(const extended_type_info * lhs, const extended_type_info * rhs) const
{
// shortcut to exploit string pooling
if(lhs->get_key() == rhs->get_key())
return false;
if(NULL == lhs->get_key())
return true;
if(NULL == rhs->get_key())
return false;
return std::strcmp(lhs->get_key(), rhs->get_key()) < 0;
}
};
// typedef std::multiset<const extended_type_info *, key_compare> type;
typedef std::set<const extended_type_info *, key_compare> type;
type m_map;
static ktmap * m_self;
ktmap(){}
class extended_type_info_arg : public extended_type_info
{
public:
extended_type_info_arg(const char * key) :
extended_type_info(NULL)
{
m_key = key;
}
virtual bool
less_than(const extended_type_info &rhs) const
{
assert(false);
return false; // to prevent a syntax error
}
};
static ktmap::type::iterator
lookup(const char *key){
extended_type_info_arg arg(key);
return m_self->m_map.find(&arg);
}
public:
~ktmap(){
m_self = NULL;
}
static void
insert(const extended_type_info * eti){
if(NULL == m_self){
static ktmap instance;
m_self = & instance;
}
// make sure that all GUIDs are unique
assert(lookup(eti->get_key()) == m_self->m_map.end());
m_self->m_map.insert(eti);
}
static const extended_type_info *
find(const char *key)
{
if(NULL == m_self)
return NULL;
extended_type_info_arg arg(key);
ktmap::type::const_iterator it;
it = m_self->m_map.find(&arg);
if(it == m_self->m_map.end())
return NULL;
return *it;
}
static void
purge(const extended_type_info * eti){
if(NULL == m_self)
return;
// note: the following can't be used as this function
// is called from a destructor of extended_type_info.
// This will generate an error on some machines - which
// makes sense be cause by this time the derived class data
// might be gone. Leave this in as a reminder not to do this
#if 0
ktmap::type::iterator it;
it = lookup(eti->get_key());
// expect it to be in there !
assert(it != m_self->m_map.end());
m_self->m_map.erase(it);
#endif
ktmap::type::iterator i = m_self->m_map.begin();
ktmap::type::iterator k = m_self->m_map.end();
while(i != k){
// note that the erase might invalidate i so save it here
ktmap::type::iterator j = i++;
if(*j == eti)
m_self->m_map.erase(j);
}
}
};
ktmap * ktmap::m_self = NULL;
} // namespace detail
BOOST_SERIALIZATION_DECL(const extended_type_info *)
extended_type_info::find(const char *key)
{
return detail::ktmap::find(key);
}
BOOST_SERIALIZATION_DECL(void)
extended_type_info::self_register()
{
detail::tkmap::insert(this);
m_self_registered = true;
}
BOOST_SERIALIZATION_DECL(void)
extended_type_info::key_register(const char *key_) {
if(NULL == key_)
return;
m_key = key_;
detail::ktmap::insert(this);
m_key_registered = true;
}
BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
extended_type_info::extended_type_info(
const char * type_info_key
) :
m_type_info_key(type_info_key),
m_self_registered(false),
m_key_registered(false),
m_is_destructing(false)
{}
BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
extended_type_info::~extended_type_info(){
// remove entries in maps which correspond to this type
m_is_destructing = true;
BOOST_TRY{
if(m_self_registered)
detail::tkmap::purge(this);
if(m_key_registered)
detail::ktmap::purge(this);
unregister_void_casts(this);
}
BOOST_CATCH(...){}
BOOST_CATCH_END
}
BOOST_SERIALIZATION_DECL(int)
extended_type_info::type_info_key_cmp(const extended_type_info & rhs) const {
if(m_type_info_key == rhs.m_type_info_key)
return 0;
//return strcmp(lhs.type_info_key, rhs.type_info_key);
// all we require is that the type_info_key be unique
// so just compare the addresses
return m_type_info_key < rhs.m_type_info_key ? -1 : 1;
}
BOOST_SERIALIZATION_DECL(const extended_type_info *)
extended_type_info::find(const extended_type_info * t)
{
return detail::tkmap::find(t);
}
BOOST_SERIALIZATION_DECL(bool)
extended_type_info::operator<(const extended_type_info &rhs) const {
int i = type_info_key_cmp(rhs);
if(i < 0)
return true;
if(i > 0)
return false;
assert(! is_destructing());
assert(! rhs.is_destructing());
return less_than(rhs);
}
} // namespace serialization
} // namespace boost