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
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
00132
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
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