Last active
December 17, 2015 11:39
-
-
Save motonacciu/5603530 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace detail { | |
| template <class T> | |
| struct deserialize_helper; | |
| template <class T> | |
| struct deserialize_helper { | |
| /** | |
| * Deserialization for integral types and POD data types. | |
| * | |
| * This is done by simply relying on the sizeof() operator of the object. | |
| * It is important that the datatype we are deserializing has a default | |
| * contructor, otherwise you need to provide a specialization for that type | |
| */ | |
| static T apply(StreamType::const_iterator& begin, StreamType::const_iterator end) { | |
| assert(begin+sizeof(T)<=end && "Error: not enough bytes to deserialize type"); | |
| T val; | |
| uint8_t* ptr = reinterpret_cast<uint8_t*>(&val); | |
| std::copy(begin, begin+sizeof(T), ptr); | |
| begin+=sizeof(T); | |
| return val; | |
| } | |
| }; | |
| template <class T> | |
| struct deserialize_helper<std::vector<T>> { | |
| /** | |
| * Deserialization for vector types. | |
| * | |
| * We read the first size_t value which contains the number of elements | |
| * and then recursively read each of them. An optimization can be done | |
| * for which we avoid recursion in the case we have a vector of PODs or | |
| * integral type (soon to come) | |
| */ | |
| static std::vector<T> apply(StreamType::const_iterator& begin, | |
| StreamType::const_iterator end) | |
| { | |
| // retrieve the number of elements | |
| size_t size = deserialize_helper<size_t>::apply(begin,end); | |
| std::vector<T> vect(size); | |
| for(size_t i=0; i<size; ++i) { | |
| /** | |
| * Call the move-copy constructor so that the additional copy | |
| * is avoided | |
| */ | |
| vect[i] = std::move(deserialize_helper<T>::apply(begin,end)); | |
| } | |
| return vect; | |
| } | |
| }; | |
| template <> | |
| struct deserialize_helper<std::string> { | |
| /** | |
| * Deserialization for strings. | |
| * | |
| * similar to vectors but we can avoid recursion since the elements | |
| * of a string are always bytes. | |
| */ | |
| static std::string apply(StreamType::const_iterator& begin, | |
| StreamType::const_iterator end) | |
| { | |
| // retrieve the number of elements | |
| size_t size = deserialize_helper<size_t>::apply(begin,end); | |
| // We need to consider the case of empty strings separately | |
| if (size == 0u) return std::string(); | |
| std::string str(size,'\0'); | |
| for(size_t i=0; i<size; ++i) { | |
| str.at(i) = deserialize_helper<uint8_t>::apply(begin,end); | |
| } | |
| return str; | |
| } | |
| }; | |
| template <class tuple_type> | |
| inline void deserialize_tuple(tuple_type& obj, StreamType::const_iterator& begin, | |
| StreamType::const_iterator end, int_<0>) { | |
| constexpr size_t idx = std::tuple_size<tuple_type>::value-1; | |
| typedef typename std::tuple_element<idx,tuple_type>::type T; | |
| // Use std::move() to force R-value copy constructor and avoid the copy | |
| std::get<idx>(obj) = std::move(deserialize_helper<T>::apply(begin, end)); | |
| } | |
| template <class tuple_type, size_t pos> | |
| inline void deserialize_tuple(tuple_type& obj, StreamType::const_iterator& begin, | |
| StreamType::const_iterator end, int_<pos>) { | |
| constexpr size_t idx = std::tuple_size<tuple_type>::value-pos-1; | |
| typedef typename std::tuple_element<idx,tuple_type>::type T; | |
| // Use std::move() to force R-value copy constructor and avoid the copy | |
| std::get<idx>(obj) = std::move(deserialize_helper<T>::apply(begin, end)); | |
| // meta-recur | |
| deserialize_tuple(obj, begin, end, int_<pos-1>()); | |
| } | |
| template <class... T> | |
| struct deserialize_helper<std::tuple<T...>> { | |
| /** | |
| * Deserialization for tuples | |
| * | |
| * same pattern as for serialization | |
| */ | |
| static std::tuple<T...> apply(StreamType::const_iterator& begin,StreamType::const_iterator end) | |
| { | |
| // if only this worked... sigh! | |
| // return std::make_tuple(deserialize_helper<T>::apply(begin,end)...); | |
| std::tuple<T...> ret; | |
| deserialize_tuple(ret, begin, end, int_<sizeof...(T)-1>()); | |
| return ret; | |
| } | |
| }; | |
| } // end detail namespace | |
| template <class T> | |
| inline T deserialize(StreamType::const_iterator& begin, const StreamType::const_iterator& end) { | |
| return detail::deserialize_helper<T>::apply(begin, end); | |
| } | |
| template <class T> | |
| inline T deserialize(const StreamType& res) { | |
| StreamType::const_iterator it = res.cbegin(); | |
| return deserialize(it, res.cend()); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment