<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2016 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_DOF_VECTOR_HH
#define DUNE_GDT_LOCAL_DOF_VECTOR_HH

#include <dune/xt/common/vector.hh>
#include <dune/xt/la/container/vector-interface.hh>
#include <dune/xt/grid/bound-object.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/spaces/mapper/interfaces.hh>

namespace Dune {
namespace GDT {
namespace internal {

// forward, required for the default in the declaration of ConstLocalDofVector
template <class Vector, class GridView>
class ConstLocalDofVectorTraits;

} // namespace internal

// forwards, required for the traits
template <class Vector, class GridView, class Traits = internal::ConstLocalDofVectorTraits<Vector, GridView>>
class ConstLocalDofVector;

template <class Vector, class GridView>
class LocalDofVector;

namespace internal {

template <class Vector, class GridView>
class ConstLocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = ConstLocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
};

template <class Vector, class GridView>
class LocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = LocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
};

} // namespace internal

/**
 * \note Since all implementations of XT::LA::VectorInterface are assumed to be thread safe, no special care needs to be
 *       taken here.
 */
template <class Vector, class GridView, class Traits>
class ConstLocalDofVector : public XT::LA::VectorInterface<Traits>,
                            public XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<GridView>>
{

  using ThisType = ConstLocalDofVector<Vector, GridView, Traits>;
  using BaseType = XT::LA::VectorInterface<Traits>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;
  using typename XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<GridView>>::ElementType;

  ConstLocalDofVector(const MapperType& mapper, const VectorType& global_vector)
    : mapper_(mapper)
    , global_vector_(global_vector)
    , global_DoF_indices_(mapper_.max_local_size())
    , size_(0)
  {
  }

  ConstLocalDofVector(const ThisType& other) = default;
  ConstLocalDofVector(ThisType&& source) = default;

protected:
  void post_bind(const ElementType& ele)
  {
    mapper_.global_indices(ele, global_DoF_indices_);
    size_ = mapper_.local_size(ele);
    DUNE_THROW_IF(global_DoF_indices_.size() < size_,
                  Exceptions::dof_vector_error,
                  "This must not happen, the mapper is broken!");
  }

public:
  size_t size() const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    return size_;
  }

  void add_to_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  void set_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    // This is not optimal, but global_vector_.get_unchecked_ref is protected.
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

protected:
  friend BaseType; // To allow access to get_unchecked_ref().

  const MapperType& mapper_;

private:
  const VectorType& global_vector_;

protected:
  DynamicVector<size_t> global_DoF_indices_;
  size_t size_;

private:
  ScalarType dummy_scalar_to_silence_the_warning_;
}; // class ConstLocalDofVector

template <class Vector, class GridView>
class LocalDofVector : public ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>
{

  using ThisType = LocalDofVector<Vector, GridView>;
  using BaseType = ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;

  LocalDofVector(const MapperType& mapper, VectorType& global_vector)
    : BaseType(mapper, global_vector)
    , global_vector_(global_vector)
  {
  }

  LocalDofVector(const ThisType&) = default;
  LocalDofVector(ThisType&&) = default;

  void add_to_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    global_vector_.add_to_entry(global_DoF_indices_[ii], value);
  }

  void set_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    global_vector_.set_entry(global_DoF_indices_[ii], value);
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t ii)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t ii)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

private:
  // To allow access to get_unchecked_ref().
  friend XT::LA::VectorInterface<internal::LocalDofVectorTraits<Vector, GridView>>;

  using BaseType::mapper_;
  VectorType& global_vector_;
  using BaseType::global_DoF_indices_;
  using BaseType::size_;
}; // class LocalDofVector

} // namespace GDT
namespace XT {
namespace Common {

template <class Vector, class GridView, class Traits>
struct VectorAbstraction<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
    : public LA::internal::VectorAbstractionBase<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
{
};

template <class Vector, class GridView>
struct VectorAbstraction<GDT::LocalDofVector<Vector, GridView>>
    : public LA::internal::VectorAbstractionBase<GDT::LocalDofVector<Vector, GridView>>
{
};

} // namespace Common
} // namespace XT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_DOF_VECTOR_HH
<commit_msg>[local.dof-vector] add missing type to trais<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2016 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_DOF_VECTOR_HH
#define DUNE_GDT_LOCAL_DOF_VECTOR_HH

#include <dune/xt/common/vector.hh>
#include <dune/xt/la/container/vector-interface.hh>
#include <dune/xt/grid/bound-object.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/spaces/mapper/interfaces.hh>

namespace Dune {
namespace GDT {
namespace internal {

// forward, required for the default in the declaration of ConstLocalDofVector
template <class Vector, class GridView>
class ConstLocalDofVectorTraits;

} // namespace internal

// forwards, required for the traits
template <class Vector, class GridView, class Traits = internal::ConstLocalDofVectorTraits<Vector, GridView>>
class ConstLocalDofVector;

template <class Vector, class GridView>
class LocalDofVector;

namespace internal {

template <class Vector, class GridView>
class ConstLocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = ConstLocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
  using RealType = typename Vector::RealType;
};

template <class Vector, class GridView>
class LocalDofVectorTraits
{
  static_assert(XT::LA::is_vector<Vector>::value, "");

public:
  using derived_type = LocalDofVector<Vector, GridView>;
  using ScalarType = typename Vector::ScalarType;
  using RealType = typename Vector::RealType;
};

} // namespace internal

/**
 * \note Since all implementations of XT::LA::VectorInterface are assumed to be thread safe, no special care needs to be
 *       taken here.
 */
template <class Vector, class GridView, class Traits>
class ConstLocalDofVector : public XT::LA::VectorInterface<Traits>,
                            public XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<GridView>>
{

  using ThisType = ConstLocalDofVector<Vector, GridView, Traits>;
  using BaseType = XT::LA::VectorInterface<Traits>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;
  using typename XT::Grid::ElementBoundObject<XT::Grid::extract_entity_t<GridView>>::ElementType;

  ConstLocalDofVector(const MapperType& mapper, const VectorType& global_vector)
    : mapper_(mapper)
    , global_vector_(global_vector)
    , global_DoF_indices_(mapper_.max_local_size())
    , size_(0)
  {
  }

  ConstLocalDofVector(const ThisType& other) = default;
  ConstLocalDofVector(ThisType&& source) = default;

protected:
  void post_bind(const ElementType& ele)
  {
    mapper_.global_indices(ele, global_DoF_indices_);
    size_ = mapper_.local_size(ele);
    DUNE_THROW_IF(global_DoF_indices_.size() < size_,
                  Exceptions::dof_vector_error,
                  "This must not happen, the mapper is broken!");
  }

public:
  size_t size() const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    return size_;
  }

  void add_to_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  void set_entry(const size_t /*ii*/, const ScalarType& /*value*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    // This is not optimal, but global_vector_.get_unchecked_ref is protected.
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t /*ii*/)
  {
    DUNE_THROW(Exceptions::dof_vector_error, "a ConstLocalDofVector is not mutable!");
    return dummy_scalar_to_silence_the_warning_;
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

protected:
  friend BaseType; // To allow access to get_unchecked_ref().

  const MapperType& mapper_;

private:
  const VectorType& global_vector_;

protected:
  DynamicVector<size_t> global_DoF_indices_;
  size_t size_;

private:
  ScalarType dummy_scalar_to_silence_the_warning_;
}; // class ConstLocalDofVector

template <class Vector, class GridView>
class LocalDofVector : public ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>
{

  using ThisType = LocalDofVector<Vector, GridView>;
  using BaseType = ConstLocalDofVector<Vector, GridView, internal::LocalDofVectorTraits<Vector, GridView>>;

public:
  using typename BaseType::ScalarType;
  using VectorType = Vector;
  using MapperType = MapperInterface<GridView>;

  LocalDofVector(const MapperType& mapper, VectorType& global_vector)
    : BaseType(mapper, global_vector)
    , global_vector_(global_vector)
  {
  }

  LocalDofVector(const ThisType&) = default;
  LocalDofVector(ThisType&&) = default;

  void add_to_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    global_vector_.add_to_entry(global_DoF_indices_[ii], value);
  }

  void set_entry(const size_t ii, const ScalarType& value)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    global_vector_.set_entry(global_DoF_indices_[ii], value);
  }

  ScalarType get_entry(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_.get_entry(global_DoF_indices_[ii]);
  }

protected:
  ScalarType& get_unchecked_ref(const size_t ii)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& get_unchecked_ref(const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

public:
  ScalarType& operator[](const size_t ii)
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

  const ScalarType& operator[](const size_t ii) const
  {
    DUNE_THROW_IF(!this->is_bound_, Exceptions::not_bound_to_an_element_yet, "");
    assert(ii < size_);
    return global_vector_[global_DoF_indices_[ii]];
  }

private:
  // To allow access to get_unchecked_ref().
  friend XT::LA::VectorInterface<internal::LocalDofVectorTraits<Vector, GridView>>;

  using BaseType::mapper_;
  VectorType& global_vector_;
  using BaseType::global_DoF_indices_;
  using BaseType::size_;
}; // class LocalDofVector

} // namespace GDT
namespace XT {
namespace Common {

template <class Vector, class GridView, class Traits>
struct VectorAbstraction<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
    : public LA::internal::VectorAbstractionBase<GDT::ConstLocalDofVector<Vector, GridView, Traits>>
{
};

template <class Vector, class GridView>
struct VectorAbstraction<GDT::LocalDofVector<Vector, GridView>>
    : public LA::internal::VectorAbstractionBase<GDT::LocalDofVector<Vector, GridView>>
{
};

} // namespace Common
} // namespace XT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_DOF_VECTOR_HH
<|endoftext|>


<commit_before>#pragma once

#include "config.h"

