Teuchos_RCPNode.cpp

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   if(extra_data) return *extra_data;
00126   const std::string type_and_name( type_name + std::string(":") + name );
00127 #ifdef TEUCHOS_DEBUG
00128   TEST_FOR_EXCEPTION(
00129     extra_data == NULL, std::invalid_argument
00130     ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" );
00131 #endif
00132   return *extra_data; // Will never be executed!
00133 }
00134 
00135 
00136 any* RCPNode::get_optional_extra_data( const std::string& type_name,
00137   const std::string& name )
00138 {
00139   if( extra_data_map_ == NULL ) return NULL;
00140   const std::string type_and_name( type_name + std::string(":") + name );
00141   extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
00142   if(itr != extra_data_map_->end())
00143     return &(*itr).second.extra_data;
00144   return NULL;
00145 }
00146 
00147 
00148 void RCPNode::impl_pre_delete_extra_data()
00149 {
00150   for(
00151     extra_data_map_t::iterator itr = extra_data_map_->begin();
00152     itr != extra_data_map_->end();
00153     ++itr
00154     )
00155   {
00156     extra_data_map_t::value_type &entry = *itr;
00157     if(entry.second.destroy_when == PRE_DESTROY)
00158       entry.second.extra_data = any();
00159   }
00160 }
00161 
00162 } // namespace Teuchos
00163 
00164 
00165 void Teuchos::add_new_RCPNode( RCPNode* rcp_node, const std::string &info )
00166 {
00167   if (loc_isTracingActiveRCPNodes) {
00168     TEST_FOR_EXCEPT(0==rcp_node_list);
00169     static int call_number = 0;
00170     (*rcp_node_list)[rcp_node] = InfoAndCallNumber(info,call_number);
00171     ++call_number;
00172   }
00173 }
00174 
00175 
00176 void Teuchos::remove_RCPNode( RCPNode* rcp_node )
00177 {
00178   // Here, we will try to remove an RCPNode reguardless if whether
00179   // loc_isTracingActiveRCPNodes==true or not.  This will not be a performance
00180   // problem and it will ensure that any RCPNode objects that are added to
00181   // this list will be removed and will not look like a memory leak.  In
00182   // non-debug mode, this function will never be called.  In debug mode, with
00183   // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
00184   // therefore this find(...) operation should be pretty cheap (even for a bad
00185   // implementation of std::map).
00186   TEST_FOR_EXCEPT(0==rcp_node_list);
00187   const rcp_node_list_t::iterator itr = rcp_node_list->find(rcp_node);
00188 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
00189   // If we have the macro TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES turned on a
00190   // compile time, then all RCPNode objects that get created will have been
00191   // added to this list.  In this case, we can asset that the node exists.
00192   TEST_FOR_EXCEPT_PRINT(itr==rcp_node_list->end(),&std::cerr);
00193 #else
00194   // If the macro TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES turned off by
00195   // default, then is is possible that an RCP got created before the bool
00196   // loc_isTracingActiveRCPNodes was turned on.  In this case, we should allow
00197   // for an RCP node not to have been added to this list.  In this case we
00198   // will just let this go!
00199 #endif
00200   if (itr != rcp_node_list->end())
00201     rcp_node_list->erase(itr);
00202 }
00203 
00204 
00205 //
00206 // PrintActiveRCPNodes
00207 //
00208 
00209 
00210 Teuchos::PrintActiveRCPNodes::PrintActiveRCPNodes()
00211 {
00212 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00213   std::cerr << "\nCalled PrintActiveRCPNodes::PrintActiveRCPNodes() : count = " << count_ << "\n";
00214 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00215   if (!rcp_node_list)
00216     rcp_node_list = new rcp_node_list_t;
00217   ++count_;
00218 }
00219 
00220 
00221 Teuchos::PrintActiveRCPNodes::~PrintActiveRCPNodes()
00222 {
00223 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00224   std::cerr << "\nCalled PrintActiveRCPNodes::~PrintActiveRCPNodes() : count = " << count_ << "\n";
00225 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00226   if( --count_ == 0 ) {
00227 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00228     std::cerr << "\nPrint active nodes!\n";
00229 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00230     std::cout << std::flush;
00231     TEST_FOR_EXCEPT(0==rcp_node_list);
00232     printActiveRCPNodes(std::cerr);
00233     delete rcp_node_list;
00234   }
00235 }
00236 
00237 
00238 void Teuchos::PrintActiveRCPNodes::foo()
00239 {
00240   int dummy = count_;
00241   ++dummy; // Avoid unused variable warning (bug 2664)
00242 }
00243 
00244 
00245 int Teuchos::PrintActiveRCPNodes::count_ = 0;
00246 
00247 
00248 
00249 
00250 //
00251 // Nonmember functions
00252 //
00253 
00254 
00255 bool Teuchos::isTracingActiveRCPNodes()
00256 {
00257   return loc_isTracingActiveRCPNodes;
00258 }
00259 
00260 #ifdef TEUCHOS_DEBUG
00261 
00262 void Teuchos::setTracingActiveRCPNodes(bool tracingActiveNodes)
00263 {
00264 #ifdef TEUCHOS_DEBUG
00265   loc_isTracingActiveRCPNodes = tracingActiveNodes;
00266 #else
00267   TEST_FOR_EXCEPT_MSG(true,"Error, you can not call setTracingActiveRCPNodes(...)"
00268     " when TEUCHOS_DEBUG is not defined!");
00269 #endif
00270 }
00271 
00272 #endif // TEUCHOS_DEBUG
00273 
00274 
00275 int Teuchos::numActiveRCPNodes() {
00276 #ifdef TEUCHOS_DEBUG
00277   TEST_FOR_EXCEPT(0==rcp_node_list);
00278   return rcp_node_list->size();
00279 #endif
00280   return 0;
00281 }
00282 
00283 
00284 void Teuchos::printActiveRCPNodes(std::ostream &out)
00285 {
00286 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00287   out
00288     << "\nCalled printActiveRCPNodes() :"
00289     << " rcp_node_list.size() = " << rcp_node_list.size() << "\n";
00290 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
00291   if (loc_isTracingActiveRCPNodes) {
00292     TEST_FOR_EXCEPT(0==rcp_node_list);
00293     rcp_node_list_t::const_iterator itr = rcp_node_list->begin();
00294     if(itr != rcp_node_list->end()) {
00295       out
00296         << "\n***"
00297         << "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
00298         << "\n*** not been destroyed yet.  This may be an indication that these objects may"
00299         << "\n*** be involved in a circular dependency!  A memory checking tool may complain"
00300         << "\n*** that these objects are not destroyed correctly."
00301         << "\n***\n";
00302       while( itr != rcp_node_list->end() ) {
00303         const rcp_node_list_t::value_type &entry = *itr;
00304         out
00305           << "\n  RCPNode address = \'" << entry.first << "\',"
00306           << " information = " << entry.second.info << ","
00307           << " call number = " << entry.second.call_number;
00308         ++itr;
00309       }
00310       out << "\n";
00311     }
00312   }
00313 }
00314 
00315 
00316 void Teuchos::throw_null_ptr_error( const std::string &type_name )
00317 {
00318   TEST_FOR_EXCEPTION(
00319     true, NullReferenceError, 
00320     type_name << " : You can not call operator->() or operator*()"
00321     <<" if getRawPtr()==0!" );
00322 }

Generated on Wed May 12 21:40:32 2010 for Teuchos - Trilinos Tools Package by  doxygen 1.4.7