You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

590 lines
18 KiB
C++

/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CORE_ARCHIVE_H
#define SEISCOMP_CORE_ARCHIVE_H
#include <cstdint>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <complex>
#include <time.h>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>
#include <boost/variant.hpp>
#include <seiscomp/core.h>
#include <seiscomp/core/defs.h>
#include <seiscomp/core/optional.h>
#include <seiscomp/core/factory.h>
#include <seiscomp/core/serialization.h>
#include <seiscomp/core/datetime.h>
#include <seiscomp/core/version.h>
#define DECLARE_ROOT_SERIALIZATION(RootClass) \
public: \
typedef Seiscomp::Core::Generic::Archive<RootClass> Archive; \
virtual void serialize(Archive&) {}
#define DECLARE_SERIALIZATION \
public: \
virtual void serialize(Archive& ar) override
namespace Seiscomp {
namespace Core {
namespace Generic {
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/** \brief A template archive interface
An archive offers an interface to read from and write to datasources.
*/
template <typename ROOT_TYPE>
class Archive {
// ------------------------------------------------------------------
// Traits
// ------------------------------------------------------------------
public:
typedef ROOT_TYPE RootType;
typedef boost::variant<int, double, std::string> PropertyValue;
typedef std::map<std::string, PropertyValue> Properties;
// ------------------------------------------------------------------
// Public Types
// ------------------------------------------------------------------
public:
//! Serialization hints
enum {
NONE = 0,
STATIC_TYPE = 0x01,
//! Objects should not serialize their child elements
IGNORE_CHILDS = 0x02,
//! Objects are stored as XML nodes not as XML attributes
XML_ELEMENT = 0x04,
//! Objects are stored as XML cdata not as XML attributes
XML_CDATA = 0x08,
//! This attribute is mandatory even if empty
XML_MANDATORY = 0x10,
//! Objects are stored in a seperate database table and
//! not in columns of the parent object table
DB_TABLE = 0x20,
//! The time is stored in two records: time and microseconds
SPLIT_TIME = 0x40,
//! This is just an informational flag used for database
//! access mostly. This flag is the only one that will
//! be kept alive when serializing child objects.
INDEX_ATTRIBUTE = 0x80
};
// ------------------------------------------------------------------
// Xstruction
// ------------------------------------------------------------------
protected:
//! Constructor
Archive();
public:
//! Destructor
virtual ~Archive() {}
// ------------------------------------------------------------------
// Public Interface
// ------------------------------------------------------------------
public:
static int PackVersion(int major, int minor) { return major << 16 | (minor & 0xFFFF); }
/** Opens an archive.
Every archive class interpretes the dataSource parameter
in its own way. It can either point to a named dataSource (file)
or to a block of memory containing the actual archive data.
*/
virtual bool open(const char* dataSource);
//! Creates a new archive
virtual bool create(const char* dataSource);
virtual void close() = 0;
/**
* @brief Sets strict reading mode. In strict mode optional attributes
* must be parsed correctly otherwise the archive is not valid.
* If strict mode is disabled then invalid optional attributes
* or objects are set to None or nullptr.
* @param strict Enabled or disabled
*/
void setStrictMode(bool strict);
bool isStrictMode() const;
//! Queries whether the archive is in reading mode or not
bool isReading() const;
//! Returns whether the last operation was successfull or not
bool success() const;
//! Returns the serialization hints to propose a special
//! behaviour to serializable objects.
int hint() const;
//! Sets the current serialization hint
void setHint(int);
//! Sets the validity during serialization if needed
void setValidity(bool);
void setVersion(Version v) { _version = v; }
Version version() const { return _version; }
int versionMajor() const { return _version.majorTag(); }
int versionMinor() const { return _version.minorTag(); }
template <int major, int minor>
bool isLowerVersion() const {
return _version.packed <VersionPacker<major,minor,0>::Value;
}
template <int major, int minor>
bool isVersion() const {
return _version.packed == VersionPacker<major,minor,0>::Value;
}
template <int major, int minor>
bool isHigherVersion() const {
return _version.packed > VersionPacker<major,minor,0>::Value;
}
template <int major, int minor>
bool supportsVersion() const {
return _version.packed >= VersionPacker<major,minor,0>::Value;
}
// ------------------------------------------------------------------
// Property interface
// ------------------------------------------------------------------
public:
//! Returns the number of user set properties
size_t propertyCount() const;
//! Sets a value for the named property. If the property does not
//! yet exist, it will be added and false will be returned. If
//! the property exists already, true is returned. The value is
//! updated in both cases.
bool setProperty(const char *name, const PropertyValue &v);
//! Returns a property (if set) or nullptr pointer given a property
//! name.
const PropertyValue *property(const char *name) const;
const int *propertyInt(const char *name) const;
const double *propertyDouble(const char *name) const;
const std::string *propertyString(const char *name) const;
//! Removes all set properties
void clearProperties();
// ------------------------------------------------------------------
// Read methods
// ------------------------------------------------------------------
public:
//! Reads an integer
virtual void read(std::int8_t &value) = 0;
virtual void read(std::int16_t &value) = 0;
virtual void read(std::int32_t &value) = 0;
virtual void read(std::int64_t &value) = 0;
//! Reads a float
virtual void read(float &value) = 0;
//! Reads a double
virtual void read(double &value) = 0;
//! Reads a float complex
virtual void read(std::complex<float> &value) = 0;
//! Reads a double complex
virtual void read(std::complex<double> &value) = 0;
//! Reads a boolean
virtual void read(bool &value) = 0;
//! Reads a vector of chars
virtual void read(std::vector<char> &value) = 0;
//! Reads a vector of ints
virtual void read(std::vector<std::int8_t> &value) = 0;
virtual void read(std::vector<std::int16_t> &value) = 0;
virtual void read(std::vector<std::int32_t> &value) = 0;
virtual void read(std::vector<std::int64_t> &value) = 0;
//! Reads a vector of floats
virtual void read(std::vector<float> &value) = 0;
//! Reads a vector of doubles
virtual void read(std::vector<double> &value) = 0;
//! Reads a vector of complex doubles
virtual void read(std::vector<std::complex<double> > &value) = 0;
//! Reads a vector of strings
virtual void read(std::vector<std::string> &value) = 0;
//! Reads a vector of time
virtual void read(std::vector<Time> &value) = 0;
//! Reads a string
virtual void read(std::string &value) = 0;
//! Reads a time
virtual void read(Time &value) = 0;
template <typename T>
void read(T &object);
void read(ROOT_TYPE &object);
//! Reads a generic pointer.
//! When the referenced type is not registered, nothing will be
//! done at all.
//! Reading pointer to non class types (int, float, ...) implies
//! compiler errors.
template <typename T>
void read(T *&object);
template <typename T>
void read(::boost::intrusive_ptr<T> &object);
template <typename T>
void read(::boost::optional<T> &object);
// ------------------------------------------------------------------
// Write methods
// ------------------------------------------------------------------
public:
//! Writes an integer
virtual void write(std::int8_t value) = 0;
virtual void write(std::int16_t value) = 0;
virtual void write(std::int32_t value) = 0;
virtual void write(std::int64_t value) = 0;
//! Writes a float
virtual void write(float value) = 0;
//! Writes a double
virtual void write(double value) = 0;
//! Writes a float complex
virtual void write(std::complex<float> &value) = 0;
//! Writes a double complex
virtual void write(std::complex<double> &value) = 0;
//! Writes a boolean
virtual void write(bool value) = 0;
//! Writes a vector of chars
virtual void write(std::vector<char> &value) = 0;
//! Writes a vector of ints
virtual void write(std::vector<std::int8_t> &value) = 0;
virtual void write(std::vector<std::int16_t> &value) = 0;
virtual void write(std::vector<std::int32_t> &value) = 0;
virtual void write(std::vector<std::int64_t> &value) = 0;
//! Writes a vector of floats
virtual void write(std::vector<float> &value) = 0;
//! Writes a vector of doubles
virtual void write(std::vector<double> &value) = 0;
//! Writes a vector of complex doubles
virtual void write(std::vector<std::complex<double> > &value) = 0;
//! Writes a vector of strings
virtual void write(std::vector<std::string> &value) = 0;
//! Writes a string
virtual void write(std::string &value) = 0;
//! Reads a vector of time
virtual void write(std::vector<Time> &value) = 0;
//! Writes a time
virtual void write(Seiscomp::Core::Time &value) = 0;
//! Writes an object
template <typename T>
void write(T &object);
void write(ROOT_TYPE &object);
//! Entry method for writing object pointers
template <typename T>
void write(T*);
template <typename T>
void write(::boost::intrusive_ptr<T>&);
template <typename T>
void write(::boost::optional<T>&);
// ------------------------------------------------------------------
// Operators
// ------------------------------------------------------------------
public:
//! Writes a C pointer into the archive
template <typename T>
Archive& operator<<(T*&);
//! Writes a smartpointer into the archive
template <typename T>
Archive& operator<<(::boost::intrusive_ptr<T>&);
//! Writes a named object into the archive
template <typename T>
Archive& operator<<(const ObjectNamer<T>&);
/**
\brief Why did you implement different versions for each generic
\brief container type instead of using a template template
\brief parameter?
To support container serialization, each container has to be
implemented in an own overloaded version, because Microsoft
Visual Studio lacks template type parameter deduction for this
kind of declaration:
template <template <typename> class CONTAINER, typename T>
Archive& operator<<(const ObjectNamer<CONTAINER<T> >&);
To support this compiler as well, different operators for each
supported container type have been implemented.
*/
//! Writes a named vector into the archive
template <typename T>
Archive& operator<<(const ObjectNamer<std::vector<T> >&);
//! Writes a named list into the archive
template <typename T>
Archive& operator<<(const ObjectNamer<std::list<T> >&);
//! Reads a C pointer from the archive
template <typename T>
Archive& operator>>(T*&);
//! Reads a smartpointer pointer from the archive
template <typename T>
Archive& operator>>(::boost::intrusive_ptr<T>&);
//! Reads an object sequence from the archive.
template <typename T>
Archive& operator>>(const ObjectIterator<T>&);
//! Reads a named object from the archive.
//! The object name will no be read but used for locating
//! the data in the archive.
template <typename T>
Archive& operator>>(const ObjectNamer<T>&);
//! Reads a vector from the archive
template <typename T>
Archive& operator>>(const ObjectNamer<std::vector<T> >&);
//! Reads a list from the archive
template <typename T>
Archive& operator>>(const ObjectNamer<std::list<T> >&);
//! Stream operator that decides by means of the _isReading flag
//! whether a the object has to be written or to be read.
template <typename T>
Archive& operator&(ObjectNamer<T>);
// ------------------------------------------------------------------
// Protected interface
// ------------------------------------------------------------------
protected:
struct SerializeDispatcher {
virtual ~SerializeDispatcher() {}
virtual void operator()(Archive&) = 0;
};
template <typename T>
struct TypedSerializeDispatcher : SerializeDispatcher {
TypedSerializeDispatcher(T* t = nullptr) : target(t) {}
TypedSerializeDispatcher& operator=(T* t) {
target = t;
return *this;
}
TypedSerializeDispatcher* operator->() { return this; }
virtual void operator()(Archive<ROOT_TYPE>& ar) {
target->serialize(ar);
}
const char* className() { return nullptr; }
T *target;
};
bool findObject(const char *name, const char *targetClass, bool nullable);
//! Locates an object inside the archive. A derived class
//! must provide its specific location code.
virtual bool locateObjectByName(const char *name, const char *targetClass, bool nullable) = 0;
virtual bool locateNextObjectByName(const char *name, const char *targetClass) = 0;
//! Whenever a nullptr object has to be serialized this method will be called.
//! It has a default implementation (which does nothing) and does not need
//! to be implemented by derived classes. But sometimes this information
//! maybe quite useful. This method gets never called while in read mode.
virtual void locateNullObjectByName(const char *name, const char *targetClass, bool first);
//! When a sequence is to be read this methods gets called
virtual void readSequence();
//! Whenever a sequence is to be written this method gets called with the
//! size of the sequence. The default implementation does nothing.
virtual void writeSequence(int size);
/** Whenever a polymorphic object has to be read, its classname
must be known to construct the object. A derived class
must implement this method to retrieve the current object
classname.
*/
virtual std::string determineClassName() = 0;
//! Sets the classname to be written
virtual void setClassName(const char*) = 0;
/** Method to serialize an polymorphic object
The default implementation simply calls
\code
object->serialize(*this);
\endcode
Derived classes can override this method to wrap
the serialization process.
\code
Do_something_nifty_before_serialization();
Archive<ROOT_TYPE>::serialize(object);
Do_really_cool_things_after_serialization();
\endcode
*/
virtual void serialize(ROOT_TYPE *object);
virtual void serialize(SerializeDispatcher &);
// ------------------------------------------------------------------
// Implementation
// ------------------------------------------------------------------
private:
template <typename T>
void readPtr(ROOT_TYPE *, T *&object);
template <typename T>
void readPtr(void*, T *&object);
//! Helper function to distinguish between pointer and non pointer
//! types to avoid nullptr pointer serialization.
template <typename T>
void read(const char *name, T &object, const char *targetClass);
template <typename T>
void read(const char *name, T *&object, const char *targetClass);
template <typename T>
void read(const char *name, ::boost::intrusive_ptr<T> &object, const char *targetClass);
template <typename T>
void read(const char *name, ::boost::optional<T> &object, const char *targetClass);
template <typename T>
void write(const char *name, T &object, const char *targetClass);
//! Helper function to distinguish between C pointer and SmartPointers
template <typename T>
void write(const char* name, T* object, const char* targetClass);
//! Helper function to distinguish between C pointer and SmartPointers
template <typename T>
void write(const char *name, ::boost::intrusive_ptr<T> &object, const char *targetClass);
//! Helper function to distinguish between C pointer and Optionals
template <typename T>
void write(const char *name, ::boost::optional<T> &object, const char *targetClass);
int setChildHint(int h);
protected:
int _hint;
bool _isReading;
bool _validObject;
bool _first;
bool _found;
bool _strict;
Version _version;
Properties _properties;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct VectorReader;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct VectorWriter;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct ListReader;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct ListWriter;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct ContainerReader;
template <typename ROOT, typename T, int CLASS_TYPE>
friend struct ContainerWriter;
};
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include "archive.inl"
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
}
}
#endif