packing.cc
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 // 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 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41