typemodel.cc
Go to the documentation of this file.
00001 #include "typemodel.hh"
00002 #include "value.hh"
00003 #include "registry.hh"
00004 
00005 #include "typename.hh"
00006 #include <boost/tuple/tuple.hpp>
00007   
00008 #include <iostream>
00009 #include <sstream>
00010 
00011 #include <numeric>
00012 #include <algorithm>
00013 using namespace std;
00014 
00015 #include <iostream>
00016 #include <boost/lexical_cast.hpp>
00017 using boost::lexical_cast;
00018 
00019 namespace Typelib
00020 {
00021     Type::Type(std::string const& name, size_t size, Category category)
00022         : m_size(size)
00023         , m_category(category)
00024         , m_metadata(new MetaData)
00025     {
00026         setName(name);
00027     }
00028 
00029     Type::Type(Type const& type)
00030         : m_name(type.m_name)
00031         , m_size(type.m_size)
00032         , m_category(type.m_category)
00033         , m_metadata(new MetaData(*type.m_metadata))
00034     {
00035     }
00036 
00037     Type::~Type()
00038     {
00039         delete m_metadata;
00040     }
00041 
00042     std::string Type::getName() const { return m_name; }
00043     std::string Type::getBasename() const { return getTypename(m_name); }
00044     std::string Type::getNamespace() const { return Typelib::getNamespace(m_name); }
00045     void Type::setName(const std::string& name) { m_name = name; }
00046     Type::Category Type::getCategory() const { return m_category; }
00047     void Type::modifiedDependencyAliases(Registry& registry) const {}
00048 
00049     void   Type::setSize(size_t size) { m_size = size; }
00050     size_t Type::getSize() const { return m_size; }
00051     bool   Type::isNull() const { return m_category == NullType; }
00052     bool   Type::operator != (Type const& with) const { return (this != &with); }
00053     bool   Type::operator == (Type const& with) const { return (this == &with); }
00054     bool   Type::isSame(Type const& with) const
00055     { 
00056         if (this == &with)
00057             return true;
00058 
00059         RecursionStack stack;
00060         stack.insert(make_pair(this, &with));
00061         return do_compare(with, true, stack);
00062     }
00063     bool   Type::canCastTo(Type const& with) const
00064     {
00065         if (this == &with)
00066             return true;
00067 
00068         RecursionStack stack;
00069         stack.insert(make_pair(this, &with));
00070         return do_compare(with, false, stack);
00071     }
00072 
00073     unsigned int Type::getTrailingPadding() const
00074     { return 0; }
00075 
00076     bool Type::rec_compare(Type const& left, Type const& right, bool equality, RecursionStack& stack) const
00077     {
00078         if (&left == &right)
00079             return true;
00080 
00081         RecursionStack::const_iterator it = stack.find(&left);
00082         if (it != stack.end())
00083         {
00089             return (&right == it->second);
00090         }
00091 
00092         RecursionStack::iterator new_it = stack.insert( make_pair(&left, &right) ).first;
00093         try {
00094             return left.do_compare(right, equality, stack);
00095         }
00096         catch(...) {
00097             stack.erase(new_it);
00098             throw;
00099         }
00100     }
00101     bool Type::do_compare(Type const& other, bool equality, RecursionStack& stack) const
00102     { return (getSize() == other.getSize() && getCategory() == other.getCategory()); }
00103 
00104     Type const& Type::merge(Registry& registry) const
00105     {
00106         RecursionStack stack;
00107         return merge(registry, stack);
00108     }
00109     Type const* Type::try_merge(Registry& registry, RecursionStack& stack) const
00110     {
00111         RecursionStack::iterator it = stack.find(this);
00112         if (it != stack.end())
00113             return it->second;
00114 
00115         Type const* old_type = registry.get(getName());
00116         if (old_type)
00117         {
00118             if (old_type->do_compare(*this, true, stack))
00119             {
00120                 stack.insert(make_pair(this, old_type));
00121                 return old_type;
00122             }
00123             else
00124                 throw DefinitionMismatch(getName());
00125         }
00126         return NULL;
00127     }
00128     Type const& Type::merge(Registry& registry, RecursionStack& stack) const
00129     {
00130         Type const* old_type = try_merge(registry, stack);
00131         if (old_type)
00132             return *old_type;
00133 
00134         Type* new_type = do_merge(registry, stack);
00135         stack.insert(make_pair(this, new_type));
00136         registry.add(new_type);
00137         return *new_type;
00138     }
00139 
00140     bool Type::resize(Registry& registry, std::map<std::string, std::pair<size_t, size_t> >& new_sizes)
00141     {
00142         size_t old_size = getSize();
00143         if (new_sizes.count(getName()))
00144             return true;
00145         else if (do_resize(registry, new_sizes))
00146         {
00147             new_sizes.insert(make_pair(getName(), make_pair(old_size, getSize()) ));
00148             return true;
00149         }
00150         else
00151             return false;
00152     }
00153 
00154     bool Type::do_resize(Registry& into, std::map<std::string, std::pair<size_t, size_t> >& new_sizes)
00155     {
00156         map<std::string, std::pair<size_t, size_t> >::const_iterator it =
00157             new_sizes.find(getName());
00158         if (it != new_sizes.end())
00159         {
00160             size_t new_size = it->second.second;
00161             if (getSize() != new_size)
00162             {
00163                 setSize(new_size);
00164                 return true;
00165             }
00166         }
00167         return false;
00168     }
00169 
00170     MetaData& Type::getMetaData() const
00171     {
00172         return *m_metadata;
00173     }
00174 
00175     MetaData::Values Type::getMetaData(std::string const& key) const
00176     {
00177         return m_metadata->get(key);
00178     }
00179 
00180     void Type::mergeMetaData(Type const& other) const
00181     {
00182         m_metadata->merge(other.getMetaData());
00183     }
00184 
00185     bool MetaData::include(std::string const& key) const
00186     {
00187         return m_values.find(key) != m_values.end();
00188     }
00189 
00190     MetaData::Map const& MetaData::get() const
00191     {
00192         return m_values;
00193     }
00194 
00195     MetaData::Values MetaData::get(std::string const& key) const
00196     {
00197         Map::const_iterator it = m_values.find(key);
00198         if (it == m_values.end())
00199             return Values();
00200         return it->second;
00201     }
00202 
00203     void MetaData::set(std::string const& key, std::string const& value)
00204     {
00205         clear(key);
00206         add(key, value);
00207     }
00208 
00209     void MetaData::add(std::string const& key, std::string const& value)
00210     {
00211         m_values[key].insert(value);
00212     }
00213 
00214     void MetaData::add(std::string const& key, Values const& values)
00215     {
00216         // This ensures that m_values[key] is at least initialized with an empty
00217         // Values object
00218         Values& key_values = m_values[key];
00219         for (Values::const_iterator it = values.begin(); it != values.end(); ++it)
00220             key_values.insert(*it);
00221     }
00222 
00223     void MetaData::clear(std::string const& key)
00224     {
00225         m_values.erase(key);
00226     }
00227 
00228     void MetaData::clear()
00229     {
00230         m_values.clear();
00231     }
00232 
00233     void MetaData::merge(MetaData const& metadata)
00234     {
00235         Map const& values = metadata.m_values;
00236         for (Map::const_iterator it = values.begin(); it != values.end(); ++it)
00237             m_values[it->first].insert(it->second.begin(), it->second.end());
00238     }
00239 
00240     bool OpaqueType::do_compare(Type const& other, bool equality, std::map<Type const*, Type const*>& stack) const
00241     { return Type::do_compare(other, equality, stack) && getName() == other.getName(); }
00242 
00243     Numeric::Numeric(std::string const& name, size_t size, NumericCategory category)
00244         : Type(name, size, Type::Numeric), m_category(category) {}
00245     Numeric::NumericCategory Numeric::getNumericCategory() const { return m_category; }
00246     bool Numeric::do_compare(Type const& type, bool equality, RecursionStack& stack) const 
00247     { return getSize() == type.getSize() && getCategory() == type.getCategory() && 
00248         m_category == static_cast<Numeric const&>(type).m_category; }
00249     Type* Numeric::do_merge(Registry& registry, RecursionStack& stack) const
00250     { return new Numeric(*this); }
00251 
00252     Indirect::Indirect(std::string const& name, size_t size, Category category, Type const& on)
00253         : Type(name, size, category)
00254         , m_indirection(on) {}
00255     Type const& Indirect::getIndirection() const { return m_indirection; }
00256     bool Indirect::do_compare(Type const& type, bool equality, RecursionStack& stack) const
00257     { return Type::do_compare(type, equality, stack) &&
00258         rec_compare(m_indirection, static_cast<Indirect const&>(type).m_indirection, equality, stack); }
00259     std::set<Type const*> Indirect::dependsOn() const
00260     {
00261         std::set<Type const*> result;
00262         result.insert(&getIndirection());
00263         return result;
00264     }
00265     Type const& Indirect::merge(Registry& registry, RecursionStack& stack) const
00266     {
00267         Type const* old_type = try_merge(registry, stack);
00268         if (old_type) return *old_type;
00269         // First, make sure the indirection is already merged and then merge
00270         // this type
00271         getIndirection().merge(registry, stack);
00272 
00273         return Type::merge(registry, stack);
00274     }
00275 
00276     void Indirect::modifiedDependencyAliases(Registry& registry) const
00277     {
00278         std::string full_name = getName();
00279         set<string> aliases = registry.getAliasesOf(getIndirection());
00280         for (set<string>::const_iterator alias_it = aliases.begin();
00281                 alias_it != aliases.end(); ++alias_it)
00282         {
00283             std::string alias_name = getIndirectTypeName(*alias_it);
00284             if (!registry.has(alias_name, false))
00285                 registry.alias(full_name, alias_name, false);
00286         }
00287     }
00288 
00289     bool Indirect::do_resize(Registry& registry, std::map<std::string, std::pair<size_t, size_t> >& new_sizes)
00290     {
00291         bool result = Type::do_resize(registry, new_sizes);
00292         return registry.get_(getIndirection()).resize(registry, new_sizes) || result;
00293     }
00294 
00295     Compound::Compound(std::string const& name)
00296         : Type(name, 0, Type::Compound) {}
00297 
00298     Compound::FieldList const&  Compound::getFields() const { return m_fields; }
00299     Field const* Compound::getField(const std::string& name) const 
00300     {
00301         for (FieldList::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00302         {
00303             if (it -> getName() == name)
00304                 return &(*it);
00305         }
00306         return NULL;
00307     }
00308     unsigned int Compound::getTrailingPadding() const
00309     {
00310         if (m_fields.empty())
00311             return getSize();
00312 
00313         FieldList::const_iterator it = m_fields.begin();
00314         FieldList::const_iterator const end = m_fields.end();
00315 
00316         int max_offset = 0;
00317         for (; it != end; ++it)
00318         {
00319             int offset = it->getOffset() + it->getType().getSize();
00320             if (offset > max_offset)
00321                 max_offset = offset;
00322         }
00323         return getSize() - max_offset;
00324     }
00325     bool Compound::do_compare(Type const& type, bool equality, RecursionStack& stack) const
00326     { 
00327         if (type.getCategory() != Type::Compound)
00328             return false;
00329         if (equality && !Type::do_compare(type, true, stack))
00330             return false;
00331 
00332         Compound const& right_type = static_cast<Compound const&>(type);
00333         if (m_fields.size() != right_type.getFields().size())
00334             return false;
00335 
00336         FieldList::const_iterator left_it = m_fields.begin(),
00337             left_end = m_fields.end(),
00338             right_it = right_type.getFields().begin();
00339 
00340         while (left_it != left_end)
00341         {
00342             if (left_it->getName() != right_it->getName()
00343                     || left_it->m_offset != right_it->m_offset
00344                     || left_it->m_name != right_it->m_name)
00345                 return false;
00346 
00347             if (!rec_compare(left_it->getType(), right_it->getType(), equality, stack))
00348                 return false;
00349             ++left_it; ++right_it;
00350         }
00351         return true;
00352     }
00353 
00354     Field const& Compound::addField(const std::string& name, Type const& type, size_t offset) 
00355     { return addField( Field(name, type), offset ); }
00356     Field const& Compound::addField(Field const& field, size_t offset)
00357     {
00358         m_fields.push_back(field);
00359         m_fields.back().setOffset(offset);
00360         size_t old_size = getSize();
00361         size_t new_size = offset + field.getType().getSize();
00362         if (old_size < new_size)
00363             setSize(new_size);
00364         return m_fields.back();
00365     }
00366     Type* Compound::do_merge(Registry& registry, RecursionStack& stack) const
00367     {
00368         auto_ptr<Compound> result(new Compound(getName()));
00369         RecursionStack::iterator it = stack.insert(make_pair(this, result.get())).first;
00370 
00371         try  {
00372             for (FieldList::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00373                 result->addField(it->getName(), it->getType().merge(registry, stack), it->getOffset());
00374         }
00375         catch(...) {
00376             stack.erase(it);
00377             throw;
00378         }
00379 
00380         result->setSize(getSize());
00381         return result.release();
00382     }
00383     std::set<Type const*> Compound::dependsOn() const
00384     {
00385         std::set<Type const*> result;
00386         for (FieldList::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00387             result.insert(&(it->getType()));
00388         return result;
00389     }
00390 
00391     bool Compound::do_resize(Registry& registry, std::map<std::string, std::pair<size_t, size_t> >& new_sizes)
00392     {
00393         size_t global_offset = 0;
00394         for (FieldList::iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00395         {
00396             it->setOffset(it->getOffset() + global_offset);
00397 
00398             Type& field_type = registry.get_(it->getType());
00399             if (field_type.resize(registry, new_sizes))
00400             {
00401                 size_t old_size = new_sizes.find(field_type.getName())->second.first;
00402                 global_offset += field_type.getSize() - old_size;
00403             }
00404         }
00405         if (global_offset != 0)
00406         {
00407             setSize(getSize() + global_offset);
00408             return true;
00409         }
00410         return false;
00411     }
00412 
00413     void Compound::mergeMetaData(Type const& other) const
00414     {
00415         Type::mergeMetaData(other);
00416         Compound const* other_compound = dynamic_cast<Compound const*>(&other);
00417         if (other_compound)
00418         {
00419             for (FieldList::const_iterator it = m_fields.begin(); it != m_fields.end(); ++it)
00420             {
00421                 Field const* other_field = other_compound->getField(it->getName());
00422                 if (other_field)
00423                     it->mergeMetaData(*other_field);
00424             }
00425         }
00426     }
00427 
00428     Enum::AlreadyExists::AlreadyExists(Type const& type, std::string const& name)
00429         : std::runtime_error("enumeration symbol " + name + " is already used in " + type.getName()) {}
00430     Enum::SymbolNotFound::SymbolNotFound(Type const& type, std::string const& name)
00431             : std::runtime_error("enumeration symbol " + name + " does not exist in " + type.getName()) {}
00432     Enum::ValueNotFound::ValueNotFound(Type const& type, int value)
00433             : std::runtime_error("no symbol associated with " + boost::lexical_cast<std::string>(value)  + " in " + type.getName()) {}
00434 
00435     namespace
00436     {
00437         enum FindSizeOfEnum { EnumField };
00438         BOOST_STATIC_ASSERT(( sizeof(FindSizeOfEnum) == sizeof(Enum::integral_type) ));
00439     }
00440     Enum::Enum(const std::string& name, Enum::integral_type initial_value)
00441         : Type (name, sizeof(FindSizeOfEnum), Type::Enum)
00442         , m_last_value(initial_value - 1) { }
00443     Enum::ValueMap const& Enum::values() const { return m_values; }
00444     bool Enum::do_compare(Type const& type, bool equality, RecursionStack& stack) const
00445     {
00446         Enum const& other_type = static_cast<Enum const&>(type);
00447         if (!Type::do_compare(type, equality, stack))
00448             return true;
00449         if (equality)
00450             return (m_values == other_type.m_values);
00451         else
00452         {
00453             ValueMap const& other_values = other_type.m_values;
00454             // returns true if +self+ is a subset of +type+
00455             if (m_values.size() > other_values.size())
00456                 return false;
00457             for (ValueMap::const_iterator it = m_values.begin(); it != m_values.end(); ++it)
00458             {
00459                 ValueMap::const_iterator other_it = other_values.find(it->first);
00460                 if (other_it == other_values.end())
00461                     return false;
00462                 if (other_it->second != it->second)
00463                     return false;
00464             }
00465             return true;
00466         }
00467     }
00468 
00469     Enum::integral_type Enum::getNextValue() const { return m_last_value + 1; }
00470     void Enum::add(std::string const& name, int value)
00471     { 
00472         std::pair<ValueMap::iterator, bool> inserted;
00473         inserted = m_values.insert( make_pair(name, value) );
00474         if (!inserted.second && inserted.first->second != value)
00475             throw AlreadyExists(*this, name);
00476         m_last_value = value;
00477     }
00478     Enum::integral_type  Enum::get(std::string const& name) const
00479     {
00480         ValueMap::const_iterator it = m_values.find(name);
00481         if (it == m_values.end())
00482             throw SymbolNotFound(*this, name);
00483         else
00484             return it->second;
00485     }
00486     std::string Enum::get(Enum::integral_type value) const
00487     {
00488         ValueMap::const_iterator it;
00489         for (it = m_values.begin(); it != m_values.end(); ++it)
00490         {
00491             if (it->second == value)
00492                 return it->first;
00493         }
00494         throw ValueNotFound(*this, value);
00495     }
00496     std::list<std::string> Enum::names() const
00497     {
00498         list<string> ret;
00499         ValueMap::const_iterator it;
00500         for (it = m_values.begin(); it != m_values.end(); ++it)
00501             ret.push_back(it->first);
00502         return ret;
00503     }
00504     Type* Enum::do_merge(Registry& registry, RecursionStack& stack) const
00505     { return new Enum(*this); }
00506 
00507     Array::Array(Type const& of, size_t new_dim)
00508         : Indirect(getArrayName(of.getName(), new_dim), new_dim * of.getSize(), Type::Array, of)
00509         , m_dimension(new_dim) { }
00510 
00511     std::string Array::getIndirectTypeName(std::string const& inside_type_name) const
00512     {
00513         return Array::getArrayName(inside_type_name, getDimension());
00514     }
00515 
00516     std::string Array::getArrayName(std::string const& name, size_t dim)
00517     { 
00518         std::ostringstream stream;
00519         stream << name << '[' << dim << ']';
00520         return stream.str();
00521     }
00522     size_t  Array::getDimension() const { return m_dimension; }
00523     bool Array::do_compare(Type const& type, bool equality, RecursionStack& stack) const
00524     {
00525         if (!Type::do_compare(type, equality, stack))
00526             return false;
00527 
00528         Array const& array = static_cast<Array const&>(type);
00529         return (m_dimension == array.m_dimension) && Indirect::do_compare(type, true, stack);
00530     }
00531     Type* Array::do_merge(Registry& registry, RecursionStack& stack) const
00532     {
00533         // The pointed-to type has already been inserted in the repository by
00534         // Indirect::merge, so we don't have to worry.
00535         Type const& indirect_type = getIndirection().merge(registry, stack);
00536         return new Array(indirect_type, m_dimension);
00537     }
00538 
00539     bool Array::do_resize(Registry& registry, std::map<std::string, std::pair<size_t, size_t> >& new_sizes)
00540     {
00541         if (!Indirect::do_resize(registry, new_sizes))
00542             return false;
00543 
00544         setSize(getDimension() * getIndirection().getSize());
00545         return true;
00546     }
00547 
00548     Pointer::Pointer(const Type& on)
00549         : Indirect( getPointerName(on.getName()), sizeof(int *), Type::Pointer, on) {}
00550     std::string Pointer::getPointerName(std::string const& base)
00551     { return base + '*'; }
00552     std::string Pointer::getIndirectTypeName(std::string const& inside_type_name) const
00553     {
00554         return Pointer::getPointerName(inside_type_name);
00555     }
00556 
00557     Type* Pointer::do_merge(Registry& registry, RecursionStack& stack) const
00558     {
00559         // The pointed-to type has already been inserted in the repository by
00560         // Indirect::merge, so we don't have to worry.
00561         Type const& indirect_type = getIndirection().merge(registry, stack);
00562         return new Pointer(indirect_type);
00563     }
00564 
00565     Container::Container(std::string const& kind, std::string const& name, size_t size, Type const& of)
00566         : Indirect( name, size, Type::Container, of )
00567         , m_kind(kind) {}
00568 
00569     std::string Container::kind() const { return m_kind; }
00570 
00571     Container::AvailableContainers Container::s_available_containers;
00572     const Container::AvailableContainers& Container::availableContainers() {
00573         return s_available_containers;
00574     }
00575 
00576     void Container::registerContainer(std::string const& name, ContainerFactory factory)
00577     {
00578         s_available_containers[name] = factory;
00579     }
00580     Container const& Container::createContainer(Registry& r, std::string const& name, Type const& on)
00581     {
00582         std::list<Type const*> temp;
00583         temp.push_back(&on);
00584         return createContainer(r, name, temp);
00585     }
00586     Container const& Container::createContainer(Registry& r, std::string const& name, std::list<Type const*> const& on)
00587     {
00588         AvailableContainers::const_iterator it = s_available_containers.find(name);
00589         if (it == s_available_containers.end())
00590             throw UnknownContainer(name);
00591         return (*it->second)(r, on);
00592     }
00593 
00594     bool Container::do_compare(Type const& other, bool equality, RecursionStack& stack) const
00595     {
00596         if (!Type::do_compare(other, true, stack))
00597             return false;
00598 
00599         Container const& container = static_cast<Container const&>(other);
00600         return (getFactory() == container.getFactory()) && Indirect::do_compare(other, true, stack);
00601     }
00602 
00603     Type* Container::do_merge(Registry& registry, RecursionStack& stack) const
00604     {
00605         // The pointed-to type has already been inserted in the repository by
00606         // Indirect::merge, so we don't have to worry.
00607         Type const& indirect_type = getIndirection().merge(registry, stack);
00608         std::list<Type const*> on;
00609         on.push_back(&indirect_type);
00610         Container* result = const_cast<Container*>(&(*getFactory())(registry, on));
00611         result->setSize(getSize());
00612         return result;
00613     }
00614 
00615     bool Container::isRandomAccess() const { return false; }
00616     void Container::setElement(void* ptr, int idx, Typelib::Value value) const
00617     { throw std::logic_error("trying to use setElement on a container that is not random-access"); }
00618     Typelib::Value Container::getElement(void* ptr, int idx) const
00619     { throw std::logic_error("trying to use getElement on a container that is not random-access"); }
00620 
00621     Field::Field(const std::string& name, const Type& type)
00622         : m_name(name), m_type(type), m_offset(0), m_metadata(new MetaData) {}
00623     Field::~Field()
00624     {
00625         delete m_metadata;
00626     }
00627     Field::Field(Field const& field)
00628         : m_name(field.m_name)
00629         , m_type(field.m_type)
00630         , m_offset(field.m_offset)
00631         , m_metadata(new MetaData(*field.m_metadata))
00632     {
00633     }
00634 
00635     std::string Field::getName() const { return m_name; }
00636     Type const& Field::getType() const { return m_type; }
00637     size_t  Field::getOffset() const { return m_offset; }
00638     void    Field::setOffset(size_t offset) { m_offset = offset; }
00639     bool Field::operator == (Field const& field) const
00640     { return m_offset == field.m_offset && m_name == field.m_name && m_type.isSame(field.m_type); }
00641     MetaData& Field::getMetaData() const
00642     { return *m_metadata; }
00643     MetaData::Values Field::getMetaData(std::string const& key) const
00644     { return m_metadata->get(key); }
00645     void Field::mergeMetaData(Field const& field) const
00646     { return m_metadata->merge(field.getMetaData()); }
00647 
00648 
00649     BadCategory::BadCategory(Type::Category found, Type::Category expected)
00650         : TypeException("bad category: found " + lexical_cast<string>(found) + " expecting " + lexical_cast<string>(expected))
00651         , found(found), expected(expected) {}
00652     NullTypeFound::NullTypeFound()
00653         : TypeException("null type found") { }
00654     NullTypeFound::NullTypeFound(Type const& type)
00655         : TypeException("null type " + type.getName() + " found") { }
00656 };
00657 


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