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
00217
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
00270
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
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
00534
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
00560
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
00606
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