ByteVector.hpp
Go to the documentation of this file.
00001 #ifndef BYTE_VECTOR_HPP
00002 #define BYTE_VECTOR_HPP
00003 
00004 #include <cstdint>
00005 #include <limits>
00006 #include <memory>
00007 #include <type_traits>
00008 #include <vector>
00009 #include "Value.hpp"
00010 
00011 namespace msp {
00012 
00013 struct Packable;
00014 
00015 class ByteVector : public std::vector<uint8_t> {
00016 public:
00020     ByteVector() : offset(0) {}
00021 
00027     template <typename T1>
00028     ByteVector(T1 arg1) : std::vector<uint8_t>(arg1), offset(0) {}
00029 
00037     template <typename T1, typename T2>
00038     ByteVector(T1 arg1, T2 arg2) :
00039         std::vector<uint8_t>(arg1, arg2),
00040         offset(0) {}
00041 
00049     template <typename T, typename std::enable_if<std::is_integral<T>::value,
00050                                                   T>::type* = nullptr>
00051     bool pack(const T& val) {
00052         // little endian packing
00053         for(size_t i(0); i < sizeof(val); ++i) {
00054             this->push_back(val >> (i * 8) & 0xFF);
00055         }
00056         return true;
00057     }
00058 
00067     template <typename T,
00068               typename std::enable_if<std::is_floating_point<T>::value,
00069                                       T>::type* = nullptr>
00070     bool pack(const T& val) {
00071         ByteVector b(sizeof(val));
00072         reinterpret_cast<T&>(b.front()) = val;
00073         return this->pack(b);
00074     }
00075 
00089     template <typename encoding_T, typename T1, typename T2,
00090               typename std::enable_if<std::is_arithmetic<T1>::value,
00091                                       T1>::type* = nullptr,
00092               typename std::enable_if<std::is_arithmetic<T2>::value,
00093                                       T2>::type* = nullptr>
00094     bool pack(const T1 val, const T2 scale, const T2 offset = 0) {
00095         auto tmp = (val + offset) * scale;
00096         if(tmp <= std::numeric_limits<encoding_T>::min())
00097             return pack(std::numeric_limits<encoding_T>::min());
00098         else if(tmp >= std::numeric_limits<encoding_T>::max())
00099             return pack(std::numeric_limits<encoding_T>::max());
00100         return pack(static_cast<encoding_T>(tmp));
00101     }
00102 
00110     bool pack(const std::string& val,
00111               size_t max_len = std::numeric_limits<size_t>::max()) {
00112         size_t count = 0;
00113         for(auto c : val) {
00114             this->push_back(c);
00115             if(++count == max_len) break;
00116         }
00117         // TODO: validate that this null termination is the right thing to do in
00118         // all cases definitly correct in tested cases
00119         this->push_back(0);
00120         return true;
00121     }
00122 
00130     bool pack(const ByteVector& data,
00131               size_t max_len = std::numeric_limits<size_t>::max()) {
00132         size_t count = 0;
00133         for(auto c : data) {
00134             this->push_back(c);
00135             if(++count == max_len) break;
00136         }
00137         return true;
00138     }
00139 
00146     template <typename T,
00147               typename std::enable_if<std::is_base_of<Packable, T>::value,
00148                                       T>::type* = nullptr>
00149     bool pack(const T& val) {
00150         return val.pack_into(*this);
00151     }
00152 
00166     template <typename encoding_T, typename T1, typename T2,
00167               typename std::enable_if<std::is_arithmetic<T1>::value,
00168                                       T1>::type* = nullptr,
00169               typename std::enable_if<std::is_arithmetic<T2>::value,
00170                                       T2>::type* = nullptr>
00171     bool pack(const Value<T1> val, const T2 scale, const T2 offset = 0) {
00172         if(!val.set()) return false;
00173         return pack<encoding_T>(val(), scale, offset);
00174     }
00175 
00183     bool pack(const Value<ByteVector>& val,
00184               size_t max_len = std::numeric_limits<size_t>::max()) {
00185         if(!val.set()) return false;
00186         return pack(val(), max_len);
00187     }
00188 
00196     bool pack(const Value<std::string>& val,
00197               size_t max_len = std::numeric_limits<size_t>::max()) {
00198         if(!val.set()) return false;
00199         return pack(val(), max_len);
00200     }
00201 
00209     template <class T> bool pack(const Value<T>& val) {
00210         if(!val.set()) return false;
00211         return pack(val());
00212     }
00213 
00222     template <typename T, typename std::enable_if<std::is_integral<T>::value,
00223                                                   T>::type* = nullptr>
00224     bool unpack(T& val) const {
00225         if(unpacking_remaining() < sizeof(val)) return false;
00226         val = 0;
00227         for(size_t i(0); i < sizeof(val); ++i) {
00228             val |= (*this)[offset++] << (8 * i);
00229         }
00230         return true;
00231     }
00232 
00238     bool unpack(bool& val) const {
00239         if(unpacking_remaining() < 1) return false;
00240         val = (*this)[offset++];
00241         return true;
00242     }
00243 
00253     template <typename T,
00254               typename std::enable_if<std::is_floating_point<T>::value,
00255                                       T>::type* = nullptr>
00256     bool unpack(T& val) const {
00257         if(unpacking_remaining() < sizeof(val)) return false;
00258         val = reinterpret_cast<const T&>((*this)[offset]);
00259         offset += sizeof(val);
00260         return true;
00261     }
00262 
00271     bool unpack(std::string& val,
00272                 size_t count = std::numeric_limits<size_t>::max()) const {
00273         if(count == std::numeric_limits<size_t>::max())
00274             count = unpacking_remaining();
00275         if(count > unpacking_remaining()) return false;
00276         bool rc = true;
00277         val.clear();
00278         int8_t tmp;
00279         for(size_t i = 0; i < count; ++i) {
00280             rc &= unpack(tmp);
00281             val += tmp;
00282         }
00283         return rc;
00284     }
00285 
00295     bool unpack(ByteVector& val,
00296                 size_t count = std::numeric_limits<size_t>::max()) const {
00297         if(count == std::numeric_limits<size_t>::max())
00298             count = unpacking_remaining();
00299         if(!consume(count)) return false;
00300         val.clear();
00301         val.insert(
00302             val.end(), unpacking_iterator(), unpacking_iterator() + count);
00303         return true;
00304     }
00305 
00319     template <typename encoding_T, typename T1, typename T2,
00320               typename std::enable_if<std::is_arithmetic<T1>::value,
00321                                       T1>::type* = nullptr,
00322               typename std::enable_if<std::is_arithmetic<T2>::value,
00323                                       T2>::type* = nullptr>
00324     bool unpack(T1& val, T2 scale, T2 offset = 0) const {
00325         bool rc        = true;
00326         encoding_T tmp = 0;
00327         rc &= unpack(tmp);
00328         val = tmp / scale;
00329         val -= offset;
00330         return rc;
00331     }
00332 
00338     template <typename T,
00339               typename std::enable_if<std::is_base_of<Packable, T>::value,
00340                                       T>::type* = nullptr>
00341     bool unpack(T& obj) const {
00342         return obj.unpack_from(*this);
00343     }
00344 
00353     template <class T> bool unpack(Value<T>& val) const {
00354         return val.set() = unpack(val());
00355     }
00356 
00366     bool unpack(Value<std::string>& val,
00367                 size_t count = std::numeric_limits<size_t>::max()) const {
00368         return val.set() = unpack(val(), count);
00369     }
00370 
00380     bool unpack(Value<ByteVector>& val,
00381                 size_t count = std::numeric_limits<size_t>::max()) const {
00382         return val.set() = unpack(val(), count);
00383     }
00384 
00398     template <typename encoding_T, typename T1, typename T2,
00399               typename std::enable_if<std::is_arithmetic<T1>::value,
00400                                       T1>::type* = nullptr,
00401               typename std::enable_if<std::is_arithmetic<T2>::value,
00402                                       T2>::type* = nullptr>
00403     bool unpack(Value<T1>& val, T2 scale = 1, T2 offset = 0) const {
00404         return val.set() = unpack<encoding_T>(val(), scale, offset);
00405     }
00406 
00412     std::size_t unpacking_offset() const { return offset; }
00413 
00418     std::vector<uint8_t>::iterator unpacking_iterator() {
00419         return this->begin() + offset;
00420     }
00421 
00426     std::vector<uint8_t>::const_iterator unpacking_iterator() const {
00427         return this->begin() + offset;
00428     }
00429 
00436     bool consume(std::size_t count) const {
00437         if(count > unpacking_remaining()) {
00438             return false;
00439         }
00440         offset += count;
00441         return true;
00442     }
00443 
00448     std::size_t unpacking_remaining() const { return this->size() - offset; }
00449 
00450 protected:
00451     mutable std::size_t offset;
00452 };
00453 
00458 struct Packable {
00459     virtual ~Packable() {}
00460     virtual bool pack_into(ByteVector& data) const   = 0;
00461     virtual bool unpack_from(const ByteVector& data) = 0;
00462 };
00463 
00464 typedef std::shared_ptr<ByteVector> ByteVectorPtr;
00465 typedef std::unique_ptr<ByteVector> ByteVectorUptr;
00466 
00467 }  // namespace msp
00468 
00469 inline std::ostream& operator<<(std::ostream& s, const msp::ByteVector& val) {
00470     s << std::hex;
00471     for(const auto& v : val) {
00472         s << uint32_t(v) << " ";
00473     }
00474     s << std::dec << std::endl;
00475     return s;
00476 }
00477 
00478 #endif


msp
Author(s): Christian Rauch
autogenerated on Thu Jun 20 2019 19:40:38