archive.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file archive.h
  3. /// \brief Classes to make (de)serializing to/from streams convenient
  4. ///
  5. /// $Date: 2014-09-09 10:49:13 +0200 (mar, 09 sep 2014) $
  6. ///
  7. ///////////////////////////////////////////////////////////////////////////////////////
  8. #ifndef LPJ_GUESS_ARCHIVE_H
  9. #define LPJ_GUESS_ARCHIVE_H
  10. #include <ostream>
  11. #include <istream>
  12. #include <vector>
  13. /// Abstract base class for ArchiveInStream and ArchiveOutStream
  14. /** The base class declares the transfer function, which will read
  15. * data from a stream in ArchiveInStream, and write data to a stream
  16. * in ArchiveOutStream. By having the same interface for both
  17. * cases, classes can have one function for both serializing and
  18. * deserializing.
  19. *
  20. * Sometimes we do need to know which direction the ArchiveStream
  21. * is working in though, so that can be queried with the save
  22. * function.
  23. */
  24. class ArchiveStream {
  25. public:
  26. /// Checks if this ArchiveStream is saving data to stream or reading
  27. virtual bool save() const = 0;
  28. /// Write or read data to/from a stream
  29. /** \param s Data buffer to write out, or read to.
  30. * Needs to be n bytes.
  31. * \param n Number of bytes to read or write
  32. */
  33. virtual void transfer(char* s, std::streamsize n) = 0;
  34. };
  35. /// Class for reading data from an istream
  36. /** \see ArchiveStream for more documentation */
  37. class ArchiveInStream : public ArchiveStream {
  38. public:
  39. ArchiveInStream(std::istream& strm);
  40. bool save() const;
  41. void transfer(char* s, std::streamsize n);
  42. private:
  43. /// The stream we're reading from
  44. std::istream& in;
  45. };
  46. /// Class for writing data to an ostream
  47. /** \see ArchiveStream for more documentation */
  48. class ArchiveOutStream : public ArchiveStream {
  49. public:
  50. ArchiveOutStream(std::ostream& strm);
  51. bool save() const;
  52. void transfer(char* s, std::streamsize n);
  53. private:
  54. /// The stream we're writing to
  55. std::ostream& out;
  56. };
  57. /// Interface showing that a class can serialize itself
  58. /** Classes which can serialize themselves through an ArchiveStream
  59. * should inherit from this class, and implement the serialize function.
  60. */
  61. class Serializable {
  62. public:
  63. /// Needs to be implemented by all sub-classes
  64. virtual void serialize(ArchiveStream& arch) = 0;
  65. };
  66. /// Function for checking if something inherits from Serializable
  67. /** This variant will be chosen by the compiler for anything which
  68. * isn't Serializable (because of the overload below), and so always
  69. * returns false.
  70. *
  71. * Only intended to be used from the operator& implementation below,
  72. * which has the added benefit that if & is used for a class which
  73. * doesn't inherit from Serializable, many modern compilers will
  74. * warn because we're trying to send a non-POD type to a variadic
  75. * function.
  76. */
  77. inline bool inheritsFromSerializable(...) {
  78. return false;
  79. }
  80. /// Overload for Serializable, always returns true
  81. inline bool inheritsFromSerializable(const Serializable& s) {
  82. return true;
  83. }
  84. /// Operator overloading of &, allowing serialization to be chained
  85. /** Since the operator returns the original stream, we can serialize
  86. * multiple items in the following way:
  87. *
  88. * \code
  89. * ArchiveOutStream arch(os);
  90. *
  91. * arch & width & height & name;
  92. * \endcode
  93. *
  94. * This function can be used for any item where the memory representation
  95. * of the item can be written to file bit by bit, such as the primitive
  96. * data types, or classes implementing Serializable.
  97. */
  98. template<typename T>
  99. ArchiveStream& operator&(ArchiveStream& stream, T& data) {
  100. if (inheritsFromSerializable(data)) {
  101. ((Serializable&)data).serialize(stream);
  102. }
  103. else {
  104. stream.transfer((char*)&data, sizeof(data));
  105. }
  106. return stream;
  107. }
  108. template<typename T>
  109. ArchiveStream& operator&(ArchiveStream& stream, std::vector<T>& data) {
  110. if (stream.save()) {
  111. size_t size = data.size();
  112. stream & size;
  113. }
  114. else {
  115. size_t size;
  116. stream & size;
  117. data.resize(size);
  118. }
  119. for (size_t i = 0; i < data.size(); ++i) {
  120. stream & data[i];
  121. }
  122. return stream;
  123. }
  124. #endif // LPJ_GUESS_ARCHIVE_H