KeyValueContainer.hpp 5.29 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 70 71
    /**
     * @brief Stores raw key/value data in this KeyValueContainer.
     * This function is virtual and must be overloaded in the child class.
     *
     * @param key Key
     * @param buffer Value
     *
72
     * @return A valid ProductID if the key did not already exist, an invalid one otherwise.
Matthieu Dorier's avatar
Matthieu Dorier committed
73
     */
74 75 76 77 78 79 80
    virtual ProductID storeRawData(const std::string& key, const std::string& value) = 0;

    virtual ProductID storeRawData(std::string&& key, std::string&& value) = 0;

    virtual ProductID storeRawData(WriteBatch& batch, const std::string& key, const std::string& value) = 0;

    virtual ProductID storeRawData(WriteBatch& batch, std::string&& key, std::string&& value) = 0;
Matthieu Dorier's avatar
Matthieu Dorier committed
81 82 83 84 85 86 87 88 89 90

    /**
     * @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.
     */
91
    virtual bool loadRawData(const std::string& key, std::string& buffer) const = 0;
Matthieu Dorier's avatar
Matthieu Dorier committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

    /**
     * @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>
109
    ProductID store(const K& key, const V& value) {
110 111 112 113 114 115 116 117 118 119
        std::string key_str, val_str;
        serializeKeyValue(key, value, key_str, val_str);
        return storeRawData(std::move(key_str), std::move(val_str));
    }

    template<typename K, typename V>
    ProductID store(WriteBatch& batch, const K& key, const V& value) {
        std::string key_str, val_str;
        serializeKeyValue(key, value, key_str, val_str);
        return storeRawData(batch, std::move(key_str), std::move(val_str));
Matthieu Dorier's avatar
Matthieu Dorier committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    }

    /**
     * @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 {
139
        std::string buffer;
Matthieu Dorier's avatar
Matthieu Dorier committed
140 141 142 143 144 145
        std::stringstream ss_key;
        ss_key << key << "#" << demangle<V>();
        if(!loadRawData(ss_key.str(), buffer)) {
            return false;
        }
        try {
146
            std::stringstream ss(buffer);
147
            InputArchive ia(getDataStore(), ss);
Matthieu Dorier's avatar
Matthieu Dorier committed
148 149 150 151 152 153
            ia >> value;
        } catch(...) {
            throw Exception("Exception occured during serialization");
        }
        return true;
    }
154 155 156 157 158 159 160 161 162 163

    private:

    template<typename K, typename V>
    static void serializeKeyValue(const K& key, const V& value,
            std::string& key_str, std::string& value_str) {
        std::stringstream ss_value;
        std::stringstream ss_key;
        ss_key << key << "#" << demangle<V>();
        key_str = std::move(ss_key.str());
164
        boost::archive::binary_oarchive oa(ss_value, boost::archive::archive_flags::no_header);
165 166 167 168 169 170 171
        try {
            oa << value;
        } catch(...) {
            throw Exception("Exception occured during serialization");
        }
        value_str = ss_value.str();
    }
Matthieu Dorier's avatar
Matthieu Dorier committed
172 173 174 175 176
};

}

#endif