$search
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