$search
00001 #include "containers.hh" 00002 #include <typelib/registry.hh> 00003 #include <typelib/typemodel.hh> 00004 #include <typelib/value_ops.hh> 00005 #include <typelib/value_ops_details.hh> 00006 #include <boost/tuple/tuple.hpp> 00007 #include <string.h> 00008 #include <limits> 00009 00010 #include <iostream> 00011 00012 using namespace Typelib; 00013 using namespace std; 00014 00015 BOOST_STATIC_ASSERT(( sizeof(vector<void*>) == sizeof(vector<Container>) )); 00016 00017 string Vector::fullName(std::string const& element_name) 00018 { return "/std/vector<" + element_name + ">"; } 00019 00020 Vector::Vector(Type const& on) 00021 : Container("/std/vector", fullName(on.getName()), getNaturalSize(), on) 00022 , is_memcpy(false) 00023 { 00024 try { 00025 MemoryLayout ops = Typelib::layout_of(on); 00026 is_memcpy = (ops.size() == 2 && ops[0] == MemLayout::FLAG_MEMCPY); 00027 } 00028 catch(std::runtime_error) 00029 { 00030 // No layout for this type. Simply disable memcpy 00031 is_memcpy = false; 00032 } 00033 } 00034 00035 size_t Vector::getElementCount(void const* ptr) const 00036 { 00037 size_t byte_count = reinterpret_cast< std::vector<int8_t> const* >(ptr)->size(); 00038 return byte_count / getIndirection().getSize(); 00039 } 00040 void Vector::init(void* ptr) const 00041 { 00042 new(ptr) vector<int8_t>(); 00043 } 00044 void Vector::destroy(void* ptr) const 00045 { 00046 std::vector<uint8_t>* vector_ptr = 00047 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00048 resize(vector_ptr, 0); 00049 vector_ptr->~vector<uint8_t>(); 00050 } 00051 void Vector::clear(void* ptr) const 00052 { 00053 std::vector<uint8_t>* vector_ptr = 00054 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00055 resize(vector_ptr, 0); 00056 } 00057 00058 bool Vector::isRandomAccess() const 00059 { return true; } 00060 void Vector::setElement(void* ptr, int idx, Typelib::Value value) const 00061 { 00062 std::vector<uint8_t>* vector_ptr = 00063 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00064 Typelib::copy( 00065 Value(&(*vector_ptr)[idx * getIndirection().getSize()], getIndirection()), 00066 value); 00067 } 00068 00069 Typelib::Value Vector::getElement(void* ptr, int idx) const 00070 { 00071 std::vector<uint8_t>* vector_ptr = 00072 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00073 return Value(&(*vector_ptr)[idx * getIndirection().getSize()], getIndirection()); 00074 } 00075 00076 long Vector::getNaturalSize() const 00077 { 00078 return sizeof(std::vector<void*>); 00079 } 00080 00081 void Vector::resize(std::vector<uint8_t>* ptr, size_t new_size) const 00082 { 00083 Type const& element_t = getIndirection(); 00084 size_t element_size = getIndirection().getSize(); 00085 00086 // 00087 // BIG FAT WARNING 00088 // 00089 // This assumes that std::vector is implemented so that the data structure 00090 // does *not* contain pointers towards its own location 00091 // 00092 // If this assumption is broken, we would need to have a saner (but less 00093 // efficient) implementation 00094 // 00095 // This assumption is tested in test_containers.cc in the C++ test suite 00096 // 00097 00098 size_t old_raw_size = ptr->size(); 00099 size_t old_size = getElementCount(ptr); 00100 size_t new_raw_size = new_size * element_size; 00101 00102 if (!is_memcpy && old_size > new_size) 00103 { 00104 // Need to destroy the elements that are at the end of the container 00105 for (size_t i = new_raw_size; i < old_raw_size; i += element_size) 00106 Typelib::destroy(Value(&(*ptr)[i], element_t)); 00107 } 00108 00109 ptr->resize(new_raw_size); 00110 00111 if (!is_memcpy && old_size < new_size) 00112 { 00113 // Need to initialize the new elements at the end of the container 00114 for (size_t i = old_raw_size; i < new_raw_size; i += element_size) 00115 Typelib::init(Value(&(*ptr)[i], element_t)); 00116 } 00117 } 00118 00119 void Vector::push(void* ptr, Value v) const 00120 { 00121 if (v.getType() != getIndirection()) 00122 throw std::runtime_error("type mismatch in vector insertion"); 00123 00124 std::vector<uint8_t>* vector_ptr = 00125 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00126 00127 size_t size = getElementCount(ptr); 00128 resize(vector_ptr, size + 1); 00129 Typelib::copy( 00130 Value(&(*vector_ptr)[size * getIndirection().getSize()], getIndirection()), 00131 v); 00132 } 00133 00134 bool Vector::erase(void* ptr, Value v) const 00135 { 00136 if (v.getType() != getIndirection()) 00137 throw std::runtime_error("type mismatch in vector insertion"); 00138 00139 std::vector<uint8_t>* vector_ptr = 00140 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00141 Type const& element_t = getIndirection(); 00142 size_t element_size = element_t.getSize(); 00143 size_t element_count = getElementCount(vector_ptr); 00144 00145 uint8_t* base_ptr = &(*vector_ptr)[0]; 00146 00147 for (size_t i = 0; i < element_count; ++i) 00148 { 00149 uint8_t* element_ptr = base_ptr + i * element_size; 00150 Value element_v(element_ptr, element_t); 00151 if (Typelib::compare(element_v, v)) 00152 { 00153 erase(vector_ptr, i); 00154 return true; 00155 } 00156 } 00157 return false; 00158 } 00159 00160 void Vector::erase(std::vector<uint8_t>* ptr, size_t idx) const 00161 { 00162 // Copy the remaining elements to the right place 00163 size_t element_count = getElementCount(ptr); 00164 if (element_count > idx + 1) 00165 copy(ptr, idx, ptr, idx + 1, element_count - idx - 1); 00166 00167 // Then shrink the vector 00168 resize(ptr, element_count - 1); 00169 } 00170 00171 bool Vector::compare(void* ptr, void* other) const 00172 { 00173 std::vector<uint8_t>* a_ptr = 00174 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00175 std::vector<uint8_t>* b_ptr = 00176 reinterpret_cast< std::vector<uint8_t>* >(other); 00177 00178 size_t element_count = getElementCount(a_ptr); 00179 Type const& element_t = getIndirection(); 00180 size_t element_size = element_t.getSize(); 00181 if (element_count != getElementCount(b_ptr)) 00182 return false; 00183 00184 uint8_t* base_a = &(*a_ptr)[0]; 00185 uint8_t* base_b = &(*b_ptr)[0]; 00186 for (size_t i = 0; i < element_count; ++i) 00187 { 00188 if (!Typelib::compare( 00189 Value(base_a + i * element_size, element_t), 00190 Value(base_b + i * element_size, element_t))) 00191 return false; 00192 } 00193 return true; 00194 } 00195 00196 void Vector::copy(void* dst, void* src) const 00197 { 00198 std::vector<uint8_t>* dst_ptr = 00199 reinterpret_cast< std::vector<uint8_t>* >(dst); 00200 std::vector<uint8_t>* src_ptr = 00201 reinterpret_cast< std::vector<uint8_t>* >(src); 00202 00203 size_t element_count = getElementCount(src_ptr); 00204 resize(dst_ptr, element_count); 00205 copy(dst_ptr, 0, src_ptr, 0, element_count); 00206 } 00207 00208 void Vector::copy(std::vector<uint8_t>* dst_ptr, size_t dst_idx, std::vector<uint8_t>* src_ptr, size_t src_idx, size_t count) const 00209 { 00210 Type const& element_t = getIndirection(); 00211 size_t element_size = element_t.getSize(); 00212 uint8_t* base_src = &(*src_ptr)[src_idx * element_size]; 00213 uint8_t* base_dst = &(*dst_ptr)[dst_idx * element_size]; 00214 if (is_memcpy) 00215 { 00216 if (dst_ptr == src_ptr) 00217 memmove(base_dst, base_src, element_size * count); 00218 else 00219 memcpy(base_dst, base_src, element_size * count); 00220 } 00221 else 00222 { 00223 for (size_t i = 0; i < count; ++i) 00224 { 00225 Typelib::copy( 00226 Value(base_dst + i * element_size, element_t), 00227 Value(base_src + i * element_size, element_t)); 00228 } 00229 } 00230 } 00231 00232 00233 bool Vector::visit(void* ptr, ValueVisitor& visitor) const 00234 { 00235 std::vector<uint8_t>* vector_ptr = 00236 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00237 uint8_t* base = &(*vector_ptr)[0]; 00238 size_t element_size = getIndirection().getSize(); 00239 size_t element_count = getElementCount(vector_ptr); 00240 const Type &indirect(getIndirection()); 00241 00242 for (size_t i = 0; i < element_count; ++i) 00243 visitor.dispatch(Value(base + i * element_size, indirect)); 00244 00245 return true; 00246 } 00247 00248 void Vector::delete_if_impl(void* ptr, DeleteIfPredicate& pred) const 00249 { 00250 std::vector<uint8_t>* vector_ptr = 00251 reinterpret_cast< std::vector<uint8_t>* >(ptr); 00252 00253 size_t element_count = getElementCount(vector_ptr); 00254 Type const& element_t = getIndirection(); 00255 size_t element_size = element_t.getSize(); 00256 00257 uint8_t* base = &(*vector_ptr)[0]; 00258 for (size_t i = 0; i < element_count; ) 00259 { 00260 uint8_t* element_ptr = base + i * element_size; 00261 Value element_v(element_ptr, element_t); 00262 if (pred.should_delete(element_v)) 00263 { 00264 erase(vector_ptr, i); 00265 element_count--; 00266 } 00267 else 00268 ++i; 00269 } 00270 } 00271 00272 Container::MarshalOps::const_iterator Vector::dump( 00273 void const* container_ptr, size_t element_count, OutputStream& stream, 00274 MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const 00275 { 00276 std::vector<uint8_t> const* vector_ptr = 00277 reinterpret_cast< std::vector<uint8_t> const* >(container_ptr); 00278 00279 MarshalOps::const_iterator it = begin; 00280 if (is_memcpy) 00281 { 00282 // optimize a bit: do a huge memcpy if possible 00283 size_t size = *(++it) * element_count; 00284 stream.write(&(*vector_ptr)[0], size); 00285 return begin + 2; 00286 } 00287 else 00288 { 00289 MarshalOps::const_iterator it_end = begin; 00290 size_t in_offset = 0; 00291 for (size_t i = 0; i < element_count; ++i) 00292 { 00293 boost::tie(in_offset, it_end) = ValueOps::dump( 00294 &(*vector_ptr)[i * getIndirection().getSize()], 0, 00295 stream, begin, end); 00296 } 00297 return it_end; 00298 } 00299 } 00300 00301 Container::MarshalOps::const_iterator Vector::load( 00302 void* container_ptr, size_t element_count, 00303 InputStream& stream, 00304 MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const 00305 { 00306 std::vector<uint8_t>* vector_ptr = 00307 reinterpret_cast< std::vector<uint8_t>* >(container_ptr); 00308 00309 Type const& element_t = getIndirection(); 00310 size_t element_size = element_t.getSize(); 00311 resize(vector_ptr, element_count); 00312 00313 MarshalOps::const_iterator it = begin; 00314 if (is_memcpy) 00315 { 00316 size_t size = *(++it) * element_count; 00317 stream.read(&(*vector_ptr)[0], size); 00318 return begin + 2; 00319 } 00320 else 00321 { 00322 MarshalOps::const_iterator it_end; 00323 size_t out_offset = 0; 00324 for (size_t i = 0; i < element_count; ++i) 00325 { 00326 boost::tie(out_offset, it_end) = 00327 ValueOps::load(&(*vector_ptr)[i * element_size], 0, 00328 stream, begin, end); 00329 } 00330 return it_end; 00331 } 00332 } 00333 00334 std::string Vector::getIndirectTypeName(std::string const& element_name) const 00335 { 00336 return Vector::fullName(element_name); 00337 } 00338 00339 Container const& Vector::factory(Registry& registry, std::list<Type const*> const& on) 00340 { 00341 if (on.size() != 1) 00342 throw std::runtime_error("expected only one template argument for std::vector"); 00343 00344 Type const& contained_type = *on.front(); 00345 std::string full_name = Vector::fullName(contained_type.getName()); 00346 if (! registry.has(full_name)) 00347 { 00348 Vector* new_type = new Vector(contained_type); 00349 registry.add(new_type); 00350 return *new_type; 00351 } 00352 else 00353 return dynamic_cast<Container const&>(*registry.get(full_name)); 00354 } 00355 Container::ContainerFactory Vector::getFactory() const { return factory; } 00356 00357 00358 Type const& String::getElementType(Typelib::Registry const& registry) 00359 { 00360 if (std::numeric_limits<char>::is_signed) 00361 return *registry.get("/int8_t"); 00362 else 00363 return *registry.get("/uint8_t"); 00364 } 00365 String::String(Typelib::Registry const& registry) 00366 : Container("/std/string", "/std/string", getNaturalSize(), String::getElementType(registry)) {} 00367 00368 size_t String::getElementCount(void const* ptr) const 00369 { 00370 size_t byte_count = reinterpret_cast< std::string const* >(ptr)->length(); 00371 return byte_count / getIndirection().getSize(); 00372 } 00373 void String::init(void* ptr) const 00374 { 00375 new(ptr) std::string(); 00376 } 00377 void String::destroy(void* ptr) const 00378 { 00379 reinterpret_cast< std::string* >(ptr)->~string(); 00380 } 00381 void String::clear(void* ptr) const 00382 { 00383 reinterpret_cast< std::string* >(ptr)->clear(); 00384 } 00385 00386 00387 long String::getNaturalSize() const 00388 { 00389 return sizeof(std::string); 00390 } 00391 00392 void String::push(void* ptr, Value v) const 00393 { 00394 if (v.getType() != getIndirection()) 00395 throw std::runtime_error("type mismatch in string insertion"); 00396 00397 std::string* string_ptr = 00398 reinterpret_cast< std::string* >(ptr); 00399 00400 string_ptr->append(reinterpret_cast<std::string::value_type*>(v.getData()), 1); 00401 } 00402 00403 bool String::erase(void* ptr, Value v) const 00404 { 00405 return false; 00406 } 00407 00408 bool String::compare(void* ptr, void* other) const 00409 { 00410 std::string* a_ptr = reinterpret_cast< std::string* >(ptr); 00411 std::string* b_ptr = reinterpret_cast< std::string* >(other); 00412 return *a_ptr == *b_ptr; 00413 } 00414 00415 void String::copy(void* dst, void* src) const 00416 { 00417 std::string* dst_ptr = reinterpret_cast< std::string* >(dst); 00418 std::string* src_ptr = reinterpret_cast< std::string* >(src); 00419 *dst_ptr = *src_ptr; 00420 } 00421 00422 bool String::visit(void* ptr, ValueVisitor& visitor) const 00423 { 00424 std::string* string_ptr = 00425 reinterpret_cast< std::string* >(ptr); 00426 char* base = const_cast<char*>(string_ptr->c_str()); 00427 size_t element_count = string_ptr->length(); 00428 00429 for (size_t i = 0; i < element_count; ++i) 00430 visitor.dispatch(Value(base + i, getIndirection())); 00431 00432 return true; 00433 } 00434 00435 Container::MarshalOps::const_iterator String::dump( 00436 void const* container_ptr, size_t element_count, OutputStream& stream, 00437 MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const 00438 { 00439 const std::string* string_ptr = 00440 reinterpret_cast< const std::string* >(container_ptr); 00441 00442 stream.write(reinterpret_cast<uint8_t const*>(string_ptr->c_str()), element_count); 00443 return begin + 2; 00444 } 00445 00446 Container::MarshalOps::const_iterator String::load( 00447 void* container_ptr, size_t element_count, 00448 InputStream& stream, 00449 MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const 00450 { 00451 std::string* string_ptr = 00452 reinterpret_cast< std::string* >(container_ptr); 00453 00454 std::vector<uint8_t> buffer; 00455 buffer.resize(element_count); 00456 stream.read(&buffer[0], element_count); 00457 (*string_ptr).append(reinterpret_cast<const char*>(&buffer[0]), element_count); 00458 return begin + 2; 00459 } 00460 void String::delete_if_impl(void* ptr, DeleteIfPredicate& pred) const 00461 {} 00462 00463 Container const& String::factory(Registry& registry, std::list<Type const*> const& on) 00464 { 00465 if (registry.has("/std/string")) 00466 return dynamic_cast<Container const&>(*registry.get("/std/string")); 00467 00468 if (on.size() != 1) 00469 throw std::runtime_error("expected only one template argument for std::string"); 00470 00471 Type const& contained_type = *on.front(); 00472 Type const& expected_type = String::getElementType(registry); 00473 if (contained_type != expected_type) 00474 throw std::runtime_error("std::string can only be built on top of '" + expected_type.getName() + "' -- found " + contained_type.getName()); 00475 00476 String* new_type = new String(registry); 00477 registry.add(new_type); 00478 return *new_type; 00479 } 00480 Container::ContainerFactory String::getFactory() const { return factory; } 00481