KeyValueContainer.hpp 7.49 KB
Newer Older
Matthieu Dorier's avatar
Matthieu Dorier committed
1 2 3 4 5
/*
 * (C) 2018 The University of Chicago
 * 
 * See COPYRIGHT in top-level directory.
 */
Matthieu Dorier's avatar
Matthieu Dorier committed
6 7 8 9 10
#ifndef __HEPNOS_KEYVAL_CONTAINER_H
#define __HEPNOS_KEYVAL_CONTAINER_H

#include <memory>
#include <string>
11
#include <sstream>
Matthieu Dorier's avatar
Matthieu Dorier committed
12 13 14
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/string.hpp>
15 16
#include <hepnos/InputArchive.hpp>
#include <hepnos/ProductID.hpp>
Matthieu Dorier's avatar
Matthieu Dorier committed
17 18 19 20 21
#include <hepnos/Demangle.hpp>
#include <hepnos/Exception.hpp>

namespace hepnos {

22 23
class WriteBatch;

Matthieu Dorier's avatar
Matthieu Dorier committed
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
class KeyValueContainer {

    public:

    /**
     * @brief Default constructor.
     */
    KeyValueContainer() = default;

    /**
     * @brief Copy constructor.
     */
    KeyValueContainer(const KeyValueContainer& other) = default;

    /**
     * @brief Move constructor.
     */
    KeyValueContainer(KeyValueContainer&& other) = default;

    /**
     * @brief Copy-assignment operator.
     */
    KeyValueContainer& operator=(const KeyValueContainer& other) = default;

    /**
     * @brief Move-assignment operator.
     */
    KeyValueContainer& operator=(KeyValueContainer&& other) = default;

    /**
     * @brief Destructor.
     */
    virtual ~KeyValueContainer() = default;

58 59 60 61 62 63 64
    /**
     * @brief Gets the DataStore to which this instance of KeyValueContainer belongs.
     *
     * @return DataStore.
     */
    virtual DataStore* getDataStore() const = 0;

Matthieu Dorier's avatar
Matthieu Dorier committed
65 66 67 68 69
    /**
     * @brief Stores raw key/value data in this KeyValueContainer.
     * This function is virtual and must be overloaded in the child class.
     *
     * @param key Key
70 71
     * @param value Value pointer
     * @param vsize Value size (in bytes)
Matthieu Dorier's avatar
Matthieu Dorier committed
72
     *
73
     * @return A valid ProductID if the key did not already exist, an invalid one otherwise.
Matthieu Dorier's avatar
Matthieu Dorier committed
74
     */
75
    virtual ProductID storeRawData(const std::string& key, const char* value, size_t vsize) = 0;
76

77 78 79 80 81 82 83 84 85 86 87 88
    /**
     * @brief Stores raw key/value data in a WriteBatch.
     * This function is virtual and must be overloaded in the child class.
     *
     * @param batch Batch in which to write.
     * @param key Key
     * @param value Value pointer
     * @param vsize Value size (in bytes)
     *
     * @return 
     */
    virtual ProductID storeRawData(WriteBatch& batch, const std::string& key, const char* value, size_t vsize) = 0;
Matthieu Dorier's avatar
Matthieu Dorier committed
89 90 91 92 93 94 95 96 97 98

    /**
     * @brief Loads raw key/value data from this KeyValueContainer.
     * This function is virtual and must be overloaded in the child class.
     *
     * @param key Key
     * @param buffer Buffer used to hold the value.
     *
     * @return true if the key exists, false otherwise.
     */
99
    virtual bool loadRawData(const std::string& key, std::string& buffer) const = 0;
Matthieu Dorier's avatar
Matthieu Dorier committed
100

101 102
    virtual bool loadRawData(const std::string& key, char* value, size_t* vsize) const = 0;

Matthieu Dorier's avatar
Matthieu Dorier committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    /**
     * @brief Stores a key/value pair into the KeyValueContainer.
     * The type of the key should have operator<< available
     * to stream it into a std::stringstream for the purpose
     * of converting it into an std::string. The resulting
     * string must not have the "/", or "%" characters. The
     * type of the value must be serializable using Boost.
     *
     * @tparam K type of the key.
     * @tparam V type of the value.
     * @param key Key to store.
     * @param value Value to store.
     *
     * @return true if the key was found. false otherwise.
     */
    template<typename K, typename V>
119
    ProductID store(const K& key, const V& value) {
120
        return storeImpl(key, value, std::is_pod<V>());
121 122 123 124
    }

