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.
exercise_2/colmap-dev/lib/FLANN/util/serialization.h

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_