containers.cc
Go to the documentation of this file.
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<char>) ));
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 
00353     const Type *type = registry.get(full_name);
00354     if (type->getCategory() != Type::Container) {
00355         throw BadCategory(type->getCategory(), Type::Container);
00356     } else {
00357         return dynamic_cast<Container const &>(*type);
00358     }
00359 }
00360 Container::ContainerFactory Vector::getFactory() const { return factory; }
00361 
00362 
00363 Type const& String::getElementType(Typelib::Registry const& registry)
00364 {
00365     std::string element_type_name;
00366     if (std::numeric_limits<char>::is_signed)
00367         element_type_name = "/int8_t";
00368     else
00369         element_type_name = "/uint8_t";
00370 
00371     Type const* element_type = registry.get(element_type_name);
00372     if (!element_type)
00373         throw std::runtime_error("cannot find string element " + element_type_name + " in registry");
00374     return *element_type;
00375 }
00376 String::String(Typelib::Registry const& registry)
00377     : Container("/std/string", "/std/string", getNaturalSize(), String::getElementType(registry)) {}
00378 
00379 size_t String::getElementCount(void const* ptr) const
00380 {
00381     size_t byte_count = reinterpret_cast< std::string const* >(ptr)->length();
00382     return byte_count / getIndirection().getSize();
00383 }
00384 void String::init(void* ptr) const
00385 {
00386     new(ptr) std::string();
00387 }
00388 void String::destroy(void* ptr) const
00389 {
00390     reinterpret_cast< std::string* >(ptr)->~string();
00391 }
00392 void String::clear(void* ptr) const
00393 {
00394     reinterpret_cast< std::string* >(ptr)->clear();
00395 }
00396 
00397 
00398 long String::getNaturalSize() const
00399 {
00400     return sizeof(std::string);
00401 }
00402 
00403 void String::push(void* ptr, Value v) const
00404 {
00405     if (v.getType() != getIndirection())
00406         throw std::runtime_error("type mismatch in string insertion");
00407 
00408     std::string* string_ptr =
00409         reinterpret_cast< std::string* >(ptr);
00410 
00411     string_ptr->append(reinterpret_cast<std::string::value_type*>(v.getData()), 1);
00412 }
00413 
00414 bool String::erase(void* ptr, Value v) const
00415 {
00416     return false;
00417 }
00418 
00419 bool String::compare(void* ptr, void* other) const
00420 {
00421     std::string* a_ptr = reinterpret_cast< std::string* >(ptr);
00422     std::string* b_ptr = reinterpret_cast< std::string* >(other);
00423     return *a_ptr == *b_ptr;
00424 }
00425 
00426 void String::copy(void* dst, void* src) const
00427 {
00428     std::string* dst_ptr = reinterpret_cast< std::string* >(dst);
00429     std::string* src_ptr = reinterpret_cast< std::string* >(src);
00430     *dst_ptr = *src_ptr;
00431 }
00432 
00433 bool String::visit(void* ptr, ValueVisitor& visitor) const
00434 {
00435     std::string* string_ptr =
00436         reinterpret_cast< std::string* >(ptr);
00437     char* base = const_cast<char*>(string_ptr->c_str());
00438     size_t   element_count = string_ptr->length();
00439 
00440     for (size_t i = 0; i < element_count; ++i)
00441         visitor.dispatch(Value(base + i, getIndirection()));
00442 
00443     return true;
00444 }
00445 
00446 Container::MarshalOps::const_iterator String::dump(
00447         void const* container_ptr, size_t element_count, OutputStream& stream,
00448         MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const
00449 {
00450     const std::string* string_ptr =
00451         reinterpret_cast< const std::string* >(container_ptr);
00452 
00453     stream.write(reinterpret_cast<uint8_t const*>(string_ptr->c_str()), element_count);
00454     return begin + 2;
00455 }
00456 
00457 Container::MarshalOps::const_iterator String::load(
00458         void* container_ptr, size_t element_count,
00459         InputStream& stream,
00460         MarshalOps::const_iterator const begin, MarshalOps::const_iterator const end) const
00461 {
00462     std::string* string_ptr =
00463         reinterpret_cast< std::string* >(container_ptr);
00464 
00465     string_ptr->clear();
00466         
00467     std::vector<uint8_t> buffer;
00468     buffer.resize(element_count);
00469     stream.read(&buffer[0], element_count);
00470     (*string_ptr).append(reinterpret_cast<const char*>(&buffer[0]), element_count);
00471     return begin + 2;
00472 }
00473 void String::delete_if_impl(void* ptr, DeleteIfPredicate& pred) const
00474 {}
00475 
00476 Container const& String::factory(Registry& registry, std::list<Type const*> const& on)
00477 {
00478     if (registry.has("/std/string"))
00479         return dynamic_cast<Container const&>(*registry.get("/std/string"));
00480 
00481     if (on.size() != 1)
00482         throw std::runtime_error("expected only one template argument for std::string");
00483 
00484     Type const& contained_type = *on.front();
00485     Type const& expected_type  = String::getElementType(registry);
00486     if (contained_type != expected_type)
00487         throw std::runtime_error("std::string can only be built on top of '" + expected_type.getName() + "' -- found " + contained_type.getName());
00488 
00489     String* new_type = new String(registry);
00490     registry.add(new_type);
00491     return *new_type;
00492 }
00493 Container::ContainerFactory String::getFactory() const { return factory; }
00494 


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