CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/src/FWCore/Utilities/src/ReflexTools.cc

Go to the documentation of this file.
00001 #include <algorithm>
00002 #include <sstream>
00003 
00004 #include "boost/algorithm/string.hpp"
00005 #include "boost/thread/tss.hpp"
00006 
00007 #include "Reflex/Base.h"
00008 #include "Reflex/Member.h"
00009 #include "Reflex/TypeTemplate.h"
00010 #include "Api.h" // for G__ClassInfo
00011 
00012 #include "FWCore/Utilities/interface/ReflexTools.h"
00013 #include "FWCore/Utilities/interface/Algorithms.h"
00014 
00015 using Reflex::Base;
00016 using Reflex::FINAL;
00017 using Reflex::Member;
00018 using Reflex::Object;
00019 using Reflex::SCOPED;
00020 using Reflex::Type;
00021 using Reflex::TypeTemplate;
00022 using Reflex::Type_Iterator;
00023 
00024 namespace edm {
00025 
00026   Type get_final_type(Type t) {
00027     while (t.IsTypedef()) t = t.ToType();
00028     return t;
00029   }
00030 
00031   bool
00032   find_nested_type_named(std::string const& nested_type,
00033                          Type const& type_to_search,
00034                          Type& found_type) {
00035     // Look for a sub-type named 'nested_type'
00036     for (Type_Iterator
00037            i = type_to_search.SubType_Begin(),
00038            e = type_to_search.SubType_End();
00039            i != e;
00040            ++i) {
00041       if (i->Name() == nested_type) {
00042         found_type = get_final_type(*i);
00043         return true;
00044       }
00045     }
00046     return false;
00047   }
00048 
00049   bool
00050   if_edm_ref_get_value_type(Type const& possible_ref,
00051                             Type& result) {
00052     TypeTemplate primary_template_id(possible_ref.TemplateFamily());
00053     if (primary_template_id == TypeTemplate::ByName("edm::Ref", 3)) {
00054       (void)value_type_of(possible_ref, result);
00055       return true;
00056     } else {
00057       result = possible_ref;    
00058       return false;
00059     }
00060   }
00061 
00062   bool
00063   if_edm_ptr_get_value_type(Type const& possible_ref,
00064                             Type& result) {
00065     TypeTemplate primary_template_id(possible_ref.TemplateFamily());
00066     if (primary_template_id == TypeTemplate::ByName("edm::Ptr", 1)) {
00067       (void)value_type_of(possible_ref, result);
00068       return true;
00069     } else {
00070       result = possible_ref;    
00071       return false;
00072     }
00073   }
00074 
00075   bool
00076   if_edm_refToBase_get_value_type(Type const& possible_ref,
00077                                   Type& result) {
00078     TypeTemplate primary_template_id(possible_ref.TemplateFamily());
00079     if (primary_template_id == TypeTemplate::ByName("edm::RefToBase", 1)) {
00080       (void)value_type_of(possible_ref, result);
00081       return true;
00082     } else {
00083       result = possible_ref;    
00084       return false;
00085     }
00086   }
00087 
00088   bool
00089   is_sequence_wrapper(Type const& possible_sequence_wrapper,
00090                       Type& found_sequence_value_type) {
00091     Type possible_sequence;
00092     if (!edm::wrapper_type_of(possible_sequence_wrapper, possible_sequence)) {
00093       return false;
00094     }
00095 
00096     Type outer_value_type;
00097     if (!edm::value_type_of(possible_sequence, outer_value_type)) {
00098       return false;
00099     }
00100 
00101     if (!if_edm_ref_get_value_type(outer_value_type,
00102                                    found_sequence_value_type)) {
00103 
00104       if (!if_edm_ptr_get_value_type(outer_value_type,
00105                                      found_sequence_value_type)) {
00106 
00107         if_edm_refToBase_get_value_type(outer_value_type,
00108                                         found_sequence_value_type);
00109       }
00110     }
00111     return true;
00112   }
00113 
00114   bool
00115   is_RefVector(Reflex::Type const& possible_ref_vector,
00116                Reflex::Type& value_type) {
00117 
00118     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::RefVector", 3));
00119     static std::string member_type("member_type");
00120     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00121     if (primary_template_id == ref_vector_template_id) {
00122       return find_nested_type_named(member_type, possible_ref_vector, value_type);
00123     }
00124     return false;
00125   }
00126 
00127   bool
00128   is_PtrVector(Reflex::Type const& possible_ref_vector,
00129                Reflex::Type& value_type) {
00130 
00131     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::PtrVector", 1));
00132     static std::string member_type("member_type");
00133     static std::string val_type("value_type");
00134     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00135     if (primary_template_id == ref_vector_template_id) {
00136       Reflex::Type ptrType;
00137       if (find_nested_type_named(val_type, possible_ref_vector, ptrType)) {
00138         return find_nested_type_named(val_type, ptrType, value_type);
00139       }
00140     }
00141     return false;
00142   }
00143 
00144   bool
00145   is_RefToBaseVector(Reflex::Type const& possible_ref_vector,
00146                      Reflex::Type& value_type) {
00147 
00148     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::RefToBaseVector", 1));
00149     static std::string member_type("member_type");
00150     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00151     if (primary_template_id == ref_vector_template_id) {
00152       return find_nested_type_named(member_type, possible_ref_vector, value_type);
00153     }
00154     return false;
00155   }
00156 
00157   namespace {
00158 
00159     int const oneParamArraySize = 6;
00160     std::string const oneParam[oneParamArraySize] = {
00161       "vector",
00162       "basic_string",
00163       "set",
00164       "list",
00165       "deque",
00166       "multiset"
00167     };
00168     int const twoParamArraySize = 3;
00169     std::string const twoParam[twoParamArraySize] = {
00170       "map",
00171       "pair",
00172       "multimap"
00173     };
00174 
00175 
00176     bool
00177     hasCintDictionary(std::string const& name) {
00178       std::auto_ptr<G__ClassInfo> ci(new G__ClassInfo(name.c_str()));
00179         return (ci.get() && ci->IsLoaded());
00180     }
00181 
00182     // Checks if there is a Reflex dictionary for the Type t.
00183     // If noComponents is false, checks members and base classes recursively.
00184     // If noComponents is true, checks Type t only.
00185     void
00186     checkType(Type t, bool noComponents = false) {
00187 
00188       // The only purpose of this cache is to stop infinite recursion.
00189       // Reflex maintains its own internal cache.
00190       static boost::thread_specific_ptr<StringSet> found_types;
00191       if (0 == found_types.get()) {
00192         found_types.reset(new StringSet);
00193       }
00194 
00195       // ToType strips const, volatile, array, pointer, reference, etc.,
00196       // and also translates typedefs.
00197       // To be safe, we do this recursively until we either get a null type
00198       // or the same type.
00199       Type null;
00200       for (Type x = t.ToType(); x != null && x != t; t = x, x = t.ToType()) {}
00201 
00202       std::string name = t.Name(SCOPED);
00203       boost::trim(name);
00204 
00205       if (found_types->end() != found_types->find(name) || missingTypes().end() != missingTypes().find(name)) {
00206         // Already been processed.  Prevents infinite loop.
00207         return;
00208       }
00209 
00210       if (name.empty() || t.IsFundamental() || t.IsEnum()) {
00211         found_types->insert(name);
00212         return;
00213       }
00214 
00215       if (!bool(t)) {
00216         if (hasCintDictionary(name)) {
00217           found_types->insert(name);
00218         } else {
00219           missingTypes().insert(name);
00220         }
00221         return;
00222       }
00223 
00224       found_types->insert(name);
00225       if (noComponents) return;
00226 
00227       if (name.find("std::") == 0) {
00228         if (t.IsTemplateInstance()) {
00229           std::string::size_type n = name.find('<');
00230           int cnt = 0;
00231           if (std::find(oneParam, oneParam + oneParamArraySize, name.substr(5, n - 5)) != oneParam + oneParamArraySize) {
00232             cnt = 1;
00233           } else if (std::find(twoParam, twoParam + twoParamArraySize, name.substr(5, n - 5)) != twoParam + twoParamArraySize) {
00234             cnt = 2;
00235           }
00236           for(int i = 0; i < cnt; ++i) {
00237             checkType(t.TemplateArgumentAt(i));
00238           }
00239         }
00240       } else {
00241         int mcnt = t.DataMemberSize();
00242         for(int i = 0; i < mcnt; ++i) {
00243           Member m = t.DataMemberAt(i);
00244           if(m.IsTransient() || m.IsStatic()) continue;
00245           checkType(m.TypeOf());
00246         }
00247         int cnt = t.BaseSize();
00248         for(int i = 0; i < cnt; ++i) {
00249           checkType(t.BaseAt(i).ToType());
00250         }
00251       }
00252     }
00253   } // end unnamed namespace
00254 
00255   StringSet& missingTypes() {
00256     static boost::thread_specific_ptr<StringSet> missingTypes_;
00257     if (0 == missingTypes_.get()) {
00258       missingTypes_.reset(new StringSet);
00259     }
00260     return *missingTypes_.get();
00261   }
00262 
00263   void checkDictionaries(std::string const& name, bool noComponents) {
00264     Type null;
00265     Type t = Type::ByName(name);
00266     if (t == null) {
00267       missingTypes().insert(name);
00268       return;
00269     }
00270     checkType(Type::ByName(name), noComponents);
00271   }
00272 
00273   void public_base_classes(const Type& type,
00274                            std::vector<Type>& baseTypes) {
00275 
00276     if (type.IsClass() || type.IsStruct()) {
00277 
00278       int nBase = type.BaseSize();
00279       for (int i = 0; i < nBase; ++i) {
00280 
00281         Base base = type.BaseAt(i);
00282         if (base.IsPublic()) {
00283 
00284           Type baseType = type.BaseAt(i).ToType();
00285           if (bool(baseType)) {
00286 
00287             while (baseType.IsTypedef() == true) {
00288               baseType = baseType.ToType();
00289             }
00290 
00291             // Check to make sure this base appears only once in the
00292             // inheritance heirarchy.
00293             if (!search_all(baseTypes, baseType)) {
00294               // Save the type and recursive look for its base types
00295               baseTypes.push_back(baseType);
00296               public_base_classes(baseType, baseTypes);
00297             }
00298             // For now just ignore it if the class appears twice,
00299             // After some more testing we may decide to uncomment the following
00300             // exception.
00301             /*
00302             else {
00303               throw edm::Exception(edm::errors::UnimplementedFeature)
00304                 << "DataFormats/Common/src/ReflexTools.cc in function public_base_classes.\n"
00305                 << "Encountered class that has a public base class that appears\n"
00306                 << "multiple times in its inheritance heirarchy.\n"
00307                 << "Please contact the EDM Framework group with details about\n"
00308                 << "this exception.  It was our hope that this complicated situation\n"
00309                 << "would not occur.  There are three possible solutions.  1. Change\n"
00310                 << "the class design so the public base class does not appear multiple\n"
00311                 << "times in the inheritance heirarchy.  In many cases, this is a\n"
00312                 << "sign of bad design.  2.  Modify the code that supports Views to\n"
00313                 << "ignore these base classes, but not supply support for creating a\n"
00314                 << "View of this base class.  3.  Improve the View infrastructure to\n"
00315                 << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
00316             }
00317             */
00318           }
00319         }
00320       }
00321     }
00322   }
00323 
00324   void const*
00325   reflex_pointer_adjust(void* raw,
00326                         Type const& dynamicType,
00327                         std::type_info const& toType)
00328   {
00329     Object  obj(dynamicType, raw);
00330     return obj.CastObject(Type::ByTypeInfo(toType)).Address();
00331   }
00332 }