Boost logo

Boost-Commit :

From: ramey_at_[hidden]
Date: 2007-09-27 00:09:18


Author: ramey
Date: 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
New Revision: 39567
URL: http://svn.boost.org/trac/boost/changeset/39567

Log:
improvements to extended type info system - unfortunately, these break the export.
Text files modified:
   branches/serialization_next_release/boost/libs/serialization/src/basic_oarchive.cpp | 2
   branches/serialization_next_release/boost/libs/serialization/src/binary_iarchive.cpp | 16
   branches/serialization_next_release/boost/libs/serialization/src/binary_oarchive.cpp | 8
   branches/serialization_next_release/boost/libs/serialization/src/extended_type_info.cpp | 336 +++++++++++++--------------------
   branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_no_rtti.cpp | 24 --
   branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_typeid.cpp | 147 ++++++++++++--
   branches/serialization_next_release/boost/libs/serialization/src/void_cast.cpp | 399 +++++++++++++++++++++++----------------
   7 files changed, 503 insertions(+), 429 deletions(-)

Modified: branches/serialization_next_release/boost/libs/serialization/src/basic_oarchive.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/basic_oarchive.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/basic_oarchive.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -164,7 +164,7 @@
 };
 
 //////////////////////////////////////////////////////////////////////
-// implementation of basic_oarchive implementation functions
+// basic_oarchive implementation functions
 
 // given a type_info - find its bos
 // return NULL if not found

Modified: branches/serialization_next_release/boost/libs/serialization/src/binary_iarchive.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/binary_iarchive.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/binary_iarchive.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -23,28 +23,28 @@
 // explicitly instantiate for this type of stream
 template class basic_binary_iprimitive<
     naked_binary_iarchive,
- char,
- std::char_traits<char>
+ std::istream::char_type,
+ std::istream::traits_type
>;
 template class basic_binary_iarchive<naked_binary_iarchive> ;
 template class binary_iarchive_impl<
     naked_binary_iarchive,
- char,
- std::char_traits<char>
+ std::istream::char_type,
+ std::istream::traits_type
>;
 template class detail::archive_pointer_iserializer<naked_binary_iarchive> ;
 
 // explicitly instantiate for this type of stream
 template class basic_binary_iprimitive<
     binary_iarchive,
- char,
- std::char_traits<char>
+ std::istream::char_type,
+ std::istream::traits_type
>;
 template class basic_binary_iarchive<binary_iarchive> ;
 template class binary_iarchive_impl<
     binary_iarchive,
- char,
- std::char_traits<char>
+ std::istream::char_type,
+ std::istream::traits_type
>;
 template class detail::archive_pointer_iserializer<binary_iarchive> ;
 

Modified: branches/serialization_next_release/boost/libs/serialization/src/binary_oarchive.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/binary_oarchive.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/binary_oarchive.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -23,14 +23,14 @@
 // explicitly instantiate for this type of binary stream
 template class basic_binary_oprimitive<
     binary_oarchive,
- char,
- std::char_traits<char>
+ std::ostream::char_type,
+ std::ostream::traits_type
>;
 template class basic_binary_oarchive<binary_oarchive> ;
 template class binary_oarchive_impl<
     binary_oarchive,
- char,
- std::char_traits<char>
+ std::ostream::char_type,
+ std::ostream::traits_type
>;
 template class detail::archive_pointer_oserializer<binary_oarchive> ;
 

Modified: branches/serialization_next_release/boost/libs/serialization/src/extended_type_info.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/extended_type_info.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/extended_type_info.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -24,270 +24,202 @@
 #endif
 
 #include <boost/detail/no_exceptions_support.hpp>
+#include <boost/detail/lightweight_mutex.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;
+ operator()(
+ const extended_type_info * lhs,
+ const extended_type_info * rhs
+ ) const {
+ return *lhs < *rhs;
         }
     };
+ // the reason that we use multiset rather than set is that its possible
+ // that multiple eti records will be created as DLLS that use the same
+ // eti are loaded. Using a multset will automatically keep track of the
+ // times this occurs so that when the last dll is unloaded, the type will
+ // become "unregistered"
     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)