    template<typename K, typename V>
    ProductID store(WriteBatch& batch, const K& key, const V& value) {
125
        return storeImpl(batch, key, value, std::is_pod<V>());
Matthieu Dorier's avatar
Matthieu Dorier committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    }

    /**
     * @brief Loads a value associated with a key from the 
     * KeyValueContainer. The type of the key should have 
     * operator<< available to stream it into a std::stringstream 
     * for the purpose of converting it into an std::string. 
     * The resulting string must not have the "/" or "%" characters.
     * The type of the value must be serializable using Boost.
     *
     * @tparam K type of the key.
     * @tparam V type of the value.
     * @param key Key to load.
     * @param value Value to load.
     *
     * @return true if the key exists and was loaded. False otherwise.
     */
    template<typename K, typename V>
    bool load(const K& key, V& value) const {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
        return loadImpl(key, value, std::is_pod<V>());
    }

    private:

    template<typename K, typename V>
    ProductID storeImpl(const K& key, const V& value,
            const std::integral_constant<bool, false>&) {
        std::string key_str, val_str;
        serializeKeyValue(key, value, key_str, val_str);
        return storeRawData(key_str, val_str.data(), val_str.size());
    }

    template<typename K, typename V>
    ProductID storeImpl(WriteBatch& batch, const K& key, const V& value,
            const std::integral_constant<bool, false>&) {
        std::string key_str, val_str;
        serializeKeyValue(key, value, key_str, val_str);
        return storeRawData(batch, key_str, val_str.data(), val_str.size());
    }

    template<typename K, typename V>
    ProductID storeImpl(const K& key, const V& value,
            const std::integral_constant<bool, true>&) {
        std::string key_str;
        serializeKeyValue(key, value, key_str);
        return storeRawData(key_str, reinterpret_cast<const char*>(&value), sizeof(value));
    }

    template<typename K, typename V>
    ProductID storeImpl(WriteBatch& batch, const K& key, const V& value,
            const std::integral_constant<bool, true>&) {
        std::string key_str;
        serializeKeyValue(key, value, key_str);
        return storeRawData(batch, key_str, reinterpret_cast<const char*>(&value), sizeof(value));
    }

    template<typename K, typename V>
    bool loadImpl(const K& key, V& value,
            const std::integral_constant<bool, true>&) const {
        std::string buffer;
        std::stringstream ss_key;
        ss_key << key << "#" << demangle<V>();
        size_t vsize = sizeof(value);
        if(!loadRawData(ss_key.str(), reinterpret_cast<char*>(&value), &vsize)) {
            return false;
        }
        return vsize == sizeof(value);
    }

    template<typename K, typename V>
    bool loadImpl(const K& key, V& value,
            const std::integral_constant<bool, false>&) const {
198
        std::string buffer;
Matthieu Dorier's avatar
Matthieu Dorier committed
199 200 201 202 203 204
        std::stringstream ss_key;
        ss_key << key << "#" << demangle<V>();
        if(!loadRawData(ss_key.str(), buffer)) {
            return false;
        }
        try {
205
            std::stringstream ss(buffer);
206
            InputArchive ia(getDataStore(), ss);
Matthieu Dorier's avatar
Matthieu Dorier committed
207 208 209 210 211 212
            ia >> value;
        } catch(...) {
            throw Exception("Exception occured during serialization");
        }
        return true;
    }
213 214 215 216

    template<typename K, typename V>
    static void serializeKeyValue(const K& key, const V& value,
            std::string& key_str, std::string& value_str) {
217
        serializeKeyValue(key, value, key_str);
218
        std::stringstream ss_value;
219
        boost::archive::binary_oarchive oa(ss_value, boost::archive::archive_flags::no_header);
220 221 222 223 224 225 226
        try {
            oa << value;
        } catch(...) {
            throw Exception("Exception occured during serialization");
        }
        value_str = ss_value.str();
    }
227 228 229 230 231 232 233

    template<typename K, typename V>
    static void serializeKeyValue(const K& key, const V& value, std::string& key_str) {
        std::stringstream ss_key;
        ss_key << key << "#" << demangle<V>();
        key_str = std::move(ss_key.str());
    }
Matthieu Dorier's avatar
Matthieu Dorier committed
234 235 236 237 238
};

}

#endif