registry.cc
Go to the documentation of this file.
00001 #include "registry.hh"
00002 #include "registryiterator.hh"
00003 #include "typebuilder.hh"
00004 #include "typedisplay.hh"
00005 
00006 #include <memory>
00007 #include <iostream>
00008 #include <set>
00009 using namespace std;
00010 
00011 #include <ctype.h>
00012 
00013 #include <boost/static_assert.hpp>
00014 #include <boost/lexical_cast.hpp>
00015 using boost::lexical_cast;
00016 
00017 #include <typelib/pluginmanager.hh>
00018 
00019 using namespace Typelib;
00020 
00021 /* Returns true if \c name1 is either in a more in-depth namespace than
00022  * name2 (i.e. name2 == /A/B/class and name1 == /A/B/C/class2 or if 
00023  * name2 < name1 (lexicographic sort). Otherwise, returns false
00024  */
00025 bool Typelib::nameSort( const std::string& name1, const std::string& name2 )
00026 {
00027     if (name1 == name2)
00028         return false;
00029 
00030     NameTokenizer tok1(name1);
00031     NameTokenizer tok2(name2);
00032     NameTokenizer::const_iterator it1 = tok1.begin();
00033     NameTokenizer::const_iterator it2 = tok2.begin();
00034 
00035     std::string ns1, ns2;
00036     // we sort /A/B/C/ before /A/B/C/class
00037     // and /A/B/C/class2 after /A/B/class1
00038     for (; it1 != tok1.end() && it2 != tok2.end(); ++it1, ++it2)
00039     {
00040         ns1 = *it1;
00041         ns2 = *it2;
00042 
00043         int value = ns1.compare(ns2);
00044         if (value) return value < 0;
00045         //cout << ns1 << " " << ns2 << endl;
00046     }
00047 
00048     if (it1 == tok1.end()) 
00049         return true;  // there is namespace names left in name1, and not in name2
00050     if (it2 == tok2.end()) 
00051         return false; // there is namespace names left in name2, and not in name1
00052     int value = ns1.compare(ns2);
00053     if (value) 
00054         return value < 0;
00055 
00056     return false;
00057 }
00058 
00059 namespace Typelib
00060 {
00061     Type const& Registry::null() { 
00062         static NullType const null_type("/nil");
00063         return null_type; 
00064     }
00065     
00066     Registry::Registry()
00067         : m_global(nameSort)
00068     { 
00069         PluginManager::self manager;
00070         manager->registerPluginTypes(*this);
00071         setDefaultNamespace("/");
00072     }
00073     Registry::~Registry() { clear(); }
00074 
00075     void Registry::updateCurrentNameMap()
00076     {
00077         m_current.clear();
00078 
00079         for (TypeMap::iterator it = m_global.begin(); it != m_global.end(); ++it)
00080             m_current.insert( make_pair(it->first, it->second) );
00081 
00082         importNamespace(NamespaceMarkString);
00083         std::string cur_space = NamespaceMarkString;
00084         NameTokenizer tokens( m_namespace );
00085         NameTokenizer::const_iterator ns_it = tokens.begin();
00086         for (; ns_it != tokens.end(); ++ns_it)
00087         {
00088             cur_space += *ns_it + NamespaceMarkString;
00089             importNamespace(cur_space, true);
00090         }
00091     }
00092 
00093     std::string Registry::getDefaultNamespace() const { return m_namespace; }
00094     bool Registry::setDefaultNamespace(const std::string& space)
00095     {
00096         if (! isValidNamespace(space, true))
00097             return false;
00098 
00099         m_namespace = getNormalizedNamespace(space);
00100         updateCurrentNameMap();
00101         return true;
00102     }
00103 
00104     void Registry::importNamespace(const std::string& name, bool erase_existing)
00105     {
00106         const std::string norm_name(getNormalizedNamespace(name));
00107         const int         norm_length(norm_name.length());
00108             
00109         TypeMap::const_iterator it = m_global.lower_bound(norm_name);
00110 
00111         while ( it != m_global.end() && isInNamespace(it->first, norm_name, true) )
00112         {
00113             const std::string rel_name(it->first, norm_length, string::npos);
00114             if (erase_existing)
00115                 m_current.erase(rel_name);
00116             m_current.insert( make_pair(rel_name, it->second) );
00117             ++it;
00118         }
00119     }
00120 
00121     std::string Registry::getFullName(const std::string& name) const
00122     {
00123         if (isAbsoluteName(name))
00124             return name;
00125         return m_namespace + name;
00126     }
00127 
00128     namespace {
00129         template<typename T>
00130         Numeric* make_std_numeric(char const* name)
00131         {
00132             typedef numeric_limits<T>   limits;
00133             Numeric::NumericCategory category = limits::is_signed ? Numeric::SInt : Numeric::UInt;
00134             unsigned int size = (limits::digits + 1) / 8;
00135             return new Numeric(name, size, category);
00136         }
00137     }
00138 
00140     bool Registry::isIncluded(Type const& type) const
00141     {
00142         Type const* this_type = get(type.getName());
00143         return (this_type == &type);
00144     }
00145 
00146     void Registry::merge(Registry const& registry)
00147     {
00148         Typelib::Type::RecursionStack stack;
00149 
00150         // Merge non aliased types. Aliases are never used by type model classes
00151         // so we can safely call merge()
00152         for(Iterator it = registry.begin(); it != registry.end(); ++it)
00153         {
00154             if (it.isAlias()) continue;
00155             it->merge(*this, stack);
00156         }
00157 
00158         for (Iterator it = registry.begin(); it != registry.end(); ++it)
00159         {
00160             // Either the alias already points to a concrete type, and
00161             // we must check that it is the same concrete type, or
00162             // we have to add the alias
00163             if (!it.isAlias()) continue;
00164 
00165             Type const* old_type = get(it.getName());
00166             if (old_type)
00167             {
00168                 if (!old_type->isSame(*it))
00169                     throw DefinitionMismatch(it.getName());
00170             }
00171             else
00172             {
00173                 // we are sure the concrete type we are pointing to is 
00174                 // already in the target registry
00175                 alias(it->getName(), it.getName(), it.isPersistent(), it.getSource());
00176             }
00177         }
00178         copySourceIDs(registry);
00179     }
00180 
00181     void Registry::copySourceIDs(Registry const& registry)
00182     {
00183         for (Iterator it = begin(); it != end(); ++it)
00184         {
00185             RegistryIterator other_it = registry.find(it.getName());
00186             if (other_it == registry.end())
00187                 continue;
00188 
00189             string source_id = other_it.getSource();
00190             if (!source_id.empty() && it.getSource().empty())
00191                 setSourceID(*it, source_id);
00192         }
00193     }
00194 
00195     Registry* Registry::minimal(std::string const& name, bool with_aliases) const
00196     {
00197         auto_ptr<Registry> result(new Registry);
00198         Type const* type = get(name);
00199         if (!type)
00200             throw std::runtime_error("there is not type '" + name + "' in this registry");
00201 
00202         type->merge(*result);
00203 
00204         // Copy now the aliases
00205         if (with_aliases)
00206         {
00207             for(Iterator it = begin(); it != end(); ++it)
00208             {
00209                 if (!it.isAlias()) continue;
00210                 if (result->has(it->getName(), false))
00211                     result->alias(it->getName(), it.getName());
00212             }
00213         }
00214 
00215         result->copySourceIDs(*this);
00216         return result.release();
00217     }
00218 
00219     Registry* Registry::minimal(Registry const& auto_types) const
00220     {
00221         auto_ptr<Registry> result(new Registry);
00222  
00223         // Merge non aliased types. Aliases are never used by type model classes
00224         // so we can safely call merge()
00225         for(Iterator it = begin(); it != end(); ++it)
00226         {
00227             if (it.isAlias()) continue;
00228             if (!auto_types.has(it->getName()))
00229                 it->merge(*result);
00230         }
00231 
00232         for (Iterator it = begin(); it != end(); ++it)
00233         {
00234             // Either the alias already points to a concrete type, and
00235             // we must check that it is the same concrete type, or
00236             // we have to add the alias
00237             if (!it.isAlias()) continue;
00238             if (auto_types.has(it.getName())) continue;
00239             // Do not continue if it is a typedef on a type that we don't need
00240             if (!result->has(it->getName())) continue;
00241 
00242             Type const* old_type = result->get(it.getName());
00243             if (old_type)
00244             {
00245                 if (!old_type->isSame(*it))
00246                     throw DefinitionMismatch(it.getName());
00247             }
00248             else
00249             {
00250                 result->alias(it->getName(), it.getName(), it.isPersistent(), it.getSource());
00251             }
00252         }
00253 
00254         return result.release();
00255     }
00256 
00257     bool Registry::has(const std::string& name, bool build_if_missing) const
00258     {
00259         if (m_current.find(name) != m_current.end())
00260             return true;
00261 
00262         if (! build_if_missing)
00263             return false;
00264 
00265         const Type* base_type = TypeBuilder::getBaseType(*this, getFullName(name));
00266         return base_type;
00267     }
00268 
00269     const Type* Registry::build(const std::string& name)
00270     {
00271         const Type* type = get(name);
00272         if (type)
00273             return type;
00274 
00275         return TypeBuilder::build(*this, getFullName(name));
00276     }
00277 
00278     Type* Registry::get_(const std::string& name)
00279     {
00280         NameMap::const_iterator it = m_current.find(name);
00281         if (it != m_current.end()) 
00282             return it->second.type;
00283         return 0;
00284     }
00285 
00286     Type& Registry::get_(Type const& type)
00287     { return *get_(type.getName()); }
00288 
00289     const Type* Registry::get(const std::string& name) const
00290     {
00291         NameMap::const_iterator it = m_current.find(name);
00292         if (it != m_current.end()) 
00293             return it->second.type;
00294         return 0;
00295     }
00296 
00297     RegistryIterator Registry::find(std::string const& name) const
00298     {
00299         TypeMap::const_iterator global_it =
00300             m_global.find(name);
00301         return RegistryIterator(*this, global_it);
00302     }
00303 
00304     bool Registry::isPersistent(std::string const& name, Type const& type, std::string const& source_id)
00305     {
00306         if (name != type.getName())
00307             return true;
00308 
00309         switch(type.getCategory())
00310         {
00311             case Type::Pointer:
00312             case Type::Array:
00313                 return false;
00314             default:
00315                 return true;
00316         };
00317     }
00318 
00319     void Registry::add(std::string const& name, Type* new_type, bool persistent, std::string const& source_id)
00320     {
00321         if (! isValidTypename(name, true))
00322             throw BadName(name);
00323 
00324         const Type* old_type = get(name);
00325         if (old_type == new_type) 
00326             return; 
00327         else if (old_type)
00328             throw AlreadyDefined(name);
00329 
00330         RegistryType regtype = 
00331             { new_type
00332             , persistent
00333             , source_id };
00334             
00335         m_global.insert (make_pair(name, regtype));
00336         m_current.insert(make_pair(name, regtype));
00337 
00338         NameTokenizer tokens( m_namespace );
00339         NameTokenizer::const_iterator ns_it = tokens.begin();
00340         std::string cur_space = NamespaceMarkString;
00341         while(true)
00342         {
00343             if (name.size() <= cur_space.size() || string(name, 0, cur_space.size()) != cur_space)
00344                 break;
00345 
00346             string cur_name  = getRelativeName(name, cur_space);
00347 
00348             // Check if there is already a type with the same relative name
00349             TypeMap::iterator it = m_current.find(cur_name);
00350             if (it == m_current.end() || !nameSort(it->second.type->getName(), name))
00351             {
00352                 m_current.erase(cur_name);
00353                 m_current.insert(make_pair(cur_name, regtype));
00354             }
00355 
00356             if (ns_it == tokens.end())
00357                 break;
00358             cur_space += *ns_it + NamespaceMarkString;
00359             ++ns_it;
00360         }
00361     }
00362 
00363     void Registry::add(Type* new_type, const std::string& source_id)
00364     {
00365         return add(new_type, isPersistent(new_type->getName(), *new_type, source_id), source_id);
00366     }
00367 
00368     void Registry::add(Type* new_type, bool persistent, const std::string& source_id)
00369     {
00370         add(new_type->getName(), new_type, persistent, source_id);
00371 
00372         // If there are any aliases for any of the type's dependencies, trigger
00373         // modifiedDependencyAliases()
00374         set<Type const*> dependencies = new_type->dependsOn();
00375         for (set<Type const*>::const_iterator dep_it = dependencies.begin();
00376                 dep_it != dependencies.end(); ++dep_it)
00377         {
00378             if (!getAliasesOf(**dep_it).empty())
00379             {
00380                 new_type->modifiedDependencyAliases(*this);
00381                 break;
00382             }
00383         }
00384     }
00385 
00386     void Registry::alias(std::string const& base, std::string const& newname, std::string const& source_id)
00387     {
00388         Type* base_type = get_(base);
00389         if (! base_type) 
00390             throw Undefined(base);
00391 
00392         return alias(base, newname, isPersistent(newname, *base_type, source_id), source_id);
00393     }
00394 
00395     void Registry::alias(std::string const& base, std::string const& newname, bool persistent, std::string const& source_id)
00396     {
00397         if (! isValidTypename(newname, true))
00398             throw BadName(newname);
00399 
00400         Type* base_type = get_(base);
00401         if (! base_type) 
00402             throw Undefined(base);
00403 
00404         add(newname, base_type, persistent, source_id);
00405 
00406         // If base_type is in use in any type, trigger
00407         // modifiedDependencyAliases() on it
00408         //
00409         // We do it in two stages as modifying a container while iterating on it
00410         // is evil ...
00411         std::list<Type const*> triggers;
00412         RegistryIterator const end = this->end();
00413         for (RegistryIterator it = begin(); it != end; ++it)
00414         {
00415             if (it.isAlias()) continue;
00416             set<Type const*> dependencies = it->dependsOn();
00417             if (dependencies.count(base_type))
00418                 triggers.push_back(&(*it));
00419         }
00420 
00421         for (list<Type const*>::const_iterator trigger_it = triggers.begin();
00422                 trigger_it != triggers.end(); ++trigger_it)
00423         {
00424             (*trigger_it)->modifiedDependencyAliases(*this);
00425         }
00426     }
00427 
00428     void Registry::clearAliases()
00429     {
00430         // We remove the aliases from +m_global+ and recompute m_current from
00431         // scratch
00432         TypeMap::iterator global_it = m_global.begin(), global_end = m_global.end();
00433         while (global_it != global_end)
00434         {
00435             if (global_it->first != global_it->second.type->getName())
00436                 m_global.erase(global_it++);
00437             else ++global_it;
00438         }
00439 
00440         updateCurrentNameMap();
00441     }
00442 
00443     size_t Registry::size() const { return m_global.size(); }
00444     void Registry::clear()
00445     {
00446         // Set the type pointer to 0 on aliases
00447         for (TypeMap::iterator it = m_global.begin(); it != m_global.end(); ++it)
00448         {
00449             if (it->first != it->second.type->getName())
00450                 it->second.type = 0;
00451         }
00452             
00453         // ... then delete the objects
00454         for (TypeMap::iterator it = m_global.begin(); it != m_global.end(); ++it)
00455             delete it->second.type;
00456             
00457         m_global.clear();
00458         m_current.clear();
00459     }
00460 
00461     namespace
00462     {
00463         bool filter_source(std::string const& filter, std::string const& source)
00464         {
00465             if (filter == "*")
00466                 return true;
00467             return filter == source;
00468         }
00469     }
00470 
00471     void Registry::dump(std::ostream& stream, int mode, const std::string& source_filter) const
00472     {
00473         stream << "Types in registry";
00474         if (source_filter == "")
00475             stream << " not defined in any type library";
00476         else if (source_filter != "*")
00477             stream << " defined in " << source_filter;
00478         stream << endl;
00479 
00480         TypeDisplayVisitor display(stream, "");
00481         for (TypeMap::const_iterator it = m_global.begin(); it != m_global.end(); ++it)
00482         {
00483             RegistryType regtype(it->second);
00484             if (! regtype.persistent)
00485                 continue;
00486             if (!filter_source(source_filter, regtype.source_id))
00487                 continue;
00488 
00489             if (mode & WithSourceId)
00490             {
00491                 string it_source_id = regtype.source_id;
00492                 if (it_source_id.empty()) stream << "\t\t";
00493                 else stream << it_source_id << "\t";
00494             }
00495 
00496             Type const* type = regtype.type;
00497             if (mode & AllType)
00498             {
00499                 if (type->getName() == it->first)
00500                 {
00501                     display.apply(*type);
00502                     stream << "\n";
00503                 }
00504                 else
00505                     stream << it->first << " is an alias for " << type->getName() << "\n";
00506             }
00507             else
00508                 stream << "\t" << type->getName() << endl;
00509         }
00510     }
00511 
00512     RegistryIterator Registry::begin() const { return RegistryIterator(*this, m_global.begin()); }
00513     RegistryIterator Registry::end() const { return RegistryIterator(*this, m_global.end()); }
00514     RegistryIterator Registry::begin(std::string const& prefix) const
00515     {
00516         RegistryIterator it(*this, m_global.lower_bound(prefix));
00517         RegistryIterator const end = this->end();
00518         if (it != end && it.getName().compare(0, prefix.length(), prefix) == 0)
00519             return it;
00520         else return end;
00521     }
00522     RegistryIterator Registry::end(std::string const& prefix) const
00523     {
00524         RegistryIterator it(begin(prefix));
00525         RegistryIterator const end = this->end();
00526         while (it != end && it.getName().compare(0, prefix.length(), prefix) == 0)
00527             ++it;
00528 
00529         return it;
00530     }
00531 
00532     bool Registry::isSame(Registry const& other) const
00533     {
00534         if (m_global.size() != other.m_global.size())
00535             return false;
00536 
00537         TypeMap::const_iterator
00538             left_it   = m_global.begin(),
00539             left_end  = m_global.end(),
00540             right_it  = other.m_global.begin();
00541 
00542         while (left_it != left_end)
00543         {
00544             if (!left_it->second.type->isSame(*right_it->second.type))
00545                 return false;
00546             left_it++; left_end++;
00547         }
00548         return true;
00549     }
00550 
00551     void Registry::resize(std::map<std::string, size_t> const& new_sizes)
00552     {
00553         typedef std::map<std::string, std::pair<size_t, size_t> > SizeMap;
00554         // First, do a copy of new_sizes for our own use. Most importantly, we
00555         // resolve aliases
00556         SizeMap sizes;
00557         for (std::map<std::string, size_t>::const_iterator it = new_sizes.begin();
00558                 it != new_sizes.end(); ++it)
00559         {
00560             Type& t = *get_(it->first);
00561             sizes.insert(make_pair(t.getName(),
00562                         make_pair(t.getSize(), it->second)
00563                         ));
00564             t.setSize(it->second);
00565         }
00566 
00567         for(Iterator it = begin(); it != end(); ++it)
00568         {
00569             if (it.isAlias()) continue;
00570             it.get_().resize(*this, sizes);
00571         }
00572     }
00573 
00574     std::set<Type const*> Registry::reverseDepends(Type const& type) const
00575     {
00576         std::set<Type const*> result;
00577         result.insert(&type);
00578 
00579         RegistryIterator const end = this->end();
00580         for (RegistryIterator it = this->begin(); it != end; ++it)
00581         {
00582             Type const& t = *it;
00583             if (it.isAlias()) continue;
00584 
00585             std::set<Type const*> dependencies = t.dependsOn();
00586             if (dependencies.count(&type))
00587                 result.insert(&t);
00588         }
00589 
00590         return result;
00591     }
00592 
00593     std::set<Type*> Registry::reverseDepends(Type const& type)
00594     {
00595         std::set<Type*> result;
00596 
00597         std::set<Type const*> const_result =
00598             static_cast<Registry const*>(this)->reverseDepends(type);
00599         std::set<Type const*>::const_iterator it, end;
00600         for (it = const_result.begin(); it != const_result.end(); ++it)
00601             result.insert(const_cast<Type*>(*it));
00602 
00603         return result;
00604     }
00605 
00606     std::set<Type *> Registry::remove(Type const& type)
00607     {
00608         std::set<Type*> types = reverseDepends(type);
00609 
00610         TypeMap::iterator global_it = m_global.begin(), global_end = m_global.end();
00611         while (global_it != global_end)
00612         {
00613             if (types.count(global_it->second.type))
00614                 m_global.erase(global_it++);
00615             else ++global_it;
00616         }
00617 
00618         NameMap::iterator current_it = m_current.begin(), current_end = m_current.end();
00619         while (current_it != current_end)
00620         {
00621             if (types.count(current_it->second.type))
00622                 m_current.erase(current_it++);
00623             else ++current_it;
00624         }
00625 
00626         return types;
00627     }
00628 
00629     std::set<std::string> Registry::getAliasesOf(Type const& type) const
00630     {
00631         set<string> result;
00632         RegistryIterator const end = this->end();
00633         for (RegistryIterator it = begin(); it != end; ++it)
00634         {
00635             if (it.isAlias() && *it == type)
00636                 result.insert(it.getName());
00637         }
00638         return result;
00639     }
00640 
00641     void Registry::setSourceID(Type const& type, std::string const& source_id)
00642     {
00643         TypeMap::iterator it = m_global.find(type.getName());
00644         if (it != m_global.end())
00645             it->second.source_id = source_id;
00646     }
00647 }; // namespace Typelib
00648 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41