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 T, size_t N> void pack(const std::array<T,N> &v);
94  template<typename T, size_t N> void unpack(std::array<T,N> &v);
95 
96  template<typename KT, typename VT> void pack(const std::map<KT, VT> &v);
97  template<typename KT, typename VT> void unpack(std::map<KT, VT> &v);
98 
99  template<typename T1, typename T2> void pack(const std::pair<T1, T2> &v);
100  template<typename T1, typename T2> void unpack(std::pair<T1, T2> &v);
101 
102  // verify that the passed value is in the stream
103  // advance past the value. return 0 if the value is found
104  // for char * case null terminator is not read
105  template <typename T> int expect(const T &val);
106  template <typename T> int expect(const T *val, unsigned long n);
107  int expect(const char *str);
108 
109  // broadcast the stream from the root process to all other processes
110  int broadcast(MPI_Comm comm, int root_rank=0);
111 
112 private:
113  // re-allocation size
114  static
115  constexpr unsigned int get_block_size()
116  { return 512; }
117 
118 private:
119  unsigned long m_size;
120  unsigned char *m_data;
121  unsigned char *m_read_p;
122  unsigned char *m_write_p;
123 };
124 
125 //-----------------------------------------------------------------------------
126 template <typename T>
127 void teca_binary_stream::pack(T *val)
128 {
129  (void)val;
130  TECA_ERROR("Error: Packing a pointer.");
131 }
132 
133 //-----------------------------------------------------------------------------
134 template <typename T>
135 void teca_binary_stream::pack(const T &val)
136 {
137  this->grow(sizeof(T));
138  *((T *)m_write_p) = val;
139  m_write_p += sizeof(T);
140 }
141 
142 //-----------------------------------------------------------------------------
143 template <typename T>
144 void teca_binary_stream::unpack(T &val)
145 {
146  val = *((T *)m_read_p);
147  m_read_p += sizeof(T);
148 }
149 
150 //-----------------------------------------------------------------------------
151 template <typename T>
152 void teca_binary_stream::pack(const T *val, unsigned long n)
153 {
154  unsigned long n_bytes = n*sizeof(T);
155  this->grow(n_bytes);
156 
157  unsigned long nn = n*sizeof(T);
158  memcpy(m_write_p, val, nn);
159  m_write_p += nn;
160 }
161 
162 //-----------------------------------------------------------------------------
163 template <typename T>
164 void teca_binary_stream::unpack(T *val, unsigned long n)
165 {
166  unsigned long nn = n*sizeof(T);
167  memcpy(val, m_read_p, nn);
168  m_read_p += nn;
169 }
170 
171 //-----------------------------------------------------------------------------
172 inline
173 void teca_binary_stream::pack(const std::string *v, unsigned long n)
174 {
175  for (unsigned long i = 0; i < n; ++i)
176  this->pack(v[i]);
177 }
178 
179 //-----------------------------------------------------------------------------
180 inline
181 void teca_binary_stream::unpack(std::string *v, unsigned long n)
182 {
183  for (unsigned long i = 0; i < n; ++i)
184  this->unpack(v[i]);
185 }
186 
187 //-----------------------------------------------------------------------------
188 inline
189 void teca_binary_stream::pack(const std::string &str)
190 {
191  unsigned long slen = str.size();
192  this->pack(slen);
193  this->pack(str.c_str(), slen);
194 }
195 
196 //-----------------------------------------------------------------------------
197 inline
198 void teca_binary_stream::unpack(std::string &str)
199 {
200  unsigned long slen = 0;
201  this->unpack(slen);
202 
203  str.resize(slen);
204  str.assign(reinterpret_cast<char*>(m_read_p), slen);
205 
206  m_read_p += slen;
207 }
208 
209 //-----------------------------------------------------------------------------
210 inline
211 void teca_binary_stream::pack(const std::vector<std::string> &v)
212 {
213  unsigned long vlen = v.size();
214  this->pack(vlen);
215  for (unsigned long i = 0; i < vlen; ++i)
216  this->pack(v[i]);
217 }
218 
219 //-----------------------------------------------------------------------------
220 inline
221 void teca_binary_stream::unpack(std::vector<std::string> &v)
222 {
223  unsigned long vlen;
224  this->unpack(vlen);
225 
226  v.resize(vlen);
227  for (unsigned long i = 0; i < vlen; ++i)
228  this->unpack(v[i]);
229 }
230 
231 //-----------------------------------------------------------------------------
232 template<typename T>
233 void teca_binary_stream::pack(const std::vector<T> &v)
234 {
235  const unsigned long vlen = v.size();
236  this->pack(vlen);
237  this->pack(v.data(), vlen);
238 }
239 
240 //-----------------------------------------------------------------------------
241 template<typename T>
242 void teca_binary_stream::unpack(std::vector<T> &v)
243 {
244  unsigned long vlen;
245  this->unpack(vlen);
246 
247  v.resize(vlen);
248  this->unpack(v.data(), vlen);
249 }
250 
251 //-----------------------------------------------------------------------------
252 template<typename T, size_t N>
253 void teca_binary_stream::pack(const std::array<T,N> &v)
254 {
255  this->pack(N);
256  this->pack(v.data(), N);
257 }
258 
259 //-----------------------------------------------------------------------------
260 template<typename T, size_t N>
261 void teca_binary_stream::unpack(std::array<T,N> &v)
262 {
263  unsigned long vlen;
264  this->unpack(vlen);
265 
266  this->unpack(v.data(), N);
267 }
268 
269 //-----------------------------------------------------------------------------
270 template<typename KT, typename VT>
271 void teca_binary_stream::pack(const std::map<KT, VT> &m)
272 {
273  unsigned long n_elem = m.size();
274  this->pack(n_elem);
275 
276  typename std::map<KT,VT>::const_iterator it = m.begin();
277 
278  for (unsigned long i = 0; i < n_elem; ++i)
279  {
280  this->pack(it->first);
281  this->pack(it->second);
282  }
283 }
284 
285 //-----------------------------------------------------------------------------
286 template<typename KT, typename VT>
287 void teca_binary_stream::unpack(std::map<KT, VT> &m)
288 {
289  unsigned long n_elem = 0;
290  this->unpack(n_elem);
291 
292  for (unsigned long i = 0; i < n_elem; ++i)
293  {
294  KT key;
295  VT val;
296 
297  this->unpack(key);
298  this->unpack(val);
299 
300  m.emplace(std::move(key), std::move(val));
301  }
302 }
303 
304 //-----------------------------------------------------------------------------
305 template<typename T1, typename T2>
306 void teca_binary_stream::pack(const std::pair<T1, T2> &p)
307 {
308  this->pack(p.first);
309  this->pack(p.second);
310 }
311 
312 //-----------------------------------------------------------------------------
313 template<typename T1, typename T2>
314 void teca_binary_stream::unpack(std::pair<T1, T2> &p)
315 {
316  this->unpack(p.first);
317  this->unpack(p.second);
318 }
319 
320 //-----------------------------------------------------------------------------
321 template<typename T>
322 int teca_binary_stream::expect(const T &val)
323 {
324  T tmp;
325  this->unpack(tmp);
326 
327  if (tmp == val)
328  return 0;
329 
330  return -1;
331 }
332 
333 //-----------------------------------------------------------------------------
334 template<typename T>
335 int teca_binary_stream::expect(const T *val, unsigned long n)
336 {
337  int same = 0;
338  T *tmp = (T*)malloc(n*sizeof(T));
339  this->unpack(tmp, n);
340  for (unsigned long i = 0; i < n; ++i)
341  {
342  if (tmp[i] != val[i])
343  {
344  same = -1;
345  break;
346  }
347  }
348  free(tmp);
349  return same;
350 }
351 
352 //-----------------------------------------------------------------------------
353 inline
354 int teca_binary_stream::expect(const char *str)
355 {
356  unsigned long n = strlen(str);
357  char *tmp = (char*)malloc(n);
358  this->unpack(tmp, n);
359  int same = strncmp(str, tmp, n);
360  free(tmp);
361  return same;
362 }
363 #endif
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:17
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:161