1/*!
2 * This file contains the implemetation of packer and unpacker for vector
3 * Created on: Jan 5, 2016
4 * Author: Yaroslav Zaluzhnyi and Pietro Incardona
5 */
6
7/*! This Function to indicate the vector class has a packer function
8 *
9 * \return true vector has a pack function
10 *
11 */
12static bool pack()
13{
14 return true;
15}
16
17/*! This Function indicate that vector class has a packRequest function
18 *
19 * \return true vector has a packRequest function
20 *
21 */
22static bool packRequest()
23{
24 return true;
25}
26
27/*! This Function indicate that vector class has a packMem function
28 *
29 * \return true vector has a packMem function
30 *
31 */
32static bool packMem()
33{
34 return true;
35}
36
37//! Structures that do a nested packing, depending on the existence of 'pack()' function inside the object
38//There is no pack() inside
39template<bool cond, typename T1, typename Memory1, int ... prp>
40struct pack_cond
41{
42 //! Trivial case it serialize the vector object as simply an array of objects
43 void packing(ExtPreAlloc<Memory1> & mem, openfpm::vector<T1> & obj, Pack_stat & sts)
44 {
45 Packer<openfpm::vector<T1>, Memory1, PACKER_ARRAY_PRIMITIVE>::pack(mem,obj,sts,obj.size());
46 }
47
48};
49
50//! Structures that do a nested packing, depending on the existence of 'pack()' function inside the object
51//There is pack() inside
52template<typename T1, typename Memory1, int ... prp>
53struct pack_cond<true, T1, Memory1, prp...>
54{
55 //! It traverse the type-tree structure to serialize the vector object into memory
56 void packing(ExtPreAlloc<Memory1> & mem, openfpm::vector<T1> & obj, Pack_stat & sts)
57 {
58 for (size_t i = 0; i < obj.size(); i++)
59 obj.get(i).template pack<prp...>(mem, sts);
60 }
61};
62
63//! Structures that calculate how many bytes are required to serialize an object
64// depending on the existence of 'packMem()' function inside of the object
65// There is no packMem() inside
66template<bool cond, typename T1>
67struct packMem_cond
68{
69 //! calculate how many bytes are needed to serialize the object
70 size_t packMemory(T1 & obj, size_t n, size_t e)
71 {
72 return grow_policy_double::grow(0,n) * sizeof(T);
73 }
74
75};
76
77//! Structures that calculate memory for an object, depending on the existence of 'packMem()'
78// function inside of the object
79// There is packMem() inside
80template<typename T1>
81struct packMem_cond<true, T1>
82{
83 //! calculate how many bytes are needed to serialize the object
84 size_t packMemory(T1 & obj, size_t n, size_t e)
85 {
86 size_t res = 0;
87 size_t count = grow_policy_double::grow(0,n) - obj.size();
88 for (size_t i = 0; i < n; i++) {
89 res += obj.get(i).packMem(n,0);
90 }
91 return res+count*sizeof(T);
92 }
93};
94
95
96//! These structures serialize a simple (no "pack()" inside) object
97// With specified properties
98template<bool sel, int ... prp>
99struct pack_simple_cond
100{
101 //! serialize the vector
102 template<typename Memory2> static inline void pack(const openfpm::vector<T,Memory,layout_base,grow_p,OPENFPM_NATIVE> & obj, ExtPreAlloc<Memory2> & mem, Pack_stat & sts)
103 {
104 //Pack the size of a vector
105 Packer<size_t, Memory2>::pack(mem,obj.size(),sts);
106
107 // Sending property object
108 typedef openfpm::vector<T,Memory,layout_base,grow_p> vctr;
109 typedef object<typename object_creator<typename vctr::value_type::type,prp...>::type> prp_object;
110
111 typedef openfpm::vector<prp_object,ExtPreAlloc<Memory2>, layout_base ,openfpm::grow_policy_identity> dtype;
112
113 // Create an object over the preallocated memory (No allocation is produced)
114 dtype dest;
115 dest.setMemory(mem);
116 dest.resize(obj.size());
117
118 auto obj_it = obj.getIterator();
119
120 while (obj_it.isNext())
121 {
122 // copy all the object in the send buffer
123 typedef encapc<1,typename vctr::value_type,typename vctr::layout_type > encap_src;
124 // destination object type
125 typedef encapc<1,prp_object,typename dtype::layout_type > encap_dst;
126
127 // Copy only the selected properties
128 object_si_d<encap_src,encap_dst,OBJ_ENCAP,prp...>(obj.get(obj_it.get()),dest.get(obj_it.get()));
129
130 ++obj_it;
131 }
132
133 // Update statistic
134 sts.incReq();
135 }
136};
137
138//! These structures serialize a simple (no "pack()" inside) object
139// Without specified properties
140template<int ... prp>
141struct pack_simple_cond<true, prp ...>
142{
143 //! serialize the vector
144 template<typename Memory2>
145 static inline void pack(const openfpm::vector<T,Memory,layout_base,grow_p,OPENFPM_NATIVE> & obj , ExtPreAlloc<Memory2> & mem, Pack_stat & sts)
146 {
147 //Pack the size of a vector
148 Packer<size_t, Memory2>::pack(mem,obj.size(),sts);
149
150 // Sending property object
151 typedef openfpm::vector<T,ExtPreAlloc<Memory2>,memory_traits_lin,openfpm::grow_policy_identity> dtype;
152
153 // Create an object over the preallocated memory (No allocation is produced)
154 dtype dest;
155 dest.setMemory(mem);
156 dest.resize(obj.size());
157
158 auto obj_it = obj.getIterator();
159
160 while (obj_it.isNext())
161 {
162 // Copy
163 dest.get(obj_it.get()) = obj.get(obj_it.get());
164
165 ++obj_it;
166 }
167
168 // Update statistic
169 sts.incReq();
170 }
171};
172
173//! These structures do an de-serialize a simple object (no pack() inside)
174// With specified properties
175template<bool sel, int ... prp>
176struct unpack_simple_cond
177{
178 //! De-serialize an object
179 template<typename Memory2>
180 static inline void unpack(openfpm::vector<T,Memory, layout_base,grow_p,OPENFPM_NATIVE> & obj , ExtPreAlloc<Memory2> & mem, Unpack_stat & ps)
181 {
182 //Unpack a size of a source vector
183 size_t u2 = 0;
184 Unpacker<size_t, Memory2>::unpack(mem,u2,ps);
185
186 //Resize a destination vector
187 obj.resize(u2);
188
189 size_t id = 0;
190
191 // Sending property object
192 typedef openfpm::vector<T> vctr;
193 typedef object<typename object_creator<typename vctr::value_type::type,prp...>::type> prp_object;
194 typedef openfpm::vector<prp_object,PtrMemory, memory_traits_lin,openfpm::grow_policy_identity> stype;
195
196
197 // Calculate the size to pack the object
198 size_t size = obj.packMem<prp...>(obj.size(),0);
199
200 // Create a Pointer object over the preallocated memory (No allocation is produced)
201 PtrMemory & ptr = *(new PtrMemory(mem.getPointerOffset(ps.getOffset()),size));
202
203 stype src;
204 src.setMemory(ptr);
205 src.resize(obj.size());
206 auto obj_it = obj.getIterator();
207
208 while (obj_it.isNext())
209 {
210 // copy all the object in the send buffer
211 typedef encapc<1,typename vctr::value_type,typename vctr::layout_type > encap_dst;
212 // destination object type
213 typedef encapc<1,prp_object,typename stype::layout_type > encap_src;
214
215 // Copy only the selected properties
216 object_s_di<encap_src,encap_dst,OBJ_ENCAP,prp...>(src.get(id),obj.get(obj_it.get()));
217
218 ++id;
219 ++obj_it;
220 }
221
222 ps.addOffset(size);
223 }
224};
225
226//! These structures de-serialize a simple object (no pack() inside)
227//! unpack Without specified properties
228template<int ... prp>
229struct unpack_simple_cond<true, prp ...>
230{
231 /*! \brief unpack from the memory the data structure and put it into obj
232 *
233 * \param obj object to deserialize
234 * \param mem object containing the raw data to deserialize
235 * \param ps statistic
236 *
237 */
238 template<typename Memory2>
239 static inline void unpack(openfpm::vector<T,Memory,layout_base, grow_p,OPENFPM_NATIVE> & obj , ExtPreAlloc<Memory2> & mem, Unpack_stat & ps)
240 {
241 //Unpack a size of a source vector
242 size_t u2 = 0;
243 Unpacker<size_t, Memory2>::unpack(mem,u2,ps);
244
245 //Resize a destination vector
246 obj.resize(u2);
247
248 size_t id = 0;
249
250 // Sending property object
251 typedef openfpm::vector<T,PtrMemory,memory_traits_lin,openfpm::grow_policy_identity> stype;
252
253 // Calculate the size to pack the object
254 size_t size = obj.packMem<prp...>(obj.size(),0);
255
256 // Create a Pointer object over the preallocated memory (No allocation is produced)
257 PtrMemory & ptr = *(new PtrMemory(mem.getPointerOffset(ps.getOffset()),size));
258
259 stype src;
260 src.setMemory(ptr);
261 src.resize(obj.size());
262 auto obj_it = obj.getIterator();
263
264 while (obj_it.isNext())
265 {
266 // Copy
267 obj.get(obj_it.get()) = src.get(id);
268
269 ++id;
270 ++obj_it;
271 }
272
273 ps.addOffset(size);
274 }
275};
276
277
278/*! \brief It calculate the number of byte required to serialize the object
279 *
280 * \tparam prp list of properties
281 *
282 * \param req reference to the total counter required to pack the information
283 *
284 */
285template<int ... prp> inline void packRequest(size_t & req) const
286{
287 //Pushback a sizeof number of elements of the internal vectors
288 req += sizeof(this->size());
289
290 // If all of the aggregate properties do not have a "pack()" member
291 if (has_pack_agg<T,prp...>::result::value == false)
292 {
293 size_t alloc_ele = this->packMem<prp...>(this->size(),0);
294 req += alloc_ele;
295 }
296 //If at least one property has "pack()"
297 else
298 {
299 for (size_t i = 0 ; i < this->size() ; i++)
300 {
301 //Call a pack request
302 call_aggregatePackRequest<decltype(this->get(i)),Memory,prp ... >::call_packRequest(this->get(i),req);
303 }
304 }
305}
306
307
308/*! \brief pack a vector selecting the properties to pack
309 *
310 * \param mem preallocated memory where to pack the vector
311 * \param sts pack-stat info
312 *
313 */
314template<int ... prp> inline void pack(ExtPreAlloc<HeapMemory> & mem, Pack_stat & sts) const
315{
316 //If all of the aggregate properties are simple (don't have "pack()" member)
317 if (has_pack_agg<T,prp...>::result::value == false)
318 //if (has_aggregatePack<T,prp ... >::has_pack() == false)
319 {
320 //Call a packer
321 pack_simple_cond<sizeof...(prp) == 0,prp...>::template pack(*this,mem,sts);
322 }
323 //If at least one property has a "pack()" member
324 else
325 {
326 //Pack the size of a vector
327 Packer<size_t, HeapMemory>::pack(mem,this->size(),sts);
328
329 for (size_t i = 0 ; i < this->size() ; i++)
330 {
331 //Call a packer in nested way
332 call_aggregatePack<decltype(this->get(i)),HeapMemory,prp ... >::call_pack(this->get(i),mem,sts);
333 }
334 }
335}
336
337/*! \brief unpack a vector
338 *
339 * \param mem preallocated memory from where to unpack the vector
340 * \param ps unpack-stat info
341 */
342template<int ... prp> inline void unpack(ExtPreAlloc<HeapMemory> & mem, Unpack_stat & ps)
343{
344 //if all of the aggregate properties are simple (don't have "pack()" member)
345 if (has_pack_agg<T,prp...>::result::value == false)
346 //if (has_aggregatePack<T,prp ... >::has_pack() == false)
347 {
348 //Call an unpacker
349 unpack_simple_cond<sizeof...(prp) == 0,prp...>::unpack(*this,mem,ps);
350 }
351 //If at least one is not simple (has a "pack()" member)
352 else
353 {
354 //Unpack a size of a source vector
355 size_t u2 = 0;
356 Unpacker<size_t, HeapMemory>::unpack(mem,u2,ps);
357
358 //Resize a destination vector
359 this->resize(u2);
360
361 for (size_t i = 0 ; i < this->size() ; i++)
362 {
363 //Call an unpacker in nested way
364 call_aggregateUnpack<decltype(this->get(i)),HeapMemory,prp ... >::call_unpack(this->get(i),mem,ps);
365 }
366 }
367}
368
369