Commit 301fd5cf authored by Matthieu Dorier's avatar Matthieu Dorier

implemented Ptr functionality

parent c9dec8f5
......@@ -103,6 +103,11 @@ class DataSet : public KeyValueContainer {
*/
~DataSet();
/**
* @brief Overrides getDataStore from KeyValueContainer class.
*/
DataStore* getDataStore() const override;
/**
* @brief Name of the DataSet.
*
......@@ -153,10 +158,10 @@ class DataSet : public KeyValueContainer {
* @param key Key.
* @param buffer Binary data to insert.
*
* @return true if the key did not already exist and the write succeeded,
* false otherwise.
* @return a valid ProductID if the key did not already exist and the write succeeded,
* an invalid one otherwise.
*/
bool storeRawData(const std::string& key, const std::vector<char>& buffer);
ProductID storeRawData(const std::string& key, const std::vector<char>& buffer) override;
/**
* @brief Loads binary data associated with a particular key from the DataSet.
......@@ -169,7 +174,7 @@ class DataSet : public KeyValueContainer {
* @return true if the key exists and the read succeeded,
* false otherwise.
*/
bool loadRawData(const std::string& key, std::vector<char>& buffer) const;
bool loadRawData(const std::string& key, std::vector<char>& buffer) const override;
/**
* @brief Comparison operator.
......
......@@ -12,11 +12,13 @@
namespace hepnos {
class ProductID;
class DataSet;
class RunSet;
class Run;
class SubRun;
class Event;
template<typename T, typename C = std::vector<T>> class Ptr;
/**
* The DataStore class is the main handle referencing an HEPnOS service.
......@@ -24,6 +26,7 @@ class Event;
*/
class DataStore {
friend class ProductID;
friend class DataSet;
friend class RunSet;
friend class Run;
......@@ -246,6 +249,15 @@ class DataStore {
*/
DataSet createDataSet(const std::string& name);
template<typename T>
Ptr<T> makePtr(const ProductID& productID);
template<typename T, typename C = std::vector<T>>
Ptr<T,C> makePtr(const ProductID& productID, std::size_t index);
template<typename T>
bool loadProduct(const ProductID& productID, T& t);
/**
* @brief Shuts down the HEPnOS service.
*/
......@@ -258,6 +270,8 @@ class DataStore {
*/
class Impl;
std::unique_ptr<Impl> m_impl; /*!< Pointer to implementation */
bool loadRawProduct(const ProductID& productID, std::vector<char>& buffer);
};
class DataStore::const_iterator {
......@@ -485,4 +499,38 @@ class DataStore::iterator : public DataStore::const_iterator {
}
#include <hepnos/ProductID.hpp>
#include <hepnos/Ptr.hpp>
namespace hepnos {
template<typename T>
Ptr<T> DataStore::makePtr(const ProductID& productID) {
return Ptr<T>(this, productID);
}
template<typename T, typename C = std::vector<T>>
Ptr<T,C> DataStore::makePtr(const ProductID& productID, std::size_t index) {
return Ptr<T,C>(this, productID, index);
}
template<typename T>
bool DataStore::loadProduct(const ProductID& productID, T& t) {
std::vector<char> buffer;
if(!loadRawProduct(productID, buffer)) {
return false;
}
std::string serialized(buffer.begin(), buffer.end());
std::stringstream ss(serialized);
InputArchive ia(this, ss);
try {
ia >> t;
} catch(...) {
throw Exception("Exception occured during serialization");
}
return true;
}
}
#endif
......@@ -8,10 +8,10 @@
#include <memory>
#include <string>
#include <hepnos/KeyValueContainer.hpp>
#include <hepnos/DataStore.hpp>
#include <hepnos/EventNumber.hpp>
#include <hepnos/Exception.hpp>
#include <hepnos/KeyValueContainer.hpp>
namespace hepnos {
......@@ -78,6 +78,11 @@ class Event : public KeyValueContainer {
*/
~Event();
/**
* @brief Overrides getDataStore from KeyValueContainer class.
*/
DataStore* getDataStore() const override;
/**
* @brief Returns the next Event in the same container,
* sorted by event number. If no such event exists, an Event instance
......@@ -102,9 +107,9 @@ class Event : public KeyValueContainer {
* @param key Key
* @param buffer Value
*
* @return true if the key did not already exist, false otherwise.
* @return a valid ProductID if the key did not already exist, an invalid one otherwise.
*/
bool storeRawData(const std::string& key, const std::vector<char>& buffer);
ProductID storeRawData(const std::string& key, const std::vector<char>& buffer) override;
/**
* @brief Loads raw key/value data from this Event.
......@@ -114,7 +119,7 @@ class Event : public KeyValueContainer {
*
* @return true if the key exists, false otherwise.
*/
bool loadRawData(const std::string& key, std::vector<char>& buffer) const;
bool loadRawData(const std::string& key, std::vector<char>& buffer) const override;
/**
* @brief Compares this Event with another Event. The Events must point to
......
/*
* (C) 2018 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#ifndef __HEPNOS_INPUT_ARCHIVE_H
#define __HEPNOS_INPUT_ARCHIVE_H
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
#include <boost/archive/impl/basic_binary_iarchive.ipp>
namespace hepnos {
class DataStore;
class InputArchive;
using iarchive = boost::archive::binary_iarchive_impl<InputArchive, std::istream::char_type, std::istream::traits_type>;
/**
* @brief This InputArchive class derives from boost's binary input archive.
* It lets caller embed a pointer to the DataStore storing the object.
* This is necessary to deserialize Ptr instances, for example.
*/
class InputArchive : public iarchive {
friend class boost::archive::detail::interface_iarchive<InputArchive>;
friend class boost::archive::basic_binary_iarchive<InputArchive>;
friend class boost::archive::load_access;
private:
DataStore* m_datastore = nullptr;
public:
template<typename ... Args>
InputArchive(DataStore* datastore, Args&& ... args)
: iarchive(std::forward<Args>(args)..., 0)
, m_datastore(datastore) {}
DataStore* getDataStore() const {
return m_datastore;
}
};
}
#endif
......@@ -8,11 +8,12 @@
#include <memory>
#include <string>
#include <sstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <hepnos/InputArchive.hpp>
#include <hepnos/ProductID.hpp>
#include <hepnos/Demangle.hpp>
#include <hepnos/Exception.hpp>
......@@ -52,6 +53,13 @@ class KeyValueContainer {
*/
virtual ~KeyValueContainer() = default;
/**
* @brief Gets the DataStore to which this instance of KeyValueContainer belongs.
*
* @return DataStore.
*/
virtual DataStore* getDataStore() const = 0;
/**
* @brief Stores raw key/value data in this KeyValueContainer.
* This function is virtual and must be overloaded in the child class.
......@@ -59,9 +67,9 @@ class KeyValueContainer {
* @param key Key
* @param buffer Value
*
* @return true if the key did not already exist, false otherwise.
* @return A valid ProductID if the key did not already exist, an invalid one otherwise.
*/
virtual bool storeRawData(const std::string& key, const std::vector<char>& buffer) = 0;
virtual ProductID storeRawData(const std::string& key, const std::vector<char>& buffer) = 0;
/**
* @brief Loads raw key/value data from this KeyValueContainer.
......@@ -90,7 +98,7 @@ class KeyValueContainer {
* @return true if the key was found. false otherwise.
*/
template<typename K, typename V>
bool store(const K& key, const V& value) {
ProductID store(const K& key, const V& value) {
std::stringstream ss_value;
std::stringstream ss_key;
ss_key << key << "#" << demangle<V>();
......@@ -131,7 +139,8 @@ class KeyValueContainer {
try {
std::string serialized(buffer.begin(), buffer.end());
std::stringstream ss(serialized);
boost::archive::binary_iarchive ia(ss);
//boost::archive::binary_iarchive ia(ss);
InputArchive ia(getDataStore(), ss);
ia >> value;
} catch(...) {
throw Exception("Exception occured during serialization");
......
/*
* (C) 2018 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#ifndef __HEPNOS_PRODUCT_ID_H
#define __HEPNOS_PRODUCT_ID_H
#include <string>
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <hepnos/DataStore.hpp>
namespace hepnos {
class ProductID {
friend class DataStore;
friend class DataStore::Impl;
friend class boost::serialization::access;
private:
std::uint8_t m_level;
std::string m_containerName;
std::string m_objectName;
ProductID(std::uint8_t level, const std::string& containerName, const std::string& objectName)
: m_level(level)
, m_containerName(containerName)
, m_objectName(objectName) {}
public:
ProductID() = default;
/**
* @brief Copy constructor.
*
* @param other ProductID to copy.
*/
ProductID(const ProductID& other) = default;
/**
* @brief Move constructor.
*
* @param other ProductID to move.
*/
ProductID(ProductID&& other) = default;
/**
* @brief Copy-assignment operator.
*
* @param other ProductID to assign.
*
* @return Reference to this ProductID.
*/
ProductID& operator=(const ProductID& other) = default;
/**
* @brief Move-assignment operator.
*
* @param other ProductID to move from.
*
* @return Reference to this ProductID.
*/
ProductID& operator=(ProductID&& other) = default;
/**
* @brief Destructor.
*/
~ProductID() = default;
/**
* @brief Indicates whether this ProductID instance points to a valid
* product in the underlying storage service.
*
* @return True if the ProductID instance points to a valid product in the
* underlying service, false otherwise.
*/
bool valid() const {
return m_objectName.size() != 0;
}
/**
* @brief Conversion to bool.
*
* @return True if the ProductID instance points to a valid product in the
* underlying service, false otherwise.
*/
inline operator bool() const {
return valid();
}
/**
* @brief Compares this ProductID with another ProductID.
*
* @param other ProductID instance to compare against.
*
* @return true if the ProductIDs are the same, false otherwise.
*/
bool operator==(const ProductID& other) const {
return m_level == other.m_level
&& m_containerName == other.m_containerName
&& m_objectName == other.m_objectName;
}
/**
* @brief Compares this ProductID with another ProductID.
*
* @param other ProductID instance to compare against.
*
* @return true if the ProductIDs are different, false otherwise.
*/
bool operator!=(const ProductID& other) const {
return !(*this == other);
}
private:
template<typename Archive>
void serialize(Archive& ar, const unsigned int version) {
ar & m_level;
ar & m_containerName;
ar & m_objectName;
}
};
}
#endif
/*
* (C) 2018 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#ifndef __HEPNOS_PTR_H
#define __HEPNOS_PTR_H
#include <memory>
#include <string>
#include <vector>
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/split_member.hpp>
#include <hepnos/InputArchive.hpp>
#include <hepnos/ProductID.hpp>
#include <hepnos/DataStore.hpp>
#include <hepnos/Exception.hpp>
namespace hepnos {
template<typename T, typename C>
class Ptr {
friend class boost::serialization::access;
friend class DataStore;
private:
DataStore* m_datastore = nullptr;
ProductID m_product_id = ProductID();
std::size_t m_index = 0;
bool m_is_in_container = false;
C* m_container = nullptr;
T* m_data = nullptr;
size_t* m_refcount = nullptr;
Ptr(DataStore* datastore, const ProductID& product_id)
: m_datastore(datastore)
, m_product_id(product_id)
, m_index(0)
, m_is_in_container(false) {}
Ptr(DataStore* datastore, const ProductID& product_id, std::size_t index)
: m_datastore(datastore)
, m_product_id(product_id)
, m_index(index)
, m_is_in_container(true) {};
public:
Ptr() = default;
/**
* @brief Copy constructor.
*
* @param other Ptr to copy.
*/
Ptr(const Ptr& other)
: m_datastore(other.m_datastore)
, m_product_id(other.m_product_id)
, m_index(other.m_index)
, m_is_in_container(other.m_is_in_container)
, m_data(other.m_data)
, m_container(other.m_container)
, m_refcount(other.m_refcount) {
if(m_refcount) {
*m_refcount += 1;
}
}
/**
* @brief Move constructor.
*
* @param other Ptr to move.
*/
Ptr(Ptr&& other)
: m_datastore(other.m_datastore)
, m_product_id(std::move(other.m_product_id))
, m_index(other.m_index)
, m_is_in_container(other.m_is_in_container)
, m_container(other.m_container)
, m_refcount(other.m_refcount) {
other.m_refcount = nullptr;
other.m_container = nullptr;
other.m_data = nullptr;
other.m_product_id = ProductID();
}
/**
* @brief Copy-assignment operator.
*
* @param other Ptr to assign.
*
* @return Reference to this Ptr.
*/
Ptr& operator=(const Ptr& other) {
if(&other == this) return *this;
if(other.m_data == m_data) return *this;
if(m_data) {
this->~Ptr();
}
m_datastore = other.m_datastore;
m_product_id = other.m_product_id;
m_index = other.m_index;
m_is_in_container = other.m_is_in_container;
m_container = other.m_container;
m_refcount = other.m_refcount;
if(m_refcount) {
*m_refcount += 1;
}
return *this;
}
/**
* @brief Move-assignment operator.
*
* @param other Ptr to move from.
*
* @return Reference to this Ptr.
*/
Ptr& operator=(Ptr&& other) {
if(&other == this) return *this;
if(other.m_data == m_data) return *this;
if(m_data) {
this->~Ptr();
}
m_datastore = other.m_datastore;
m_product_id = std::move(other.m_product_id);
m_index = other.m_index;
m_is_in_container = other.m_is_in_container;
m_container = other.m_container;
m_refcount = other.m_refcount;
other.m_datastore = nullptr;
other.m_index = 0;
other.m_container = nullptr;
other.m_refcount = nullptr;
return *this;
}
/**
* @brief Destructor.
*/
~Ptr() {
if(m_refcount) {
*m_refcount -= 1;
if(*m_refcount == 0) {
delete m_refcount;
if(m_is_in_container) {
delete m_container;
} else {
delete m_data;
}
}
}
}
/**
* @brief Indicates whether this Ptr instance points to a valid
* product in the underlying storage service.
*
* @return True if the Ptr instance points to a valid product in the
* underlying service, false otherwise.
*/
bool valid() const {
return m_datastore != nullptr && m_product_id.valid();
}
/**
* @brief Compares this Ptr with another Ptr. The Ptrs must point to
* the same product.
*
* @param other Ptr instance to compare against.
*
* @return true if the Ptrs are the same, false otherwise.
*/
bool operator==(const Ptr& other) const {
return m_product_id == other.m_product_id;
}
/**
* @brief Compares this Ptr with another Ptr.
*
* @param other Ptr instance to compare against.
*
* @return true if the Ptrs are different, false otherwise.
*/
bool operator!=(const Ptr& other) const {
return m_product_id != other.m_product_id;
}
/**
* @brief Dereference operator. This operator will load
* the data from the underlying storage if it hasn't been
* loaded yet.
*
* @return Reference to the pointed data.
*/
const T& operator*()
{
if(m_data)
return *m_data;
else {
loadData();
}
return *m_data;
}
/**
* @brief Dereference operator. This operator will load the data
* from the underlying storage if it hasn't been loaded yet.
*
* @return Pointer to the pointed data.
*/
const T* operator->()
{
if(m_data)
return m_data;
else {
loadData();
}
return m_data;
}
private:
/**
* @brief Serialization function for Boost.
*
* @tparam Archive Archive type.
* @param ar Archive.
* @param version Version number.
*/
template<typename Archive>
void save(Archive& ar, const unsigned int version) const {
ar & m_product_id;
}
/**
* @brief Serialization function for Boost.
*
* @tparam Archive Archive type.
* @param ar Archive.
* @param version Version number.
*/
template<typename Archive>
void load(Archive& ar, const unsigned int version) {
ar & m_product_id;
m_datastore = ar.getDataStore();
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
/**
* @brief This function is called to load the actual data from storage.
*/
void loadData() {
if(m_is_in_container) {
m_container = new C();
if(!(m_datastore->loadProduct(m_product_id, *m_container))) {
throw Exception("Could not load product from DataStore");
}
m_data = &((*m_container)[m_index]);
} else {
m_data = new T();
m_container = nullptr;
if(!(m_datastore->loadProduct(m_product_id, *m_data))) {
throw Exception("Could not load product from DataStore");
}
}
}
};
}
#endif
......@@ -8,11 +8,11 @@
#include <memory>
#include <string>
#include <hepnos/KeyValueContainer.hpp>
#include <hepnos/DataStore.hpp>
#include <hepnos/RunNumber.hpp>
#include <hepnos/SubRun.hpp>
#include <hepnos/Exception.hpp>
#include <hepnos/KeyValueContainer.hpp>
namespace hepnos {
......@@ -84,6 +84,11 @@ class Run : public KeyValueContainer {
*/
~Run();
/**
* @brief Overrides getDataStore from KeyValueContainer class.
*/
DataStore* getDataStore() const override;
/**
* @brief Returns the next Run in the same container,
* sorted by run number. If no such run exists, a Run instance
......@@ -108,9 +113,9 @@ class Run : public KeyValueContainer {
* @param key Key
* @param buffer Value
*
* @return true if the key did not already exist, false otherwise.
* @return a valid ProductID if the key did not already exist, an invalid one otherwise.
*/
bool storeRawData(const std::string& key, const std::vector<char>& buffer);
ProductID storeRawData(const std::string& key, const std::vector<char>& buffer) override;
/**
* @brief Loads raw key/value data from this Run.
......@@ -120,7 +125,7 @@ class Run : public KeyValueContainer {
*
* @return true if the key exists, false otherwise.
*/
bool loadRawData(const std::string& key, std::vector<char>& buffer) const;
bool loadRawData(const std::string& key, std::vector<char>& buffer) const override;
/**
* @brief Compares this Run with another Run. The Runs must point to
......
......@@ -8,11 +8,11 @@
#include <memory>
#include <string>
#include <hepnos/KeyValueContainer.hpp>