LCOV - code coverage report
Current view: top level - pairinteraction - Serializable.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 62 248 25.0 %
Date: 2024-04-29 00:41:50 Functions: 11 22 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved.
       3             :  *
       4             :  * This file is part of the pairinteraction library.
       5             :  *
       6             :  * The pairinteraction library is free software: you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * The pairinteraction library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #ifndef SERIALIZABLE_H
      21             : #define SERIALIZABLE_H
      22             : 
      23             : #include <iterator>
      24             : #include <memory>
      25             : #include <typeindex>
      26             : #include <typeinfo>
      27             : #include <unordered_map>
      28             : #include <vector>
      29             : 
      30             : typedef uint8_t byte_t;
      31             : typedef uint16_t type_t;
      32             : typedef int32_t storage_idx_t;
      33             : typedef std::vector<byte_t> bytes_t;
      34             : 
      35             : class Serializable {
      36             : public:
      37         270 :     virtual ~Serializable() = default;
      38             :     virtual bytes_t &serialize() = 0;
      39             :     virtual void deserialize(bytes_t &bytes) = 0;
      40             : };
      41             : 
      42             : class Serializer {
      43             : public:
      44          27 :     Serializer() {
      45          27 :         type_ids[std::type_index(typeid(int8_t))] = 1008;
      46          27 :         type_ids[std::type_index(typeid(int16_t))] = 1016;
      47          27 :         type_ids[std::type_index(typeid(int32_t))] = 1032;
      48          27 :         type_ids[std::type_index(typeid(int64_t))] = 1064;
      49          27 :         type_ids[std::type_index(typeid(uint8_t))] = 1108;
      50          27 :         type_ids[std::type_index(typeid(uint16_t))] = 1116;
      51          27 :         type_ids[std::type_index(typeid(uint32_t))] = 1132;
      52          27 :         type_ids[std::type_index(typeid(uint64_t))] = 1164;
      53          27 :         type_ids[std::type_index(typeid(float))] = 2032;  // float32_t
      54          27 :         type_ids[std::type_index(typeid(double))] = 2064; // float64_t
      55          27 :         type_ids[std::type_index(typeid(char))] = 3000;
      56          27 :         type_ids[std::type_index(typeid(bool))] = 4000;
      57          27 :     }
      58             : 
      59           0 :     void load(const bytes_t &bytes) {
      60           0 :         cpbytes = bytes.begin();
      61           0 :         cpbytes_start = cpbytes;
      62           0 :         cpbytes_end = bytes.end();
      63           0 :     }
      64             : 
      65          27 :     void save(bytes_t &bytes) {
      66          27 :         size_t nItems = buffer_types.size();
      67             : 
      68             :         // clear and resize bytes
      69          27 :         bytes.clear();
      70          27 :         bytes.resize(size());
      71             : 
      72             :         // save items to bytes
      73          27 :         pbytes = bytes.begin();
      74             : 
      75         353 :         for (size_t i = 0; i < nItems; ++i) {
      76         326 :             if (buffer_isVector[i]) {
      77         164 :                 serialize(&type_ids[std::type_index(typeid(storage_idx_t))], sizeof(type_t));
      78         164 :                 serialize(&buffer_nums[i], sizeof(storage_idx_t));
      79             :             }
      80             : 
      81         326 :             serialize(&buffer_types[i], sizeof(type_t));
      82         326 :             serialize(buffer_pitems[i], buffer_nums[i] * buffer_sizes[i]);
      83             :         }
      84             : 
      85             :         // the buffers are not needed anymore
      86          27 :         buffer_isVector.clear();
      87          27 :         buffer_types.clear();
      88          27 :         buffer_pitems.clear();
      89          27 :         buffer_nums.clear();
      90          27 :         buffer_sizes.clear();
      91          27 :     }
      92             : 
      93             :     size_t position() {
      94             :         size_t sz = size();
      95             :         if (sz > 0) {
      96             :             return sz;
      97             :         }
      98             :         return std::distance(cpbytes_start, cpbytes);
      99             :     }
     100             : 
     101             :     template <class T>
     102         162 :     friend void operator<<(Serializer &s, const T &data) {
     103         162 :         s.buffer_isVector.push_back(false);
     104         162 :         s.buffer_types.push_back(s.type_ids[std::type_index(typeid(T))]);
     105         162 :         s.buffer_pitems.push_back(reinterpret_cast<const byte_t *>(&data));
     106         162 :         s.buffer_nums.push_back(1);
     107         162 :         s.buffer_sizes.push_back(sizeof(T));
     108         162 :     }
     109             : 
     110             :     template <class T>
     111         164 :     friend void operator<<(Serializer &s, const std::vector<T> &data) {
     112         164 :         s.buffer_isVector.push_back(true);
     113         164 :         s.buffer_types.push_back(s.type_ids[std::type_index(typeid(T))]);
     114         328 :         s.buffer_pitems.push_back(
     115         164 :             reinterpret_cast<const byte_t *>(!data.empty() ? &data[0] : nullptr));
     116         164 :         s.buffer_nums.push_back(data.size());
     117         164 :         s.buffer_sizes.push_back(sizeof(T));
     118         164 :     }
     119             : 
     120             :     template <class T>
     121           0 :     friend void operator>>(Serializer &s, T &data) {
     122           0 :         s.deserialize(data, 1);
     123           0 :     }
     124             : 
     125             :     template <class T>
     126           0 :     friend void operator>>(Serializer &s, std::vector<T> &data) {
     127             :         size_t szvector;
     128           0 :         s.deserialize(szvector, 1);
     129           0 :         s.deserialize(data, szvector);
     130           0 :     }
     131             : 
     132             : private:
     133          27 :     size_t size() {
     134          27 :         size_t nItems = buffer_types.size();
     135          27 :         size_t totalsize = 0;
     136             : 
     137         353 :         for (size_t i = 0; i < nItems; ++i) {
     138         326 :             if (buffer_isVector[i]) {
     139         164 :                 totalsize += sizeof(type_t);
     140         164 :                 totalsize += sizeof(storage_idx_t);
     141             :             }
     142         326 :             totalsize += sizeof(type_t);
     143         326 :             totalsize += buffer_nums[i] * buffer_sizes[i];
     144             :         }
     145             : 
     146          27 :         return totalsize;
     147             :     }
     148             : 
     149             :     template <class T>
     150         980 :     void serialize(const T *pdata, size_t sz) {
     151         980 :         auto data_reinterpreted = reinterpret_cast<const byte_t *>(pdata);
     152         980 :         std::copy(data_reinterpreted, data_reinterpreted + sz, pbytes);
     153         980 :         pbytes += sz;
     154         980 :     }
     155             : 
     156             :     template <class T>
     157           0 :     void deserialize(T &data, size_t num) {
     158           0 :         uint16_t type = 0;
     159             : 
     160           0 :         if (cpbytes + sizeof(uint16_t) > cpbytes_end) {
     161           0 :             throw std::runtime_error(
     162             :                 "Corrupted data discovered."); // TODO use checksum of "bytes" (write checksum into
     163             :                                                // the beginning of "bytes")
     164             :         }
     165           0 :         auto pbytes_reinterpreted = reinterpret_cast<const type_t *>(&(*cpbytes));
     166           0 :         std::copy(pbytes_reinterpreted, pbytes_reinterpreted + 1, &type);
     167           0 :         cpbytes += sizeof(uint16_t);
     168             : 
     169           0 :         if (type == type_ids[std::type_index(typeid(int8_t))]) {
     170           0 :             if (cpbytes + sizeof(int8_t) * num > cpbytes_end) {
     171           0 :                 throw std::runtime_error("Corrupted data discovered.");
     172             :             }
     173           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int8_t *>(&(*cpbytes));
     174           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     175           0 :             cpbytes += sizeof(int8_t) * num;
     176           0 :         } else if (type == type_ids[std::type_index(typeid(int16_t))]) {
     177           0 :             if (cpbytes + sizeof(int16_t) * num > cpbytes_end) {
     178           0 :                 throw std::runtime_error("Corrupted data discovered.");
     179             :             }
     180           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int16_t *>(&(*cpbytes));
     181           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     182           0 :             cpbytes += sizeof(int16_t) * num;
     183           0 :         } else if (type == type_ids[std::type_index(typeid(int32_t))]) {
     184           0 :             if (cpbytes + sizeof(int32_t) * num > cpbytes_end) {
     185           0 :                 throw std::runtime_error("Corrupted data discovered.");
     186             :             }
     187           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int32_t *>(&(*cpbytes));
     188           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     189           0 :             cpbytes += sizeof(int32_t) * num;
     190           0 :         } else if (type == type_ids[std::type_index(typeid(int64_t))]) {
     191           0 :             if (cpbytes + sizeof(int64_t) * num > cpbytes_end) {
     192           0 :                 throw std::runtime_error("Corrupted data discovered.");
     193             :             }
     194           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int64_t *>(&(*cpbytes));
     195           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     196           0 :             cpbytes += sizeof(int64_t) * num;
     197           0 :         } else if (type == type_ids[std::type_index(typeid(uint8_t))]) {
     198           0 :             if (cpbytes + sizeof(uint8_t) * num > cpbytes_end) {
     199           0 :                 throw std::runtime_error("Corrupted data discovered.");
     200             :             }
     201           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint8_t *>(&(*cpbytes));
     202           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     203           0 :             cpbytes += sizeof(uint8_t) * num;
     204           0 :         } else if (type == type_ids[std::type_index(typeid(uint16_t))]) {
     205           0 :             if (cpbytes + sizeof(uint16_t) * num > cpbytes_end) {
     206           0 :                 throw std::runtime_error("Corrupted data discovered.");
     207             :             }
     208           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint16_t *>(&(*cpbytes));
     209           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     210           0 :             cpbytes += sizeof(uint16_t) * num;
     211           0 :         } else if (type == type_ids[std::type_index(typeid(uint32_t))]) {
     212           0 :             if (cpbytes + sizeof(uint32_t) * num > cpbytes_end) {
     213           0 :                 throw std::runtime_error("Corrupted data discovered.");
     214             :             }
     215           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint32_t *>(&(*cpbytes));
     216           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     217           0 :             cpbytes += sizeof(uint32_t) * num;
     218           0 :         } else if (type == type_ids[std::type_index(typeid(uint64_t))]) {
     219           0 :             if (cpbytes + sizeof(uint64_t) * num > cpbytes_end) {
     220           0 :                 throw std::runtime_error("Corrupted data discovered.");
     221             :             }
     222           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint64_t *>(&(*cpbytes));
     223           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     224           0 :             cpbytes += sizeof(uint64_t) * num;
     225           0 :         } else if (type == type_ids[std::type_index(typeid(float))]) {
     226           0 :             if (cpbytes + sizeof(float) * num > cpbytes_end) {
     227           0 :                 throw std::runtime_error("Corrupted data discovered.");
     228             :             }
     229           0 :             auto pbytes_reinterpreted = reinterpret_cast<const float *>(&(*cpbytes));
     230           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     231           0 :             cpbytes += sizeof(float) * num;
     232           0 :         } else if (type == type_ids[std::type_index(typeid(double))]) {
     233           0 :             if (cpbytes + sizeof(double) * num > cpbytes_end) {
     234           0 :                 throw std::runtime_error("Corrupted data discovered.");
     235             :             }
     236           0 :             auto pbytes_reinterpreted = reinterpret_cast<const double *>(&(*cpbytes));
     237           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     238           0 :             cpbytes += sizeof(double) * num;
     239           0 :         } else if (type == type_ids[std::type_index(typeid(char))]) {
     240           0 :             if (cpbytes + sizeof(char) * num > cpbytes_end) {
     241           0 :                 throw std::runtime_error("Corrupted data discovered.");
     242             :             }
     243           0 :             auto pbytes_reinterpreted = reinterpret_cast<const char *>(&(*cpbytes));
     244           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     245           0 :             cpbytes += sizeof(char) * num;
     246           0 :         } else if (type == type_ids[std::type_index(typeid(bool))]) {
     247           0 :             if (cpbytes + sizeof(bool) * num > cpbytes_end) {
     248           0 :                 throw std::runtime_error("Corrupted data discovered.");
     249             :             }
     250           0 :             auto pbytes_reinterpreted = reinterpret_cast<const bool *>(&(*cpbytes));
     251           0 :             std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
     252           0 :             cpbytes += sizeof(bool) * num;
     253             :         } else {
     254           0 :             throw std::runtime_error("Corrupted data discovered.");
     255             :             // auto pbytes_reinterpreted = reinterpret_cast<const T*>(&(*cpbytes));
     256             :             // std::copy(pbytes_reinterpreted, pbytes_reinterpreted+num, &data);
     257             :             // cpbytes += sizeof(T)*num;
     258             :         }
     259           0 :     }
     260             : 
     261             :     template <class T>
     262           0 :     void deserialize(std::vector<T> &data, size_t num) {
     263           0 :         uint16_t type = 0;
     264             : 
     265           0 :         if (cpbytes + sizeof(uint16_t) > cpbytes_end) {
     266           0 :             throw std::runtime_error("Corrupted data discovered.");
     267             :         }
     268           0 :         auto pbytes_reinterpreted = reinterpret_cast<const type_t *>(&(*cpbytes));
     269           0 :         std::copy(pbytes_reinterpreted, pbytes_reinterpreted + 1, &type);
     270           0 :         cpbytes += sizeof(uint16_t);
     271             : 
     272           0 :         if (type == type_ids[std::type_index(typeid(int8_t))]) {
     273           0 :             if (cpbytes + sizeof(int8_t) * num > cpbytes_end) {
     274           0 :                 throw std::runtime_error("Corrupted data discovered.");
     275             :             }
     276           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int8_t *>(&(*cpbytes));
     277           0 :             std::vector<int8_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     278           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     279           0 :             cpbytes += sizeof(int8_t) * num;
     280           0 :         } else if (type == type_ids[std::type_index(typeid(int16_t))]) {
     281           0 :             if (cpbytes + sizeof(int16_t) * num > cpbytes_end) {
     282           0 :                 throw std::runtime_error("Corrupted data discovered.");
     283             :             }
     284           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int16_t *>(&(*cpbytes));
     285           0 :             std::vector<int16_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     286           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     287           0 :             cpbytes += sizeof(int16_t) * num;
     288           0 :         } else if (type == type_ids[std::type_index(typeid(int32_t))]) {
     289           0 :             if (cpbytes + sizeof(int32_t) * num > cpbytes_end) {
     290           0 :                 throw std::runtime_error("Corrupted data discovered.");
     291             :             }
     292           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int32_t *>(&(*cpbytes));
     293           0 :             std::vector<int32_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     294           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     295           0 :             cpbytes += sizeof(int32_t) * num;
     296           0 :         } else if (type == type_ids[std::type_index(typeid(int64_t))]) {
     297           0 :             if (cpbytes + sizeof(int64_t) * num > cpbytes_end) {
     298           0 :                 throw std::runtime_error("Corrupted data discovered.");
     299             :             }
     300           0 :             auto pbytes_reinterpreted = reinterpret_cast<const int64_t *>(&(*cpbytes));
     301           0 :             std::vector<int64_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     302           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     303           0 :             cpbytes += sizeof(int64_t) * num;
     304           0 :         } else if (type == type_ids[std::type_index(typeid(uint8_t))]) {
     305           0 :             if (cpbytes + sizeof(uint8_t) * num > cpbytes_end) {
     306           0 :                 throw std::runtime_error("Corrupted data discovered.");
     307             :             }
     308           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint8_t *>(&(*cpbytes));
     309           0 :             std::vector<uint8_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     310           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     311           0 :             cpbytes += sizeof(uint8_t) * num;
     312           0 :         } else if (type == type_ids[std::type_index(typeid(uint16_t))]) {
     313           0 :             if (cpbytes + sizeof(uint16_t) * num > cpbytes_end) {
     314           0 :                 throw std::runtime_error("Corrupted data discovered.");
     315             :             }
     316           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint16_t *>(&(*cpbytes));
     317           0 :             std::vector<uint16_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     318           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     319           0 :             cpbytes += sizeof(uint16_t) * num;
     320           0 :         } else if (type == type_ids[std::type_index(typeid(uint32_t))]) {
     321           0 :             if (cpbytes + sizeof(uint32_t) * num > cpbytes_end) {
     322           0 :                 throw std::runtime_error("Corrupted data discovered.");
     323             :             }
     324           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint32_t *>(&(*cpbytes));
     325           0 :             std::vector<uint32_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     326           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     327           0 :             cpbytes += sizeof(uint32_t) * num;
     328           0 :         } else if (type == type_ids[std::type_index(typeid(uint64_t))]) {
     329           0 :             if (cpbytes + sizeof(uint64_t) * num > cpbytes_end) {
     330           0 :                 throw std::runtime_error("Corrupted data discovered.");
     331             :             }
     332           0 :             auto pbytes_reinterpreted = reinterpret_cast<const uint64_t *>(&(*cpbytes));
     333           0 :             std::vector<uint64_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     334           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     335           0 :             cpbytes += sizeof(uint64_t) * num;
     336           0 :         } else if (type == type_ids[std::type_index(typeid(float))]) {
     337           0 :             if (cpbytes + sizeof(float) * num > cpbytes_end) {
     338           0 :                 throw std::runtime_error("Corrupted data discovered.");
     339             :             }
     340           0 :             auto pbytes_reinterpreted = reinterpret_cast<const float *>(&(*cpbytes));
     341           0 :             std::vector<float> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     342           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     343           0 :             cpbytes += sizeof(float) * num;
     344           0 :         } else if (type == type_ids[std::type_index(typeid(double))]) {
     345           0 :             if (cpbytes + sizeof(double) * num > cpbytes_end) {
     346           0 :                 throw std::runtime_error("Corrupted data discovered.");
     347             :             }
     348           0 :             auto pbytes_reinterpreted = reinterpret_cast<const double *>(&(*cpbytes));
     349           0 :             std::vector<double> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     350           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     351           0 :             cpbytes += sizeof(double) * num;
     352           0 :         } else if (type == type_ids[std::type_index(typeid(char))]) {
     353           0 :             if (cpbytes + sizeof(char) * num > cpbytes_end) {
     354           0 :                 throw std::runtime_error("Corrupted data discovered.");
     355             :             }
     356           0 :             auto pbytes_reinterpreted = reinterpret_cast<const char *>(&(*cpbytes));
     357           0 :             std::vector<char> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     358           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     359           0 :             cpbytes += sizeof(char) * num;
     360           0 :         } else if (type == type_ids[std::type_index(typeid(bool))]) {
     361           0 :             if (cpbytes + sizeof(bool) * num > cpbytes_end) {
     362           0 :                 throw std::runtime_error("Corrupted data discovered.");
     363             :             }
     364           0 :             auto pbytes_reinterpreted = reinterpret_cast<const bool *>(&(*cpbytes));
     365           0 :             std::vector<bool> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
     366           0 :             data.insert(data.end(), vectmp.begin(), vectmp.end());
     367           0 :             cpbytes += sizeof(bool) * num;
     368             :         } else {
     369           0 :             throw std::runtime_error("Corrupted data discovered.");
     370             :             // auto pbytes_reinterpreted = reinterpret_cast<const T*>(&(*cpbytes));
     371             :             // std::copy(pbytes_reinterpreted, pbytes_reinterpreted+num,back_inserter(data));
     372             :             // cpbytes += sizeof(T)*num;
     373             :         }
     374           0 :     }
     375             : 
     376             :     std::unordered_map<std::type_index, uint16_t> type_ids;
     377             :     bytes_t::iterator pbytes;
     378             :     bytes_t::const_iterator cpbytes;
     379             :     bytes_t::const_iterator cpbytes_start;
     380             :     bytes_t::const_iterator cpbytes_end;
     381             :     std::vector<bool> buffer_isVector;
     382             :     std::vector<uint16_t> buffer_types;
     383             :     std::vector<const byte_t *> buffer_pitems;
     384             :     std::vector<storage_idx_t> buffer_nums;
     385             :     std::vector<size_t> buffer_sizes;
     386             : };
     387             : 
     388             : #endif

Generated by: LCOV version 1.14