$search
00001 #include "packing.hh" 00002 #include <typelib/typemodel.hh> 00003 #include <typelib/typevisitor.hh> 00004 #include <boost/lexical_cast.hpp> 00005 #include <typelib/typedisplay.hh> 00006 00007 00009 // 00010 // Check some assumptions we make in the packing code 00011 // 00012 00013 #include <boost/mpl/size.hpp> 00014 #include "packing/tools.tcc" 00015 #include "packing/check_arrays.tcc" 00016 #include "packing/check_struct_in_struct.tcc" 00017 #include "packing/check_size_criteria.tcc" 00018 00019 #include <vector> 00020 #include <set> 00021 #include <map> 00022 00023 namespace 00024 { 00025 struct PackingInfo 00026 { 00027 size_t size; 00028 size_t packing; 00029 PackingInfo() 00030 : size(0), packing(0) {} 00031 }; 00032 00033 int const packing_info_size = ::boost::mpl::size<podlist>::type::value; 00034 PackingInfo packing_info[packing_info_size]; 00035 00036 template<typename T> 00037 struct DiscoverCollectionPacking 00038 { 00039 int8_t v; 00040 T collection; 00041 00042 static size_t get() { 00043 DiscoverCollectionPacking<T> obj; 00044 return reinterpret_cast<uint8_t*>(&obj.collection) - reinterpret_cast<uint8_t*>(&obj); 00045 } 00046 }; 00047 00048 struct CollectionPackingInfo 00049 { 00050 char const* name; 00051 size_t packing; 00052 }; 00053 00059 // To get the size of an empty struct 00060 struct EmptyStruct { }; 00061 // Rounded size is 24 00062 struct StructSizeDiscovery1 { int64_t a; int64_t z; int8_t end; }; 00063 struct StructSizeDiscovery2 { int32_t a; int32_t b; int64_t z; int8_t end; }; 00064 // Rounded size is 20 00065 struct StructSizeDiscovery3 { int32_t a; int32_t b; int32_t c; int32_t d; int8_t end; }; 00066 struct StructSizeDiscovery4 { int32_t a[4]; int8_t end; }; 00067 struct StructSizeDiscovery5 { int16_t a[2]; int32_t b[3]; int8_t end; }; 00068 // Rounded size is 18 00069 struct StructSizeDiscovery6 { int16_t a[2]; int16_t b[6]; int8_t end; }; 00070 struct StructSizeDiscovery7 { int8_t a[4]; int16_t b[6]; int8_t end; }; 00071 // Rounded size is 17 00072 struct StructSizeDiscovery8 { int8_t a[4]; int8_t b[12]; int8_t end; }; 00073 00074 BOOST_STATIC_ASSERT( 00075 (sizeof(long) == 8 && sizeof(StructSizeDiscovery1) == 24) || 00076 (sizeof(long) == 4 && sizeof(StructSizeDiscovery1) == 20)); 00077 BOOST_STATIC_ASSERT( 00078 (sizeof(long) == 8 && sizeof(StructSizeDiscovery2) == 24) || 00079 (sizeof(long) == 4 && sizeof(StructSizeDiscovery2) == 20)); 00080 00081 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery3) == 20); 00082 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery4) == 20); 00083 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery5) == 20); 00084 00085 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery6) == 18); 00086 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery7) == 18); 00087 00088 BOOST_STATIC_ASSERT(sizeof(StructSizeDiscovery8) == 17); 00089 00090 } 00091 #include "packing/build_packing_info.tcc" 00092 00093 // build_packing_info builds a 00094 // PackingInfo[] packing_info 00095 // 00096 // where the first element is the size to 00097 // consider and the second its packing 00098 00099 00100 namespace { 00102 // 00103 // Helpers for client code 00104 // 00105 00106 using namespace Typelib; 00107 00108 struct GetPackingSize : public TypeVisitor 00109 { 00110 int size; 00111 00112 GetPackingSize(Type const& base_type) 00113 : size(-1) 00114 { apply(base_type); } 00115 00116 bool visit_(Numeric const& value) 00117 { size = value.getSize(); 00118 return false; } 00119 bool visit_(Enum const& value) 00120 { size = value.getSize(); 00121 return false; } 00122 bool visit_(Pointer const& value) 00123 { size = value.getSize(); 00124 return false; } 00125 bool visit_(Compound const& value) 00126 { 00127 typedef Compound::FieldList Fields; 00128 Fields const& fields(value.getFields()); 00129 if (fields.empty()) 00130 throw Packing::FoundNullStructure(); 00131 00132 // TODO: add a static check for this 00133 // we assume that unions are packed as their biggest field 00134 00135 int max_size = 0; 00136 for (Fields::const_iterator it = fields.begin(); it != fields.end(); ++it) 00137 { 00138 GetPackingSize recursive(it->getType()); 00139 if (recursive.size == -1) 00140 throw std::runtime_error("cannot compute the packing size for " + value.getName()); 00141 00142 max_size = std::max(max_size, recursive.size); 00143 } 00144 size = max_size; 00145 return true; 00146 } 00147 bool visit_(Container const& value) 00148 { 00149 CollectionPackingInfo collection_packing_info[] = { 00150 { "/std/vector", DiscoverCollectionPacking< std::vector<uint16_t> >::get() }, 00151 { "/std/set", DiscoverCollectionPacking< std::set<uint8_t> >::get() }, 00152 { "/std/map", DiscoverCollectionPacking< std::map<uint8_t, uint8_t> >::get() }, 00153 { "/std/string", DiscoverCollectionPacking< std::string >::get() }, 00154 { 0, 0 } 00155 }; 00156 00157 for (CollectionPackingInfo* info = collection_packing_info; info->name; ++info) 00158 { 00159 if (info->name == std::string(value.getName(), 0, std::string(info->name).size())) 00160 { 00161 size = info->packing; 00162 return true; 00163 } 00164 } 00165 00166 throw Packing::PackingUnknown("cannot compute the packing of " + boost::lexical_cast<std::string>(value.getName())); 00167 } 00168 }; 00169 }; 00170 00171 #include <iostream> 00172 using std::cout; 00173 using std::endl; 00174 00175 int Typelib::Packing::getOffsetOf(const Field& last_field, const Type& append_field, size_t packing) 00176 { 00177 if (packing == 0) 00178 return 0; 00179 int base_offset = last_field.getOffset() + last_field.getType().getSize(); 00180 return (base_offset + (packing - 1)) / packing * packing; 00181 } 00182 int Typelib::Packing::getOffsetOf(Compound const& compound, const Type& append_field, size_t packing) 00183 { 00184 Compound::FieldList const& fields(compound.getFields()); 00185 if (fields.empty()) 00186 return 0; 00187 00188 return getOffsetOf(fields.back(), append_field, packing); 00189 } 00190 00191 int Typelib::Packing::getOffsetOf(const Field& last_field, const Type& append_field) 00192 { 00193 00194 GetPackingSize visitor(append_field); 00195 if (visitor.size == -1) 00196 throw PackingUnknown("cannot compute the packing of " + boost::lexical_cast<std::string>(append_field.getName())); 00197 00198 size_t const size(visitor.size); 00199 00200 for (int i = 0; i < packing_info_size; ++i) 00201 { 00202 if (packing_info[i].size == size) 00203 return getOffsetOf(last_field, append_field, packing_info[i].packing); 00204 } 00205 throw PackingUnknown("cannot compute the packing of " + boost::lexical_cast<std::string>(append_field.getName())); 00206 } 00207 int Typelib::Packing::getOffsetOf(const Compound& current, const Type& append_field) 00208 { 00209 Compound::FieldList const& fields(current.getFields()); 00210 if (fields.empty()) 00211 return 0; 00212 00213 return getOffsetOf(fields.back(), append_field); 00214 } 00215 00216 struct AlignmentBaseTypeVisitor : public TypeVisitor 00217 { 00218 Type const* result; 00219 00220 bool handleType(Type const& type) 00221 { 00222 if (!result || result->getSize() < type.getSize()) 00223 result = &type; 00224 return true; 00225 } 00226 00227 virtual bool visit_ (NullType const& type) { throw UnsupportedType(type, "cannot represent alignment of null types"); } 00228 virtual bool visit_ (OpaqueType const& type) { throw UnsupportedType(type, "cannot represent alignment of opaque types"); }; 00229 virtual bool visit_ (Numeric const& type) { return handleType(type); } 00230 virtual bool visit_ (Enum const& type) { return handleType(type); } 00231 00232 virtual bool visit_ (Pointer const& type) { return handleType(type); } 00233 virtual bool visit_ (Container const& type) { return handleType(type); } 00234 // arrays and compound are handled recursively 00235 00236 static Type const* find(Type const& type) 00237 { 00238 AlignmentBaseTypeVisitor visitor; 00239 visitor.result = NULL; 00240 visitor.apply(type); 00241 return visitor.result; 00242 } 00243 }; 00244 00245 int Typelib::Packing::getSizeOfCompound(Compound const& compound) 00246 { 00247 // Find the biggest type in the compound 00248 Compound::FieldList const& fields(compound.getFields()); 00249 if (fields.empty()) 00250 return sizeof(EmptyStruct); 00251 00252 Type const* biggest_type = AlignmentBaseTypeVisitor::find(compound); 00253 00254 return getOffsetOf(compound, *biggest_type); 00255 } 00256