Newer
Older
/*
* ArrayAccessor.h
*
* Created on: Jun 07, 2016
* Author: Martin Hierholzer
*/
#ifndef CHIMERATK_ARRAY_ACCESSOR_H
#define CHIMERATK_ARRAY_ACCESSOR_H
#include <string>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/thread.hpp>
#include "Accessor.h"
namespace ChimeraTK {
Martin Christoph Hierholzer
committed
/** Accessor for array variables (i.e. vectors). Note for users: Preferrably use the convenience classes
* ArrayPollInput, ArrayPushInput, ArrayOutput instead of this class directly. */
template< typename UserType >
class ArrayAccessor : public Accessor<UserType> {
public:
ArrayAccessor(Module *owner, const std::string &name, VariableDirection direction, std::string unit,
Martin Christoph Hierholzer
committed
size_t nElements, UpdateMode mode, const std::string &description)
: Accessor<UserType>(owner, name, direction, unit, nElements, mode, description)
Martin Christoph Hierholzer
committed
/** Default constructor creates a dysfunction accessor (to be assigned with a real accessor later) */
ArrayAccessor() {}
void read() {
if(Accessor<UserType>::_mode == UpdateMode::push) {
Martin Christoph Hierholzer
committed
impl->read();
boost::this_thread::interruption_point();
}
else {
/// @todo TODO empty the queue to always receive the latest value
impl->readNonBlocking();
boost::this_thread::interruption_point();
}
} // LCOV_EXCL_LINE this line somehow ends up having a negative counter in the coverage report, which leads to a failure
void write() {
impl->write();
boost::this_thread::interruption_point();
}
bool readNonBlocking() {
boost::this_thread::interruption_point();
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
return impl->readNonBlocking();
}
/** Get or set buffer content by [] operator.
* @attention No bounds checking is performed, use getNumberOfElements() to obtain the number of elements in
* the register.
* Note: Using the iterators is slightly more efficient than using this operator! */
UserType& operator[](unsigned int element) {
return impl->accessData(0,element);
}
/** Return number of elements/samples in the register */
unsigned int getNElements() {
return impl->getNumberOfSamples();
}
/** Access data with std::vector-like iterators */
typedef typename std::vector<UserType>::iterator iterator;
typedef typename std::vector<UserType>::const_iterator const_iterator;
typedef typename std::vector<UserType>::reverse_iterator reverse_iterator;
typedef typename std::vector<UserType>::const_reverse_iterator const_reverse_iterator;
iterator begin() { return impl->accessChannel(0).begin(); }
const_iterator begin() const { return impl->accessChannel(0).cbegin(); }
const_iterator cbegin() const { return impl->accessChannel(0).cbegin(); }
iterator end() { return impl->accessChannel(0).end(); }
const_iterator end() const { return impl->accessChannel(0).cend(); }
const_iterator cend() const { return impl->accessChannel(0).cend(); }
reverse_iterator rbegin() { return impl->accessChannel(0).rbegin(); }
const_reverse_iterator rbegin() const { return impl->accessChannel(0).crbegin(); }
const_reverse_iterator crbegin() const { return impl->accessChannel(0).crbegin(); }
reverse_iterator rend() { return impl->accessChannel(0).rend(); }
const_reverse_iterator rend() const { return impl->accessChannel(0).crend(); }
const_reverse_iterator crend() const { return impl->accessChannel(0).crend(); }
/* Swap content of (cooked) buffer with std::vector */
void swap(std::vector<UserType> &x) {
if(x.size() != impl->accessChannel(0).size()) {
throw DeviceException("Swapping with a buffer of a different size is not allowed.",
DeviceException::WRONG_PARAMETER);
}
impl->accessChannel(0).swap(x);
}
Martin Christoph Hierholzer
committed
/** Assignment operator */
ArrayAccessor<UserType>& operator=(const std::vector<UserType> &rightHandSide) {
impl->accessChannel(0) = rightHandSide;
return *this;
}
bool isInitialised() const {
return impl != nullptr;
}
void useProcessVariable(const boost::shared_ptr<TransferElement > &var) {
impl = boost::dynamic_pointer_cast<NDRegisterAccessor<UserType>>(var);
assert(impl);
if(Accessor<UserType>::getDirection() == VariableDirection::consuming) {
assert(impl->isReadable());
}
else {
assert(impl->isWriteable());
}
}
Martin Christoph Hierholzer
committed
using Accessor<UserType>::impl;
Martin Christoph Hierholzer
committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/** Convenience class for input array accessors with UpdateMode::push */
template< typename UserType >
struct ArrayPushInput : public ArrayAccessor<UserType> {
ArrayPushInput(Module *owner, const std::string &name, std::string unit, size_t nElements, const std::string &description)
: ArrayAccessor<UserType>(owner, name, VariableDirection::consuming, unit, nElements, UpdateMode::push, description)
{}
ArrayPushInput() : ArrayAccessor<UserType>() {}
using ArrayAccessor<UserType>::operator=;
};
/** Convenience class for input array accessors with UpdateMode::poll */
template< typename UserType >
struct ArrayPollInput : public ArrayAccessor<UserType> {
ArrayPollInput(Module *owner, const std::string &name, std::string unit, size_t nElements, const std::string &description)
: ArrayAccessor<UserType>(owner, name, VariableDirection::consuming, unit, nElements, UpdateMode::poll, description)
{}
ArrayPollInput() : ArrayAccessor<UserType>() {}
using ArrayAccessor<UserType>::operator=;
};
/** Convenience class for output array accessors (always UpdateMode::push) */
template< typename UserType >
struct ArrayOutput : public ArrayAccessor<UserType> {
ArrayOutput(Module *owner, const std::string &name, std::string unit, size_t nElements, const std::string &description)
: ArrayAccessor<UserType>(owner, name, VariableDirection::feeding, unit, nElements, UpdateMode::push, description)
{}
ArrayOutput() : ArrayAccessor<UserType>() {}
using ArrayAccessor<UserType>::operator=;
};
} /* namespace ChimeraTK */
#endif /* CHIMERATK_ARRAY_ACCESSOR_H */