You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
814 lines
20 KiB
814 lines
20 KiB
#ifndef SERIALIZATION_H_
|
|
#define SERIALIZATION_H_
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdio.h>
|
|
#include "FLANN/ext/lz4.h"
|
|
#include "FLANN/ext/lz4hc.h"
|
|
|
|
|
|
namespace flann
|
|
{
|
|
struct IndexHeaderStruct {
|
|
char signature[24];
|
|
char version[16];
|
|
flann_datatype_t data_type;
|
|
flann_algorithm_t index_type;
|
|
size_t rows;
|
|
size_t cols;
|
|
size_t compression;
|
|
size_t first_block_size;
|
|
};
|
|
|
|
namespace serialization
|
|
{
|
|
|
|
struct access
|
|
{
|
|
template<typename Archive, typename T>
|
|
static inline void serialize(Archive& ar, T& type)
|
|
{
|
|
type.serialize(ar);
|
|
}
|
|
};
|
|
|
|
|
|
template<typename Archive, typename T>
|
|
inline void serialize(Archive& ar, T& type)
|
|
{
|
|
access::serialize(ar,type);
|
|
}
|
|
|
|
template<typename T>
|
|
struct Serializer
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, T& val)
|
|
{
|
|
serialization::serialize(ar,val);
|
|
}
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, const T& val)
|
|
{
|
|
serialization::serialize(ar,const_cast<T&>(val));
|
|
}
|
|
};
|
|
|
|
#define BASIC_TYPE_SERIALIZER(type)\
|
|
template<> \
|
|
struct Serializer<type> \
|
|
{\
|
|
template<typename InputArchive>\
|
|
static inline void load(InputArchive& ar, type& val)\
|
|
{\
|
|
ar.load(val);\
|
|
}\
|
|
template<typename OutputArchive>\
|
|
static inline void save(OutputArchive& ar, const type& val)\
|
|
{\
|
|
ar.save(val);\
|
|
}\
|
|
}
|
|
|
|
#define ENUM_SERIALIZER(type)\
|
|
template<>\
|
|
struct Serializer<type>\
|
|
{\
|
|
template<typename InputArchive>\
|
|
static inline void load(InputArchive& ar, type& val)\
|
|
{\
|
|
int int_val;\
|
|
ar & int_val;\
|
|
val = (type) int_val;\
|
|
}\
|
|
template<typename OutputArchive>\
|
|
static inline void save(OutputArchive& ar, const type& val)\
|
|
{\
|
|
int int_val = (int)val;\
|
|
ar & int_val;\
|
|
}\
|
|
}
|
|
|
|
|
|
// declare serializers for simple types
|
|
BASIC_TYPE_SERIALIZER(char);
|
|
BASIC_TYPE_SERIALIZER(unsigned char);
|
|
BASIC_TYPE_SERIALIZER(short);
|
|
BASIC_TYPE_SERIALIZER(unsigned short);
|
|
BASIC_TYPE_SERIALIZER(int);
|
|
BASIC_TYPE_SERIALIZER(unsigned int);
|
|
BASIC_TYPE_SERIALIZER(long);
|
|
BASIC_TYPE_SERIALIZER(unsigned long);
|
|
BASIC_TYPE_SERIALIZER(unsigned long long);
|
|
BASIC_TYPE_SERIALIZER(float);
|
|
BASIC_TYPE_SERIALIZER(double);
|
|
BASIC_TYPE_SERIALIZER(bool);
|
|
#ifdef _MSC_VER
|
|
// unsigned __int64 ~= unsigned long long
|
|
// Will throw error on VS2013
|
|
#if _MSC_VER < 1800
|
|
BASIC_TYPE_SERIALIZER(unsigned __int64);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
// serializer for std::vector
|
|
template<typename T>
|
|
struct Serializer<std::vector<T> >
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, std::vector<T>& val)
|
|
{
|
|
size_t size;
|
|
ar & size;
|
|
val.resize(size);
|
|
for (size_t i=0;i<size;++i) {
|
|
ar & val[i];
|
|
}
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, const std::vector<T>& val)
|
|
{
|
|
ar & val.size();
|
|
for (size_t i=0;i<val.size();++i) {
|
|
ar & val[i];
|
|
}
|
|
}
|
|
};
|
|
|
|
// serializer for std::vector
|
|
template<typename K, typename V>
|
|
struct Serializer<std::map<K,V> >
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, std::map<K,V>& map_val)
|
|
{
|
|
size_t size;
|
|
ar & size;
|
|
for (size_t i = 0; i < size; ++i)
|
|
{
|
|
K key;
|
|
ar & key;
|
|
V value;
|
|
ar & value;
|
|
map_val[key] = value;
|
|
}
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, const std::map<K,V>& map_val)
|
|
{
|
|
ar & map_val.size();
|
|
for (typename std::map<K,V>::const_iterator i=map_val.begin(); i!=map_val.end(); ++i) {
|
|
ar & i->first;
|
|
ar & i->second;
|
|
}
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Serializer<T*>
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, T*& val)
|
|
{
|
|
ar.load(val);
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, T* const& val)
|
|
{
|
|
ar.save(val);
|
|
}
|
|
};
|
|
|
|
template<typename T, int N>
|
|
struct Serializer<T[N]>
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, T (&val)[N])
|
|
{
|
|
ar.load(val);
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, T const (&val)[N])
|
|
{
|
|
ar.save(val);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
struct binary_object
|
|
{
|
|
void const * ptr_;
|
|
size_t size_;
|
|
|
|
binary_object( void * const ptr, size_t size) :
|
|
ptr_(ptr),
|
|
size_(size)
|
|
{}
|
|
binary_object(const binary_object & rhs) :
|
|
ptr_(rhs.ptr_),
|
|
size_(rhs.size_)
|
|
{}
|
|
|
|
binary_object & operator=(const binary_object & rhs) {
|
|
ptr_ = rhs.ptr_;
|
|
size_ = rhs.size_;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
inline const binary_object make_binary_object(/* const */ void * t, size_t size){
|
|
return binary_object(t, size);
|
|
}
|
|
|
|
template<>
|
|
struct Serializer<const binary_object>
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, const binary_object& b)
|
|
{
|
|
ar.load_binary(const_cast<void *>(b.ptr_), b.size_);
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, const binary_object& b)
|
|
{
|
|
ar.save_binary(b.ptr_, b.size_);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct Serializer<binary_object>
|
|
{
|
|
template<typename InputArchive>
|
|
static inline void load(InputArchive& ar, binary_object& b)
|
|
{
|
|
ar.load_binary(const_cast<void *>(b.ptr_), b.size_);
|
|
}
|
|
|
|
template<typename OutputArchive>
|
|
static inline void save(OutputArchive& ar, const binary_object& b)
|
|
{
|
|
ar.save_binary(b.ptr_, b.size_);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
template <bool C_>
|
|
struct bool_ {
|
|
static const bool value = C_;
|
|
typedef bool value_type;
|
|
};
|
|
|
|
|
|
class ArchiveBase
|
|
{
|
|
public:
|
|
void* getObject() { return object_; }
|
|
|
|
void setObject(void* object) { object_ = object; }
|
|
|
|
private:
|
|
void* object_;
|
|
};
|
|
|
|
|
|
template<typename Archive>
|
|
class InputArchive : public ArchiveBase
|
|
{
|
|
protected:
|
|
InputArchive() {};
|
|
public:
|
|
typedef bool_<true> is_loading;
|
|
typedef bool_<false> is_saving;
|
|
|
|
template<typename T>
|
|
Archive& operator& (T& val)
|
|
{
|
|
Serializer<T>::load(*static_cast<Archive*>(this),val);
|
|
return *static_cast<Archive*>(this);
|
|
}
|
|
};
|
|
|
|
|
|
template<typename Archive>
|
|
class OutputArchive : public ArchiveBase
|
|
{
|
|
protected:
|
|
OutputArchive() {};
|
|
public:
|
|
typedef bool_<false> is_loading;
|
|
typedef bool_<true> is_saving;
|
|
|
|
template<typename T>
|
|
Archive& operator& (const T& val)
|
|
{
|
|
Serializer<T>::save(*static_cast<Archive*>(this),val);
|
|
return *static_cast<Archive*>(this);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
class SizeArchive : public OutputArchive<SizeArchive>
|
|
{
|
|
size_t size_;
|
|
public:
|
|
|
|
SizeArchive() : size_(0)
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
void save(const T& val)
|
|
{
|
|
size_ += sizeof(val);
|
|
}
|
|
|
|
template<typename T>
|
|
void save_binary(T* ptr, size_t size)
|
|
{
|
|
size_ += size;
|
|
}
|
|
|
|
|
|
void reset()
|
|
{
|
|
size_ = 0;
|
|
}
|
|
|
|
size_t size()
|
|
{
|
|
return size_;
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
//class PrintArchive : public OutputArchive<PrintArchive>
|
|
//{
|
|
//public:
|
|
// template<typename T>
|
|
// void save(const T& val)
|
|
// {
|
|
// std::cout << val << std::endl;
|
|
// }
|
|
//
|
|
// template<typename T>
|
|
// void save_binary(T* ptr, size_t size)
|
|
// {
|
|
// std::cout << "<binary object>" << std::endl;
|
|
// }
|
|
//};
|
|
|
|
#define BLOCK_BYTES (1024 * 64)
|
|
|
|
class SaveArchive : public OutputArchive<SaveArchive>
|
|
{
|
|
/**
|
|
* Based on blockStreaming_doubleBuffer code at:
|
|
* https://github.com/Cyan4973/lz4/blob/master/examples/blockStreaming_doubleBuffer.c
|
|
*/
|
|
|
|
FILE* stream_;
|
|
bool own_stream_;
|
|
char *buffer_;
|
|
size_t offset_;
|
|
|
|
int first_block_;
|
|
char *buffer_blocks_;
|
|
char *compressed_buffer_;
|
|
LZ4_streamHC_t lz4Stream_body;
|
|
LZ4_streamHC_t* lz4Stream;
|
|
|
|
void initBlock()
|
|
{
|
|
// Alloc the space for both buffer blocks (each compressed block
|
|
// references the previous)
|
|
buffer_ = buffer_blocks_ = (char *)malloc(BLOCK_BYTES*2);
|
|
compressed_buffer_ = (char *)malloc(LZ4_COMPRESSBOUND(BLOCK_BYTES) + sizeof(size_t));
|
|
if (buffer_ == NULL || compressed_buffer_ == NULL) {
|
|
throw FLANNException("Error allocating compression buffer");
|
|
}
|
|
|
|
// Init the LZ4 stream
|
|
lz4Stream = &lz4Stream_body;
|
|
LZ4_resetStreamHC(lz4Stream, 9);
|
|
first_block_ = true;
|
|
|
|
offset_ = 0;
|
|
}
|
|
|
|
void flushBlock()
|
|
{
|
|
size_t compSz = 0;
|
|
// Handle header
|
|
if (first_block_) {
|
|
// Copy & set the header
|
|
IndexHeaderStruct *head = (IndexHeaderStruct *)buffer_;
|
|
size_t headSz = sizeof(IndexHeaderStruct);
|
|
|
|
assert(head->compression == 0);
|
|
head->compression = 1; // Bool now, enum later
|
|
|
|
// Do the compression for the block
|
|
compSz = LZ4_compress_HC_continue(
|
|
lz4Stream, buffer_+headSz, compressed_buffer_+headSz, offset_-headSz,
|
|
LZ4_COMPRESSBOUND(BLOCK_BYTES));
|
|
|
|
if(compSz <= 0) {
|
|
throw FLANNException("Error compressing (first block)");
|
|
}
|
|
|
|
// Handle header
|
|
head->first_block_size = compSz;
|
|
memcpy(compressed_buffer_, buffer_, headSz);
|
|
|
|
compSz += headSz;
|
|
first_block_ = false;
|
|
} else {
|
|
size_t headSz = sizeof(compSz);
|
|
|
|
// Do the compression for the block
|
|
compSz = LZ4_compress_HC_continue(
|
|
lz4Stream, buffer_, compressed_buffer_+headSz, offset_,
|
|
LZ4_COMPRESSBOUND(BLOCK_BYTES));
|
|
|
|
if(compSz <= 0) {
|
|
throw FLANNException("Error compressing");
|
|
}
|
|
|
|
// Save the size of the compressed block as the header
|
|
memcpy(compressed_buffer_, &compSz, headSz);
|
|
compSz += headSz;
|
|
}
|
|
|
|
// Write the compressed buffer
|
|
fwrite(compressed_buffer_, compSz, 1, stream_);
|
|
|
|
// Switch the buffer to the *other* block
|
|
if (buffer_ == buffer_blocks_)
|
|
buffer_ = &buffer_blocks_[BLOCK_BYTES];
|
|
else
|
|
buffer_ = buffer_blocks_;
|
|
offset_ = 0;
|
|
}
|
|
|
|
void endBlock()
|
|
{
|
|
// Cleanup memory
|
|
free(buffer_blocks_);
|
|
buffer_blocks_ = NULL;
|
|
buffer_ = NULL;
|
|
free(compressed_buffer_);
|
|
compressed_buffer_ = NULL;
|
|
|
|
// Write a '0' size for next block
|
|
size_t z = 0;
|
|
fwrite(&z, sizeof(z), 1, stream_);
|
|
}
|
|
|
|
public:
|
|
SaveArchive(const char* filename)
|
|
{
|
|
stream_ = fopen(filename, "wb");
|
|
own_stream_ = true;
|
|
initBlock();
|
|
}
|
|
|
|
SaveArchive(FILE* stream) : stream_(stream), own_stream_(false)
|
|
{
|
|
initBlock();
|
|
}
|
|
|
|
~SaveArchive()
|
|
{
|
|
flushBlock();
|
|
endBlock();
|
|
if (buffer_) {
|
|
free(buffer_);
|
|
buffer_ = NULL;
|
|
}
|
|
if (own_stream_) {
|
|
fclose(stream_);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void save(const T& val)
|
|
{
|
|
assert(sizeof(val) < BLOCK_BYTES);
|
|
if (offset_+sizeof(val) > BLOCK_BYTES)
|
|
flushBlock();
|
|
memcpy(buffer_+offset_, &val, sizeof(val));
|
|
offset_ += sizeof(val);
|
|
}
|
|
|
|
template<typename T>
|
|
void save(T* const& val)
|
|
{
|
|
// don't save pointers
|
|
//fwrite(&val, sizeof(val), 1, handle_);
|
|
}
|
|
|
|
template<typename T>
|
|
void save_binary(T* ptr, size_t size)
|
|
{
|
|
while (size > BLOCK_BYTES) {
|
|
// Flush existing block
|
|
flushBlock();
|
|
|
|
// Save large chunk
|
|
memcpy(buffer_, ptr, BLOCK_BYTES);
|
|
offset_ += BLOCK_BYTES;
|
|
ptr = ((char *)ptr) + BLOCK_BYTES;
|
|
size -= BLOCK_BYTES;
|
|
}
|
|
|
|
// Save existing block if new data will make it too big
|
|
if (offset_+size > BLOCK_BYTES)
|
|
flushBlock();
|
|
|
|
// Copy out requested data
|
|
memcpy(buffer_+offset_, ptr, size);
|
|
offset_ += size;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class LoadArchive : public InputArchive<LoadArchive>
|
|
{
|
|
/**
|
|
* Based on blockStreaming_doubleBuffer code at:
|
|
* https://github.com/Cyan4973/lz4/blob/master/examples/blockStreaming_doubleBuffer.c
|
|
*/
|
|
|
|
FILE* stream_;
|
|
bool own_stream_;
|
|
char *buffer_;
|
|
char *ptr_;
|
|
|
|
char *buffer_blocks_;
|
|
char *compressed_buffer_;
|
|
LZ4_streamDecode_t lz4StreamDecode_body;
|
|
LZ4_streamDecode_t* lz4StreamDecode;
|
|
size_t block_sz_;
|
|
|
|
void decompressAndLoadV10(FILE* stream)
|
|
{
|
|
buffer_ = NULL;
|
|
|
|
// Find file size
|
|
size_t pos = ftell(stream);
|
|
fseek(stream, 0, SEEK_END);
|
|
size_t fileSize = ftell(stream)-pos;
|
|
fseek(stream, pos, SEEK_SET);
|
|
size_t headSz = sizeof(IndexHeaderStruct);
|
|
|
|
// Read the (compressed) file to a buffer
|
|
char *compBuffer = (char *)malloc(fileSize);
|
|
if (compBuffer == NULL) {
|
|
throw FLANNException("Error allocating file buffer space");
|
|
}
|
|
if (fread(compBuffer, fileSize, 1, stream) != 1) {
|
|
free(compBuffer);
|
|
throw FLANNException("Invalid index file, cannot read from disk (compressed)");
|
|
}
|
|
|
|
// Extract header
|
|
IndexHeaderStruct *head = (IndexHeaderStruct *)(compBuffer);
|
|
|
|
// Backward compatability
|
|
size_t compressedSz = fileSize-headSz;
|
|
size_t uncompressedSz = head->first_block_size-headSz;
|
|
|
|
// Check for compression type
|
|
if (head->compression != 1) {
|
|
free(compBuffer);
|
|
throw FLANNException("Compression type not supported");
|
|
}
|
|
|
|
// Allocate a decompressed buffer
|
|
ptr_ = buffer_ = (char *)malloc(uncompressedSz+headSz);
|
|
if (buffer_ == NULL) {
|
|
free(compBuffer);
|
|
throw FLANNException("Error (re)allocating decompression buffer");
|
|
}
|
|
|
|
// Extract body
|
|
size_t usedSz = LZ4_decompress_safe(compBuffer+headSz,
|
|
buffer_+headSz,
|
|
compressedSz,
|
|
uncompressedSz);
|
|
|
|
// Check if the decompression was the expected size.
|
|
if (usedSz != uncompressedSz) {
|
|
free(compBuffer);
|
|
throw FLANNException("Unexpected decompression size");
|
|
}
|
|
|
|
// Copy header data
|
|
memcpy(buffer_, compBuffer, headSz);
|
|
free(compBuffer);
|
|
|
|
// Put the file pointer at the end of the data we've read
|
|
if (compressedSz+headSz+pos != fileSize)
|
|
fseek(stream, compressedSz+headSz+pos, SEEK_SET);
|
|
block_sz_ = uncompressedSz+headSz;
|
|
}
|
|
|
|
void initBlock(FILE *stream)
|
|
{
|
|
size_t pos = ftell(stream);
|
|
buffer_ = NULL;
|
|
buffer_blocks_ = NULL;
|
|
compressed_buffer_ = NULL;
|
|
size_t headSz = sizeof(IndexHeaderStruct);
|
|
|
|
// Read the file header to a buffer
|
|
IndexHeaderStruct *head = (IndexHeaderStruct *)malloc(headSz);
|
|
if (head == NULL) {
|
|
throw FLANNException("Error allocating header buffer space");
|
|
}
|
|
if (fread(head, headSz, 1, stream) != 1) {
|
|
free(head);
|
|
throw FLANNException("Invalid index file, cannot read from disk (header)");
|
|
}
|
|
|
|
// Backward compatability
|
|
if (head->signature[13] == '1' && head->signature[15] == '0') {
|
|
free(head);
|
|
fseek(stream, pos, SEEK_SET);
|
|
return decompressAndLoadV10(stream);
|
|
}
|
|
|
|
// Alloc the space for both buffer blocks (each block
|
|
// references the previous)
|
|
buffer_ = buffer_blocks_ = (char *)malloc(BLOCK_BYTES*2);
|
|
compressed_buffer_ = (char *)malloc(LZ4_COMPRESSBOUND(BLOCK_BYTES));
|
|
if (buffer_ == NULL || compressed_buffer_ == NULL) {
|
|
free(head);
|
|
throw FLANNException("Error allocating compression buffer");
|
|
}
|
|
|
|
// Init the LZ4 stream
|
|
lz4StreamDecode = &lz4StreamDecode_body;
|
|
LZ4_setStreamDecode(lz4StreamDecode, NULL, 0);
|
|
|
|
// Read first block
|
|
memcpy(buffer_, head, headSz);
|
|
loadBlock(buffer_+headSz, head->first_block_size, stream);
|
|
block_sz_ += headSz;
|
|
ptr_ = buffer_;
|
|
free(head);
|
|
}
|
|
|
|
void loadBlock(char* buffer_, size_t compSz, FILE* stream)
|
|
{
|
|
if(compSz >= LZ4_COMPRESSBOUND(BLOCK_BYTES)) {
|
|
throw FLANNException("Requested block size too large");
|
|
}
|
|
|
|
// Read the block into the compressed buffer
|
|
if (fread(compressed_buffer_, compSz, 1, stream) != 1) {
|
|
throw FLANNException("Invalid index file, cannot read from disk (block)");
|
|
}
|
|
|
|
// Decompress into the regular buffer
|
|
const int decBytes = LZ4_decompress_safe_continue(
|
|
lz4StreamDecode, compressed_buffer_, buffer_, compSz, BLOCK_BYTES);
|
|
if(decBytes <= 0) {
|
|
throw FLANNException("Invalid index file, cannot decompress block");
|
|
}
|
|
block_sz_ = decBytes;
|
|
}
|
|
|
|
void preparePtr(size_t size)
|
|
{
|
|
// Return if the new size is less than (or eq) the size of a block
|
|
if (ptr_+size <= buffer_+block_sz_)
|
|
return;
|
|
|
|
// Switch the buffer to the *other* block
|
|
if (buffer_ == buffer_blocks_)
|
|
buffer_ = &buffer_blocks_[BLOCK_BYTES];
|
|
else
|
|
buffer_ = buffer_blocks_;
|
|
|
|
// Find the size of the next block
|
|
size_t cmpSz = 0;
|
|
size_t readCnt = fread(&cmpSz, sizeof(cmpSz), 1, stream_);
|
|
if(cmpSz <= 0 || readCnt != 1) {
|
|
throw FLANNException("Requested to read next block past end of file");
|
|
}
|
|
|
|
// Load block & init ptr
|
|
loadBlock(buffer_, cmpSz, stream_);
|
|
ptr_ = buffer_;
|
|
}
|
|
|
|
void endBlock()
|
|
{
|
|
// If not v1.0 format hack...
|
|
if (buffer_blocks_ != NULL) {
|
|
// Read the last '0' in the file
|
|
size_t zero = -1;
|
|
if (fread(&zero, sizeof(zero), 1, stream_) != 1) {
|
|
throw FLANNException("Invalid index file, cannot read from disk (end)");
|
|
}
|
|
if (zero != 0) {
|
|
throw FLANNException("Invalid index file, last block not zero length");
|
|
}
|
|
}
|
|
|
|
// Free resources
|
|
if (buffer_blocks_ != NULL) {
|
|
free(buffer_blocks_);
|
|
buffer_blocks_ = NULL;
|
|
}
|
|
if (compressed_buffer_ != NULL) {
|
|
free(compressed_buffer_);
|
|
compressed_buffer_ = NULL;
|
|
}
|
|
ptr_ = NULL;
|
|
}
|
|
|
|
public:
|
|
LoadArchive(const char* filename)
|
|
{
|
|
// Open the file
|
|
stream_ = fopen(filename, "rb");
|
|
own_stream_ = true;
|
|
|
|
initBlock(stream_);
|
|
}
|
|
|
|
LoadArchive(FILE* stream)
|
|
{
|
|
stream_ = stream;
|
|
own_stream_ = false;
|
|
|
|
initBlock(stream);
|
|
}
|
|
|
|
~LoadArchive()
|
|
{
|
|
endBlock();
|
|
if (own_stream_) {
|
|
fclose(stream_);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void load(T& val)
|
|
{
|
|
preparePtr(sizeof(val));
|
|
memcpy(&val, ptr_, sizeof(val));
|
|
ptr_ += sizeof(val);
|
|
}
|
|
|
|
template<typename T>
|
|
void load(T*& val)
|
|
{
|
|
// don't load pointers
|
|
//fread(&val, sizeof(val), 1, handle_);
|
|
}
|
|
|
|
template<typename T>
|
|
void load_binary(T* ptr, size_t size)
|
|
{
|
|
while (size > BLOCK_BYTES) {
|
|
// Load next block
|
|
preparePtr(BLOCK_BYTES);
|
|
|
|
// Load large chunk
|
|
memcpy(ptr, ptr_, BLOCK_BYTES);
|
|
ptr_ += BLOCK_BYTES;
|
|
ptr = ((char *)ptr) + BLOCK_BYTES;
|
|
size -= BLOCK_BYTES;
|
|
}
|
|
|
|
// Load next block if needed
|
|
preparePtr(size);
|
|
|
|
// Load the data
|
|
memcpy(ptr, ptr_, size);
|
|
ptr_ += size;
|
|
}
|
|
};
|
|
|
|
} // namespace serialization
|
|
} // namespace flann
|
|
#endif // SERIALIZATION_H_
|