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
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
00118
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 }
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