Go to the documentation of this file.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
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
00060 struct EmptyStruct { };
00061
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
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
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
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
00094
00095
00096
00097
00098
00099
00100 namespace {
00102
00103
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
00133
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
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
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