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