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


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