#include "libpldm/platform.h"
#include "libpldm/states.h"

#include "common/utils.hpp"
#include "libpldmresponder/pdr.hpp"
#include "pdr_utils.hpp"
#include "pldmd/handler.hpp"

#include <cstdint>
#include <map>

namespace pldm
{
namespace responder
{
namespace platform_state_sensor
{

/** @brief Function to get the sensor state
 *
 *  @tparam[in] DBusInterface - DBus interface type
 *  @param[in] dBusIntf - The interface object of DBusInterface
 *  @param[in] stateToDbusValue - Map of DBus property State to attribute value
 *  @param[in] dbusMapping - The d-bus object
 *
 *  @return - Enumeration of SensorState
 */
template <class DBusInterface>
uint8_t getStateSensorEventState(
    const DBusInterface& dBusIntf,
    const std::map<pldm::responder::pdr_utils::State,
                   pldm::utils::PropertyValue>& stateToDbusValue,
    const pldm::utils::DBusMapping& dbusMapping)
{
    try
    {
        auto propertyValue = dBusIntf.getDbusPropertyVariant(
            dbusMapping.objectPath.c_str(), dbusMapping.propertyName.c_str(),
            dbusMapping.interface.c_str());

        for (const auto& stateValue : stateToDbusValue)
        {
            if (stateValue.second == propertyValue)
            {
                return stateValue.first;
            }
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << '\n';
    }

    return PLDM_SENSOR_UNKNOWN;
}

/** @brief Function to get the state sensor readings requested by pldm requester
 *
 *  @tparam[in] DBusInterface - DBus interface type
 *  @tparam[in] Handler - pldm::responder::platform::Handler
 *  @param[in] dBusIntf - The interface object of DBusInterface
 *  @param[in] handler - The interface object of
 *             pldm::responder::platform::Handler
 *  @param[in] sensorId - Sensor ID sent by the requester to act on
 *  @param[in] sensorRearmCnt - Each bit location in this field corresponds to a
 *              particular sensor within the state sensor
 *  @param[out] compSensorCnt - composite sensor count
 *  @param[out] stateField - The state field data for each of the states,
 *              equal to composite sensor count in number
 *  @return - Success or failure in setting the states. Returns failure in
 * terms of PLDM completion codes if atleast one state fails to be set
 */
template <class DBusInterface, class Handler>
int getStateSensorReadingsHandler(
    const DBusInterface& dBusIntf, Handler& handler, uint16_t sensorId,
    uint8_t sensorRearmCnt, uint8_t& compSensorCnt,
    std::vector<get_sensor_state_field>& stateField)
{
    using namespace pldm::responder::pdr;
    using namespace pldm::utils;

    pldm_state_sensor_pdr* pdr = nullptr;

    std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
        pldm_pdr_init(), pldm_pdr_destroy);
    pldm::responder::pdr_utils::Repo stateSensorPDRs(stateSensorPdrRepo.get());
    getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
    if (stateSensorPDRs.empty())
    {
        std::cerr << "Failed to get record by PDR type\n";
        return PLDM_PLATFORM_INVALID_SENSOR_ID;
    }

    pldm::responder::pdr_utils::PdrEntry pdrEntry{};
    auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
    while (pdrRecord)
    {
        pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
        assert(pdr != NULL);
        if (pdr->sensor_id != sensorId)
        {
            pdr = nullptr;
            pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
            continue;
        }

        compSensorCnt = pdr->composite_sensor_count;
        if (sensorRearmCnt > compSensorCnt)
        {
            std::cerr << "The requester sent wrong sensorRearm"
                      << " count for the sensor, SENSOR_ID=" << sensorId
                      << "SENSOR_REARM_COUNT=" << sensorRearmCnt << "\n";
            return PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE;
        }

        if (sensorRearmCnt == 0)
        {
            sensorRearmCnt = compSensorCnt;
            stateField.resize(sensorRearmCnt);
        }

        break;
    }

    if (!pdr)
    {
        return PLDM_PLATFORM_INVALID_SENSOR_ID;
    }

    int rc = PLDM_SUCCESS;
    try
    {
        const auto& [dbusMappings, dbusValMaps] = handler.getDbusObjMaps(
            sensorId, pldm::responder::pdr_utils::TypeId::PLDM_SENSOR_ID);

        stateField.clear();
        for (size_t i = 0; i < sensorRearmCnt; i++)
        {
            auto& dbusMapping = dbusMappings[i];

            uint8_t sensorEvent = getStateSensorEventState<DBusInterface>(
                dBusIntf, dbusValMaps[i], dbusMapping);

            uint8_t opState = PLDM_SENSOR_ENABLED;
            if (sensorEvent == PLDM_SENSOR_UNKNOWN)
            {
                opState = PLDM_SENSOR_UNAVAILABLE;
            }

            stateField.push_back({opState, PLDM_SENSOR_NORMAL,
                                  PLDM_SENSOR_UNKNOWN, sensorEvent});
        }
    }
    catch (const std::out_of_range& e)
    {
        std::cerr << "the sensorId does not exist. sensor id: " << sensorId
                  << e.what() << '\n';
        rc = PLDM_ERROR;
    }

    return rc;
}

} // namespace platform_state_sensor
} // namespace responder
} // namespace pldm
<commit_msg>responder : Improve tracing to debug problems<commit_after>#pragma once

#include "config.h"

#include "libpldm/platform.h"
#include "libpldm/states.h"

#include "common/utils.hpp"
#include "libpldmresponder/pdr.hpp"
#include "pdr_utils.hpp"
#include "pldmd/handler.hpp"

#include <cstdint>
#include <map>

namespace pldm
{
namespace responder
{
namespace platform_state_sensor
{

/** @brief Function to get the sensor state
 *
 *  @tparam[in] DBusInterface - DBus interface type
 *  @param[in] dBusIntf - The interface object of DBusInterface
 *  @param[in] stateToDbusValue - Map of DBus property State to attribute value
 *  @param[in] dbusMapping - The d-bus object
 *
 *  @return - Enumeration of SensorState
 */
template <class DBusInterface>
uint8_t getStateSensorEventState(
    const DBusInterface& dBusIntf,
    const std::map<pldm::responder::pdr_utils::State,
                   pldm::utils::PropertyValue>& stateToDbusValue,
    const pldm::utils::DBusMapping& dbusMapping)
{
    try
    {
        auto propertyValue = dBusIntf.getDbusPropertyVariant(
            dbusMapping.objectPath.c_str(), dbusMapping.propertyName.c_str(),
            dbusMapping.interface.c_str());

        for (const auto& stateValue : stateToDbusValue)
        {
            if (stateValue.second == propertyValue)
            {
                return stateValue.first;
            }
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << "Get StateSensor EventState from dbus Error, interface : "
                  << dbusMapping.objectPath.c_str()
                  << " ,exception : " << e.what() << '\n';
    }

    return PLDM_SENSOR_UNKNOWN;
}

/** @brief Function to get the state sensor readings requested by pldm requester
 *
 *  @tparam[in] DBusInterface - DBus interface type
 *  @tparam[in] Handler - pldm::responder::platform::Handler
 *  @param[in] dBusIntf - The interface object of DBusInterface
 *  @param[in] handler - The interface object of
 *             pldm::responder::platform::Handler
 *  @param[in] sensorId - Sensor ID sent by the requester to act on
 *  @param[in] sensorRearmCnt - Each bit location in this field corresponds to a
 *              particular sensor within the state sensor
 *  @param[out] compSensorCnt - composite sensor count
 *  @param[out] stateField - The state field data for each of the states,
 *              equal to composite sensor count in number
 *  @return - Success or failure in setting the states. Returns failure in
 * terms of PLDM completion codes if atleast one state fails to be set
 */
template <class DBusInterface, class Handler>
int getStateSensorReadingsHandler(
    const DBusInterface& dBusIntf, Handler& handler, uint16_t sensorId,
    uint8_t sensorRearmCnt, uint8_t& compSensorCnt,
    std::vector<get_sensor_state_field>& stateField)
{
    using namespace pldm::responder::pdr;
    using namespace pldm::utils;

    pldm_state_sensor_pdr* pdr = nullptr;

    std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> stateSensorPdrRepo(
        pldm_pdr_init(), pldm_pdr_destroy);
    pldm::responder::pdr_utils::Repo stateSensorPDRs(stateSensorPdrRepo.get());
    getRepoByType(handler.getRepo(), stateSensorPDRs, PLDM_STATE_SENSOR_PDR);
    if (stateSensorPDRs.empty())
    {
        std::cerr << "Failed to get record by PDR type\n";
        return PLDM_PLATFORM_INVALID_SENSOR_ID;
    }

    pldm::responder::pdr_utils::PdrEntry pdrEntry{};
    auto pdrRecord = stateSensorPDRs.getFirstRecord(pdrEntry);
    while (pdrRecord)
    {
        pdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdrEntry.data);
        assert(pdr != NULL);
        if (pdr->sensor_id != sensorId)
        {
            pdr = nullptr;
            pdrRecord = stateSensorPDRs.getNextRecord(pdrRecord, pdrEntry);
            continue;
        }

        compSensorCnt = pdr->composite_sensor_count;
        if (sensorRearmCnt > compSensorCnt)
        {
            std::cerr << "The requester sent wrong sensorRearm"
                      << " count for the sensor, SENSOR_ID=" << sensorId
                      << "SENSOR_REARM_COUNT=" << sensorRearmCnt << "\n";
            return PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE;
        }

        if (sensorRearmCnt == 0)
        {
            sensorRearmCnt = compSensorCnt;
            stateField.resize(sensorRearmCnt);
        }

        break;
    }

    if (!pdr)
    {
        return PLDM_PLATFORM_INVALID_SENSOR_ID;
    }

    int rc = PLDM_SUCCESS;
    try
    {
        const auto& [dbusMappings, dbusValMaps] = handler.getDbusObjMaps(
            sensorId, pldm::responder::pdr_utils::TypeId::PLDM_SENSOR_ID);

        stateField.clear();
        for (size_t i = 0; i < sensorRearmCnt; i++)
        {
            auto& dbusMapping = dbusMappings[i];

            uint8_t sensorEvent = getStateSensorEventState<DBusInterface>(
                dBusIntf, dbusValMaps[i], dbusMapping);

            uint8_t opState = PLDM_SENSOR_ENABLED;
            if (sensorEvent == PLDM_SENSOR_UNKNOWN)
            {
                opState = PLDM_SENSOR_UNAVAILABLE;
            }

            stateField.push_back({opState, PLDM_SENSOR_NORMAL,
                                  PLDM_SENSOR_UNKNOWN, sensorEvent});
        }
    }
    catch (const std::out_of_range& e)
    {
        std::cerr << "the sensorId does not exist. sensor id: " << sensorId
                  << e.what() << '\n';
        rc = PLDM_ERROR;
    }

    return rc;
}

} // namespace platform_state_sensor
} // namespace responder
} // namespace pldm
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>

