aboutsummaryrefslogtreecommitdiff
path: root/Source/Utils/MsgLogger/MsgLoggerSerialization.H
blob: ed642a1487ff993e13c88ddbd11efa0db472c4e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* Copyright 2021 Luca Fedeli
 *
 * This file is part of WarpX.
 *
 * License: BSD-3-Clause-LBNL
 */

#ifndef WARPX_MSG_LOGGER_SERIALIZATION_H_
#define WARPX_MSG_LOGGER_SERIALIZATION_H_

#include <algorithm>
#include <array>
#include <cstring>
#include <string>
#include <type_traits>
#include <vector>

namespace Utils{
namespace MsgLogger{

    /**
    * This function transforms a variable of type T into a vector of chars holding its
    * byte representation and it appends this vector at the end of an
    * existing vector of chars. T must be either a trivially copyable type or an std::string
    *
    * @tparam T the variable type
    * @param[in] val a variable of type T to be serialized
    * @param[in, out] vec a reference to the vector to which the byte representation of val is appended
    */
    template <typename T>
    void put_in(const T& val, std::vector<char>& vec)
    {
        if constexpr (std::is_same<T, std::string>()){
            const char* c_str = val.c_str();
            const auto length = static_cast<int>(val.size());

            put_in(length, vec);
            vec.insert(vec.end(), c_str, c_str+length);
        }
        else{
            static_assert(std::is_trivially_copyable<T>(),
                "Cannot serialize non-trivally copyable types, except std::string.");

            const auto* ptr_val = reinterpret_cast<const char*>(&val);
            vec.insert(vec.end(), ptr_val, ptr_val+sizeof(T));
        }
    }

    /**
    * This function transforms an std::vector<T> into a vector of chars holding its
    * byte representation and it appends this vector at the end of an
    * existing vector of chars. T must be either a trivially copyable type or an std::string.
    * A specialization exists in case val is a vector of chars.
    *
    * @tparam T the variable type
    * @param[in] val a variable of type T to be serialized
    * @param[in, out] vec a reference to the vector to which the byte representation of val is appended
    */
    template <typename T>
    inline void put_in_vec (const std::vector<T>& val, std::vector<char>& vec)
    {
        if constexpr (std::is_same<T,char>()){
            put_in(static_cast<int>(val.size()), vec);
            vec.insert(vec.end(), val.begin(), val.end());
        }
        else{
            static_assert(std::is_trivially_copyable<T>() || std::is_same<T,std::string>(),
                "Cannot serialize vectors of non-trivally copyable types"
                ", except vectors of std::string.");

            put_in(static_cast<int>(val.size()), vec);
            for (const auto& el : val)
                put_in(el, vec);
        }
    }

    /**
    * This function extracts a variable of type T from a byte vector, at the position
    * given by a std::vector<char> iterator. The iterator is then advanced according to
    * the number of bytes read from the byte vector. T must be either a trivially copyable type
    * or an std::string.
    *
    * @tparam T the variable type (must be trivially copyable)
    * @param[in, out] it the iterator to a byte vector
    * @return the variable extracted from the byte array
    */
    template<typename T>
    T get_out(std::vector<char>::const_iterator& it)
    {
        if constexpr (std::is_same<T,std::string>()){
            const auto length = get_out<int> (it);
            const auto str = std::string{it, it+length};
            it += length;

            return str;
        }
        else{
            static_assert(std::is_trivially_copyable<T>(),
                "Cannot extract non-trivally copyable types from char vectors,"
                " with the exception of std::string.");

            auto temp = std::array<char, sizeof(T)>{};
            std::copy(it, it + sizeof(T), temp.begin());
            it += sizeof(T);
            T res;
            std::memcpy(&res, temp.data(), sizeof(T));

        return res;
        }
    }

    /**
    * This function extracts an std::vector<T> from a byte vector, at the position
    * given by a std::vector<char> iterator. The iterator is then advanced according to
    * the number of bytes read from the byte vector. T must be either a trivially copyable type
    * or an std::string.
    *
    * @tparam T the variable type (must be trivially copyable)
    * @param[in, out] it the iterator to a byte vector
    * @return the variable extracted from the byte array
    */
    template<typename T>
    inline std::vector<T> get_out_vec (std::vector<char>::const_iterator& it)
    {
        if constexpr (std::is_same<T,std::string>()){
            const auto length = get_out<int> (it);
            std::vector<char> res(length);
            std::copy(it, it+length, res.begin());
            it += length;

            return res;
        }
        else
        {
            static_assert(std::is_trivially_copyable<T>() || std::is_same<T,std::string>(),
                "Cannot extract non-trivally copyable types from char vectors,"
                " with the exception of std::string.");

            const auto length = get_out<int> (it);
            std::vector<T> res(length);
            for (int i = 0; i < length; ++i)
                res[i] = get_out<T>(it);

            return res;
        }
    }
}
}

#endif //WARPX_MSG_LOGGER_SERIALIZATION_H_