serialize.hpp 4.93 KB
Newer Older
Matthieu Dorier's avatar
Matthieu Dorier committed
1 2 3 4 5
/*
 * (C) 2017 The University of Chicago
 * 
 * See COPYRIGHT in top-level directory.
 */
6 7 8
#ifndef SERIALIZE_H
#define SERIALIZE_H

Matthieu Dorier's avatar
Matthieu Dorier committed
9 10 11 12
#include <thallium/config.hpp>

#ifndef THALLIUM_USE_CEREAL

13
#include <utility>
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
#include <type_traits>

namespace thallium {

template<typename... T>
using void_t = void;

/**
 * Type trait for input archives.
 */
struct input_archive {};
/**
 * Type trait for output archives.
 */
struct output_archive {};

/**
 * Check at compile-time if the type T is an input archive
 * (the type T has the type trait input_archive).
 */
template<typename T>
struct is_input_archive : public std::is_base_of<input_archive,T> {};

/**
 * Check at compile-time if the type T is an output archive
 * (the type T has the type trait output_archive).
 */
template<typename T>
struct is_output_archive : public std::is_base_of<output_archive,T> {};

/**
 * Compile-time check for a serialize member method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T, typename = void_t<>>
struct has_serialize_method {
50
    constexpr static bool value = false;
51 52 53 54 55 56 57 58
};

/**
 * Compile-time check for a serialize member method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T>
struct has_serialize_method<A, T, 
59 60
    void_t<decltype(std::declval<T&>().serialize(std::declval<A&>()))>> {
        constexpr static bool value = true;
61
};
62

63 64 65 66 67 68
/**
 * Compile-time check for a load method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T, typename = void_t<>>
struct has_load_method {
69
    constexpr static bool value = false;
70 71 72 73 74 75 76 77
};

/**
 * Compile-time check for a load method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T>
struct has_load_method<A, T, 
78 79
    void_t<decltype(std::declval<T&>().load(std::declval<A&>()))>> {
        constexpr static bool value = true;
80 81 82 83 84 85 86 87
};

/**
 * Compile-time check for a save method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T, typename = void_t<>>
struct has_save_method {
88
    constexpr static bool value = false;
89 90 91 92 93 94 95 96
};

/**
 * Compile-time check for a save method in a type T, and
 * appropriate for an archive of type A.
 */
template <typename A, typename T>
struct has_save_method<A, T, 
97 98
    void_t<decltype(std::declval<T&>().save(std::declval<A&>()))>> {
        constexpr static bool value = true;
99 100 101 102 103 104 105 106 107 108 109
};

/**
 * Serializer structure, will provide an apply method that
 * depends on the presence of a serialize function in the provided type.
 */
template<class A, typename T, bool has_serialize>
struct serializer;

template<class A, typename T>
struct serializer<A,T,true> {
110
    static inline void apply(A& ar, T&& t) {
111 112
        t.serialize(ar);
    }
113 114 115 116
};

template<class A, typename T>
struct serializer<A,T,false> {
117
    static inline void apply(A& ar, T&& t) {
118 119 120
        static_assert(has_serialize_method<A,T>::value, 
                "Undefined \"serialize\" member function");
    }
121 122 123 124 125 126
};

/**
 * Generic serialize method calling apply on a serializer.
 */
template<class A, typename T>
127
inline void serialize(A& ar, T& t) {
128
    serializer<A,T,has_serialize_method<A,T>::value>::apply(ar,std::forward<T>(t));
129 130 131 132 133 134 135 136 137 138 139
}

/**
 * Saver structure, will provide an apply method that depends
 * on the presence of a save function in the provided type.
 */
template<class A, typename T, bool has_save>
struct saver;

template<class A, typename T> 
struct saver<A,T,true> {
140
    static inline void apply(A& ar, T& t) {
141 142
        t.save(ar);
    }
143 144 145 146
};

template<class A, typename T>
struct saver<A,T,false> {
147
    static inline void apply(A& ar, T& t) {
148 149
        serialize(ar,t);
    }
150 151 152 153 154 155
};

/**
 * Generic save method calling apply on a saver.
 */
template<class A, typename T>
156
inline void save(A& ar, T& t) {
157
    saver<A,T,has_save_method<A,T>::value>::apply(ar,t);
158 159
}

160
template<class A, typename T>
161
inline void save(A& ar, const T& t) {
162 163 164
    save(ar, const_cast<T&>(t));
}

165 166 167 168 169 170 171 172 173
/**
 * Loader structure, will provide an apply method that depends
 * on the presence of a load function in the provided type.
 */
template<class A, typename T, bool has_load>
struct loader;

template<class A, typename T>
struct loader<A,T,true> {
174
    static inline void apply(A& ar, T& t) {
175 176
        t.load(ar);
    }
177 178 179 180
};

template<class A, typename T>
struct loader<A,T,false> {
181
    static inline void apply(A& ar, T& t) {
182 183
        serialize(ar,t);
    }
184 185 186 187 188 189
};

/**
 * Generic load method calling allpy on a loader.
 */
template<class A, typename T>
190
inline void load(A& ar, T& t) {
191
    loader<A,T,has_load_method<A,T>::value>::apply(ar,t);
192 193 194 195 196 197 198
}

/**
 * Helper function that serializes an arbitrary number of
 * objects passed as arguments.
 */
template<class A, typename T1, typename... Tn>
199
inline void serialize_many(A& ar, T1&& t1, Tn&&... rest) {
200 201
    ar & std::forward<T1>(t1);
    serialize_many(ar, std::forward<Tn>(rest)...);
202 203 204
}

template<class A, typename T>
205
inline void serialize_many(A& ar, T&& t) {
206
    ar & std::forward<T>(t);
207 208 209 210 211
}

}

#endif
Matthieu Dorier's avatar
Matthieu Dorier committed
212
#endif