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
00184
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
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
00434
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
00460
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
00511
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