00001 #ifndef RTABMAP_SERIALIZATION_H_
00002 #define RTABMAP_SERIALIZATION_H_
00003
00004 #include <vector>
00005 #include <map>
00006 #include <cstdlib>
00007 #include <cstring>
00008 #include <stdio.h>
00009 #include "rtflann/ext/lz4.h"
00010 #include "rtflann/ext/lz4hc.h"
00011
00012
00013 namespace rtflann
00014 {
00015 struct IndexHeaderStruct {
00016 char signature[24];
00017 char version[16];
00018 flann_datatype_t data_type;
00019 flann_algorithm_t index_type;
00020 size_t rows;
00021 size_t cols;
00022 size_t compression;
00023 size_t first_block_size;
00024 };
00025
00026 namespace serialization
00027 {
00028
00029 struct access
00030 {
00031 template<typename Archive, typename T>
00032 static inline void serialize(Archive& ar, T& type)
00033 {
00034 type.serialize(ar);
00035 }
00036 };
00037
00038
00039 template<typename Archive, typename T>
00040 inline void serialize(Archive& ar, T& type)
00041 {
00042 access::serialize(ar,type);
00043 }
00044
00045 template<typename T>
00046 struct Serializer
00047 {
00048 template<typename InputArchive>
00049 static inline void load(InputArchive& ar, T& val)
00050 {
00051 serialization::serialize(ar,val);
00052 }
00053 template<typename OutputArchive>
00054 static inline void save(OutputArchive& ar, const T& val)
00055 {
00056 serialization::serialize(ar,const_cast<T&>(val));
00057 }
00058 };
00059
00060 #define BASIC_TYPE_SERIALIZER(type)\
00061 template<> \
00062 struct Serializer<type> \
00063 {\
00064 template<typename InputArchive>\
00065 static inline void load(InputArchive& ar, type& val)\
00066 {\
00067 ar.load(val);\
00068 }\
00069 template<typename OutputArchive>\
00070 static inline void save(OutputArchive& ar, const type& val)\
00071 {\
00072 ar.save(val);\
00073 }\
00074 }
00075
00076 #define ENUM_SERIALIZER(type)\
00077 template<>\
00078 struct Serializer<type>\
00079 {\
00080 template<typename InputArchive>\
00081 static inline void load(InputArchive& ar, type& val)\
00082 {\
00083 int int_val;\
00084 ar & int_val;\
00085 val = (type) int_val;\
00086 }\
00087 template<typename OutputArchive>\
00088 static inline void save(OutputArchive& ar, const type& val)\
00089 {\
00090 int int_val = (int)val;\
00091 ar & int_val;\
00092 }\
00093 }
00094
00095
00096
00097 BASIC_TYPE_SERIALIZER(char);
00098 BASIC_TYPE_SERIALIZER(unsigned char);
00099 BASIC_TYPE_SERIALIZER(short);
00100 BASIC_TYPE_SERIALIZER(unsigned short);
00101 BASIC_TYPE_SERIALIZER(int);
00102 BASIC_TYPE_SERIALIZER(unsigned int);
00103 BASIC_TYPE_SERIALIZER(long);
00104 BASIC_TYPE_SERIALIZER(unsigned long);
00105 BASIC_TYPE_SERIALIZER(unsigned long long);
00106 BASIC_TYPE_SERIALIZER(float);
00107 BASIC_TYPE_SERIALIZER(double);
00108 BASIC_TYPE_SERIALIZER(bool);
00109 #ifdef _MSC_VER
00110
00111
00112 #if _MSC_VER != 1800
00113
00114 #endif
00115 #endif
00116
00117
00118
00119 template<typename T>
00120 struct Serializer<std::vector<T> >
00121 {
00122 template<typename InputArchive>
00123 static inline void load(InputArchive& ar, std::vector<T>& val)
00124 {
00125 size_t size;
00126 ar & size;
00127 val.resize(size);
00128 for (size_t i=0;i<size;++i) {
00129 ar & val[i];
00130 }
00131 }
00132
00133 template<typename OutputArchive>
00134 static inline void save(OutputArchive& ar, const std::vector<T>& val)
00135 {
00136 ar & val.size();
00137 for (size_t i=0;i<val.size();++i) {
00138 ar & val[i];
00139 }
00140 }
00141 };
00142
00143
00144 template<typename K, typename V>
00145 struct Serializer<std::map<K,V> >
00146 {
00147 template<typename InputArchive>
00148 static inline void load(InputArchive& ar, std::map<K,V>& map_val)
00149 {
00150 size_t size;
00151 ar & size;
00152 for (size_t i = 0; i < size; ++i)
00153 {
00154 K key;
00155 ar & key;
00156 V value;
00157 ar & value;
00158 map_val[key] = value;
00159 }
00160 }
00161
00162 template<typename OutputArchive>
00163 static inline void save(OutputArchive& ar, const std::map<K,V>& map_val)
00164 {
00165 ar & map_val.size();
00166 for (typename std::map<K,V>::const_iterator i=map_val.begin(); i!=map_val.end(); ++i) {
00167 ar & i->first;
00168 ar & i->second;
00169 }
00170 }
00171 };
00172
00173 template<typename T>
00174 struct Serializer<T*>
00175 {
00176 template<typename InputArchive>
00177 static inline void load(InputArchive& ar, T*& val)
00178 {
00179 ar.load(val);
00180 }
00181
00182 template<typename OutputArchive>
00183 static inline void save(OutputArchive& ar, T* const& val)
00184 {
00185 ar.save(val);
00186 }
00187 };
00188
00189 template<typename T, int N>
00190 struct Serializer<T[N]>
00191 {
00192 template<typename InputArchive>
00193 static inline void load(InputArchive& ar, T (&val)[N])
00194 {
00195 ar.load(val);
00196 }
00197
00198 template<typename OutputArchive>
00199 static inline void save(OutputArchive& ar, T const (&val)[N])
00200 {
00201 ar.save(val);
00202 }
00203 };
00204
00205
00206
00207
00208 struct binary_object
00209 {
00210 void const * ptr_;
00211 size_t size_;
00212
00213 binary_object( void * const ptr, size_t size) :
00214 ptr_(ptr),
00215 size_(size)
00216 {}
00217 binary_object(const binary_object & rhs) :
00218 ptr_(rhs.ptr_),
00219 size_(rhs.size_)
00220 {}
00221
00222 binary_object & operator=(const binary_object & rhs) {
00223 ptr_ = rhs.ptr_;
00224 size_ = rhs.size_;
00225 return *this;
00226 }
00227 };
00228
00229 inline const binary_object make_binary_object( void * t, size_t size){
00230 return binary_object(t, size);
00231 }
00232
00233 template<>
00234 struct Serializer<const binary_object>
00235 {
00236 template<typename InputArchive>
00237 static inline void load(InputArchive& ar, const binary_object& b)
00238 {
00239 ar.load_binary(const_cast<void *>(b.ptr_), b.size_);
00240 }
00241
00242 template<typename OutputArchive>
00243 static inline void save(OutputArchive& ar, const binary_object& b)
00244 {
00245 ar.save_binary(b.ptr_, b.size_);
00246 }
00247 };
00248
00249 template<>
00250 struct Serializer<binary_object>
00251 {
00252 template<typename InputArchive>
00253 static inline void load(InputArchive& ar, binary_object& b)
00254 {
00255 ar.load_binary(const_cast<void *>(b.ptr_), b.size_);
00256 }
00257
00258 template<typename OutputArchive>
00259 static inline void save(OutputArchive& ar, const binary_object& b)
00260 {
00261 ar.save_binary(b.ptr_, b.size_);
00262 }
00263 };
00264
00265
00266
00267 template <bool C_>
00268 struct bool_ {
00269 static const bool value = C_;
00270 typedef bool value_type;
00271 };
00272
00273
00274 class ArchiveBase
00275 {
00276 public:
00277 void* getObject() { return object_; }
00278
00279 void setObject(void* object) { object_ = object; }
00280
00281 private:
00282 void* object_;
00283 };
00284
00285
00286 template<typename Archive>
00287 class InputArchive : public ArchiveBase
00288 {
00289 protected:
00290 InputArchive() {};
00291 public:
00292 typedef bool_<true> is_loading;
00293 typedef bool_<false> is_saving;
00294
00295 template<typename T>
00296 Archive& operator& (T& val)
00297 {
00298 Serializer<T>::load(*static_cast<Archive*>(this),val);
00299 return *static_cast<Archive*>(this);
00300 }
00301 };
00302
00303
00304 template<typename Archive>
00305 class OutputArchive : public ArchiveBase
00306 {
00307 protected:
00308 OutputArchive() {};
00309 public:
00310 typedef bool_<false> is_loading;
00311 typedef bool_<true> is_saving;
00312
00313 template<typename T>
00314 Archive& operator& (const T& val)
00315 {
00316 Serializer<T>::save(*static_cast<Archive*>(this),val);
00317 return *static_cast<Archive*>(this);
00318 }
00319 };
00320
00321
00322
00323 class SizeArchive : public OutputArchive<SizeArchive>
00324 {
00325 size_t size_;
00326 public:
00327
00328 SizeArchive() : size_(0)
00329 {
00330 }
00331
00332 template<typename T>
00333 void save(const T& val)
00334 {
00335 size_ += sizeof(val);
00336 }
00337
00338 template<typename T>
00339 void save_binary(T* ptr, size_t size)
00340 {
00341 size_ += size;
00342 }
00343
00344
00345 void reset()
00346 {
00347 size_ = 0;
00348 }
00349
00350 size_t size()
00351 {
00352 return size_;
00353 }
00354 };
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 #define BLOCK_BYTES (1024 * 64)
00375
00376 class SaveArchive : public OutputArchive<SaveArchive>
00377 {
00383 FILE* stream_;
00384 bool own_stream_;
00385 char *buffer_;
00386 size_t offset_;
00387
00388 int first_block_;
00389 char *buffer_blocks_;
00390 char *compressed_buffer_;
00391 LZ4_streamHC_t lz4Stream_body;
00392 LZ4_streamHC_t* lz4Stream;
00393
00394 void initBlock()
00395 {
00396
00397
00398 buffer_ = buffer_blocks_ = (char *)malloc(BLOCK_BYTES*2);
00399 compressed_buffer_ = (char *)malloc(LZ4_COMPRESSBOUND(BLOCK_BYTES) + sizeof(size_t));
00400 if (buffer_ == NULL || compressed_buffer_ == NULL) {
00401 throw FLANNException("Error allocating compression buffer");
00402 }
00403
00404
00405 lz4Stream = &lz4Stream_body;
00406 LZ4_resetStreamHC(lz4Stream, 9);
00407 first_block_ = true;
00408
00409 offset_ = 0;
00410 }
00411
00412 void flushBlock()
00413 {
00414 size_t compSz = 0;
00415
00416 if (first_block_) {
00417
00418 IndexHeaderStruct *head = (IndexHeaderStruct *)buffer_;
00419 size_t headSz = sizeof(IndexHeaderStruct);
00420
00421 assert(head->compression == 0);
00422 head->compression = 1;
00423
00424
00425 compSz = LZ4_compress_HC_continue(
00426 lz4Stream, buffer_+headSz, compressed_buffer_+headSz, offset_-headSz,
00427 LZ4_COMPRESSBOUND(BLOCK_BYTES));
00428
00429 if(compSz <= 0) {
00430 throw FLANNException("Error compressing (first block)");
00431 }
00432
00433
00434 head->first_block_size = compSz;
00435 memcpy(compressed_buffer_, buffer_, headSz);
00436
00437 compSz += headSz;
00438 first_block_ = false;
00439 } else {
00440 size_t headSz = sizeof(compSz);
00441
00442
00443 compSz = LZ4_compress_HC_continue(
00444 lz4Stream, buffer_, compressed_buffer_+headSz, offset_,
00445 LZ4_COMPRESSBOUND(BLOCK_BYTES));
00446
00447 if(compSz <= 0) {
00448 throw FLANNException("Error compressing");
00449 }
00450
00451
00452 memcpy(compressed_buffer_, &compSz, headSz);
00453 compSz += headSz;
00454 }
00455
00456
00457 fwrite(compressed_buffer_, compSz, 1, stream_);
00458
00459
00460 if (buffer_ == buffer_blocks_)
00461 buffer_ = &buffer_blocks_[BLOCK_BYTES];
00462 else
00463 buffer_ = buffer_blocks_;
00464 offset_ = 0;
00465 }
00466
00467 void endBlock()
00468 {
00469
00470 free(buffer_blocks_);
00471 buffer_blocks_ = NULL;
00472 buffer_ = NULL;
00473 free(compressed_buffer_);
00474 compressed_buffer_ = NULL;
00475
00476
00477 size_t z = 0;
00478 fwrite(&z, sizeof(z), 1, stream_);
00479 }
00480
00481 public:
00482 SaveArchive(const char* filename)
00483 {
00484 stream_ = fopen(filename, "wb");
00485 own_stream_ = true;
00486 initBlock();
00487 }
00488
00489 SaveArchive(FILE* stream) : stream_(stream), own_stream_(false)
00490 {
00491 initBlock();
00492 }
00493
00494 ~SaveArchive()
00495 {
00496 flushBlock();
00497 endBlock();
00498 if (buffer_) {
00499 free(buffer_);
00500 buffer_ = NULL;
00501 }
00502 if (own_stream_) {
00503 fclose(stream_);
00504 }
00505 }
00506
00507 template<typename T>
00508 void save(const T& val)
00509 {
00510 assert(sizeof(val) < BLOCK_BYTES);
00511 if (offset_+sizeof(val) > BLOCK_BYTES)
00512 flushBlock();
00513 memcpy(buffer_+offset_, &val, sizeof(val));
00514 offset_ += sizeof(val);
00515 }
00516
00517 template<typename T>
00518 void save(T* const& val)
00519 {
00520
00521
00522 }
00523
00524 template<typename T>
00525 void save_binary(T* ptr, size_t size)
00526 {
00527 while (size > BLOCK_BYTES) {
00528
00529 flushBlock();
00530
00531
00532 memcpy(buffer_, ptr, BLOCK_BYTES);
00533 offset_ += BLOCK_BYTES;
00534 ptr = ((char *)ptr) + BLOCK_BYTES;
00535 size -= BLOCK_BYTES;
00536 }
00537
00538
00539 if (offset_+size > BLOCK_BYTES)
00540 flushBlock();
00541
00542
00543 memcpy(buffer_+offset_, ptr, size);
00544 offset_ += size;
00545 }
00546
00547 };
00548
00549
00550 class LoadArchive : public InputArchive<LoadArchive>
00551 {
00557 FILE* stream_;
00558 bool own_stream_;
00559 char *buffer_;
00560 char *ptr_;
00561
00562 char *buffer_blocks_;
00563 char *compressed_buffer_;
00564 LZ4_streamDecode_t lz4StreamDecode_body;
00565 LZ4_streamDecode_t* lz4StreamDecode;
00566 size_t block_sz_;
00567
00568 void decompressAndLoadV10(FILE* stream)
00569 {
00570 buffer_ = NULL;
00571
00572
00573 size_t pos = ftell(stream);
00574 fseek(stream, 0, SEEK_END);
00575 size_t fileSize = ftell(stream)-pos;
00576 fseek(stream, pos, SEEK_SET);
00577 size_t headSz = sizeof(IndexHeaderStruct);
00578
00579
00580 char *compBuffer = (char *)malloc(fileSize);
00581 if (compBuffer == NULL) {
00582 throw FLANNException("Error allocating file buffer space");
00583 }
00584 if (fread(compBuffer, fileSize, 1, stream) != 1) {
00585 free(compBuffer);
00586 throw FLANNException("Invalid index file, cannot read from disk (compressed)");
00587 }
00588
00589
00590 IndexHeaderStruct *head = (IndexHeaderStruct *)(compBuffer);
00591
00592
00593 size_t compressedSz = fileSize-headSz;
00594 size_t uncompressedSz = head->first_block_size-headSz;
00595
00596
00597 if (head->compression != 1) {
00598 free(compBuffer);
00599 throw FLANNException("Compression type not supported");
00600 }
00601
00602
00603 ptr_ = buffer_ = (char *)malloc(uncompressedSz+headSz);
00604 if (buffer_ == NULL) {
00605 free(compBuffer);
00606 throw FLANNException("Error (re)allocating decompression buffer");
00607 }
00608
00609
00610 size_t usedSz = LZ4_decompress_safe(compBuffer+headSz,
00611 buffer_+headSz,
00612 compressedSz,
00613 uncompressedSz);
00614
00615
00616 if (usedSz != uncompressedSz) {
00617 free(compBuffer);
00618 throw FLANNException("Unexpected decompression size");
00619 }
00620
00621
00622 memcpy(buffer_, compBuffer, headSz);
00623 free(compBuffer);
00624
00625
00626 if (compressedSz+headSz+pos != fileSize)
00627 fseek(stream, compressedSz+headSz+pos, SEEK_SET);
00628 block_sz_ = uncompressedSz+headSz;
00629 }
00630
00631 void initBlock(FILE *stream)
00632 {
00633 size_t pos = ftell(stream);
00634 buffer_ = NULL;
00635 buffer_blocks_ = NULL;
00636 compressed_buffer_ = NULL;
00637 size_t headSz = sizeof(IndexHeaderStruct);
00638
00639
00640 IndexHeaderStruct *head = (IndexHeaderStruct *)malloc(headSz);
00641 if (head == NULL) {
00642 throw FLANNException("Error allocating header buffer space");
00643 }
00644 if (fread(head, headSz, 1, stream) != 1) {
00645 free(head);
00646 throw FLANNException("Invalid index file, cannot read from disk (header)");
00647 }
00648
00649
00650 if (head->signature[13] == '1' && head->signature[15] == '0') {
00651 free(head);
00652 fseek(stream, pos, SEEK_SET);
00653 return decompressAndLoadV10(stream);
00654 }
00655
00656
00657
00658 buffer_ = buffer_blocks_ = (char *)malloc(BLOCK_BYTES*2);
00659 compressed_buffer_ = (char *)malloc(LZ4_COMPRESSBOUND(BLOCK_BYTES));
00660 if (buffer_ == NULL || compressed_buffer_ == NULL) {
00661 free(head);
00662 throw FLANNException("Error allocating compression buffer");
00663 }
00664
00665
00666 lz4StreamDecode = &lz4StreamDecode_body;
00667 LZ4_setStreamDecode(lz4StreamDecode, NULL, 0);
00668
00669
00670 memcpy(buffer_, head, headSz);
00671 loadBlock(buffer_+headSz, head->first_block_size, stream);
00672 block_sz_ += headSz;
00673 ptr_ = buffer_;
00674 free(head);
00675 }
00676
00677 void loadBlock(char* buffer_, size_t compSz, FILE* stream)
00678 {
00679 if(compSz >= LZ4_COMPRESSBOUND(BLOCK_BYTES)) {
00680 throw FLANNException("Requested block size too large");
00681 }
00682
00683
00684 if (fread(compressed_buffer_, compSz, 1, stream) != 1) {
00685 throw FLANNException("Invalid index file, cannot read from disk (block)");
00686 }
00687
00688
00689 const int decBytes = LZ4_decompress_safe_continue(
00690 lz4StreamDecode, compressed_buffer_, buffer_, compSz, BLOCK_BYTES);
00691 if(decBytes <= 0) {
00692 throw FLANNException("Invalid index file, cannot decompress block");
00693 }
00694 block_sz_ = decBytes;
00695 }
00696
00697 void preparePtr(size_t size)
00698 {
00699
00700 if (ptr_+size <= buffer_+block_sz_)
00701 return;
00702
00703
00704 if (buffer_ == buffer_blocks_)
00705 buffer_ = &buffer_blocks_[BLOCK_BYTES];
00706 else
00707 buffer_ = buffer_blocks_;
00708
00709
00710 size_t cmpSz = 0;
00711 size_t readCnt = fread(&cmpSz, sizeof(cmpSz), 1, stream_);
00712 if(cmpSz <= 0 || readCnt != 1) {
00713 throw FLANNException("Requested to read next block past end of file");
00714 }
00715
00716
00717 loadBlock(buffer_, cmpSz, stream_);
00718 ptr_ = buffer_;
00719 }
00720
00721 void endBlock()
00722 {
00723
00724 if (buffer_blocks_ != NULL) {
00725
00726 size_t zero = -1;
00727 if (fread(&zero, sizeof(zero), 1, stream_) != 1) {
00728 throw FLANNException("Invalid index file, cannot read from disk (end)");
00729 }
00730 if (zero != 0) {
00731 throw FLANNException("Invalid index file, last block not zero length");
00732 }
00733 }
00734
00735
00736 if (buffer_blocks_ != NULL) {
00737 free(buffer_blocks_);
00738 buffer_blocks_ = NULL;
00739 }
00740 if (compressed_buffer_ != NULL) {
00741 free(compressed_buffer_);
00742 compressed_buffer_ = NULL;
00743 }
00744 ptr_ = NULL;
00745 }
00746
00747 public:
00748 LoadArchive(const char* filename)
00749 {
00750
00751 stream_ = fopen(filename, "rb");
00752 own_stream_ = true;
00753
00754 initBlock(stream_);
00755 }
00756
00757 LoadArchive(FILE* stream)
00758 {
00759 stream_ = stream;
00760 own_stream_ = false;
00761
00762 initBlock(stream);
00763 }
00764
00765 ~LoadArchive()
00766 {
00767 endBlock();
00768 if (own_stream_) {
00769 fclose(stream_);
00770 }
00771 }
00772
00773 template<typename T>
00774 void load(T& val)
00775 {
00776 preparePtr(sizeof(val));
00777 memcpy(&val, ptr_, sizeof(val));
00778 ptr_ += sizeof(val);
00779 }
00780
00781 template<typename T>
00782 void load(T*& val)
00783 {
00784
00785
00786 }
00787
00788 template<typename T>
00789 void load_binary(T* ptr, size_t size)
00790 {
00791 while (size > BLOCK_BYTES) {
00792
00793 preparePtr(BLOCK_BYTES);
00794
00795
00796 memcpy(ptr, ptr_, BLOCK_BYTES);
00797 ptr_ += BLOCK_BYTES;
00798 ptr = ((char *)ptr) + BLOCK_BYTES;
00799 size -= BLOCK_BYTES;
00800 }
00801
00802
00803 preparePtr(size);
00804
00805
00806 memcpy(ptr, ptr_, size);
00807 ptr_ += size;
00808 }
00809 };
00810
00811 }
00812 }
00813 #endif // SERIALIZATION_H_