#include "med/Process.hpp"
#include "med/Snapshot.hpp"
#include "med/MedException.hpp"
#include "med/MedCommon.hpp"
#include "med/MemOperator.hpp"

using namespace std;

Snapshot::Snapshot(SnapshotScanService* service) {
  if (service == NULL) {
    this->service = new SnapshotScanService();
  }
  else {
    this->service = service;
  }
  scanUnknown = false;
}
Snapshot::~Snapshot() {
  memoryBlocks.clear();
  delete this->service;
}

void Snapshot::save(Process* process) {
  this->process = process;

  if (!hasProcess()) {
    throw MedException("Process ID is empty");
  }
  memoryBlocks.clear();
  memoryBlocks = pullProcessMemory();

  scanUnknown = true;
}

vector<SnapshotScanPtr> Snapshot::compare(const ScanParser::OpType& opType, const ScanType& scanType) {
  vector<SnapshotScanPtr> result;
  if (opType == ScanParser::OpType::SnapshotSave) {
    cerr << "Filter should not use \"?\"" << endl;
    return result;
  }

  if (!hasProcess()) {
    throw MedException("Process ID is empty");
  }

  if (isUnknown()) {
    if (memoryBlocks.getSize() == 0) {
      throw MedException("Memory blocks is empty");
    }

    MemoryBlocks currentMemoryBlocks = pullProcessMemory();

    MemoryBlockPairs pairs = createMemoryBlockPairs(memoryBlocks, currentMemoryBlocks);

    result = filterUnknown(pairs, opType, scanType);
  }
  else {
    result = filter(opType, scanType);
  }
  return result;
}

MemoryBlockPairs Snapshot::createMemoryBlockPairs(MemoryBlocks prev, MemoryBlocks curr) {
  MemoryBlockPairs pairs;
  vector<MemoryBlock> prevBlocks = prev.getData();
  vector<MemoryBlock> currBlocks = curr.getData();
  for (size_t i = 0; i < prevBlocks.size(); i++) {
    for (size_t j = 0; j < currBlocks.size(); j++) {
      if (isBlockMatched(prevBlocks[i], currBlocks[j])) {
        MemoryBlockPair pair(currBlocks[j], prevBlocks[i]); // The current one compare to the previous one.
        pairs.push_back(pair);
        break;
      }
    }
  }
  return pairs;
}

bool Snapshot::isBlockMatched(MemoryBlock block1, MemoryBlock block2) {
  MemAddr firstAddress1 = block1.getAddress();
  MemAddr lastAddress1 = firstAddress1 + block1.getSize();
  MemAddr firstAddress2 = block2.getAddress();
  MemAddr lastAddress2 = firstAddress2 + block2.getSize();
  return (firstAddress1 <= firstAddress2 && lastAddress1 >= firstAddress2) ||
    (firstAddress1 <= lastAddress2 && lastAddress1 >= lastAddress2);
}

vector<SnapshotScanPtr> Snapshot::filterUnknown(const MemoryBlockPairs& pairs, const ScanParser::OpType& opType, const ScanType& scanType) {
  for (size_t i = 0; i < pairs.size(); i++) {
    vector<SnapshotScanPtr> found = comparePair(pairs[i], opType, scanType);
    scans.insert(scans.end(), found.begin(), found.end());
  }
  clearUnknown();
  return scans;
}

vector<SnapshotScanPtr> Snapshot::comparePair(const MemoryBlockPair& pair, const ScanParser::OpType& opType, const ScanType& scanType) {
  MemoryBlock curr = pair.first;
  MemoryBlock prev = pair.second;

  int offset = prev.getAddress() - curr.getAddress();
  int currOffset = 0;
  int prevOffset = 0;
  if (offset < 0) {
    prevOffset = offset;
  }
  else {
    currOffset = offset;
  }

  int currLength = curr.getSize();
  int prevLength = prev.getSize();

  int typeSize = scanTypeToSize(scanType);

  auto currData = curr.getData();
  auto prevData = prev.getData();

  vector<SnapshotScanPtr> scan;
  for (int i = 0; (i < currLength - typeSize + 1 - currOffset) && (i < prevLength - typeSize + 1 + prevOffset); i++) {

    bool result = memCompare(&currData[i + currOffset], &prevData[i - prevOffset], typeSize, opType);
    if (result) {
      // TODO: Should use shared_ptr, so that I need not to care to free it.
      SnapshotScanPtr matched = SnapshotScanPtr(new SnapshotScan(curr.getAddress() + i + currOffset, scanType));
      Bytes* copied = Bytes::newCopy(&currData[i + currOffset], typeSize);
      matched->setScannedValue(copied);
      scan.push_back(matched);
    }
  }
  return scan;
}

bool Snapshot::isUnknown() {
  return scanUnknown;
}

void Snapshot::clearUnknown() {
  scanUnknown = false;
  memoryBlocks.clear();
}

vector<SnapshotScanPtr> Snapshot::filter(const ScanParser::OpType& opType, const ScanType& scanType) {
  vector<SnapshotScanPtr> newScans;
  for (size_t i = 0; i < scans.size(); i++) {
    SnapshotScanPtr scan = scans[i];
    long pid = getProcessPid();
    if (service->compareScan(scan.get(), pid, opType, scanType)) {
      service->updateScannedValue(scan.get(), pid, scanType);
      newScans.push_back(scan);
    }
    else {
      scan->freeScannedValue();
    }
  }

  scans = newScans;
  return scans;
}

bool Snapshot::hasProcess() {
  return process->pid.length() != 0;
}

MemoryBlocks Snapshot::pullProcessMemory() {
  return process->pullMemory();
}

long Snapshot::getProcessPid() {
  return stol(process->pid);
}
<commit_msg>Fix create memory block pairs<commit_after>#include <iostream>
#include <cstdio>

#include "med/Process.hpp"
#include "med/Snapshot.hpp"
#include "med/MedException.hpp"
#include "med/MedCommon.hpp"
#include "med/MemOperator.hpp"

using namespace std;

Snapshot::Snapshot(SnapshotScanService* service) {
  if (service == NULL) {
    this->service = new SnapshotScanService();
  }
  else {
    this->service = service;
  }
  scanUnknown = false;
}
Snapshot::~Snapshot() {
  memoryBlocks.clear();
  delete this->service;
}

void Snapshot::save(Process* process) {
  this->process = process;

  if (!hasProcess()) {
    throw MedException("Process ID is empty");
  }
  memoryBlocks.clear();
  memoryBlocks = pullProcessMemory();

  scanUnknown = true;
}

vector<SnapshotScanPtr> Snapshot::compare(const ScanParser::OpType& opType, const ScanType& scanType) {
  vector<SnapshotScanPtr> result;
  if (opType == ScanParser::OpType::SnapshotSave) {
    cerr << "Filter should not use \"?\"" << endl;
    return result;
  }

  if (!hasProcess()) {
    throw MedException("Process ID is empty");
  }

  if (isUnknown()) {
    if (memoryBlocks.getSize() == 0) {
      throw MedException("Memory blocks is empty");
    }

    MemoryBlocks currentMemoryBlocks = pullProcessMemory();

    MemoryBlockPairs pairs = createMemoryBlockPairs(memoryBlocks, currentMemoryBlocks);

    result = filterUnknown(pairs, opType, scanType);
  }
  else {
    result = filter(opType, scanType);
  }
  return result;
}

MemoryBlockPairs Snapshot::createMemoryBlockPairs(MemoryBlocks prev, MemoryBlocks curr) {
  MemoryBlockPairs pairs;
  vector<MemoryBlock> prevBlocks = prev.getData();
  vector<MemoryBlock> currBlocks = curr.getData();
  for (size_t i = 0; i < prevBlocks.size(); i++) {
    for (size_t j = 0; j < currBlocks.size(); j++) {
      if (isBlockMatched(prevBlocks[i], currBlocks[j])) {
        MemoryBlockPair pair(currBlocks[j], prevBlocks[i]); // The current one compare to the previous one.
        pairs.push_back(pair);
        break;
      }
    }
  }
  return pairs;
}

bool Snapshot::isBlockMatched(MemoryBlock block1, MemoryBlock block2) {
  MemAddr firstAddress1 = block1.getAddress();
  MemAddr lastAddress1 = firstAddress1 + block1.getSize();
  MemAddr firstAddress2 = block2.getAddress();
  MemAddr lastAddress2 = firstAddress2 + block2.getSize();
  return (firstAddress1 <= firstAddress2 && lastAddress1 > firstAddress2) ||
    (firstAddress1 < lastAddress2 && lastAddress1 >= lastAddress2);
}

