TECA
The Toolkit for Extreme Climate Analysis
teca_binary_stream.h
1 #ifndef teca_binary_stream_h
2 #define teca_binary_stream_h
3 
4 #include "teca_config.h"
5 #include "teca_common.h"
6 #include "teca_mpi.h"
7 
8 #include <cstdlib>
9 #include <cstring>
10 #include <string>
11 #include <map>
12 #include <vector>
13 
14 
15 /// Serialize objects into a binary stream.
17 {
18 public:
19  // construct
21  ~teca_binary_stream() noexcept;
22 
23  // copy
25  const teca_binary_stream &operator=(const teca_binary_stream &other);
26 
27  // move
29  const teca_binary_stream &operator=(teca_binary_stream &&other) noexcept;
30 
31  // evaluate to true when the stream is not empty.
32  operator bool()
33  { return m_size != 0; }
34 
35  // Release all resources, set to a uninitialized
36  // state.
37  void clear() noexcept;
38 
39  // Allocate n_bytes for the stream.
40  void resize(unsigned long n_bytes);
41 
42  // ensures space for n_bytes more to the stream.
43  void grow(unsigned long n_bytes);
44 
45  // Get a pointer to the stream internal representation.
46  unsigned char *get_data() noexcept
47  { return m_data; }
48 
49  const unsigned char *get_data() const noexcept
50  { return m_data; }
51 
52  // Get the size of the valid data in the stream.
53  // note: the internal buffer may be larger.
54  unsigned long size() const noexcept
55  { return m_write_p - m_data; }
56 
57  // Get the size of the internal buffer allocated
58  // for the stream.
59  unsigned long capacity() const noexcept
60  { return m_size; }
61 
62  // set the stream position to n bytes from the head
63  // of the stream
64  void set_read_pos(unsigned long n) noexcept
65  { m_read_p = m_data + n; }
66 
67  void set_write_pos(unsigned long n) noexcept
68  { m_write_p = m_data + n; }
69 
70  // swap the two objects
71  void swap(teca_binary_stream &other) noexcept;
72 
73  // Insert/Extract to/from the stream.
74  template <typename T> void pack(T *val);
75  template <typename T> void pack(const T &val);
76  template <typename T> void unpack(T &val);
77  template <typename T> void pack(const T *val, unsigned long n);
78  template <typename T> void unpack(T *val, unsigned long n);
79 
80  // specializations
81  void pack(const std::string *v, unsigned long n);
82  void unpack(std::string *v, unsigned long n);
83 
84  void pack(const std::string &str);
85  void unpack(std::string &str);
86 
87  void pack(const std::vector<std::string> &v);
88  void unpack(std::vector<std::string> &v);
89 
90  template<typename T> void pack(const std::vector<T> &v);
91  template<typename T> void unpack(std::vector<T> &v);
92 
93  template<typename KT, typename VT> void pack(const std::map<KT, VT> &v);
94  template<typename KT, typename VT> void unpack(std::map<KT, VT> &v);
95 
96  template<typename T1, typename T2> void pack(const std::pair<T1, T2> &v);
97  template<typename T1, typename T2> void unpack(std::pair<T1, T2> &v);
98 
99  // verify that the passed value is in the stream
100  // advance past the value. return 0 if the value is found
101  // for char * case null terminator is not read
102  template <typename T> int expect(const T &val);
103  template <typename T> int expect(const T *val, unsigned long n);
104  int expect(const char *str);
105 
106  // broadcast the stream from the root process to all other processes
107  int broadcast(MPI_Comm comm, int root_rank=0);
108 
109 private:
110  // re-allocation size
111  static
112  constexpr unsigned int get_block_size()
113  { return 512; }
114 
115 private:
116  unsigned long m_size;
117  unsigned char *m_data;
118  unsigned char *m_read_p;
119  unsigned char *m_write_p;
120 };
121 
122 //-----------------------------------------------------------------------------
123 template <typename T>
124 void teca_binary_stream::pack(T *val)
125 {
126  (void)val;
127  TECA_ERROR("Error: Packing a pointer.");
128 }
129 
130 //-----------------------------------------------------------------------------
131 template <typename T>
132 void teca_binary_stream::pack(const T &val)
133 {
134  this->grow(sizeof(T));
135  *((T *)m_write_p) = val;
136  m_write_p += sizeof(T);
137 }
138 
139 //-----------------------------------------------------------------------------
140 template <typename T>
141 void teca_binary_stream::unpack(T &val)
142 {
143  val = *((T *)m_read_p);
144  m_read_p += sizeof(T);
145 }
146 
147 //-----------------------------------------------------------------------------
148 template <typename T>
149 void teca_binary_stream::pack(const T *val, unsigned long n)
150 {
151  unsigned long n_bytes = n*sizeof(T);
152  this->grow(n_bytes);
153 
154  unsigned long nn = n*sizeof(T);
155  memcpy(m_write_p, val, nn);
156  m_write_p += nn;
157 }
158 
159 //-----------------------------------------------------------------------------
160 template <typename T>
161 void teca_binary_stream::unpack(T *val, unsigned long n)
162 {
163  unsigned long nn = n*sizeof(T);
164  memcpy(val, m_read_p, nn);
165  m_read_p += nn;
166 }
167 
168 //-----------------------------------------------------------------------------
169 inline
170 void teca_binary_stream::pack(const std::string *v, unsigned long n)
171 {
172  for (unsigned long i = 0; i < n; ++i)
173  this->pack(v[i]);
174 }
175 
176 //-----------------------------------------------------------------------------
177 inline
178 void teca_binary_stream::unpack(std::string *v, unsigned long n)
179 {
180  for (unsigned long i = 0; i < n; ++i)
181  this->unpack(v[i]);
182 }
183 
184 //-----------------------------------------------------------------------------
185 inline
186 void teca_binary_stream::pack(const std::string &str)
187 {
188  unsigned long slen = str.size();
189  this->pack(slen);
190  this->pack(str.c_str(), slen);
191 }
192 
193 //-----------------------------------------------------------------------------
194 inline
195 void teca_binary_stream::unpack(std::string &str)
196 {
197  unsigned long slen = 0;
198  this->unpack(slen);
199 
200  str.resize(slen);
201  str.assign(reinterpret_cast<char*>(m_read_p), slen);
202 
203  m_read_p += slen;
204 }
205 
206 //-----------------------------------------------------------------------------
207 inline
208 void teca_binary_stream::pack(const std::vector<std::string> &v)
209 {
210  unsigned long vlen = v.size();
211  this->pack(vlen);
212  for (unsigned long i = 0; i < vlen; ++i)
213  this->pack(v[i]);
214 }
215 
216 //-----------------------------------------------------------------------------
217 inline
218 void teca_binary_stream::unpack(std::vector<std::string> &v)
219 {
220  unsigned long vlen;
221  this->unpack(vlen);
222 
223  v.resize(vlen);
224  for (unsigned long i = 0; i < vlen; ++i)
225  this->unpack(v[i]);
226 }
227 
228 //-----------------------------------------------------------------------------
229 template<typename T>
230 void teca_binary_stream::pack(const std::vector<T> &v)
231 {
232  const unsigned long vlen = v.size();
233  this->pack(vlen);
234  this->pack(v.data(), vlen);
235 }
236 
237 //-----------------------------------------------------------------------------
238 template<typename T>
239 void teca_binary_stream::unpack(std::vector<T> &v)
240 {
241  unsigned long vlen;
242  this->unpack(vlen);
243 
244  v.resize(vlen);
245  this->unpack(v.data(), vlen);
246 }
247 
248 //-----------------------------------------------------------------------------
249 template<typename KT, typename VT>
250 void teca_binary_stream::pack(const std::map<KT, VT> &m)
251 {
252  unsigned long n_elem = m.size();
253  this->pack(n_elem);
254 
255  typename std::map<KT,VT>::const_iterator it = m.begin();
256 
257  for (unsigned long i = 0; i < n_elem; ++i)
258  {
259  this->pack(it->first);
260  this->pack(it->second);
261  }
262 }
263 
264 //-----------------------------------------------------------------------------
265 template<typename KT, typename VT>
266 void teca_binary_stream::unpack(std::map<KT, VT> &m)
267 {
268  unsigned long n_elem = 0;
269  this->unpack(n_elem);
270 
271  for (unsigned long i = 0; i < n_elem; ++i)
272  {
273  KT key;
274  VT val;
275 
276  this->unpack(key);
277  this->unpack(val);
278 
279  m.emplace(std::move(key), std::move(val));
280  }
281 }
282 
283 //-----------------------------------------------------------------------------
284 template<typename T1, typename T2>
285 void teca_binary_stream::pack(const std::pair<T1, T2> &p)
286 {
287  this->pack(p.first);
288  this->pack(p.second);
289 }
290 
291 //-----------------------------------------------------------------------------
292 template<typename T1, typename T2>
293 void teca_binary_stream::unpack(std::pair<T1, T2> &p)
294 {
295  this->unpack(p.first);
296  this->unpack(p.second);
297 }
298 
299 //-----------------------------------------------------------------------------
300 template<typename T>
301 int teca_binary_stream::expect(const T &val)
302 {
303  T tmp;
304  this->unpack(tmp);
305 
306  if (tmp == val)
307  return 0;
308 
309  return -1;
310 }
311 
312 //-----------------------------------------------------------------------------
313 template<typename T>
314 int teca_binary_stream::expect(const T *val, unsigned long n)
315 {
316  int same = 0;
317  T *tmp = (T*)malloc(n*sizeof(T));
318  this->unpack(tmp, n);
319  for (unsigned long i = 0; i < n; ++i)
320  {
321  if (tmp[i] != val[i])
322  {
323  same = -1;
324  break;
325  }
326  }
327  free(tmp);
328  return same;
329 }
330 
331 //-----------------------------------------------------------------------------
332 inline
333 int teca_binary_stream::expect(const char *str)
334 {
335  unsigned long n = strlen(str);
336  char *tmp = (char*)malloc(n);
337  this->unpack(tmp, n);
338  int same = strncmp(str, tmp, n);
339  free(tmp);
340  return same;
341 }
342 #endif
teca_binary_stream
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:16
teca_common.h
teca_error::TECA_EXPORT
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
TECA_ERROR
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:146