Teuchos_RCPNode.cpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #include "Teuchos_RCPNode.hpp"
00030 #include "Teuchos_TestForException.hpp"
00031 #include "Teuchos_Exceptions.hpp"
00032 
00033 
00034 // Define this macro here locally and rebuild just this *.cpp file and update
00035 // the Teuchos library and you will get node tracing turned on by default when
00036 // debugging support is enabled!  Note that you also have to TEUCHOS_DEBUG
00037 // defined as well (using --enable-teuchos-debug at configure time).
00038 // #define TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
00039 
00040 
00041 namespace {
00042 
00043 
00044 struct InfoAndCallNumber {
00045   InfoAndCallNumber()
00046     :call_number(-1)
00047   {}
00048   InfoAndCallNumber(
00049         const std::string &info_in,
00050         const int &call_number_in
00051         )
00052     :info(info_in), call_number(call_number_in)
00053 
00054   {}
00055   std::string info;
00056   int call_number;
00057 };
00058 
00059 
00060 typedef std::map<Teuchos::RCPNode*,InfoAndCallNumber>
00061 rcp_node_list_t;
00062 
00063 
00064 // Here we must let the PrintActiveRCPNodes constructor and destructor handle
00065 // the creation and destruction of this map object.  This will ensure that
00066 // this map object will be valid when any global/static RCP objects are
00067 // destroyed!  Note that this object will get created and destroyed
00068 // reguardless if whether we are tracing RCPNodes or not.  This just makes our
00069 // life simpler.
00070 rcp_node_list_t *rcp_node_list = 0;
00071 
00072 
00073 bool loc_isTracingActiveRCPNodes =
00074 #if defined(TEUCHOS_DEBUG) && defined(TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES)
00075   true
00076 #else
00077   false
00078 #endif
00079   ;
00080 
00081 
00082 } // namespace
00083 
00084 
00085 //
00086 // RCPNode
00087 //
00088 
00089 
00090 namespace Teuchos {
00091 
00092 
00093 void RCPNode::set_extra_data(
00094   const any &extra_data, const std::string& name
00095   ,EPrePostDestruction destroy_when
00096   ,bool force_unique
00097   )
00098 {
00099   if(extra_data_map_==NULL) {
00100     extra_data_map_ = new extra_data_map_t;
00101   }
00102   const std::string type_and_name( extra_data.typeName() + std::string(":") + name );
00103   if( !extra_data_map_->empty() && force_unique ) {
00104     extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00105 #ifdef TEUCHOS_DEBUG
00106     TEST_FOR_EXCEPTION(
00107       itr != extra_data_map_->end(), std::invalid_argument
00108       ,"Error, the type:name pair \'" << type_and_name
00109       << "\' already exists and force_unique==true!" );
00110 #endif
00111   }
00112   (*extra_data_map_)[type_and_name] =
00113     extra_data_entry_t(extra_data,destroy_when); // This may add or replace!
00114 }
00115 
00116 
00117 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
00118 {
00119 #ifdef TEUCHOS_DEBUG
00120   TEST_FOR_EXCEPTION(
00121     extra_data_map_==NULL, std::invalid_argument
00122     ,"Error, no extra data has been set yet!" );
00123 #endif
00124   any *extra_data = get_optional_extra_data(type_name,name);
00125 #ifdef TEUCHOS_DEBUG
00126   if (!extra_data) {
00127     const std::string type_and_name( type_name + std::string(":") + name );
00128     TEST_FOR_EXCEPTION(
00129       extra_data == NULL, std::invalid_argument
00130       ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
00131   }
00132 #endif
00133   return *extra_data;
00134 }
00135 
00136 
00137 any* RCPNode::get_optional_extra_data( const std::string& type_name,
00138   const std::string& name )
00139 {
00140   if( extra_data_map_ == NULL ) return NULL;
00141   const std::string type_and_name( type_name + std::string(":") + name );
00142   extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00143   if(itr != extra_data_map_->end())
00144     return &(*itr).second.extra_data;
00145   return NULL;
00146 }
00147 
00148 
00149 void RCPNode::impl_pre_delete_extra_data()
00150 {
00151   for(
00152     extra_data_map_t::iterator itr = extra_data_map_->begin();
00153     itr != extra_data_map_->end();
00154     ++itr
00155     )
00156   {
00157     extra_data_map_t::value_type &entry = *itr;
00158     if(entry.second.destroy_when == PRE_DESTROY)
00159       entry.second.extra_data = any();
00160   }
00161 }
00162 
00163 } // namespace Teuchos
00164 
00165 
00166 void Teuchos::add_new_RCPNode( RCPNode* rcp_node, const std::string &info )
00167 {
00168   if (loc_isTracingActiveRCPNodes) {
00169     TEST_FOR_EXCEPT(0==rcp_node_list);
00170     static int call_number = 0;
00171     (*rcp_node_list)[rcp_node] = InfoAndCallNumber(info,call_number);
00172     ++call_number;
00173   }
00174 }
00175 
00176 
00177 void Teuchos::remove_RCPNode( RCPNode* rcp_node )
00178 {
00179   // Here, we will try to remove an RCPNode reguardless if whether
00180   // loc_isTracingActiveRCPNodes==true or not.  This will not be a performance
00181   // problem and it will ensure that any RCPNode objects that are added to
00182   // this list will be removed and will not look like a memory leak.  In
00183   // non-debug mode, this function will never be called.  In debug mode, with
00184   // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
00185   // therefore this find(...) operation should be pretty cheap (even for a bad
00186   // implementation of std::map).
00187   TEST_FOR_EXCEPT(0==rcp_node_list);
00188   const rcp_node_list_t::iterator itr = rcp_node_list->find(rcp_node);
00189 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
00190   // If we have the macro TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES turned on a
00191   // compile time, then all RCPNode objects that get created will have been
00192   // added to this list.  In this case, we can asset that the node exists.
00193   TEST_FOR_EXCEPT_PRINT(itr==rcp_node_list->end(),&std::cerr);
00194 #else
00195   // If the macro TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES turned off by
00196   // default, then is is possible that an RCP got created before the bool
00197   // loc_isTracingActiveRCPNodes was turned on.  In this case, we should allow
00198   // for an RCP node not to have been added to this list.  In this case we
00199   // will just let this go!
00200 #endif
00201   if (itr != rcp_node_list->end())
00202     rcp_node_list->erase(itr);
00203 }
00204 
00205 
00206 //
00207 // PrintActiveRCPNodes
00208 //
00209 
00210 
00211 Teuchos::PrintActiveRCPNodes::PrintActiveRCPNodes()
00212 {
00213 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00214   std::cerr << "\nCalled PrintActiveRCPNodes::PrintActiveRCPNodes() : count = " << count_ << "\n";
00215 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00216   if (!rcp_node_list)
00217     rcp_node_list = new rcp_node_list_t;
00218   ++count_;
00219 }
00220 
00221 
00222 Teuchos::PrintActiveRCPNodes::~PrintActiveRCPNodes()
00223 {
00224 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00225   std::cerr << "\nCalled PrintActiveRCPNodes::~PrintActiveRCPNodes() : count = " << count_ << "\n";
00226 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00227   if( --count_ == 0 ) {
00228 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00229     std::cerr << "\nPrint active nodes!\n";
00230 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00231     std::cout << std::flush;
00232     TEST_FOR_EXCEPT(0==rcp_node_list);
00233     printActiveRCPNodes(std::cerr);
00234     delete rcp_node_list;
00235   }
00236 }
00237 
00238 
00239 void Teuchos::PrintActiveRCPNodes::foo()
00240 {
00241   int dummy = count_;
00242   ++dummy; // Avoid unused variable warning (bug 2664)
00243 }
00244 
00245 
00246 int Teuchos::PrintActiveRCPNodes::count_ = 0;
00247 
00248 
00249 
00250 
00251 //
00252 // Nonmember functions
00253 //
00254 
00255 
00256 bool Teuchos::isTracingActiveRCPNodes()
00257 {
00258   return loc_isTracingActiveRCPNodes;
00259 }
00260 
00261 #ifdef TEUCHOS_DEBUG
00262 
00263 void Teuchos::setTracingActiveRCPNodes(bool tracingActiveNodes)
00264 {
00265 #ifdef TEUCHOS_DEBUG
00266   loc_isTracingActiveRCPNodes = tracingActiveNodes;
00267 #else
00268   TEST_FOR_EXCEPT_MSG(true,"Error, you can not call setTracingActiveRCPNodes(...)"
00269     " when TEUCHOS_DEBUG is not defined!");
00270 #endif
00271 }
00272 
00273 #endif // TEUCHOS_DEBUG
00274 
00275 
00276 int Teuchos::numActiveRCPNodes() {
00277 #ifdef TEUCHOS_DEBUG
00278   TEST_FOR_EXCEPT(0==rcp_node_list);
00279   return rcp_node_list->size();
00280 #endif
00281   return 0;
00282 }
00283 
00284 
00285 void Teuchos::printActiveRCPNodes(std::ostream &out)
00286 {
00287 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00288   out
00289     << "\nCalled printActiveRCPNodes() :"
00290     << " rcp_node_list.size() = " << rcp_node_list.size() << "\n";
00291 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00292   if (loc_isTracingActiveRCPNodes) {
00293     TEST_FOR_EXCEPT(0==rcp_node_list);
00294     rcp_node_list_t::const_iterator itr = rcp_node_list->begin();
00295     if(itr != rcp_node_list->end()) {
00296       out
00297         << "\n***"
00298         << "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
00299         << "\n*** not been destroyed yet.  This may be an indication that these objects may"
00300         << "\n*** be involved in a circular dependency!  A memory checking tool may complain"
00301         << "\n*** that these objects are not destroyed correctly."
00302         << "\n***\n";
00303       while( itr != rcp_node_list->end() ) {
00304         const rcp_node_list_t::value_type &entry = *itr;
00305         out
00306           << "\n  RCPNode address = \'" << entry.first << "\',"
00307           << " information = " << entry.second.info << ","
00308           << " call number = " << entry.second.call_number;
00309         ++itr;
00310       }
00311       out << "\n";
00312     }
00313   }
00314 }
00315 
00316 
00317 void Teuchos::throw_null_ptr_error( const std::string &type_name )
00318 {
00319   TEST_FOR_EXCEPTION(
00320     true, NullReferenceError, 
00321     type_name << " : You can not call operator->() or operator*()"
00322     <<" if getRawPtr()==0!" );
00323 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 20 10:14:00 2009 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.1