memory_layout.cc
Go to the documentation of this file.
00001 #include "memory_layout.hh"
00002 using namespace Typelib;
00003 
00004 void MemLayout::Visitor::push_current_op()
00005 {
00006     if (current_op_count)
00007     {
00008         ops.push_back(current_op);
00009         ops.push_back(current_op_count);
00010         current_op_count = 0;
00011     }
00012 }
00013 void MemLayout::Visitor::skip(size_t count)
00014 { add_generic_op(FLAG_SKIP, count); }
00015 void MemLayout::Visitor::memcpy(size_t count)
00016 { add_generic_op(FLAG_MEMCPY, count); }
00017 
00018 void MemLayout::Visitor::add_generic_op(size_t op, size_t size)
00019 {
00020     if (size == 0)
00021         return;
00022     if (current_op != op)
00023         push_current_op();
00024 
00025     current_op = op;
00026     current_op_count += size;
00027 }
00028 
00029 bool MemLayout::Visitor::generic_visit(Type const& value)
00030 {
00031     memcpy(value.getSize());
00032     return true;
00033 };
00034 bool MemLayout::Visitor::visit_ (Numeric const& type) { return generic_visit(type); }
00035 bool MemLayout::Visitor::visit_ (Enum    const& type) { return generic_visit(type); }
00036 bool MemLayout::Visitor::visit_ (Array   const& type)
00037 {
00038     MemoryLayout subops;
00039     MemLayout::Visitor array_visitor(subops);
00040     array_visitor.apply(type.getIndirection(), merge_skip_copy, false);
00041 
00042     if (subops.size() == 2 && subops.front() == FLAG_MEMCPY)
00043         memcpy(subops.back() * type.getDimension());
00044     else
00045     {
00046         push_current_op();
00047         ops.push_back(FLAG_ARRAY);
00048         ops.push_back(type.getDimension());
00049         ops.insert(ops.end(), subops.begin(), subops.end());
00050         ops.push_back(FLAG_END);
00051     }
00052     return true;
00053 }
00054 bool MemLayout::Visitor::visit_ (Container const& type)
00055 {
00056     push_current_op();
00057     ops.push_back(FLAG_CONTAINER);
00058     ops.push_back(reinterpret_cast<size_t>(&type));
00059 
00060     MemoryLayout subops;
00061     MemLayout::Visitor container_visitor(subops);
00062     container_visitor.apply(type.getIndirection(), merge_skip_copy, false);
00063 
00064     ops.insert(ops.end(), subops.begin(), subops.end());
00065     ops.push_back(FLAG_END);
00066     return true;
00067 }
00068 bool MemLayout::Visitor::visit_ (Compound const& type)
00069 {
00070     typedef Compound::FieldList Fields;
00071     Fields const& fields(type.getFields());
00072     Fields::const_iterator const end = fields.end();
00073 
00074     size_t current_offset = 0;
00075     for (Fields::const_iterator it = fields.begin(); it != end; ++it)
00076     {
00077         skip(it->getOffset() - current_offset);
00078         dispatch(it->getType());
00079         current_offset = it->getOffset() + it->getType().getSize();
00080     }
00081     skip(type.getSize() - current_offset);
00082     return true;
00083 }
00084 bool MemLayout::Visitor::visit_ (Pointer const& type)
00085 {
00086     if (accept_pointers)
00087         return generic_visit(type);
00088     else
00089         throw NoLayout(type, "is a pointer");
00090 }
00091 bool MemLayout::Visitor::visit_ (OpaqueType const& type)
00092 {
00093     if (accept_opaques)
00094     {
00095         skip(type.getSize());
00096         return true;
00097     }
00098     else
00099         throw NoLayout(type, "is an opaque type");
00100 }
00101 
00102 MemLayout::Visitor::Visitor(MemoryLayout& ops, bool accept_pointers, bool accept_opaques)
00103     : ops(ops), accept_pointers(accept_pointers), accept_opaques(accept_opaques)
00104     , current_op(FLAG_MEMCPY), current_op_count(0) {}
00105 
00106 void MemLayout::Visitor::apply(Type const& type, bool merge_skip_copy, bool remove_trailing_skips)
00107 {
00108     this->merge_skip_copy = merge_skip_copy;
00109 
00110     current_op = FLAG_MEMCPY;
00111     current_op_count = 0;
00112     TypeVisitor::apply(type);
00113     push_current_op();
00114 
00115     // Remove trailing skips, they are useless
00116     if (remove_trailing_skips)
00117     {
00118         while (ops.size() > 2 && ops[ops.size() - 2] == FLAG_SKIP)
00119         {
00120             ops.pop_back();
00121             ops.pop_back();
00122         }
00123     }
00124 
00125     if (merge_skip_copy)
00126         merge_skips_and_copies();
00127 }
00128 
00129 void MemLayout::Visitor::merge_skips_and_copies()
00130 {
00131     // Merge skips and memcpy: if a skip is preceded by a memcpy (or another
00132     // skip), simply merge the counts.
00133     MemoryLayout merged;
00134 
00135     MemoryLayout::const_iterator it = ops.begin();
00136     MemoryLayout::const_iterator const end = ops.end();
00137     while (it != end)
00138     {
00139         size_t op   = *it;
00140         if (op != FLAG_SKIP && op != FLAG_MEMCPY)
00141         {
00142             MemoryLayout::const_iterator element_it = it;
00143             ++(++(element_it));
00144             MemoryLayout::const_iterator block_end_it = skip_block(element_it, end);
00145             ++block_end_it;
00146             merged.insert(merged.end(), it, block_end_it);
00147             it = block_end_it;
00148             continue;
00149         }
00150 
00151         // Merge following FLAG_MEMCPY and FLAG_SKIP operations
00152         size_t size = *(++it);
00153         for (++it; it != end; ++it)
00154         {
00155             if (*it == FLAG_MEMCPY)
00156                 op = FLAG_MEMCPY;
00157             else if (*it != FLAG_SKIP)
00158                 break;
00159 
00160             size += *(++it);
00161         }
00162         merged.push_back(op);
00163         merged.push_back(size);
00164     }
00165     ops = merged;
00166 }
00167 
00168 
00169 
00170 MemoryLayout::const_iterator MemLayout::skip_block(
00171         MemoryLayout::const_iterator begin,
00172         MemoryLayout::const_iterator end)
00173 {
00174     size_t nesting = 0;
00175     for (MemoryLayout::const_iterator it = begin; it != end; ++it)
00176     {
00177         switch(*it)
00178         {
00179             case FLAG_ARRAY:
00180             case FLAG_CONTAINER:
00181                 ++it;
00182                 ++nesting;
00183                 break;
00184 
00185             case FLAG_END:
00186                 if (nesting == 0)
00187                     return it;
00188                 --nesting;
00189                 break;
00190 
00191             case FLAG_SKIP:
00192             case FLAG_MEMCPY:
00193                 ++it;
00194             default:
00195                 break;
00196         }
00197     }
00198     return end;
00199 }
00200 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22