| 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 | */ |
| 12 | static 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 | */ |
| 22 | static 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 | */ |
| 32 | static 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 |
| 39 | template<bool cond, typename T1, typename Memory1, int ... prp> |
| 40 | struct 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 |
| 52 | template<typename T1, typename Memory1, int ... prp> |
| 53 | struct 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 |
| 66 | template<bool cond, typename T1> |
| 67 | struct 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 |
| 80 | template<typename T1> |
| 81 | struct 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 |
| 98 | template<bool sel, int ... prp> |
| 99 | struct 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 |
| 140 | template<int ... prp> |
| 141 | struct 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 |
| 175 | template<bool sel, int ... prp> |
| 176 | struct 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 |
| 228 | template<int ... prp> |
| 229 | struct 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 | */ |
| 285 | template<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 | */ |
| 314 | template<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 | */ |
| 342 | template<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 | |