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