Skip to content
Snippets Groups Projects
ArrayAccessor.h 6.14 KiB
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 {

  /** 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,
          size_t nElements, UpdateMode mode, const std::string &description)
      : Accessor<UserType>(owner, name, direction, unit, nElements, mode, description)
      /** Default constructor creates a dysfunction accessor (to be assigned with a real accessor later) */
      ArrayAccessor() {}

      void read() {
        if(Accessor<UserType>::_mode == UpdateMode::push) {
          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();
        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);
      }        

      /** 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());
        }
      }
  /** 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 */