vector<SnapshotScanPtr> Snapshot::filterUnknown(const MemoryBlockPairs& pairs, const ScanParser::OpType& opType, const ScanType& scanType) {
  for (size_t i = 0; i < pairs.size(); i++) {
    vector<SnapshotScanPtr> found = comparePair(pairs[i], opType, scanType);
    scans.insert(scans.end(), found.begin(), found.end());
  }
  clearUnknown();
  return scans;
}

vector<SnapshotScanPtr> Snapshot::comparePair(const MemoryBlockPair& pair, const ScanParser::OpType& opType, const ScanType& scanType) {
  MemoryBlock curr = pair.first;
  MemoryBlock prev = pair.second;

  int offset = prev.getAddress() - curr.getAddress();
  int currOffset = 0;
  int prevOffset = 0;
  if (offset < 0) {
    prevOffset = offset;
  }
  else {
    currOffset = offset;
  }

  int currLength = curr.getSize();
  int prevLength = prev.getSize();

  int typeSize = scanTypeToSize(scanType);

  auto currData = curr.getData();
  auto prevData = prev.getData();

  vector<SnapshotScanPtr> scan;
  for (int i = 0; (i < currLength - typeSize + 1 - currOffset) && (i < prevLength - typeSize + 1 + prevOffset); i++) {

    bool result = memCompare(&currData[i + currOffset], &prevData[i - prevOffset], typeSize, opType);
    if (result) {
      // TODO: Should use shared_ptr, so that I need not to care to free it.
      SnapshotScanPtr matched = SnapshotScanPtr(new SnapshotScan(curr.getAddress() + i + currOffset, scanType));
      Bytes* copied = Bytes::newCopy(&currData[i + currOffset], typeSize);
      matched->setScannedValue(copied);
      scan.push_back(matched);
    }
  }
  return scan;
}

bool Snapshot::isUnknown() {
  return scanUnknown;
}

void Snapshot::clearUnknown() {
  scanUnknown = false;
  memoryBlocks.clear();
}

vector<SnapshotScanPtr> Snapshot::filter(const ScanParser::OpType& opType, const ScanType& scanType) {
  vector<SnapshotScanPtr> newScans;
  for (size_t i = 0; i < scans.size(); i++) {
    SnapshotScanPtr scan = scans[i];
    long pid = getProcessPid();
    if (service->compareScan(scan.get(), pid, opType, scanType)) {
      service->updateScannedValue(scan.get(), pid, scanType);
      newScans.push_back(scan);
    }
    else {
      scan->freeScannedValue();
    }
  }

  scans = newScans;
  return scans;
}

bool Snapshot::hasProcess() {
  return process->pid.length() != 0;
}

MemoryBlocks Snapshot::pullProcessMemory() {
  return process->pullMemory();
}

long Snapshot::getProcessPid() {
  return stol(process->pid);
}
<|endoftext|>


<commit_before>#include <qpdf/FileInputSource.hh>

#include <qpdf/QPDFExc.hh>
#include <qpdf/QUtil.hh>
#include <algorithm>
#include <string.h>

FileInputSource::FileInputSource() :
    close_file(false),
    file(nullptr)
{
}

FileInputSource::FileInputSource(char const* filename) :
    close_file(true),
    filename(filename),
    file(QUtil::safe_fopen(filename, "rb"))
{
}

FileInputSource::FileInputSource(
    char const* description, FILE* filep, bool close_file) :
    close_file(close_file),
    filename(description),
    file(filep)
{
}

FileInputSource::~FileInputSource()
{
    // Must be explicit and not inline -- see QPDF_DLL_CLASS in
    // README-maintainer
    if (this->file && this->close_file) {
        fclose(this->file);
    }
}

void
FileInputSource::setFilename(char const* filename)
{
    this->close_file = true;
    this->filename = filename;
    this->file = QUtil::safe_fopen(filename, "rb");
}

void
FileInputSource::setFile(char const* description, FILE* filep, bool close_file)
{
    this->filename = description;
    this->file = filep;
    this->seek(0, SEEK_SET);
}

qpdf_offset_t
FileInputSource::findAndSkipNextEOL()
{
    qpdf_offset_t result = 0;
    bool done = false;
    char buf[10240];
    while (!done) {
        qpdf_offset_t cur_offset = QUtil::tell(this->file);
        size_t len = this->read(buf, sizeof(buf));
        if (len == 0) {
            done = true;
            result = this->tell();
        } else {
            char* p1 = static_cast<char*>(memchr(buf, '\r', len));
            char* p2 = static_cast<char*>(memchr(buf, '\n', len));
            char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
            if (p) {
                result = cur_offset + (p - buf);
                // We found \r or \n.  Keep reading until we get past
                // \r and \n characters.
                this->seek(result + 1, SEEK_SET);
                char ch;
                while (!done) {
                    if (this->read(&ch, 1) == 0) {
                        done = true;
                    } else if (!((ch == '\r') || (ch == '\n'))) {
                        this->unreadCh(ch);
                        done = true;
                    }
                }
            }
        }
    }
    return result;
}

std::string const&
FileInputSource::getName() const
{
    return this->filename;
}

qpdf_offset_t
FileInputSource::tell()
{
    return QUtil::tell(this->file);
}

void
FileInputSource::seek(qpdf_offset_t offset, int whence)
{
    QUtil::os_wrapper(
        (std::string("seek to ") + this->filename + ", offset " +
         QUtil::int_to_string(offset) + " (" + QUtil::int_to_string(whence) +
         ")"),
        QUtil::seek(this->file, offset, whence));
}

void
FileInputSource::rewind()
{
    ::rewind(this->file);
}

size_t
FileInputSource::read(char* buffer, size_t length)
{
    this->last_offset = this->tell();
    size_t len = fread(buffer, 1, length, this->file);
    if (len == 0) {
        if (ferror(this->file)) {
            throw QPDFExc(
                qpdf_e_system,
                this->filename,
                "",
                this->last_offset,
                (std::string("read ") + QUtil::uint_to_string(length) +
                 " bytes"));
        } else if (length > 0) {
            this->seek(0, SEEK_END);
            this->last_offset = this->tell();
        }
    }
    return len;
}

void
FileInputSource::unreadCh(char ch)
{
    QUtil::os_wrapper(
        this->filename + ": unread character",
        ungetc(static_cast<unsigned char>(ch), this->file));
}
<commit_msg>Refactor FileInputSource::seek and FileInputSource::unreadCh<commit_after>#include <qpdf/FileInputSource.hh>

#include <qpdf/QPDFExc.hh>
#include <qpdf/QUtil.hh>
#include <algorithm>
#include <string.h>

FileInputSource::FileInputSource() :
    close_file(false),
    file(nullptr)
{
}

FileInputSource::FileInputSource(char const* filename) :
    close_file(true),
    filename(filename),
    file(QUtil::safe_fopen(filename, "rb"))
{
}

FileInputSource::FileInputSource(
    char const* description, FILE* filep, bool close_file) :
    close_file(close_file),
    filename(description),
    file(filep)
{
}

FileInputSource::~FileInputSource()
{
    // Must be explicit and not inline -- see QPDF_DLL_CLASS in
    // README-maintainer
    if (this->file && this->close_file) {
        fclose(this->file);
    }
}

void
FileInputSource::setFilename(char const* filename)
{
    this->close_file = true;
    this->filename = filename;
    this->file = QUtil::safe_fopen(filename, "rb");
}

void
FileInputSource::setFile(char const* description, FILE* filep, bool close_file)
{
    this->filename = description;
    this->file = filep;
    this->seek(0, SEEK_SET);
}

qpdf_offset_t
FileInputSource::findAndSkipNextEOL()
{
    qpdf_offset_t result = 0;
    bool done = false;
    char buf[10240];
    while (!done) {
        qpdf_offset_t cur_offset = QUtil::tell(this->file);
        size_t len = this->read(buf, sizeof(buf));
        if (len == 0) {
            done = true;
            result = this->tell();
        } else {
            char* p1 = static_cast<char*>(memchr(buf, '\r', len));
            char* p2 = static_cast<char*>(memchr(buf, '\n', len));
            char* p = (p1 && p2) ? std::min(p1, p2) : p1 ? p1 : p2;
            if (p) {
                result = cur_offset + (p - buf);
                // We found \r or \n.  Keep reading until we get past
                // \r and \n characters.
                this->seek(result + 1, SEEK_SET);
                char ch;
                while (!done) {
                    if (this->read(&ch, 1) == 0) {
                        done = true;
                    } else if (!((ch == '\r') || (ch == '\n'))) {
                        this->unreadCh(ch);
                        done = true;
                    }
                }
            }
        }
    }
    return result;
}

std::string const&
FileInputSource::getName() const
{
    return this->filename;
}

qpdf_offset_t
FileInputSource::tell()
{
    return QUtil::tell(this->file);
}

void
FileInputSource::seek(qpdf_offset_t offset, int whence)
{
    if (QUtil::seek(this->file, offset, whence) == -1) {
        QUtil::throw_system_error(
            std::string("seek to ") + this->filename + ", offset " +
            QUtil::int_to_string(offset) + " (" + QUtil::int_to_string(whence) +
            ")");
    }
}

void
FileInputSource::rewind()
{
    ::rewind(this->file);
}

size_t
FileInputSource::read(char* buffer, size_t length)
{
    this->last_offset = this->tell();
    size_t len = fread(buffer, 1, length, this->file);
    if (len == 0) {
        if (ferror(this->file)) {
            throw QPDFExc(
                qpdf_e_system,
                this->filename,
                "",
                this->last_offset,
                (std::string("read ") + QUtil::uint_to_string(length) +
                 " bytes"));
        } else if (length > 0) {
            this->seek(0, SEEK_END);
            this->last_offset = this->tell();
        }
    }
    return len;
}

void
FileInputSource::unreadCh(char ch)
{
    if (ungetc(static_cast<unsigned char>(ch), this->file) == -1) {
        QUtil::throw_system_error(this->filename + ": unread character");
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2011 by Ivan Safrin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "PolyPeer.h"
#include <string.h>
#include "PolyCore.h"
#include "PolyTimer.h"

using namespace Polycode;

PeerConnection::PeerConnection() {
	localSequence = 0;
	remoteSequence = 0;
	receivedPacketQueue.resize(32, 0);
}

PeerConnection::~PeerConnection() {

}

void PeerConnection::ackPackets(unsigned int ack) {
	std::vector<SentPacketEntry>::iterator it;
	for(it = reliablePacketQueue.begin(); it != reliablePacketQueue.end();) {
		if((*it).packet->header.sequence == ack) {
			delete (*it).packet;
			it = reliablePacketQueue.erase(it);
		} else {
			++it;
		}
	}
}

void PeerConnection::ackPacketsWithBitfield(unsigned int ack, unsigned int ackBitfield) {

	if(reliablePacketQueue.size() == 0) {
		return;
	}

	for(int i=0; i <32; i++) {
		if(ackBitfield & (1<<i)) {
			ackPackets(ack-i);
		}
	}
}

#if USE_THREADED_SOCKETS == 1
	Peer::Peer(unsigned int port) : Threaded() {
#else
	Peer::Peer(unsigned int port) : EventDispatcher() {
#endif
	socket = new Socket(port);
	socket->addEventListener(this, SocketEvent::EVENT_DATA_RECEIVED);

#if USE_THREADED_SOCKETS == 1
	CoreServices::getInstance()->getCore()->createThread(this);
	updateTimer = NULL;
#else
	updateTimer = new Timer(true, SOCKET_POLL_INTERVAL);
	updateTimer->addEventListener(this, Timer::EVENT_TRIGGER);
#endif

	reliableRetransmissionInverval = 1000;
}

Peer::~Peer() {
	delete socket;
}

PeerConnection *Peer::getPeerConnection(const Address &address) {
	for(int i=0; i < peerConnections.size(); i++) {
		if(peerConnections[i]->address == address) {
			return peerConnections[i];
		}
	}
	return NULL;
}

PeerConnection *Peer::addPeerConnection(const Address &address) {
	PeerConnection *newConnection = new PeerConnection();
	newConnection->address = address;
	peerConnections.push_back(newConnection);
	handlePeerConnection(newConnection);
	return newConnection;
}

void Peer::removePeerConnection(PeerConnection* connection) {
	for(unsigned int i=0;i<peerConnections.size();i++) {
		if(peerConnections[i] == connection) {
			peerConnections.erase(peerConnections.begin()+i);
		}
	}
}

void Peer::setReliableRetransmissionInterval(int interval) {
	reliableRetransmissionInverval = interval;
}

Packet *Peer::createPacket(const Address &target, char *data, unsigned int size, unsigned short type) {
	PeerConnection *connection = getPeerConnection(target);
	if(!connection)
		connection = addPeerConnection(target);
	Packet *packet = new Packet();
	packet->header.sequence = connection->localSequence;
	packet->header.headerHash = 20;
	packet->header.ack = connection->remoteSequence;
	packet->header.ackBitfield = 0;

	for(int i=0; i < 32; i++) {
		if(connection->receivedPacketQueue[31-i] == connection->remoteSequence-i) {
			packet->header.ackBitfield = (packet->header.ackBitfield & ~(1 << i)) | (1 << i);
		} else {
			packet->header.ackBitfield = (packet->header.ackBitfield & ~(1 << i)) | (0 << i);
		}
	}

	int sizeToCopy = size;
	if(size > MAX_PACKET_SIZE) {
		size = MAX_PACKET_SIZE;
	}

	packet->header.size = sizeToCopy;
	packet->header.type = type;

	if(size > 0)
		memcpy(packet->data, data, size);
	connection->localSequence++;
	return packet;
}

void Peer::sendReliableData(const Address &target, char *data, unsigned int size, unsigned short type) {
	PeerConnection *connection = getPeerConnection(target);
	if(!connection)
		connection = addPeerConnection(target);
	Packet *packet = createPacket(target, data, size, type);
	sendPacket(target, packet);

	SentPacketEntry entry;
	entry.packet = packet;
	entry.timestamp = CoreServices::getInstance()->getCore()->getTicks();
	connection->reliablePacketQueue.push_back(entry);

}

void Peer::sendDataToAll(char *data, unsigned int size, unsigned short type) {
	for(int i=0; i < peerConnections.size(); i++) {
		sendData(peerConnections[i]->address, data, size, type);
	}
}

void Peer::sendReliableDataToAll(char *data, unsigned int size, unsigned short type) {
	for(int i=0; i < peerConnections.size(); i++) {
		sendReliableData(peerConnections[i]->address, data, size, type);
	}
}

void Peer::sendData(const Address &target, char *data, unsigned int size, unsigned short type) {
	Packet *packet = createPacket(target, data, size, type);
	sendPacket(target, packet);
	delete packet;
}

void Peer::sendPacket(const Address &target, Packet *packet) {
	unsigned int packetSize = packet->header.size + sizeof(packet->header);
	socket->sendData(target, (char*)packet, packetSize);
}

bool Peer::checkPacketAcks(PeerConnection *connection, Packet *packet) {
	if(packet->header.sequence > connection->remoteSequence) {
		connection->remoteSequence = packet->header.sequence;
	} else {
		return false;
	}

	connection->receivedPacketQueue.push_back(packet->header.sequence);
	connection->receivedPacketQueue.pop_front();

	connection->ackPacketsWithBitfield(packet->header.ack, packet->header.ackBitfield);
	return true;
}

void Peer::handleEvent(Event *event) {
	if(event->getDispatcher() == socket) {
		SocketEvent *socketEvent = (SocketEvent*) event;
		switch(socketEvent->getEventCode()) {
			case SocketEvent::EVENT_DATA_RECEIVED:
				PeerConnection *connection = getPeerConnection(socketEvent->fromAddress);
				if(!connection)
					connection = addPeerConnection(socketEvent->fromAddress);
				if(checkPacketAcks(connection, (Packet*)socketEvent->data))
					handlePacket((Packet*)socketEvent->data, connection);
			break;
		}
	} else if(event->getDispatcher() == updateTimer) {
		updateThread();
	}
}

void Peer::updateReliableDataQueue() {
	for(int i=0; i < peerConnections.size(); i++) {
		for(int j=0; j < peerConnections[i]->reliablePacketQueue.size(); j++) {
			if(peerConnections[i]->reliablePacketQueue[j].timestamp < CoreServices::getInstance()->getCore()->getTicks() - reliableRetransmissionInverval) {
				peerConnections[i]->reliablePacketQueue[j].timestamp = CoreServices::getInstance()->getCore()->getTicks();

				Packet *oldPacket = peerConnections[i]->reliablePacketQueue[j].packet;
				peerConnections[i]->reliablePacketQueue[j].packet = createPacket(peerConnections[i]->address, oldPacket->data, oldPacket->header.size, oldPacket->header.type);
				delete oldPacket;

				sendPacket(peerConnections[i]->address, peerConnections[i]->reliablePacketQueue[j].packet);
			}
		}
	}
}

void Peer::updateThread() {
	updateReliableDataQueue();

	int received = 1;
	while( received > 0) {
		received = socket->receiveData();
	}
}
<commit_msg>Fixed initial peer packet not getting processed<commit_after>/*
Copyright (C) 2011 by Ivan Safrin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "PolyPeer.h"
#include <string.h>
#include "PolyCore.h"
#include "PolyTimer.h"

using namespace Polycode;

PeerConnection::PeerConnection() {
	localSequence = 0;
	remoteSequence = 0;
	receivedPacketQueue.resize(32, 0);
}

PeerConnection::~PeerConnection() {

}

void PeerConnection::ackPackets(unsigned int ack) {
	std::vector<SentPacketEntry>::iterator it;
	for(it = reliablePacketQueue.begin(); it != reliablePacketQueue.end();) {
		if((*it).packet->header.sequence == ack) {
			delete (*it).packet;
			it = reliablePacketQueue.erase(it);
		} else {
			++it;
		}
	}
}

void PeerConnection::ackPacketsWithBitfield(unsigned int ack, unsigned int ackBitfield) {

	if(reliablePacketQueue.size() == 0) {
		return;
	}

	for(int i=0; i <32; i++) {
		if(ackBitfield & (1<<i)) {
			ackPackets(ack-i);
		}
	}
}

#if USE_THREADED_SOCKETS == 1
	Peer::Peer(unsigned int port) : Threaded() {
#else
	Peer::Peer(unsigned int port) : EventDispatcher() {
#endif
	socket = new Socket(port);
	socket->addEventListener(this, SocketEvent::EVENT_DATA_RECEIVED);

#if USE_THREADED_SOCKETS == 1
	CoreServices::getInstance()->getCore()->createThread(this);
	updateTimer = NULL;
#else
	updateTimer = new Timer(true, SOCKET_POLL_INTERVAL);
	updateTimer->addEventListener(this, Timer::EVENT_TRIGGER);
#endif

	reliableRetransmissionInverval = 1000;
}

Peer::~Peer() {
	delete socket;
}

PeerConnection *Peer::getPeerConnection(const Address &address) {
	for(int i=0; i < peerConnections.size(); i++) {
		if(peerConnections[i]->address == address) {
			return peerConnections[i];
		}
	}
	return NULL;
}

PeerConnection *Peer::addPeerConnection(const Address &address) {
	PeerConnection *newConnection = new PeerConnection();
	newConnection->address = address;
	peerConnections.push_back(newConnection);
	handlePeerConnection(newConnection);
	return newConnection;
}

void Peer::removePeerConnection(PeerConnection* connection) {
	for(unsigned int i=0;i<peerConnections.size();i++) {
		if(peerConnections[i] == connection) {
			peerConnections.erase(peerConnections.begin()+i);
		}
	}
}

void Peer::setReliableRetransmissionInterval(int interval) {
	reliableRetransmissionInverval = interval;
}

Packet *Peer::createPacket(const Address &target, char *data, unsigned int size, unsigned short type) {
	PeerConnection *connection = getPeerConnection(target);
	if(!connection)
		connection = addPeerConnection(target);
	Packet *packet = new Packet();
	packet->header.sequence = connection->localSequence;
	packet->header.headerHash = 20;
	packet->header.ack = connection->remoteSequence;
	packet->header.ackBitfield = 0;

	for(int i=0; i < 32; i++) {
		if(connection->receivedPacketQueue[31-i] == connection->remoteSequence-i) {
			packet->header.ackBitfield = (packet->header.ackBitfield & ~(1 << i)) | (1 << i);
		} else {
			packet->header.ackBitfield = (packet->header.ackBitfield & ~(1 << i)) | (0 << i);
		}
	}

	int sizeToCopy = size;
	if(size > MAX_PACKET_SIZE) {
		size = MAX_PACKET_SIZE;
	}

	packet->header.size = sizeToCopy;
	packet->header.type = type;

	if(size > 0)
		memcpy(packet->data, data, size);
	connection->localSequence++;
	return packet;
}

void Peer::sendReliableData(const Address &target, char *data, unsigned int size, unsigned short type) {
	PeerConnection *connection = getPeerConnection(target);
	if(!connection)
		connection = addPeerConnection(target);
	Packet *packet = createPacket(target, data, size, type);
	sendPacket(target, packet);

	SentPacketEntry entry;
	entry.packet = packet;
	entry.timestamp = CoreServices::getInstance()->getCore()->getTicks();
	connection->reliablePacketQueue.push_back(entry);

}

void Peer::sendDataToAll(char *data, unsigned int size, unsigned short type) {
	for(int i=0; i < peerConnections.size(); i++) {
		sendData(peerConnections[i]->address, data, size, type);
	}
}

void Peer::sendReliableDataToAll(char *data, unsigned int size, unsigned short type) {
	for(int i=0; i < peerConnections.size(); i++) {
		sendReliableData(peerConnections[i]->address, data, size, type);
	}
}

void Peer::sendData(const Address &target, char *data, unsigned int size, unsigned short type) {
	Packet *packet = createPacket(target, data, size, type);
	sendPacket(target, packet);
	delete packet;
}

void Peer::sendPacket(const Address &target, Packet *packet) {
	unsigned int packetSize = packet->header.size + sizeof(packet->header);
	socket->sendData(target, (char*)packet, packetSize);
}

bool Peer::checkPacketAcks(PeerConnection *connection, Packet *packet) {
	if(packet->header.sequence > connection->remoteSequence || connection->remoteSequence == 0) {
		connection->remoteSequence = packet->header.sequence;
	} else {
		return false;
	}

	connection->receivedPacketQueue.push_back(packet->header.sequence);
	connection->receivedPacketQueue.pop_front();

	connection->ackPacketsWithBitfield(packet->header.ack, packet->header.ackBitfield);
	return true;
}

void Peer::handleEvent(Event *event) {
	if(event->getDispatcher() == socket) {
		SocketEvent *socketEvent = (SocketEvent*) event;
		switch(socketEvent->getEventCode()) {
			case SocketEvent::EVENT_DATA_RECEIVED:
				PeerConnection *connection = getPeerConnection(socketEvent->fromAddress);
				if(!connection)
					connection = addPeerConnection(socketEvent->fromAddress);
				if(checkPacketAcks(connection, (Packet*)socketEvent->data))
					handlePacket((Packet*)socketEvent->data, connection);
			break;
		}
	} else if(event->getDispatcher() == updateTimer) {
		updateThread();
	}
}

void Peer::updateReliableDataQueue() {
	for(int i=0; i < peerConnections.size(); i++) {
		for(int j=0; j < peerConnections[i]->reliablePacketQueue.size(); j++) {
			if(peerConnections[i]->reliablePacketQueue[j].timestamp < CoreServices::getInstance()->getCore()->getTicks() - reliableRetransmissionInverval) {
				peerConnections[i]->reliablePacketQueue[j].timestamp = CoreServices::getInstance()->getCore()->getTicks();

				Packet *oldPacket = peerConnections[i]->reliablePacketQueue[j].packet;
				peerConnections[i]->reliablePacketQueue[j].packet = createPacket(peerConnections[i]->address, oldPacket->data, oldPacket->header.size, oldPacket->header.type);
				delete oldPacket;

				sendPacket(peerConnections[i]->address, peerConnections[i]->reliablePacketQueue[j].packet);
			}
		}
	}
}

void Peer::updateThread() {
	updateReliableDataQueue();

	int received = 1;
	while( received > 0) {
		received = socket->receiveData();
	}
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/prediction/container/obstacles/obstacles_container.h"

#include <utility>

#include "modules/common/math/math_utils.h"
#include "modules/prediction/common/feature_output.h"
#include "modules/prediction/common/junction_analyzer.h"
#include "modules/prediction/common/prediction_gflags.h"
#include "modules/prediction/common/prediction_system_gflags.h"
#include "modules/prediction/container/obstacles/obstacle_clusters.h"

namespace apollo {
namespace prediction {

using apollo::perception::PerceptionObstacle;
using apollo::perception::PerceptionObstacles;
using ::google::protobuf::Message;

ObstaclesContainer::ObstaclesContainer()
    : obstacles_(FLAGS_max_num_obstacles) {}

void ObstaclesContainer::Insert(const Message& message) {
  curr_frame_predictable_obstacle_ids_.clear();
  PerceptionObstacles perception_obstacles;
  perception_obstacles.CopyFrom(
      dynamic_cast<const PerceptionObstacles&>(message));

  // Update the timestamp_ of the ObstaclesContainer
  double timestamp = 0.0;
  if (perception_obstacles.has_header() &&
      perception_obstacles.header().has_timestamp_sec()) {
    timestamp = perception_obstacles.header().timestamp_sec();
  }
  if (std::fabs(timestamp - timestamp_) > FLAGS_replay_timestamp_gap) {
    obstacles_.Clear();
    ADEBUG << "Replay mode is enabled.";
  } else if (timestamp <= timestamp_) {
    AERROR << "Invalid timestamp curr [" << timestamp << "] v.s. prev ["
           << timestamp_ << "].";
    return;
  }
  if (FLAGS_prediction_offline_mode) {
    if (std::fabs(timestamp - timestamp_) > FLAGS_replay_timestamp_gap ||
        FeatureOutput::Size() > FLAGS_max_num_dump_feature) {
      FeatureOutput::Write();
    }
  }
  timestamp_ = timestamp;
  ADEBUG << "Current timestamp is [" << timestamp_ << "]";

  // Set up the ObstacleClusters:
  // 1. Initialize ObstacleClusters
  ObstacleClusters::Init();
  // 2. Insert the Obstacles one by one
  for (const PerceptionObstacle& perception_obstacle :
       perception_obstacles.perception_obstacle()) {
    ADEBUG << "Perception obstacle [" << perception_obstacle.id() << "] "
           << "was detected";
    InsertPerceptionObstacle(perception_obstacle, timestamp_);
    ADEBUG << "Perception obstacle [" << perception_obstacle.id() << "] "
           << "was inserted";
  }
  // 3. Sort the Obstacles
  ObstacleClusters::SortObstacles();
  // 4. Deduct the NearbyObstacles info. from the sorted Obstacles
  for (const PerceptionObstacle& perception_obstacle :
       perception_obstacles.perception_obstacle()) {
    if (IsPredictable(perception_obstacle)) {
      continue;
    }
    Obstacle* obstacle_ptr = GetObstacle(perception_obstacle.id());
    if (obstacle_ptr == nullptr) {
      continue;
    }
    obstacle_ptr->SetNearbyObstacles();
  }
}

Obstacle* ObstaclesContainer::GetObstacle(const int id) {
  return obstacles_.GetSilently(id);
}

const std::vector<int>&
ObstaclesContainer::GetCurrentFramePredictableObstacleIds() const {
  return curr_frame_predictable_obstacle_ids_;
}

void ObstaclesContainer::Clear() {
  obstacles_.Clear();
  timestamp_ = -1.0;
}

void ObstaclesContainer::InsertPerceptionObstacle(
    const PerceptionObstacle& perception_obstacle, const double timestamp) {
  // Sanity checks.
  const int id = perception_obstacle.id();
  if (id < -1) {
    AERROR << "Invalid ID [" << id << "]";
    return;
  }
  if (!IsPredictable(perception_obstacle)) {
    ADEBUG << "Perception obstacle [" << id << "] is not predictable.";
    return;
  }

  // Insert the obstacle and also update the LRUCache.
  curr_frame_predictable_obstacle_ids_.push_back(id);
  Obstacle* obstacle_ptr = obstacles_.Get(id);
  if (obstacle_ptr != nullptr) {
    obstacle_ptr->Insert(perception_obstacle, timestamp);
    ADEBUG << "Refresh obstacle [" << id << "]";
  } else {
    Obstacle obstacle;
    obstacle.Insert(perception_obstacle, timestamp);
    obstacles_.Put(id, std::move(obstacle));
    ADEBUG << "Insert obstacle [" << id << "]";
  }
}

void ObstaclesContainer::BuildLaneGraph() {
  for (const int id : curr_frame_predictable_obstacle_ids_) {
    Obstacle* obstacle_ptr = obstacles_.GetSilently(id);
    if (obstacle_ptr == nullptr) {
      AERROR << "Null obstacle found.";
      continue;
    }
    if (obstacle_ptr->ToIgnore()) {
      ADEBUG << "Ignore obstacle [" << obstacle_ptr->id() << "]";
      continue;
    }
    obstacle_ptr->BuildLaneGraph();
  }
}

void ObstaclesContainer::BuildJunctionFeature() {
  for (const int id : curr_frame_predictable_obstacle_ids_) {
    Obstacle* obstacle_ptr = obstacles_.GetSilently(id);
    if (obstacle_ptr == nullptr) {
      AERROR << "Null obstacle found.";
      continue;
    }
    if (obstacle_ptr->ToIgnore()) {
      ADEBUG << "Ignore obstacle [" << obstacle_ptr->id() << "]";
      continue;
    }
    const std::string& junction_id = JunctionAnalyzer::GetJunctionId();
    if (obstacle_ptr->IsInJunction(junction_id)) {
      ADEBUG << "Build junction feature for obstacle [" << obstacle_ptr->id()
            << "] in junction [" << junction_id << "]";
      obstacle_ptr->BuildJunctionFeature();
    }
  }
}

bool ObstaclesContainer::IsPredictable(
    const PerceptionObstacle& perception_obstacle) {
  if (!perception_obstacle.has_type() ||
      perception_obstacle.type() == PerceptionObstacle::UNKNOWN_UNMOVABLE) {
    return false;
  }
  return true;
}

}  // namespace prediction
}  // namespace apollo
<commit_msg>Prediction: added some comments.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/prediction/container/obstacles/obstacles_container.h"

#include <utility>

#include "modules/common/math/math_utils.h"
#include "modules/prediction/common/feature_output.h"
#include "modules/prediction/common/junction_analyzer.h"
#include "modules/prediction/common/prediction_gflags.h"
#include "modules/prediction/common/prediction_system_gflags.h"
#include "modules/prediction/container/obstacles/obstacle_clusters.h"

namespace apollo {
namespace prediction {

using apollo::perception::PerceptionObstacle;
using apollo::perception::PerceptionObstacles;
using ::google::protobuf::Message;

ObstaclesContainer::ObstaclesContainer()
    : obstacles_(FLAGS_max_num_obstacles) {}

// This is called by Perception module at every frame to insert all
// detected obstacles.
void ObstaclesContainer::Insert(const ::google::protobuf::Message& message) {
  // Clean up the history and get the PerceptionObstacles
  curr_frame_predictable_obstacle_ids_.clear();
  PerceptionObstacles perception_obstacles;
  perception_obstacles.CopyFrom(
      dynamic_cast<const PerceptionObstacles&>(message));

  // Get the new timestamp and update it in the class
  // - If it's more than 10sec later than the most recent one, clear the
  //   obstacle history.
  // - If it's not a valid time (earlier than history), continue.
  // - Also consider the offline_mode case.

  double timestamp = 0.0;
  if (perception_obstacles.has_header() &&
      perception_obstacles.header().has_timestamp_sec()) {
    timestamp = perception_obstacles.header().timestamp_sec();
  }
  if (std::fabs(timestamp - timestamp_) > FLAGS_replay_timestamp_gap) {
    obstacles_.Clear();
    ADEBUG << "Replay mode is enabled.";
  } else if (timestamp <= timestamp_) {
    AERROR << "Invalid timestamp curr [" << timestamp << "] v.s. prev ["
           << timestamp_ << "].";
    return;
  }
  if (FLAGS_prediction_offline_mode) {
    if (std::fabs(timestamp - timestamp_) > FLAGS_replay_timestamp_gap ||
        FeatureOutput::Size() > FLAGS_max_num_dump_feature) {
      FeatureOutput::Write();
    }
  }
  timestamp_ = timestamp;
  ADEBUG << "Current timestamp is [" << timestamp_ << "]";

  // Set up the ObstacleClusters:
  // 1. Initialize ObstacleClusters
  ObstacleClusters::Init();
  // 2. Insert the Obstacles one by one
  for (const PerceptionObstacle& perception_obstacle :
       perception_obstacles.perception_obstacle()) {
    ADEBUG << "Perception obstacle [" << perception_obstacle.id() << "] "
           << "was detected";
    InsertPerceptionObstacle(perception_obstacle, timestamp_);
    ADEBUG << "Perception obstacle [" << perception_obstacle.id() << "] "
           << "was inserted";
  }
  // 3. Sort the Obstacles
  ObstacleClusters::SortObstacles();
  // 4. Deduct the NearbyObstacles info. from the sorted Obstacles
  for (const PerceptionObstacle& perception_obstacle :
       perception_obstacles.perception_obstacle()) {
    if (IsPredictable(perception_obstacle)) {
      continue;
    }
    Obstacle* obstacle_ptr = GetObstacle(perception_obstacle.id());
    if (obstacle_ptr == nullptr) {
      continue;
    }
    obstacle_ptr->SetNearbyObstacles();
  }
}

Obstacle* ObstaclesContainer::GetObstacle(const int id) {
  return obstacles_.GetSilently(id);
}

const std::vector<int>&
ObstaclesContainer::GetCurrentFramePredictableObstacleIds() const {
  return curr_frame_predictable_obstacle_ids_;
}

void ObstaclesContainer::Clear() {
  obstacles_.Clear();
  timestamp_ = -1.0;
}

void ObstaclesContainer::InsertPerceptionObstacle(
    const PerceptionObstacle& perception_obstacle, const double timestamp) {
  // Sanity checks.
  const int id = perception_obstacle.id();
  if (id < -1) {
    AERROR << "Invalid ID [" << id << "]";
    return;
  }
  if (!IsPredictable(perception_obstacle)) {
    ADEBUG << "Perception obstacle [" << id << "] is not predictable.";
    return;
  }

  // Insert the obstacle and also update the LRUCache.
  curr_frame_predictable_obstacle_ids_.push_back(id);
  Obstacle* obstacle_ptr = obstacles_.Get(id);
  if (obstacle_ptr != nullptr) {
    obstacle_ptr->Insert(perception_obstacle, timestamp);
    ADEBUG << "Refresh obstacle [" << id << "]";
  } else {
    Obstacle obstacle;
    obstacle.Insert(perception_obstacle, timestamp);
    obstacles_.Put(id, std::move(obstacle));
    ADEBUG << "Insert obstacle [" << id << "]";
  }
}

void ObstaclesContainer::BuildLaneGraph() {
  // Go through every obstacle in the current frame, after some
  // sanity checks, build lane graph for non-junction cases.
  for (const int id : curr_frame_predictable_obstacle_ids_) {
    Obstacle* obstacle_ptr = obstacles_.GetSilently(id);
    if (obstacle_ptr == nullptr) {
      AERROR << "Null obstacle found.";
      continue;
    }
    if (obstacle_ptr->ToIgnore()) {
      ADEBUG << "Ignore obstacle [" << obstacle_ptr->id() << "]";
      continue;
    }
    obstacle_ptr->BuildLaneGraph();
  }
}

void ObstaclesContainer::BuildJunctionFeature() {
  // Go through every obstacle in the current frame, after some
  // sanit checks, build junction features for those that are in junction.
  for (const int id : curr_frame_predictable_obstacle_ids_) {
    Obstacle* obstacle_ptr = obstacles_.GetSilently(id);
    if (obstacle_ptr == nullptr) {
      AERROR << "Null obstacle found.";
      continue;
    }
    if (obstacle_ptr->ToIgnore()) {
      ADEBUG << "Ignore obstacle [" << obstacle_ptr->id() << "]";
      continue;
    }
    const std::string& junction_id = JunctionAnalyzer::GetJunctionId();
    if (obstacle_ptr->IsInJunction(junction_id)) {
      ADEBUG << "Build junction feature for obstacle [" << obstacle_ptr->id()
            << "] in junction [" << junction_id << "]";
      obstacle_ptr->BuildJunctionFeature();
    }
  }
}

bool ObstaclesContainer::IsPredictable(
    const PerceptionObstacle& perception_obstacle) {
  if (!perception_obstacle.has_type() ||
      perception_obstacle.type() == PerceptionObstacle::UNKNOWN_UNMOVABLE) {
    return false;
  }
  return true;
}

}  // namespace prediction
}  // namespace apollo
<|endoftext|>


<commit_before>/*
 * This file is part of the LibreOffice project.
 *
 * Based on LLVM/Clang.
 *
 * This file is distributed under the University of Illinois Open Source
 * License. See LICENSE.TXT for details.
 *
 */

#ifndef PLUGIN_H
#define PLUGIN_H

#include <config_clang.h>

#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 2
#include <clang/Rewrite/Rewriter.h>
#else
#include <clang/Rewrite/Core/Rewriter.h>
#endif

using namespace clang;
using namespace llvm;
using namespace std;

namespace loplugin
{

/**
    Base class for plugins.

    If you want to create a non-rewriter action, inherit from this class. Remember to also
    use Plugin::Registration.
*/
class Plugin
    {
    public:
        explicit Plugin( ASTContext& context );
        virtual ~Plugin();
        virtual void run() = 0;
        template< typename T > class Registration;
        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation());
        static DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message,
            ASTContext& context, SourceLocation loc = SourceLocation());
    protected:
        bool ignoreLocation( SourceLocation loc );
        bool ignoreLocation( const Decl* decl );
        bool ignoreLocation( const Stmt* stmt );
        ASTContext& context;
    private:
        static void registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter );
        template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter );
        enum { isRewriter = false };
    };

/**
    Base class for rewriter plugins.

    Remember to also use Plugin::Registration.
*/
class RewritePlugin
    : public Plugin
    {
    public:
        explicit RewritePlugin( ASTContext& context, Rewriter& rewriter );
    protected:
        // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
        enum RemoveLineIfEmpty_t { RemoveLineIfEmpty };
        // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
        // and the trailing semicolor (is not part of the AST element range itself).
        // The trailing semicolon must be present.
        enum RemoveWholeStatement_t { RemoveWholeStatement };
        enum RemoveLineIfEmptyAndWholeStatement_t { RemoveLineIfEmptyAndWholeStatement };
        // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
        friend RemoveLineIfEmptyAndWholeStatement_t operator|( RemoveLineIfEmpty_t, RemoveWholeStatement_t )
            { return RemoveLineIfEmptyAndWholeStatement; }
        struct RewriteOptions
            : public Rewriter::RewriteOptions
            {
            RewriteOptions() : RemoveWholeStatement( false ) {} // default
            RewriteOptions( RemoveLineIfEmpty_t ) : RemoveWholeStatement( false ) { RemoveLineIfEmpty = true; }
            RewriteOptions( RemoveWholeStatement_t ) : RemoveWholeStatement( true ) {}
            RewriteOptions( RemoveLineIfEmptyAndWholeStatement_t ) : RemoveWholeStatement( true ) { RemoveLineIfEmpty = true; }
            bool RemoveWholeStatement;
            };
        // These following insert/remove/replaceText functions map to functions
        // in clang::Rewriter, with these differences:
        // - they (more intuitively) return false on failure rather than true
        // - they report a warning when the change cannot be done
        // - There is RemoveWholeStatement to also remove the trailing semicolon when removing (must be there)
        //   and al preceding whitespace.
        bool insertText( SourceLocation Loc, StringRef Str,
            bool InsertAfter = true, bool indentNewLines = false );
        bool insertTextAfter( SourceLocation Loc, StringRef Str );
        bool insertTextAfterToken( SourceLocation Loc, StringRef Str );
        bool insertTextBefore( SourceLocation Loc, StringRef Str );
        bool removeText( SourceLocation Start, unsigned Length, RewriteOptions opts = RewriteOptions());
        // CharSourceRange not supported, unless really needed, as it makes RemoveSemicolon more complicated
        //bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions());
        bool removeText( SourceRange range, RewriteOptions opts = RewriteOptions());
        bool replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr );
        bool replaceText( SourceRange range, StringRef NewStr );
        bool replaceText( SourceRange range, SourceRange replacementRange );
        Rewriter& rewriter;
    private:
        template< typename T > friend class Plugin::Registration;
        template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter );
        enum { isRewriter = true };
        bool reportEditFailure( SourceLocation loc );
        bool adjustForWholeStatement( SourceRange* range );
    };

/**
    Plugin registration helper.

    If you create a new helper class, create also an instance of this class to automatically register it.
    The passed argument is name of the plugin, used for explicitly invoking rewriter plugins
    (it is ignored for non-rewriter plugins).

    @code
    static Plugin::Registration< NameOfClass > X( "nameofclass" );
    @endcode
*/
template< typename T >
class Plugin::Registration
    {
    public:
        Registration( const char* optionName );
    };

class RegistrationCreate
    {
    public:
        template< typename T, bool > static T* create( ASTContext& context, Rewriter& rewriter );
    };

/////

inline
Plugin::~Plugin()
    {
    }

inline
bool Plugin::ignoreLocation( const Decl* decl )
    {
    return ignoreLocation( decl->getLocation());
    }

inline
bool Plugin::ignoreLocation( const Stmt* stmt )
    {
    return ignoreLocation( stmt->getLocStart());
    }

template< typename T >
Plugin* Plugin::createHelper( ASTContext& context, Rewriter& )
    {
    return new T( context );
    }

template< typename T >
Plugin* RewritePlugin::createHelper( ASTContext& context, Rewriter& rewriter )
    {
    return new T( context, rewriter );
    }

template< typename T >
inline
Plugin::Registration< T >::Registration( const char* optionName )
    {
    registerPlugin( &T::template createHelper< T >, optionName, T::isRewriter );
    }

} // namespace

#endif // COMPILEPLUGIN_H
<commit_msg>Fixed compilation error of Clang plugins on Ubuntu/Mint<commit_after>/*
 * This file is part of the LibreOffice project.
 *
 * Based on LLVM/Clang.
 *
 * This file is distributed under the University of Illinois Open Source
 * License. See LICENSE.TXT for details.
 *
 */

#ifndef PLUGIN_H
#define PLUGIN_H

#include <config_clang.h>

#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/SourceManager.h>

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 2
#include <clang/Rewrite/Rewriter.h>
#else
#include <clang/Rewrite/Core/Rewriter.h>
#endif

using namespace clang;
using namespace llvm;
using namespace std;

namespace loplugin
{

/**
    Base class for plugins.

    If you want to create a non-rewriter action, inherit from this class. Remember to also
    use Plugin::Registration.
*/
class Plugin
    {
    public:
        explicit Plugin( ASTContext& context );
        virtual ~Plugin();
        virtual void run() = 0;
        template< typename T > class Registration;
        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc = SourceLocation());
        static DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message,
            ASTContext& context, SourceLocation loc = SourceLocation());
    protected:
        bool ignoreLocation( SourceLocation loc );
        bool ignoreLocation( const Decl* decl );
        bool ignoreLocation( const Stmt* stmt );
        ASTContext& context;
    private:
        static void registerPlugin( Plugin* (*create)( ASTContext&, Rewriter& ), const char* optionName, bool isRewriter );
        template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter );
        enum { isRewriter = false };
    };

/**
    Base class for rewriter plugins.

    Remember to also use Plugin::Registration.
*/
class RewritePlugin
    : public Plugin
    {
    public:
        explicit RewritePlugin( ASTContext& context, Rewriter& rewriter );
    protected:
        // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
        enum RemoveLineIfEmpty_t { RemoveLineIfEmpty };
        // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
        // and the trailing semicolor (is not part of the AST element range itself).
        // The trailing semicolon must be present.
        enum RemoveWholeStatement_t { RemoveWholeStatement };
        enum RemoveLineIfEmptyAndWholeStatement_t { RemoveLineIfEmptyAndWholeStatement };
        // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
        friend RemoveLineIfEmptyAndWholeStatement_t operator|( RemoveLineIfEmpty_t, RemoveWholeStatement_t )
            { return RemoveLineIfEmptyAndWholeStatement; }
        struct RewriteOptions
            : public Rewriter::RewriteOptions
            {
            RewriteOptions() : RemoveWholeStatement( false ) {} // default
            RewriteOptions( RemoveLineIfEmpty_t ) : RemoveWholeStatement( false ) { RemoveLineIfEmpty = true; }
            RewriteOptions( RemoveWholeStatement_t ) : RemoveWholeStatement( true ) {}
            RewriteOptions( RemoveLineIfEmptyAndWholeStatement_t ) : RemoveWholeStatement( true ) { RemoveLineIfEmpty = true; }
            bool RemoveWholeStatement;
            };
        // These following insert/remove/replaceText functions map to functions
        // in clang::Rewriter, with these differences:
        // - they (more intuitively) return false on failure rather than true
        // - they report a warning when the change cannot be done
        // - There is RemoveWholeStatement to also remove the trailing semicolon when removing (must be there)
        //   and al preceding whitespace.
        bool insertText( SourceLocation Loc, StringRef Str,
            bool InsertAfter = true, bool indentNewLines = false );
        bool insertTextAfter( SourceLocation Loc, StringRef Str );
        bool insertTextAfterToken( SourceLocation Loc, StringRef Str );
        bool insertTextBefore( SourceLocation Loc, StringRef Str );
        bool removeText( SourceLocation Start, unsigned Length, RewriteOptions opts = RewriteOptions());
        // CharSourceRange not supported, unless really needed, as it makes RemoveSemicolon more complicated
        //bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions());
        bool removeText( SourceRange range, RewriteOptions opts = RewriteOptions());
        bool replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr );
        bool replaceText( SourceRange range, StringRef NewStr );
        bool replaceText( SourceRange range, SourceRange replacementRange );
        Rewriter& rewriter;
    private:
        template< typename T > friend class Plugin::Registration;
        template< typename T > static Plugin* createHelper( ASTContext& context, Rewriter& rewriter );
        enum { isRewriter = true };
        bool reportEditFailure( SourceLocation loc );
        bool adjustForWholeStatement( SourceRange* range );
    };

/**
    Plugin registration helper.

    If you create a new helper class, create also an instance of this class to automatically register it.
    The passed argument is name of the plugin, used for explicitly invoking rewriter plugins
    (it is ignored for non-rewriter plugins).

    @code
    static Plugin::Registration< NameOfClass > X( "nameofclass" );
    @endcode
*/
template< typename T >
class Plugin::Registration
    {
    public:
        Registration( const char* optionName );
    };

class RegistrationCreate
    {
    public:
        template< typename T, bool > static T* create( ASTContext& context, Rewriter& rewriter );
    };

/////

inline
Plugin::~Plugin()
    {
    }

inline
bool Plugin::ignoreLocation( const Decl* decl )
    {
    return ignoreLocation( decl->getLocation());
    }

inline
bool Plugin::ignoreLocation( const Stmt* stmt )
    {
    return ignoreLocation( stmt->getLocStart());
    }

template< typename T >
Plugin* Plugin::createHelper( ASTContext& context, Rewriter& )
    {
    return new T( context );
    }

template< typename T >
Plugin* RewritePlugin::createHelper( ASTContext& context, Rewriter& rewriter )
    {
    return new T( context, rewriter );
    }

template< typename T >
inline
Plugin::Registration< T >::Registration( const char* optionName )
    {
    registerPlugin( &T::template createHelper< T >, optionName, T::isRewriter );
    }

} // namespace

#endif // COMPILEPLUGIN_H
<|endoftext|>