- {
+ extended_type_info_arg(const char * key){
             m_key = key;
         }
- virtual bool
- less_than(const extended_type_info &rhs) const
- {
- assert(false);
- return false; // to prevent a syntax error
+ ~extended_type_info_arg(){
+ m_key = NULL;
         }
     };
- 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
+ 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);
+ m_map.insert(eti);
     }
- static const extended_type_info *
+ 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())
+ const extended_type_info_arg eti(key);
+ ktmap::type::iterator it;
+ it = m_map.find(& eti);
+ if(it == m_map.end())
             return NULL;
         return *it;
     }
+ void
+ purge(const extended_type_info * eti){
+ ktmap::type::iterator it;
+ it = m_map.find(eti);
+ // expect it to be in there ! but check anyway !
+ if(it != m_map.end())
+ m_map.erase(it);
+ }
+};
+
+// the above structer is fine - except for:
+// - its not thread-safe
+// - it doesn't support the necessary initialization
+// to be a singleton.
+//
+// Here we add the sauce to address this
+
+class safe_ktmap {
+ // this addresses a problem. Our usage patter for a typical case is:
+ // extended_type_info
+ // key_register
+ // ktmap
+ // insert item
+ // ...
+ // ~extended_type_info
+ // purge item
+ // ~ktmap
+ // ~extended_type_info // crash!! ktmap already deleted
+ safe_ktmap(){
+ ++count;
+ }
+ ~safe_ktmap(){
+ --count;
+ }
+ static short int count;
+
+ static boost::detail::lightweight_mutex &
+ get_mutex(){
+ static boost::detail::lightweight_mutex m;
+ return m;
+ }
+ static ktmap & get_instance(){
+ static ktmap m;
+ return m;
+ }
+public:
+ static void
+ insert(const extended_type_info * eti){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ get_instance().insert(eti);
+ }
+ static const extended_type_info *
+ find(const char *key){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ return get_instance().find(key);
+ }
     static void
     purge(const extended_type_info * eti){
- if(NULL == m_self)
+ if(0 == detail::safe_ktmap::count)
             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);
- }
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ get_instance().purge(eti);
     }
 };
 
-ktmap * ktmap::m_self = NULL;
+short int safe_ktmap::count = 0;
 
 } // 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;
+ return detail::safe_ktmap::find(key);
 }
 
 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;
+extended_type_info::key_register(const char *k) {
+ assert(NULL != k);
+ m_key = k;
+ detail::safe_ktmap::insert(this);
 }
 
