Commit 13011618 authored by Jens Petit's avatar Jens Petit
Browse files

Working draft of static handler

parent ddae7314
......@@ -37,17 +37,17 @@ endif()
# add the elsa modules
add_subdirectory(core)
add_subdirectory(logging)
add_subdirectory(io)
add_subdirectory(operators)
add_subdirectory(functionals)
add_subdirectory(problems)
add_subdirectory(solvers)
add_subdirectory(projectors)
#add_subdirectory(logging)
#add_subdirectory(io)
#add_subdirectory(operators)
#add_subdirectory(functionals)
#add_subdirectory(problems)
#add_subdirectory(solvers)
#add_subdirectory(projectors)
if(ELSA_BUILD_CUDA_PROJECTORS)
add_subdirectory(projectors_cuda)
#add_subdirectory(projectors_cuda)
endif(ELSA_BUILD_CUDA_PROJECTORS)
add_subdirectory(generators)
#add_subdirectory(generators)
# library to build and add all registered components of the library
......
This diff is collapsed.
......@@ -33,10 +33,7 @@ namespace elsa
class DataContainer
{
public:
using DCType = DataContainer<data_t, handler_t>;
/// union of all possible handler raw pointers
using HandlerTypes_t = std::variant<DataHandlerCPU<data_t>*, DataHandlerMapCPU<data_t>*>;
using DataContainer_t = DataContainer<data_t, handler_t>;
/// delete default constructor (without metadata there can be no valid container)
DataContainer() = delete;
......@@ -47,8 +44,7 @@ namespace elsa
* \param[in] dataDescriptor containing the associated metadata
* \param[in] handlerType the data handler (default: CPU)
*/
explicit DataContainer(const DataDescriptor& dataDescriptor,
DataHandlerType handlerType = DataHandlerType::CPU);
explicit DataContainer(const DataDescriptor& dataDescriptor);
/**
* \brief Constructor for DataContainer, initializing it with a DataVector
......@@ -58,22 +54,21 @@ namespace elsa
* \param[in] handlerType the data handler (default: CPU)
*/
DataContainer(const DataDescriptor& dataDescriptor,
const Eigen::Matrix<data_t, Eigen::Dynamic, 1>& data,
DataHandlerType handlerType = DataHandlerType::CPU);
const Eigen::Matrix<data_t, Eigen::Dynamic, 1>& data);
/**
* \brief Copy constructor for DataContainer
*
* \param[in] other DataContainer to copy
*/
DataContainer(const DCType& other);
DataContainer(const DataContainer_t& other);
/**
* \brief copy assignment for DataContainer
*
* \param[in] other DataContainer to copy
*/
DataContainer<data_t, handler_t>& operator=(const DataContainer<data_t, handler_t>& other);
DataContainer_t& operator=(const DataContainer_t& other);
/**
* \brief Move constructor for DataContainer
......@@ -84,7 +79,7 @@ namespace elsa
* fulfilled for any member functions, the object should not be used. After move- or copy-
* assignment, this is possible again.
*/
DataContainer(DataContainer<data_t, handler_t>&& other) noexcept;
DataContainer(DataContainer_t&& other) noexcept;
/**
* \brief Move assignment for DataContainer
......@@ -95,7 +90,7 @@ namespace elsa
* fulfilled for any member functions, the object should not be used. After move- or copy-
* assignment, this is possible again.
*/
DataContainer<data_t, handler_t>& operator=(DataContainer<data_t, handler_t>&& other);
DataContainer_t& operator=(DataContainer_t&& other);
/**
* \brief Expression evaluation assignment for DataContainer
......@@ -106,9 +101,9 @@ namespace elsa
* the DataHandler in use.
*/
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>& operator=(Source const& source)
DataContainer_t& operator=(Source const& source)
{
_dataHandler->accessData() = source.eval();
_dataHandler.accessData() = source.eval();
return *this;
}
......@@ -123,8 +118,7 @@ namespace elsa
*/
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>(Source const& source)
: DataContainer<data_t, handler_t>(source.getDataMetaInfo().first, source.eval(),
source.getDataMetaInfo().second)
: DataContainer<data_t, handler_t>(source.getDataMetaInfo().first, source.eval())
{
}
......@@ -170,7 +164,7 @@ namespace elsa
}
/// return the dot product of this signal with the one from container other
data_t dot(const DataContainer<data_t, handler_t>& other) const;
data_t dot(const DataContainer_t& other) const;
/// return the dot product of this signal with the one from an expression
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
......@@ -192,87 +186,87 @@ namespace elsa
data_t sum() const;
/// compute in-place element-wise addition of another container
DataContainer<data_t, handler_t>& operator+=(const DataContainer<data_t, handler_t>& dc);
DataContainer_t& operator+=(const DataContainer_t& dc);
/// compute in-place element-wise addition with another expression
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>& operator+=(Source const& source)
DataContainer_t& operator+=(Source const& source)
{
*this = *this + source;
return *this;
}
/// compute in-place element-wise subtraction of another container
DataContainer<data_t, handler_t>& operator-=(const DataContainer<data_t, handler_t>& dc);
DataContainer_t& operator-=(const DataContainer_t& dc);
/// compute in-place element-wise subtraction with another expression
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>& operator-=(Source const& source)
DataContainer_t& operator-=(Source const& source)
{
*this = *this - source;
return *this;
}
/// compute in-place element-wise multiplication with another container
DataContainer<data_t, handler_t>& operator*=(const DataContainer<data_t, handler_t>& dc);
DataContainer_t& operator*=(const DataContainer_t& dc);
/// compute in-place element-wise multiplication with another expression
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>& operator*=(Source const& source)
DataContainer_t& operator*=(Source const& source)
{
*this = *this * source;
return *this;
}
/// compute in-place element-wise division by another container
DataContainer<data_t, handler_t>& operator/=(const DataContainer<data_t, handler_t>& dc);
DataContainer_t& operator/=(const DataContainer_t& dc);
/// compute in-place element-wise division with another expression
template <typename Source, typename = std::enable_if_t<isExpression<Source>>>
DataContainer<data_t, handler_t>& operator/=(Source const& source)
DataContainer_t& operator/=(Source const& source)
{
*this = *this / source;
return *this;
}
/// compute in-place addition of a scalar
DataContainer<data_t, handler_t>& operator+=(data_t scalar);
DataContainer_t& operator+=(data_t scalar);
/// compute in-place subtraction of a scalar
DataContainer<data_t, handler_t>& operator-=(data_t scalar);
DataContainer_t& operator-=(data_t scalar);
/// compute in-place multiplication with a scalar
DataContainer<data_t, handler_t>& operator*=(data_t scalar);
DataContainer_t& operator*=(data_t scalar);
/// compute in-place division by a scalar
DataContainer<data_t, handler_t>& operator/=(data_t scalar);
DataContainer_t& operator/=(data_t scalar);
/// assign a scalar to the DataContainer
DataContainer<data_t, handler_t>& operator=(data_t scalar);
DataContainer_t& operator=(data_t scalar);
/// comparison with another DataContainer
bool operator==(const DataContainer<data_t, handler_t>& other) const;
bool operator==(const DataContainer_t& other) const;
/// comparison with another DataContainer
bool operator!=(const DataContainer<data_t, handler_t>& other) const;
bool operator!=(const DataContainer_t& other) const;
/// returns a reference to the i-th block, wrapped in a DataContainer
DataContainer<data_t, handler_t> getBlock(index_t i);
DataContainer<data_t, DataHandlerType::MAP_CPU> getBlock(index_t i);
/// returns a const reference to the i-th block, wrapped in a DataContainer
const DataContainer<data_t, handler_t> getBlock(index_t i) const;
const DataContainer<data_t, DataHandlerType::MAP_CPU> getBlock(index_t i) const;
/// return a view of this DataContainer with a different descriptor
DataContainer<data_t, handler_t> viewAs(const DataDescriptor& dataDescriptor);
DataContainer<data_t, DataHandlerType::MAP_CPU> viewAs(const DataDescriptor& dataDescriptor);
/// return a const view of this DataContainer with a different descriptor
const DataContainer<data_t, handler_t> viewAs(const DataDescriptor& dataDescriptor) const;
const DataContainer<data_t, DataHandlerType::MAP_CPU> viewAs(const DataDescriptor& dataDescriptor) const;
/// iterator for DataContainer (random access and continuous)
using iterator = DataContainerIterator<DataContainer<data_t, handler_t>>;
using iterator = DataContainerIterator<DataContainer_t>;
/// const iterator for DataContainer (random access and continuous)
using const_iterator = ConstDataContainerIterator<DataContainer<data_t, handler_t>>;
using const_iterator = ConstDataContainerIterator<DataContainer_t>;
/// alias for reverse iterator
using reverse_iterator = std::reverse_iterator<iterator>;
......@@ -341,32 +335,16 @@ namespace elsa
template <class Operand, std::enable_if_t<isDataContainer<Operand>, int>>
friend constexpr auto evaluateOrReturn(Operand const& operand);
private:
/// returns the underlying derived handler as a raw pointer in a std::variant
HandlerTypes_t getHandlerPtr() const;
/// private constructor accepting a DataDescriptor and a DataHandler
explicit DataContainer(const DataDescriptor& dataDescriptor, DataHandlerMapCPU<data_t> dataHandler);
private:
/// the current DataDescriptor
std::unique_ptr<DataDescriptor> _dataDescriptor;
/// the current DataHandler
std::unique_ptr<std::conditional_t<(handler_t == DataHandlerType::CPU
|| handler_t == DataHandlerType::MAP_CPU),
DataHandler<data_t>, DataHandler<data_t>>>
_dataHandler;
/// the current DataHandlerType
DataHandlerType _dataHandlerType;
/// factory method to create DataHandlers based on handlerType with perfect forwarding of
/// constructor arguments
template <typename... Args>
std::unique_ptr<DataHandler<data_t>> createDataHandler(DataHandlerType handlerType,
Args&&... args);
/// private constructor accepting a DataDescriptor and a DataHandler
explicit DataContainer(const DataDescriptor& dataDescriptor,
std::unique_ptr<DataHandler<data_t>> dataHandler,
DataHandlerType dataType = DataHandlerType::CPU);
std::conditional_t<(handler_t == DataHandlerType::MAP_CPU), DataHandlerMapCPU<data_t>,
DataHandlerCPU<data_t>> _dataHandler;
};
/// User-defined template argument deduction guide for the expression based constructor
......
#pragma once
#include "elsaDefines.h"
#include "Cloneable.h"
#include "ExpressionPredicates.h"
#include <Eigen/Core>
......@@ -27,14 +26,16 @@ namespace elsa
* documentation for details.
*/
template <typename data_t = real_t>
class DataHandler : public Cloneable<DataHandler<data_t>>
class DataHandler
{
/// for enabling accessData()
template <class Operand, std::enable_if_t<isDataContainer<Operand>, int>>
friend constexpr auto evaluateOrReturn(Operand const& operand);
/// for enabling accessData()
friend DataContainer<data_t>;
friend DataContainer<data_t, 0>;
friend DataContainer<data_t, 1>;
friend DataContainer<data_t, 2>;
protected:
/// convenience typedef for the Eigen::Matrix data vector
......@@ -44,6 +45,13 @@ namespace elsa
using DataMap_t = Eigen::Map<DataVector_t>;
public:
virtual bool operator==(DataHandler const& other) const = 0;
bool operator!=(DataHandler const& other) const {
return !this->operator==(other);
}
/// convenience typedef to access data type that is internally stored
using value_type = data_t;
......@@ -120,13 +128,11 @@ namespace elsa
/// return a reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
virtual std::unique_ptr<DataHandler<data_t>> getBlock(index_t startIndex,
index_t numberOfElements) = 0;
///virtual DataHandlerMapCPU<data_t> getBlock(index_t startIndex,
/// return a const reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
virtual std::unique_ptr<const DataHandler<data_t>>
getBlock(index_t startIndex, index_t numberOfElements) const = 0;
///virtual const DataHandlerMapCPU<data_t> getBlock(index_t startIndex, index_t numberOfElements) const = 0;
protected:
/// slow element-wise dot product fall-back for when DataHandler types do not match
......
......@@ -247,18 +247,17 @@ namespace elsa
}
template <typename data_t>
std::unique_ptr<DataHandler<data_t>> DataHandlerCPU<data_t>::getBlock(index_t startIndex,
DataHandlerMapCPU<data_t> DataHandlerCPU<data_t>::getBlock(index_t startIndex,
index_t numberOfElements)
{
if (startIndex >= getSize() || numberOfElements > getSize() - startIndex)
throw std::invalid_argument("DataHandler: requested block out of bounds");
return std::unique_ptr<DataHandlerMapCPU<data_t>>{
new DataHandlerMapCPU{this, _data->data() + startIndex, numberOfElements}};
return DataHandlerMapCPU{this, _data->data() + startIndex, numberOfElements};
}
template <typename data_t>
std::unique_ptr<const DataHandler<data_t>>
const DataHandlerMapCPU<data_t>
DataHandlerCPU<data_t>::getBlock(index_t startIndex, index_t numberOfElements) const
{
if (startIndex >= getSize() || numberOfElements > getSize() - startIndex)
......@@ -268,18 +267,11 @@ namespace elsa
// Eigen objects
auto mutableThis = const_cast<DataHandlerCPU<data_t>*>(this);
auto mutableData = const_cast<data_t*>(_data->data() + startIndex);
return std::unique_ptr<const DataHandlerMapCPU<data_t>>{
new DataHandlerMapCPU{mutableThis, mutableData, numberOfElements}};
return DataHandlerMapCPU{mutableThis, mutableData, numberOfElements};
}
template <typename data_t>
DataHandlerCPU<data_t>* DataHandlerCPU<data_t>::cloneImpl() const
{
return new DataHandlerCPU<data_t>(*this);
}
template <typename data_t>
bool DataHandlerCPU<data_t>::isEqual(const DataHandler<data_t>& other) const
bool DataHandlerCPU<data_t>::operator==(DataHandler<data_t> const& other) const
{
if (const auto otherHandler = dynamic_cast<const DataHandlerMapCPU<data_t>*>(&other)) {
......
......@@ -6,6 +6,7 @@
#include <Eigen/Core>
#include <list>
#include <memory>
namespace elsa
{
......@@ -42,12 +43,22 @@ namespace elsa
template <typename data_t>
class DataHandlerCPU : public DataHandler<data_t>
{
/// for enabling accessData()
template <class Operand, std::enable_if_t<isDataContainer<Operand>, int>>
friend constexpr auto evaluateOrReturn(Operand const& operand);
/// declare DataHandlerMapCPU as friend, allows the use of Eigen for improved performance
friend DataHandlerMapCPU<data_t>;
/// used for testing only and defined in test file
friend long useCount<>(const DataHandlerCPU<data_t>& dh);
/// for enabling accessData()
friend DataContainer<data_t, 0>;
friend DataContainer<data_t, 1>;
friend DataContainer<data_t, 2>;
protected:
/// convenience typedef for the Eigen::Matrix data vector
using DataVector_t = Eigen::Matrix<data_t, Eigen::Dynamic, 1>;
......@@ -60,7 +71,7 @@ namespace elsa
DataHandlerCPU() = delete;
/// default destructor
~DataHandlerCPU() override;
~DataHandlerCPU();
/**
* \brief Constructor initializing an appropriately sized vector with zeros
......@@ -148,14 +159,14 @@ namespace elsa
/// return a reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
std::unique_ptr<DataHandler<data_t>> getBlock(index_t startIndex,
index_t numberOfElements) override;
DataHandlerMapCPU<data_t> getBlock(index_t startIndex, index_t numberOfElements);
/// return a const reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
std::unique_ptr<const DataHandler<data_t>>
getBlock(index_t startIndex, index_t numberOfElements) const override;
const DataHandlerMapCPU<data_t> getBlock(index_t startIndex, index_t numberOfElements) const;
/// implement the polymorphic comparison operation
bool operator==(DataHandler<data_t> const& other) const override;
protected:
/// the vector storing the data
std::shared_ptr<DataVector_t> _data;
......@@ -164,10 +175,7 @@ namespace elsa
std::list<DataHandlerMapCPU<data_t>*> _associatedMaps;
/// implement the polymorphic clone operation
DataHandlerCPU<data_t>* cloneImpl() const override;
/// implement the polymorphic comparison operation
bool isEqual(const DataHandler<data_t>& other) const override;
DataHandlerCPU<data_t>* cloneImpl() const;
/// copy the data stored in other
void assign(const DataHandler<data_t>& other) override;
......
......@@ -242,19 +242,17 @@ namespace elsa
}
template <typename data_t>
std::unique_ptr<DataHandler<data_t>>
DataHandlerMapCPU<data_t>
DataHandlerMapCPU<data_t>::getBlock(index_t startIndex, index_t numberOfElements)
{
if (startIndex >= getSize() || numberOfElements > getSize() - startIndex)
throw std::invalid_argument("DataHandler: requested block out of bounds");
return std::unique_ptr<DataHandlerMapCPU<data_t>>(
new DataHandlerMapCPU{_dataOwner, _map.data() + startIndex, numberOfElements});
return DataHandlerMapCPU{_dataOwner, _map.data() + startIndex, numberOfElements};
}
template <typename data_t>
std::unique_ptr<const DataHandler<data_t>>
DataHandlerMapCPU<data_t>::getBlock(index_t startIndex, index_t numberOfElements) const
const DataHandlerMapCPU<data_t> DataHandlerMapCPU<data_t>::getBlock(index_t startIndex, index_t numberOfElements) const
{
if (startIndex >= getSize() || numberOfElements > getSize() - startIndex)
throw std::invalid_argument("DataHandler: requested block out of bounds");
......@@ -262,8 +260,7 @@ namespace elsa
// using a const_cast here is fine as long as the DataHandlers never expose the internal
// Eigen objects
auto mutableData = const_cast<data_t*>(_map.data() + startIndex);
return std::unique_ptr<const DataHandlerMapCPU<data_t>>(
new DataHandlerMapCPU{_dataOwner, mutableData, numberOfElements});
return DataHandlerMapCPU{_dataOwner, mutableData, numberOfElements};
}
template <typename data_t>
......@@ -277,7 +274,7 @@ namespace elsa
}
template <typename data_t>
bool DataHandlerMapCPU<data_t>::isEqual(const DataHandler<data_t>& other) const
bool DataHandlerMapCPU<data_t>::operator==(DataHandler<data_t> const& other) const
{
if (auto otherHandler = dynamic_cast<const DataHandlerMapCPU*>(&other)) {
......
......@@ -45,6 +45,15 @@ namespace elsa
/// declare DataHandlerCPU as friend, allows the use of Eigen for improved performance
friend class DataHandlerCPU<data_t>;
/// for enabling accessData()
friend DataContainer<data_t, 0>;
friend DataContainer<data_t, 1>;
friend DataContainer<data_t, 2>;
/// for enabling accessData()
template <class Operand, std::enable_if_t<isDataContainer<Operand>, int>>
friend constexpr auto evaluateOrReturn(Operand const& operand);
protected:
/// convenience typedef for the Eigen::Matrix data vector
using DataVector_t = Eigen::Matrix<data_t, Eigen::Dynamic, 1>;
......@@ -60,7 +69,7 @@ namespace elsa
DataHandlerMapCPU(DataHandlerMapCPU<data_t>&& other) = default;
/// default destructor
~DataHandlerMapCPU() override;
~DataHandlerMapCPU();
/// return the size of the vector
index_t getSize() const override;
......@@ -123,13 +132,14 @@ namespace elsa
/// return a reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
std::unique_ptr<DataHandler<data_t>> getBlock(index_t startIndex,
index_t numberOfElements) override;
DataHandlerMapCPU<data_t> getBlock(index_t startIndex, index_t numberOfElements);
/// return a const reference to the sequential block starting at startIndex and containing
/// numberOfElements elements
std::unique_ptr<const DataHandler<data_t>>
getBlock(index_t startIndex, index_t numberOfElements) const override;
const DataHandlerMapCPU<data_t> getBlock(index_t startIndex, index_t numberOfElements) const;
/// implement the polymorphic comparison operation
bool operator==(DataHandler<data_t> const& other) const override;
protected:
/// vector mapping of the data
......@@ -142,10 +152,7 @@ namespace elsa
typename std::list<DataHandlerMapCPU<data_t>*>::iterator _handle;
/// implement the polymorphic clone operation
DataHandlerCPU<data_t>* cloneImpl() const override;
/// implement the polymorphic comparison operation
bool isEqual(const DataHandler<data_t>& other) const override;
DataHandlerCPU<data_t>* cloneImpl() const;
void assign(const DataHandler<data_t>& other) override;
......
......@@ -27,7 +27,7 @@ namespace elsa
template <class Operand, std::enable_if_t<isDataContainer<Operand>, int> = 0>
constexpr auto evaluateOrReturn(Operand const& operand)
{
return operand._dataHandler->accessData();
return operand._dataHandler.accessData();
}
/// Type trait which decides if const lvalue reference or not
......
......@@ -37,8 +37,8 @@ namespace elsa
};
/// Partial specialization which inherits true
template <typename data_t>
struct IsDataContainerType<DataContainer<data_t>> : std::true_type {
template <typename data_t, int handler_t>
struct IsDataContainerType<DataContainer<data_t, handler_t>> : std::true_type {
};
/// Predicate to check Operand
......@@ -80,8 +80,8 @@ namespace elsa
};
/// Partial specialization to infer data_t from DataContainer
template <typename data_type>
struct GetOperandDataType<DataContainer<data_type>> {
template <typename data_type, int handler_t>
struct GetOperandDataType<DataContainer<data_type, handler_t>> {
using data_t = data_type;
};
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment