Program Listing for File exact_time.hpp

Return to documentation for file (include/message_filters/sync_policies/exact_time.hpp)

// Copyright 2009, Willow Garage, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the Willow Garage nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MESSAGE_FILTERS__SYNC_POLICIES__EXACT_TIME_HPP_
#define MESSAGE_FILTERS__SYNC_POLICIES__EXACT_TIME_HPP_

#include <cstdint>
#include <deque>
#include <map>
#include <string>
#include <tuple>

#include <rclcpp/rclcpp.hpp>

#include "message_filters/connection.hpp"
#include "message_filters/message_traits.hpp"
#include "message_filters/null_types.hpp"
#include "message_filters/signal9.hpp"
#include "message_filters/synchronizer.hpp"

namespace message_filters
{
namespace sync_policies
{

template<typename M0, typename M1, typename M2 = NullType, typename M3 = NullType,
  typename M4 = NullType, typename M5 = NullType, typename M6 = NullType,
  typename M7 = NullType, typename M8 = NullType>
struct ExactTime : public PolicyBase<M0, M1, M2, M3, M4, M5, M6, M7, M8>
{
  typedef Synchronizer<ExactTime> Sync;
  typedef PolicyBase<M0, M1, M2, M3, M4, M5, M6, M7, M8> Super;
  typedef typename Super::Messages Messages;
  typedef typename Super::Signal Signal;
  typedef typename Super::Events Events;
  typedef typename Super::RealTypeCount RealTypeCount;
  typedef typename Super::M0Event M0Event;
  typedef typename Super::M1Event M1Event;
  typedef typename Super::M2Event M2Event;
  typedef typename Super::M3Event M3Event;
  typedef typename Super::M4Event M4Event;
  typedef typename Super::M5Event M5Event;
  typedef typename Super::M6Event M6Event;
  typedef typename Super::M7Event M7Event;
  typedef typename Super::M8Event M8Event;
  typedef Events Tuple;

  ExactTime(uint32_t queue_size)  // NOLINT(runtime/explicit)
  : parent_(0)
    , queue_size_(queue_size)
  {
  }

  ExactTime(const ExactTime & e)
  {
    *this = e;
  }

  ExactTime & operator=(const ExactTime & rhs)
  {
    parent_ = rhs.parent_;
    queue_size_ = rhs.queue_size_;
    last_signal_time_ = rhs.last_signal_time_;
    tuples_ = rhs.tuples_;

    return *this;
  }

  void initParent(Sync * parent)
  {
    parent_ = parent;
  }

  template<int i>
  void add(const typename std::tuple_element<i, Events>::type & evt)
  {
    assert(parent_);

    namespace mt = message_filters::message_traits;

    std::lock_guard<std::mutex> lock(mutex_);

    Tuple & t = tuples_[mt::TimeStamp<typename std::tuple_element<i, Messages>::type>::value(
          *evt.getMessage())];
    std::get<i>(t) = evt;

    checkTuple(t);
  }

  template<class C>
  Connection registerDropCallback(const C & callback)
  {
    return drop_signal_.addCallback(callback);
  }

  template<class C>
  Connection registerDropCallback(C & callback)
  {
    return drop_signal_.addCallback(callback);
  }

  template<class C, typename T>
  Connection registerDropCallback(const C & callback, T * t)
  {
    return drop_signal_.addCallback(callback, t);
  }

  template<class C, typename T>
  Connection registerDropCallback(C & callback, T * t)
  {
    return drop_signal_.addCallback(callback, t);
  }

  rclcpp::Time getLastSignalTime() const
  {
    return last_signal_time_;
  }

private:
  // assumes mutex_ is already locked
  void checkTuple(Tuple & t)
  {
    namespace mt = message_filters::message_traits;

    bool full = true;
    full = full && static_cast<bool>(std::get<0>(t).getMessage());
    full = full && static_cast<bool>(std::get<1>(t).getMessage());
    full = full && (RealTypeCount::value > 2 ?
      static_cast<bool>(std::get<2>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 3 ?
      static_cast<bool>(std::get<3>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 4 ?
      static_cast<bool>(std::get<4>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 5 ?
      static_cast<bool>(std::get<5>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 6 ?
      static_cast<bool>(std::get<6>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 7 ?
      static_cast<bool>(std::get<7>(t).getMessage()) : true);
    full = full && (RealTypeCount::value > 8 ?
      static_cast<bool>(std::get<8>(t).getMessage()) : true);

    if (full) {
      parent_->signal(
        std::get<0>(t), std::get<1>(t), std::get<2>(t),
        std::get<3>(t), std::get<4>(t), std::get<5>(t),
        std::get<6>(t), std::get<7>(t), std::get<8>(t));

      last_signal_time_ = mt::TimeStamp<M0>::value(*std::get<0>(t).getMessage());

      tuples_.erase(last_signal_time_);

      clearOldTuples();
    }

    if (queue_size_ > 0) {
      while (tuples_.size() > queue_size_) {
        Tuple & t2 = tuples_.begin()->second;
        drop_signal_.call(
          std::get<0>(t2), std::get<1>(t2), std::get<2>(t2),
          std::get<3>(t2), std::get<4>(t2), std::get<5>(t2),
          std::get<6>(t2), std::get<7>(t2), std::get<8>(t2));
        tuples_.erase(tuples_.begin());
      }
    }
  }

  // assumes mutex_ is already locked
  void clearOldTuples()
  {
    typename M_TimeToTuple::iterator it = tuples_.begin();
    typename M_TimeToTuple::iterator end = tuples_.end();
    for (; it != end; ) {
      if (it->first <= last_signal_time_) {
        typename M_TimeToTuple::iterator old = it;
        ++it;

        Tuple & t = old->second;
        drop_signal_.call(
          std::get<0>(t), std::get<1>(t), std::get<2>(t),
          std::get<3>(t), std::get<4>(t), std::get<5>(t),
          std::get<6>(t), std::get<7>(t), std::get<8>(t));
        tuples_.erase(old);
      } else {
        // the map is sorted by time, so we can ignore anything after this if this one's time is ok
        break;
      }
    }
  }

private:
  Sync * parent_;

  uint32_t queue_size_;
  typedef std::map<rclcpp::Time, Tuple> M_TimeToTuple;
  M_TimeToTuple tuples_;
  rclcpp::Time last_signal_time_;

  Signal drop_signal_;

  std::mutex mutex_;
};

}  // namespace sync_policies
}  // namespace message_filters

#endif  // MESSAGE_FILTERS__SYNC_POLICIES__EXACT_TIME_HPP_