-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)
-{}
+extended_type_info::extended_type_info() :
+ m_key(NULL)
+{
+}
 
 BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
 extended_type_info::~extended_type_info(){
+ if(NULL == m_key)
+ return;
     // 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);
+ detail::safe_ktmap::purge(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)
+operator==(
+ const extended_type_info & lhs,
+ const extended_type_info & rhs
+){
+ if(& lhs == & rhs)
+ return true;
+ const char * l = lhs.get_key();
+ const char * r = rhs.get_key();
+ // neither have been exported
+ if(NULL == l && NULL == r)
+ // then the above test is definitive
+ return false;
+ // shortcut to exploit string pooling
+ if(l == r)
+ return true;
+ if(NULL == r)
+ return false;
+ if(NULL == l)
+ return false;
+ return 0 == std::strcmp(l, r);
 }
 
-BOOST_SERIALIZATION_DECL(bool)
-extended_type_info::operator<(const extended_type_info &rhs) const {
- int i = type_info_key_cmp(rhs);
- if(i < 0)
+BOOST_SERIALIZATION_DECL(bool)
+operator<(
+ const extended_type_info & lhs,
+ const extended_type_info & rhs
+){
+ // shortcut to exploit string pooling
+ const char * l = lhs.get_key();
+ const char * r = rhs.get_key();
+ // neither have been exported
+ if(NULL == l && NULL == r)
+ // order by address
+ return & lhs < & rhs;
+ // exported types are "higher" than non-exported types
+ if(NULL == l)
         return true;
- if(i > 0)
+ if(NULL == r)
         return false;
- assert(! is_destructing());
- assert(! rhs.is_destructing());
- return less_than(rhs);
+ // for exported types, use the string key so that
+ // multiple instances in different translation units
+ // can be matched up
+ return -1 == std::strcmp(l, r);
 }
 
 } // namespace serialization

Modified: branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_no_rtti.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_no_rtti.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_no_rtti.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -17,27 +17,3 @@
 
 #define BOOST_SERIALIZATION_SOURCE
 #include <boost/serialization/extended_type_info_no_rtti.hpp>
-
-namespace boost {
-namespace serialization {
-namespace detail {
-
-BOOST_SERIALIZATION_DECL(bool)
-extended_type_info_no_rtti_0::less_than(
- const boost::serialization::extended_type_info &rhs) const
-{
- return std::strcmp(m_key, rhs.get_key()) < 0;
-}
-
-BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-extended_type_info_no_rtti_0::extended_type_info_no_rtti_0() :
- boost::serialization::extended_type_info("extended_type_info_no_rtti")
-{}
-
-BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-extended_type_info_no_rtti_0::~extended_type_info_no_rtti_0()
-{}
-
-} // namespece detail
-} // namespace serialization
-} // namespace boost

Modified: branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_typeid.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_typeid.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/extended_type_info_typeid.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -9,6 +9,14 @@
 
 // See http://www.boost.org for updates, documentation, and revision history.
 
+#include <algorithm>
+#include <set>
+#include <cassert>
+#include <typeinfo>
+
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/detail/lightweight_mutex.hpp>
+
 #define BOOST_SERIALIZATION_SOURCE
 #include <boost/serialization/extended_type_info_typeid.hpp>
 
@@ -16,40 +24,137 @@
 namespace serialization {
 namespace detail {
 
-BOOST_SERIALIZATION_DECL(bool)
-extended_type_info_typeid_0::less_than(const extended_type_info &rhs) const
-{
- return 0 != get_eti().before(
- static_cast<const extended_type_info_typeid_0 &>(rhs).get_eti()
- );
-}
+// map for finding the unique global extended type entry for a given type
+class tkmap {
+ struct type_compare
+ {
+ bool
+ operator()(
+ const extended_type_info_typeid_0 * lhs,
+ const extended_type_info_typeid_0 * rhs
+ ) const {
+ const std::type_info & l = lhs->get_typeid();
+ const std::type_info & r = rhs->get_typeid();
+ return l.before(r);
+ }
+ };
+ // the reason that we use multiset rather than set is that its possible
+ // that multiple eti records will be created as DLLS that use the same
+ // eti are loaded. Using a multset will automatically keep track of the
+ // times this occurs so that when the last dll is unloaded, the type will
+ // become "unregistered"
+ typedef std::multiset<
+ const extended_type_info_typeid_0 *,
+ type_compare
+ > type;
+
+ type m_map;
 
-BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-extended_type_info_typeid_0::extended_type_info_typeid_0() :
- extended_type_info("extended_type_info_typeid")
-{}
+public:
+ void
+ insert(const extended_type_info_typeid_0 * eti){
+ m_map.insert(eti);
+ }
+ const extended_type_info_typeid_0 *
+ find(const extended_type_info_typeid_0 * eti){
+ tkmap::type::const_iterator it;
+ it = m_map.find(eti);
+ if(it == m_map.end())
+ return NULL;
+ return *it;
+ }
+ void
+ purge(const extended_type_info_typeid_0 * eti){
+ tkmap::type::iterator it;
+ it = m_map.find(eti);
+ if(it != m_map.end())
+ m_map.erase(it);
+ }
+};
+
+class safe_tkmap {
+ // this addresses a problem. Our usage patter for a typical case is:
+ // extended_type_info_typeid
+ // type_register
+ // tkmap
+ // insert item
+ // ...
+ // ~extended_type_info_typeid
+ // purge item
+ // tkmap
+ // ~extended_type_info_typeid // crash!! tkmap already deleted
+ safe_tkmap(){
+ ++count;
+ }
+ ~safe_tkmap(){
+ --count;
+ }
+ static short int count;
+
+ static boost::detail::lightweight_mutex &
+ get_mutex(){
+ static boost::detail::lightweight_mutex m;
+ return m;
+ }
+ static tkmap & get_instance(){
+ static tkmap m;
+ return m;
+ }
+public:
+ static void
+ insert(const extended_type_info_typeid_0 * eti){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ get_instance().insert(eti);
+ }
+ static const extended_type_info_typeid_0 *
+ find(const extended_type_info_typeid_0 * eti){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ return get_instance().find(eti);
+ }
+ static void
+ purge(const extended_type_info_typeid_0 * eti){
+ if(0 == count)
+ return;
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ get_instance().purge(eti);
+ }
+};
+
+short int safe_tkmap::count = 0;
 
 BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
 extended_type_info_typeid_0::~extended_type_info_typeid_0()
-{}
+{
+ if(NULL == m_ti)
+ return;
+ // remove entries in maps which correspond to this type
+ BOOST_TRY{
+ detail::safe_tkmap::purge(this);
+ }
+ BOOST_CATCH(...){}
+ BOOST_CATCH_END
+}
+
+BOOST_SERIALIZATION_DECL(void)
+extended_type_info_typeid_0::type_register(const std::type_info & ti){
+ m_ti = & ti;
+ detail::safe_tkmap::insert(this);
+}
 
 // this derivation is used for creating search arguments
 class extended_type_info_typeid_arg :
     public extended_type_info_typeid_0
 {
-private:
- const std::type_info & ti;
- virtual const std::type_info &get_eti() const
- {
- return ti;
- }
 public:
- extended_type_info_typeid_arg(const std::type_info & ti_)
- : ti(ti_)
+ extended_type_info_typeid_arg(const std::type_info & ti)
     {
         // note absense of self register and key as this is used only as
         // search argument given a type_info reference and is not to
         // be added to the map.
+ m_ti = & ti;
+ }
+ ~extended_type_info_typeid_arg(){
+ m_ti = NULL;
     }
 };
 
@@ -58,7 +163,7 @@
     const std::type_info & ti
 ){
     detail::extended_type_info_typeid_arg etia(ti);
- return extended_type_info::find(& etia);
+ return safe_tkmap::find(& etia);
 }
 
 } // namespace detail

Modified: branches/serialization_next_release/boost/libs/serialization/src/void_cast.cpp
==============================================================================
--- branches/serialization_next_release/boost/libs/serialization/src/void_cast.cpp (original)
+++ branches/serialization_next_release/boost/libs/serialization/src/void_cast.cpp 2007-09-27 00:09:17 EDT (Thu, 27 Sep 2007)
@@ -8,7 +8,7 @@
 // <gennadiy.rozental_at_[hidden]>
 
 // 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
@@ -22,7 +22,8 @@
 #include <cassert>
 
 // BOOST
-#include <boost/shared_ptr.hpp>
+#include <boost/detail/lightweight_mutex.hpp>
+
 #define BOOST_SERIALIZATION_SOURCE
 #include <boost/serialization/extended_type_info.hpp>
 #include <boost/serialization/void_cast.hpp>
@@ -31,121 +32,30 @@
 namespace serialization {
 namespace void_cast_detail {
 
-struct void_caster_compare
+// just used as a search key
+class void_caster_argument : public void_caster
 {
- bool
- operator()(
- shared_ptr<const void_caster> lhs,
- shared_ptr<const void_caster> rhs ) const
- {
- if( lhs.get()->m_derived_type < rhs.get()->m_derived_type )
- return true;
-
- if( rhs.get()->m_derived_type < lhs.get()->m_derived_type)
- return false;
-
- if( lhs.get()->m_base_type < rhs.get()->m_base_type )
- return true;
-
- return false;
+ virtual void const*
+ upcast( void const* t ) const {
+ assert(false);
+ return NULL;
     }
-};
-
-struct null_deleter
-{
- void operator()(void const *) const
- {}
-};
-
-// 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
-class void_caster_registry
-{
- typedef shared_ptr<const void_caster> value_type;
- typedef std::set<value_type, void_caster_compare> set_type;
- set_type m_set;
- static void_caster_registry * m_self;
- static void_caster_registry *
- self(){
- if(NULL == m_self){
- static void_caster_registry instance;
- m_self = & instance;
- }
- return m_self;
+ virtual void const*
+ downcast( void const* t ) const {
+ assert(false);
+ return NULL;
     }
- void_caster_registry(){}
 public:
- ~void_caster_registry(){
- m_self = 0;
- }
- typedef set_type::iterator iterator;
- typedef set_type::const_iterator const_iterator;
- static iterator
- begin() {
- return self()->m_set.begin();
- }
- static iterator
- end() {
- return self()->m_set.end();
- }
- static const_iterator
- find(void_caster * vcp){
- return self()->m_set.find(value_type(vcp, null_deleter()));
- }
- static std::pair<iterator, bool>
- insert(const value_type & vcp){
- return self()->m_set.insert(vcp);
- }
- static bool
- empty(){
- if(NULL == m_self)
- return true;
- return m_self->m_set.empty();
- }
- static void
- purge(const extended_type_info * eti);
+ void_caster_argument(
+ extended_type_info const& derived_type_,
+ extended_type_info const& base_type_
+ ) :
+ void_caster(derived_type_, base_type_)
+ {}
 };
 
-void_caster_registry * void_caster_registry::m_self = NULL;
-
-void
-void_caster_registry::purge(const extended_type_info * eti){
- if(NULL == m_self)
- return;
- if(! empty()){
- iterator i = m_self->m_set.begin();
- while(i != m_self->m_set.end()){
- // note that the erase might invalidate i so save it here
- iterator j = i++;
- if((*j)->includes(eti))
- m_self->m_set.erase(j);
- }
- }
-}
-
-BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-void_caster::void_caster(
- extended_type_info const & derived_type_,
- extended_type_info const & base_type_
-) :
- m_derived_type( derived_type_),
- m_base_type(base_type_)
-{}
-
-BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-void_caster::~void_caster(){}
-
-bool
-void_caster::includes(const extended_type_info * eti) const {
- return & m_derived_type == eti || & m_base_type == eti;
-}
-
-void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-void_caster::static_register(const void_caster * vcp)
-{
- void_caster_registry::insert(shared_ptr<const void_caster>(vcp, null_deleter()));
-}
+//////////////////////////////////////////////////////
+// void_caster implementation for indirect inheritance
 
 class void_caster_derived : public void_caster
 {
@@ -169,43 +79,59 @@
     {}
 };
 
-// just used as a search key
-class void_caster_argument : public void_caster
+////////////////////////////////////////////////////////////
+// registry to hold all casters for all base/derived pairs
+// used.
+
+class void_caster_registry
 {
- virtual void const*
- upcast( void const* t ) const {
- assert(false);
- return NULL;
- }
- virtual void const*
- downcast( void const* t ) const {
- assert(false);
- return NULL;
- }
+ struct void_caster_compare
+ {
+ bool
+ operator()(
+ const void_caster * lhs,
+ const void_caster * rhs
+ ) const {
+ return *lhs < *rhs;
+ }
+ };
+ // note usage of multi-set since it's possible that dynamically
+ // loaded libraries might create multiple instances of a given
+ // instance of a void caster. This implements automatic counting
+ typedef std::multiset<const void_caster *, void_caster_compare> set_type;
+ set_type m_set;
 public:
- void_caster_argument(
- extended_type_info const& derived_type_,
- extended_type_info const& base_type_
- ) :
- void_caster(derived_type_, base_type_)
- {}
+ typedef set_type::iterator iterator;
+ typedef set_type::const_iterator const_iterator;
+ void
+ insert(const void_caster * vcp){
+ m_set.insert(vcp);
+ }
+ void
+ purge(const void_caster * vcp){
+ iterator it = m_set.find(vcp);
+ // expect it to be in there ! but check anyway !
+ assert(it != m_set.end());
+ m_set.erase(it);
+ }
+ void const *
+ upcast(
+ extended_type_info const & derived_type,
+ extended_type_info const & base_type,
+ void const * const t,
+ bool top
+ );
+ void const *
+ downcast(
+ const extended_type_info & derived_type,
+ const extended_type_info & base_type,
+ const void * const t,
+ bool top
+ );
 };
 
-} // namespace void_cast_detail
-
-void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
-unregister_void_casts(extended_type_info *eti)
-{
- void_cast_detail::void_caster_registry::purge(eti);
-}
-
-// Given a void *, assume that it really points to an instance of one type
-// and alter it so that it would point to an instance of a related type.
-// Return the altered pointer. If there exists no sequence of casts that
-// can transform from_type to to_type, return a NULL.
-
-BOOST_SERIALIZATION_DECL(void const *)
-void_upcast(
+inline void const *
+void_caster_registry::upcast(
     extended_type_info const & derived_type,
     extended_type_info const & base_type,
     void const * const t,
@@ -216,21 +142,21 @@
         return t;
     
     // check to see if base/derived pair is found in the registry
- void_cast_detail::void_caster_argument ca(derived_type, base_type );
- void_cast_detail::void_caster_registry::const_iterator it;
- it = void_cast_detail::void_caster_registry::find( &ca );
+ void_caster_argument ca(derived_type, base_type );
+ const_iterator it;
+ it = m_set.find( &ca );
     
     const void * t_new = NULL;
 
     // if so
- if (it != void_cast_detail::void_caster_registry::end())
+ if (it != m_set.end())
         // we're done
         return (*it)->upcast(t);
 
     // try to find a chain that gives us what we want
     for(
- it = void_cast_detail::void_caster_registry::begin();
- it != void_cast_detail::void_caster_registry::end();
+ it = m_set.begin();
+ it != m_set.end();
         ++it
     ){
         // if the current candidate doesn't cast to the desired target type
@@ -249,15 +175,13 @@
                 if(top){
                     // register the this pair so we will have to go through
                     // keep this expensive search process more than once.
- void_cast_detail::void_caster * vcp =
- new void_cast_detail::void_caster_derived(
+ const void_caster * vcp =
+ new void_caster_derived(
                             derived_type,
                             base_type,
                             static_cast<const char*>(t_new) - static_cast<const char*>(t)
                         );
- void_cast_detail::void_caster_registry::insert(
- shared_ptr<const void_cast_detail::void_caster>(vcp)
- );
+ m_set.insert(vcp);
                 }
                 break;
             }
@@ -266,8 +190,8 @@
     return t_new;
 }
 
-BOOST_SERIALIZATION_DECL(void const *)
-void_downcast(
+inline void const *
+void_caster_registry::downcast(
     const extended_type_info & derived_type,
     const extended_type_info & base_type,
     const void * const t,
@@ -278,20 +202,20 @@
         return t;
     
     // check to see if base/derived pair is found in the registry
- void_cast_detail::void_caster_argument ca(derived_type, base_type );
- void_cast_detail::void_caster_registry::const_iterator it;
- it = void_cast_detail::void_caster_registry::find( &ca );
+ void_caster_argument ca(derived_type, base_type );
+ const_iterator it;
+ it = m_set.find( &ca );
     
     // if so
- if (it != void_cast_detail::void_caster_registry::end())
+ if (it != m_set.end())
         // we're done
         return (*it)->downcast(t);
 
     const void * t_new = NULL;
     // try to find a chain that gives us what we want
     for(
- it = void_cast_detail::void_caster_registry::begin();
- it != void_cast_detail::void_caster_registry::end();
+ it = m_set.begin();
+ it != m_set.end();
         ++it
     ){
         // if the current candidate doesn't casts from the desired target type
@@ -310,15 +234,13 @@
                 if(top){
                     // register the this pair so we will have to go through
                     // keep this expensive search process more than once.
- void_cast_detail::void_caster * vcp =
- new void_cast_detail::void_caster_derived(
+ const void_caster * vcp =
+ new void_caster_derived(
                             derived_type,
                             base_type,
                             static_cast<const char*>(t) - static_cast<const char*>(t_new)
                         );
- void_cast_detail::void_caster_registry::insert(
- shared_ptr<const void_cast_detail::void_caster>(vcp)
- );
+ m_set.insert(vcp);
                 }
                 break;
             }
@@ -327,7 +249,146 @@
     return t_new;
 }
 
+// the above structer is fine - except for:
+// - its not thread-safe
+// - it doesn't support the necessary initialization
+// to be a singleton.
+//
+// Here we add the sauce to address this
+
+class safe_void_caster_registry {
+ // this addresses a problem. Our usage patter for a typical case is:
+ // void_caster
+ // void_caster_register
+ // void_caster_registry
+ // insert item
+ // ...
+ // ~void_caster
+ // purge item
+ // ~void_caster_registry
+ // ~void_caster // crash!! void_caster_registry already deleted
+ safe_void_caster_registry (){
+ ++count;
+ }
+ ~safe_void_caster_registry (){
+ --count;
+ }
+ static short int count;
+
+ static boost::detail::lightweight_mutex &
+ get_mutex(){
+ static boost::detail::lightweight_mutex m;
+ return m;
+ }
+ static void_caster_registry & get_instance(){
+ static void_caster_registry m;
+ return m;
+ }
+public:
+ static void
+ insert(const void_caster * vcp){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ get_instance().insert(vcp);
+ }
+ static void const *
+ upcast(
+ extended_type_info const & derived_type,
+ extended_type_info const & base_type,
+ void const * const t,
+ bool top
+ ){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ return get_instance().upcast(derived_type, base_type, t, top);
+ }
+ static void const *
+ downcast(
+ const extended_type_info & derived_type,
+ const extended_type_info & base_type,
+ const void * const t,
+ bool top
+ ){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ return get_instance().downcast(derived_type, base_type, t, top);
+ }
+ static void
+ purge(const void_caster * vcp){
+ boost::detail::lightweight_mutex::scoped_lock sl(get_mutex());
+ if(count == 0)
+ return;
+ get_instance().purge(vcp);
+ }
+};
+
+short int safe_void_caster_registry::count = 0;
+
+////////////////////////////////////////////////
+// void_caster implementation
+
+BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
+void_caster::void_caster(
+ extended_type_info const & derived_type_,
+ extended_type_info const & base_type_
+) :
+ m_derived_type( derived_type_),
+ m_base_type(base_type_)
+{}
+
+BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
+void_caster::~void_caster(){
+ safe_void_caster_registry::purge(this);
+}
+
+void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
+void_caster::static_register(const void_caster * vcp)
+{
+ safe_void_caster_registry::insert(vcp);
+}
+
+BOOST_SERIALIZATION_DECL(bool)
+operator<(const void_caster & lhs, const void_caster & rhs){
+ if( lhs.m_derived_type < rhs.m_derived_type )
+ return true;
+
+ if( rhs.m_derived_type < lhs.m_derived_type)
+ return false;
+
+ if( lhs.m_base_type < rhs.m_base_type )
+ return true;
+
+ return false;
+}
+
+} // namespace void_cast_detail
+
+// Given a void *, assume that it really points to an instance of one type
+// and alter it so that it would point to an instance of a related type.
+// Return the altered pointer. If there exists no sequence of casts that
+// can transform from_type to to_type, return a NULL.
+
+BOOST_SERIALIZATION_DECL(void const *)
+void_upcast(
+ extended_type_info const & derived_type,
+ extended_type_info const & base_type,
+ void const * const t,
+ bool top
+){
+ return void_cast_detail::safe_void_caster_registry::upcast(
+ derived_type, base_type, t, top
+ );
+}
+
+BOOST_SERIALIZATION_DECL(void const *)
+void_downcast(
+ const extended_type_info & derived_type,
+ const extended_type_info & base_type,
+ const void * const t,
+ bool top
+){
+ return void_cast_detail::safe_void_caster_registry::downcast(
+ derived_type, base_type, t, top
+ );
+}
+
 } // namespace serialization
 } // namespace boost
 
-// EOF


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk