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


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22