1 /*
2   This file is part of MADNESS.
3 
4   Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20   For more information please contact:
21 
22   Robert J. Harrison
23   Oak Ridge National Laboratory
24   One Bethel Valley Road
25   P.O. Box 2008, MS-6367
26 
27   email: harrisonrj@ornl.gov
28   tel:   865-241-3937
29   fax:   865-572-0680
30 */
31 
32 #ifndef MADNESS_WORLD_BUFFER_ARCHIVE_H__INCLUDED
33 #define MADNESS_WORLD_BUFFER_ARCHIVE_H__INCLUDED
34 
35 /**
36  \file buffer_archive.h
37  \brief Implements an archive wrapping a memory buffer.
38  \ingroup serialization
39 */
40 
41 #include <type_traits>
42 #include <madness/world/archive.h>
43 #include <madness/world/print.h>
44 #include <cstring>
45 
46 namespace madness {
47     namespace archive {
48 
49         /// \addtogroup serialization
50         /// @{
51 
52         /// Wraps an archive around a memory buffer for output.
53 
54         /// \note Type checking is disabled for efficiency.
55         ///
56         /// \throw madness::MadnessException in case of buffer overflow.
57         ///
58         /// The default constructor can also be used to count stuff.
59         class BufferOutputArchive : public BaseOutputArchive {
60         private:
61             unsigned char * const ptr; ///< The memory buffer.
62             const std::size_t nbyte; ///< Buffer size.
63             mutable std::size_t i; /// Current output location.
64             bool countonly; ///< If true just count, don't copy.
65 
66         public:
67             /// Default constructor; the buffer will only count data.
BufferOutputArchive()68             BufferOutputArchive()
69                     : ptr(nullptr), nbyte(0), i(0), countonly(true) {}
70 
71             /// Constructor that assigns a buffer.
72 
73             /// \param[in] ptr Pointer to the buffer.
74             /// \param[in] nbyte Size of the buffer.
BufferOutputArchive(void * ptr,std::size_t nbyte)75             BufferOutputArchive(void* ptr, std::size_t nbyte)
76                     : ptr((unsigned char *) ptr), nbyte(nbyte), i(0), countonly(false) {}
77 
78             /// Stores (counts) data into the memory buffer.
79 
80             /// The function only appears (due to \c enable_if) if \c T is
81             /// serializable.
82             /// \tparam T Type of the data to be stored (counted).
83             /// \param[in] t Pointer to the data to be stored (counted).
84             /// \param[in] n Size of data to be stored (counted).
85             template <typename T>
86             inline
87             typename std::enable_if< madness::is_trivially_serializable<T>::value, void >::type
store(const T * t,long n)88             store(const T* t, long n) const {
89                 std::size_t m = n*sizeof(T);
90                 if (countonly) {
91                     i += m;
92                 }
93                 else if (i+m > nbyte) {
94                     madness::print("BufferOutputArchive:ptr,nbyte,i,n,m,i+m:",(void *)ptr,nbyte,i,n,m,i+m);
95                     MADNESS_ASSERT(i+m<=nbyte);
96                 }
97                 else {
98                     memcpy(ptr+i, t, m);
99                     i += m;
100                 }
101             }
102 
103             /// Open a buffer with a specific size.
open(std::size_t)104             void open(std::size_t /*hint*/) {}
105 
106             /// Close the archive.
close()107             void close() {}
108 
109             /// Flush the archive.
flush()110             void flush() {}
111 
112             /// Determine if this buffer is used for counting.
113 
114             /// \return True if this buffer is only used for counting.
count_only()115             bool count_only() const { return countonly; }
116 
117             /// Return the amount of data stored (counted) in the buffer.
118 
119             /// \return The amount of data stored (counted) in the buffer.
size()120             inline std::size_t size() const {
121                 return i;
122             };
123         };
124 
125 
126         /// Wraps an archive around a memory buffer for input.
127 
128         /// \note Type checking is disabled for efficiency.
129         ///
130         /// \throw madness::MadnessException in case of buffer overrun.
131         class BufferInputArchive : public BaseInputArchive {
132         private:
133             const unsigned char* const ptr; ///< The memory buffer.
134             const std::size_t nbyte; ///< Buffer size.
135             mutable std::size_t i; ///< Current input location.
136 
137         public:
138             /// Constructor that assigns a buffer.
139 
140             /// \param[in] ptr Pointer to the buffer.
141             /// \param[in] nbyte Size of the buffer.
BufferInputArchive(const void * ptr,std::size_t nbyte)142             BufferInputArchive(const void* ptr, std::size_t nbyte)
143                     : ptr((const unsigned char *) ptr), nbyte(nbyte), i(0) {};
144 
145             /// Reads data from the memory buffer.
146 
147             /// The function only appears (due to \c enable_if) if \c T is
148             /// serializable.
149             /// \tparam T Type of the data to be read.
150             /// \param[out] t Where to store the read data.
151             /// \param[in] n Size of data to be read.
152             template <class T>
153             inline
154             typename std::enable_if< madness::is_trivially_serializable<T>::value, void >::type
load(T * t,long n)155             load(T* t, long n) const {
156                 std::size_t m = n*sizeof(T);
157                 MADNESS_ASSERT(m+i <=  nbyte);
158                 memcpy((unsigned char*) t, ptr+i, m);
159                 i += m;
160             }
161 
162             /// Open the archive.
open()163             void open() {};
164 
165             /// Reset the read location to the beginning of the buffer.
rewind()166             void rewind() const {
167                 i=0;
168             };
169 
170             /// Get the amount of space yet to be read from the buffer.
171 
172             /// \return The amount of space yet to be read from the buffer.
nbyte_avail()173             std::size_t nbyte_avail() const {
174                 return nbyte-i;
175             };
176 
177             /// Close the archive.
close()178             void close() {}
179         };
180 
181         /// Implement pre/postamble storage routines for a \c BufferOutputArchive.
182 
183         /// \note No type checking over the buffer stream, for efficiency.
184         /// \tparam T The type to be stored.
185         template <class T>
186         struct ArchivePrePostImpl<BufferOutputArchive, T> {
187             /// Write the preamble to the archive.
188             static inline void preamble_store(const BufferOutputArchive& /*ar*/) {}
189 
190             /// Write the postamble to the archive.
191             static inline void postamble_store(const BufferOutputArchive& /*ar*/) {}
192         };
193 
194         /// Implement pre/postamble load routines for a \c BufferInputArchive.
195 
196         /// \note No type checking over \c Buffer stream, for efficiency.
197         /// \tparam T The type to be loaded.
198         template <class T>
199         struct ArchivePrePostImpl<BufferInputArchive, T> {
200             /// Load the preamble.
201             static inline void preamble_load(const BufferInputArchive& /*ar*/) {}
202 
203             /// Load the postamble.
204             static inline void postamble_load(const BufferInputArchive& /*ar*/) {}
205         };
206 
207         /// @}
208     }
209 }
210 #endif // MADNESS_WORLD_BUFFER_ARCHIVE_H__INCLUDED
211