<commit_before>#pragma once

//#define BOOST_RESULT_OF_USE_DECLTYPE
#include <type_traits>
#include <array>

#ifdef NDEBUG
#define BOOST_DISABLE_ASSERTS
#endif

#include <boost/multi_array.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>

#include "tuple_tools.hpp"

namespace gftools {

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_base;

template <typename ValueType, size_t N>
struct container;

template<typename ContainerType, size_t M = ContainerType::N_>
using container_view = container_base<typename ContainerType::value_type, ContainerType::N_, typename ContainerType::boost_t::template array_view<M>::type>;

template <typename ValueType, size_t N>
using container_ref = container_base<ValueType, N, boost::multi_array_ref<ValueType,N>>;

namespace extra {
template <typename, bool View=false> struct container_traits;

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_traits<container_base<ValueType,N,BoostContainerType>,false>
{
    typedef BoostContainerType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef container_base<ValueType,N-1,boost_under_type> type;
    typedef container_base<ValueType,N-1,boost_under_type> ref_type;
};

template <typename ValueType, typename BoostContainerType>
struct container_traits<container_base<ValueType,1,BoostContainerType>,false>
{
    typedef BoostContainerType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef ValueType type;
    typedef ValueType& ref_type;
};

template <typename ValueType, size_t N, typename BoostViewType>
struct container_traits<container_base<ValueType,N,BoostViewType>,true>
{
    typedef BoostViewType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef ValueType type;
    typedef ValueType& ref_type;
};

}; // end of namespace extra

// ================================================================== //

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_base
{
    constexpr static size_t N_ = N;
    constexpr static bool is_view_ = (N != BoostContainerType::dimensionality);

    typedef ValueType value_type;
    typedef typename extra::container_traits<container_base, is_view_>::type under_type;
    typedef typename extra::container_traits<container_base, is_view_>::ref_type under_ref_type;
    typedef typename extra::container_traits<container_base, is_view_>::boost_under_type boost_under_type;

    typedef BoostContainerType boost_t;
    typedef Eigen::Array<ValueType, Eigen::Dynamic, 1> EigenArray;
    typedef Eigen::Map<EigenArray> EigenMap;
    typedef Eigen::Matrix<ValueType,Eigen::Dynamic, Eigen::Dynamic> MatrixType;
    typedef Eigen::Matrix<ValueType,Eigen::Dynamic, 1> VectorType;

    typedef std::function<under_type(boost_under_type)> action_type;
    typedef boost::transform_iterator<action_type,typename boost_t::iterator> iterator;
    typedef boost::transform_iterator<action_type,typename boost_t::iterator> const_iterator;

    container_base(const boost_t &in):storage_(in){};
    /** Copy constructor. */
    container_base(const container_base<ValueType,N,boost_t> &rhs):storage_(rhs.storage_){};
    template <typename BT2>
        container_base(const container_base<ValueType,N,BT2> &rhs):storage_(rhs.boost_container_()){};
    template <typename BT2>
        container_base& operator=(const container_base<ValueType,N,BT2> &rhs){storage_ = rhs.boost_container_(); return (*this);};
    container_base& operator=(const container_base<ValueType,N,boost_t> &rhs){storage_ = rhs.storage_; return (*this);};
    /** Move constructor. */
    container_base(container_base<ValueType,N,boost_t> &&rhs):storage_(std::forward<boost_t>(rhs.storage_)){ }
    container_base& operator=(container_base<ValueType,N,boost_t> &&rhs){std::swap(storage_,rhs.storage_); return (*this);};
    void swap(container_base& rhs) {std::swap(storage_,rhs.storage_);}

    /** Access operators. */
    auto operator[](size_t i) -> under_ref_type { return under_ref_type(storage_[i]); }
    auto operator[](size_t i) const -> under_ref_type const { return under_ref_type(storage_[i]); }

    boost_t& boost_container_() const {return storage_; }
    ValueType& operator()(std::array<size_t, N> indices){return storage_(indices);}
    const ValueType& operator() (std::array<size_t, N> indices) const {return storage_(indices);}

    container_base<ValueType,1,boost::multi_array_ref<ValueType,1>> flatten();
// TODO : put views

    template <size_t N2 = N, typename DT = boost_t>
    using Is2d = typename std::enable_if<N2==2,DT>::type;
    /** Return operators. */
    template<size_t N2 = N, typename U = Is2d<N2>>
    container_base<ValueType,N,boost_t>& operator=(MatrixType rhs);

    template<size_t N2 = N, typename U = Is2d<N2>>
    container<ValueType,N> transpose() { return container<ValueType, N>( this->as_matrix().transpose()); }
    template<size_t N2 = N, typename U = Is2d<N2>>
    container<ValueType,N> hermite_conj() { return this->transpose().conj(); }

    template<size_t N2 = N, typename U = Is2d<N2>>
    MatrixType as_matrix() const;
    /** Return a diagonal matrix, corresponding to the object */
    MatrixType as_diagonal_matrix() const;
    /** Return a vector, corresponding to the object. */
    VectorType as_vector() const;

    /** Conjugate. */
    //container<ValueType,N>&& conj();
    template<typename T=ValueType> typename std::enable_if< std::is_same<T, complex_type>::value, container<ValueType,N>>::type conj() const;
    template<typename T=ValueType> typename std::enable_if<!std::is_same<T, complex_type>::value, container<ValueType,N>>::type conj() const;
    //typename std::enable_if<!std::is_convertible<ValueType, complex_type>::value, container<ValueType,N>&&>::type conj_d();
    //container<ValueType,N>&& conj();
    /** Sum of all values in the container. */
    ValueType sum() const;
    ValueType* data() { return storage_.origin(); }
    int size() const;
    std::array<size_t,N> shape() const;
    template <typename V2, typename DT>
    double diff(const container_base<V2,N,DT>& r) const
        { return std::sqrt(std::abs( ((*this)*(*this).conj()).sum() + (r*r.conj()).sum() - ((*this)*r.conj()).sum() - ((*this).conj()*r).sum())); }

    /** Make the object streamable. */
    template <typename V1, size_t M, typename B>
    friend std::ostream& operator<<(std::ostream& lhs, const container_base<V1, M, B> &in);

    /** Begin iterator. */
    const_iterator begin() const;
    /** End iterator. */
    const_iterator end() const;

    /** Mathematical operators. */
    template <typename T>
        typename std::enable_if<std::is_convertible<T,ValueType>::value,container_base&>::type operator=(T rhs);// { Base(*this) = rhs; return (*this);}

    template <typename T>
    using BaseRefIfContainer = typename std::enable_if<T::N_>=1, container_base<ValueType,N,boost_t>&>::type;
    template <typename T>
    using ContainerIfContainer = typename std::enable_if<T::N_>=1, container<ValueType,N>>::type;
    template <typename T>
    using BaseRefIfValue = typename std::enable_if<std::is_convertible<T,ValueType>::value, container_base<ValueType,N,boost_t>&>::type;
    template <typename T>
    using ContainerIfValue = typename std::enable_if<std::is_convertible<T,ValueType>::value, container<ValueType,N>>::type;

    template <typename R>
        BaseRefIfContainer<R> operator+=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator+(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator+=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator+(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator-=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator-(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator-=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator-(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator*=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator*(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator*=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator*(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator/=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator/(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator/=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator/(const R2& rhs) const;

    friend container<ValueType,N> operator* (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs*lhs;};
    friend container<ValueType,N> operator+ (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs+lhs;};
    friend container<ValueType,N> operator- (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs*(-1.0)+lhs;};
    friend container<ValueType,N> operator/ (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {container<ValueType,N> out(rhs); out=lhs; return out/rhs;};

    class ex_wrong_index : public std::exception { virtual const char* what() const throw(){return "Index out of bounds";}};

//-----------------------------//
    protected:
    friend struct container<ValueType,N>;

    mutable boost_t storage_;
};

template <typename ValueType, size_t N>
struct container : container_base<ValueType,N,typename boost::multi_array<ValueType, N>> {
    typedef boost::multi_array<ValueType, N> boost_t;
    typedef container_base<ValueType,N,boost_t> Base;
    using Base::storage_;
    typedef typename Base::MatrixType MatrixType;

    template <typename T>
    using IsNotContainer = typename std::enable_if<!(T::N_>=1)>::type;

    container(std::array<int,N> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(shape)) {};
    explicit container(std::array<size_t,N> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(shape)) {};
    container(std::initializer_list<int> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(std::array<int, N>(shape))) {};

    template <typename CT>
        container(container_base<ValueType,N,CT> in) : container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(in.storage_) {};

    template<typename ...ShapeArgs,
        typename = typename std::enable_if<sizeof...(ShapeArgs) == N
               && (std::is_same<std::tuple<ShapeArgs...>, typename tuple_tools::repeater<int,N>::tuple_type>::value // Arguments have to be strictly ints
               || std::is_same<std::tuple<ShapeArgs...>, typename tuple_tools::repeater<size_t,N>::tuple_type>::value) // or size_t
        ,int>::type>
        container(ShapeArgs...in):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(std::array<int,N>({{in...}}))) {
            static_assert(sizeof...(in) == N,"arg mismatch");
        };

    template<size_t N2 = N, typename U = typename std::enable_if<N2==2, bool>>
        container<ValueType,N> (MatrixType rhs);
    using Base::operator+=;
    using Base::operator-=;
    using Base::operator*=;
    using Base::operator/=;
    //using Base::operator=;
    template <typename T> typename std::enable_if<std::is_convertible<T,ValueType>::value,container&>::type operator=(T rhs) {
        typename std::add_lvalue_reference<Base>::type(*this) = rhs; return (*this);}
};

}; // end of namespace gftools

#include "container.hxx"
<commit_msg>container : transpose is const<commit_after>#pragma once

//#define BOOST_RESULT_OF_USE_DECLTYPE
#include <type_traits>
#include <array>

#ifdef NDEBUG
#define BOOST_DISABLE_ASSERTS
#endif

#include <boost/multi_array.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>

#include "tuple_tools.hpp"

namespace gftools {

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_base;

template <typename ValueType, size_t N>
struct container;

template<typename ContainerType, size_t M = ContainerType::N_>
using container_view = container_base<typename ContainerType::value_type, ContainerType::N_, typename ContainerType::boost_t::template array_view<M>::type>;

template <typename ValueType, size_t N>
using container_ref = container_base<ValueType, N, boost::multi_array_ref<ValueType,N>>;

namespace extra {
template <typename, bool View=false> struct container_traits;

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_traits<container_base<ValueType,N,BoostContainerType>,false>
{
    typedef BoostContainerType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef container_base<ValueType,N-1,boost_under_type> type;
    typedef container_base<ValueType,N-1,boost_under_type> ref_type;
};

template <typename ValueType, typename BoostContainerType>
struct container_traits<container_base<ValueType,1,BoostContainerType>,false>
{
    typedef BoostContainerType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef ValueType type;
    typedef ValueType& ref_type;
};

template <typename ValueType, size_t N, typename BoostViewType>
struct container_traits<container_base<ValueType,N,BoostViewType>,true>
{
    typedef BoostViewType boost_t;
    typedef typename boost_t::reference boost_under_type;
    typedef ValueType type;
    typedef ValueType& ref_type;
};

}; // end of namespace extra

// ================================================================== //

template <typename ValueType, size_t N, typename BoostContainerType>
struct container_base
{
    constexpr static size_t N_ = N;
    constexpr static bool is_view_ = (N != BoostContainerType::dimensionality);

    typedef ValueType value_type;
    typedef typename extra::container_traits<container_base, is_view_>::type under_type;
    typedef typename extra::container_traits<container_base, is_view_>::ref_type under_ref_type;
    typedef typename extra::container_traits<container_base, is_view_>::boost_under_type boost_under_type;

    typedef BoostContainerType boost_t;
    typedef Eigen::Array<ValueType, Eigen::Dynamic, 1> EigenArray;
    typedef Eigen::Map<EigenArray> EigenMap;
    typedef Eigen::Matrix<ValueType,Eigen::Dynamic, Eigen::Dynamic> MatrixType;
    typedef Eigen::Matrix<ValueType,Eigen::Dynamic, 1> VectorType;

    typedef std::function<under_type(boost_under_type)> action_type;
    typedef boost::transform_iterator<action_type,typename boost_t::iterator> iterator;
    typedef boost::transform_iterator<action_type,typename boost_t::iterator> const_iterator;

    container_base(const boost_t &in):storage_(in){};
    /** Copy constructor. */
    container_base(const container_base<ValueType,N,boost_t> &rhs):storage_(rhs.storage_){};
    template <typename BT2>
        container_base(const container_base<ValueType,N,BT2> &rhs):storage_(rhs.boost_container_()){};
    template <typename BT2>
        container_base& operator=(const container_base<ValueType,N,BT2> &rhs){storage_ = rhs.boost_container_(); return (*this);};
    container_base& operator=(const container_base<ValueType,N,boost_t> &rhs){storage_ = rhs.storage_; return (*this);};
    /** Move constructor. */
    container_base(container_base<ValueType,N,boost_t> &&rhs):storage_(std::forward<boost_t>(rhs.storage_)){ }
    container_base& operator=(container_base<ValueType,N,boost_t> &&rhs){std::swap(storage_,rhs.storage_); return (*this);};
    void swap(container_base& rhs) {std::swap(storage_,rhs.storage_);}

    /** Access operators. */
    auto operator[](size_t i) -> under_ref_type { return under_ref_type(storage_[i]); }
    auto operator[](size_t i) const -> under_ref_type const { return under_ref_type(storage_[i]); }

    boost_t& boost_container_() const {return storage_; }
    ValueType& operator()(std::array<size_t, N> indices){return storage_(indices);}
    const ValueType& operator() (std::array<size_t, N> indices) const {return storage_(indices);}

    container_base<ValueType,1,boost::multi_array_ref<ValueType,1>> flatten();
// TODO : put views

    template <size_t N2 = N, typename DT = boost_t>
    using Is2d = typename std::enable_if<N2==2,DT>::type;
    /** Return operators. */
    template<size_t N2 = N, typename U = Is2d<N2>>
    container_base<ValueType,N,boost_t>& operator=(MatrixType rhs);

    template<size_t N2 = N, typename U = Is2d<N2>>
    container<ValueType,N> transpose() const { return container<ValueType, N>( this->as_matrix().transpose()); }
    template<size_t N2 = N, typename U = Is2d<N2>>
    container<ValueType,N> hermite_conj() const { return this->transpose().conj(); }

    template<size_t N2 = N, typename U = Is2d<N2>>
    MatrixType as_matrix() const;
    /** Return a diagonal matrix, corresponding to the object */
    MatrixType as_diagonal_matrix() const;
    /** Return a vector, corresponding to the object. */
    VectorType as_vector() const;

    /** Conjugate. */
    //container<ValueType,N>&& conj();
    template<typename T=ValueType> typename std::enable_if< std::is_same<T, complex_type>::value, container<ValueType,N>>::type conj() const;
    template<typename T=ValueType> typename std::enable_if<!std::is_same<T, complex_type>::value, container<ValueType,N>>::type conj() const;
    //typename std::enable_if<!std::is_convertible<ValueType, complex_type>::value, container<ValueType,N>&&>::type conj_d();
    //container<ValueType,N>&& conj();
    /** Sum of all values in the container. */
    ValueType sum() const;
    ValueType* data() { return storage_.origin(); }
    int size() const;
    std::array<size_t,N> shape() const;
    template <typename V2, typename DT>
    double diff(const container_base<V2,N,DT>& r) const
        { return std::sqrt(std::abs( ((*this)*(*this).conj()).sum() + (r*r.conj()).sum() - ((*this)*r.conj()).sum() - ((*this).conj()*r).sum())); }

    /** Make the object streamable. */
    template <typename V1, size_t M, typename B>
    friend std::ostream& operator<<(std::ostream& lhs, const container_base<V1, M, B> &in);

    /** Begin iterator. */
    const_iterator begin() const;
    /** End iterator. */
    const_iterator end() const;

    /** Mathematical operators. */
    template <typename T>
        typename std::enable_if<std::is_convertible<T,ValueType>::value,container_base&>::type operator=(T rhs);// { Base(*this) = rhs; return (*this);}

    template <typename T>
    using BaseRefIfContainer = typename std::enable_if<T::N_>=1, container_base<ValueType,N,boost_t>&>::type;
    template <typename T>
    using ContainerIfContainer = typename std::enable_if<T::N_>=1, container<ValueType,N>>::type;
    template <typename T>
    using BaseRefIfValue = typename std::enable_if<std::is_convertible<T,ValueType>::value, container_base<ValueType,N,boost_t>&>::type;
    template <typename T>
    using ContainerIfValue = typename std::enable_if<std::is_convertible<T,ValueType>::value, container<ValueType,N>>::type;

    template <typename R>
        BaseRefIfContainer<R> operator+=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator+(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator+=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator+(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator-=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator-(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator-=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator-(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator*=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator*(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator*=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator*(const R2& rhs) const;

    template <typename R>
        BaseRefIfContainer<R> operator/=(const R &rhs);
    template <typename R>
        ContainerIfContainer<R> operator/(const R &rhs) const;
    template <typename R2>
        BaseRefIfValue<R2> operator/=(const R2& rhs);
    template <typename R2>
        ContainerIfValue<R2> operator/(const R2& rhs) const;

    friend container<ValueType,N> operator* (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs*lhs;};
    friend container<ValueType,N> operator+ (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs+lhs;};
    friend container<ValueType,N> operator- (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {return rhs*(-1.0)+lhs;};
    friend container<ValueType,N> operator/ (const ValueType & lhs, const container_base<ValueType,N,boost_t> & rhs) {container<ValueType,N> out(rhs); out=lhs; return out/rhs;};

    class ex_wrong_index : public std::exception { virtual const char* what() const throw(){return "Index out of bounds";}};

//-----------------------------//
    protected:
    friend struct container<ValueType,N>;

    mutable boost_t storage_;
};

template <typename ValueType, size_t N>
struct container : container_base<ValueType,N,typename boost::multi_array<ValueType, N>> {
    typedef boost::multi_array<ValueType, N> boost_t;
    typedef container_base<ValueType,N,boost_t> Base;
    using Base::storage_;
    typedef typename Base::MatrixType MatrixType;

    template <typename T>
    using IsNotContainer = typename std::enable_if<!(T::N_>=1)>::type;

    container(std::array<int,N> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(shape)) {};
    explicit container(std::array<size_t,N> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(shape)) {};
    container(std::initializer_list<int> shape):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(std::array<int, N>(shape))) {};

    template <typename CT>
        container(container_base<ValueType,N,CT> in) : container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(in.storage_) {};

    template<typename ...ShapeArgs,
        typename = typename std::enable_if<sizeof...(ShapeArgs) == N
               && (std::is_same<std::tuple<ShapeArgs...>, typename tuple_tools::repeater<int,N>::tuple_type>::value // Arguments have to be strictly ints
               || std::is_same<std::tuple<ShapeArgs...>, typename tuple_tools::repeater<size_t,N>::tuple_type>::value) // or size_t
        ,int>::type>
        container(ShapeArgs...in):container_base<ValueType,N,typename boost::multi_array<ValueType, N>>(boost::multi_array<ValueType, N>(std::array<int,N>({{in...}}))) {
            static_assert(sizeof...(in) == N,"arg mismatch");
        };

    template<size_t N2 = N, typename U = typename std::enable_if<N2==2, bool>>
        container<ValueType,N> (MatrixType rhs);
    using Base::operator+=;
    using Base::operator-=;
    using Base::operator*=;
    using Base::operator/=;
    //using Base::operator=;
    template <typename T> typename std::enable_if<std::is_convertible<T,ValueType>::value,container&>::type operator=(T rhs) {
        typename std::add_lvalue_reference<Base>::type(*this) = rhs; return (*this);}
};

}; // end of namespace gftools

#include "container.hxx"
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 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/perception/onboard/component/radar_detection_component.h"
#include "modules/perception/common/sensor_manager/sensor_manager.h"
#include "modules/perception/lib/utils/perf.h"

namespace apollo {
namespace perception {
namespace onboard {

bool RadarDetectionComponent::Init() {
  RadarComponentConfig comp_config;
  if (!GetProtoConfig(&comp_config)) {
    return false;
  }
  AINFO << "Radar Component Configs: " << comp_config.DebugString();

  // To load component configs
  tf_child_frame_id_ = comp_config.tf_child_frame_id();
  radar_forward_distance_ = comp_config.radar_forward_distance();
  preprocessor_method_ = comp_config.radar_preprocessor_method();
  perception_method_ = comp_config.radar_perception_method();
  pipeline_name_ = comp_config.radar_pipeline_name();
  odometry_channel_name_ = comp_config.odometry_channel_name();

  if (!common::SensorManager::Instance()->GetSensorInfo(
          comp_config.radar_name(), &radar_info_)) {
    AERROR << "Failed to get sensor info, sensor name: "
           << comp_config.radar_name();
    return false;
  }

  writer_ = node_->CreateWriter<SensorFrameMessage>(
      comp_config.output_channel_name());

  // Init algorithm plugin
  CHECK(InitAlgorithmPlugin()) << "Failed to init algorithm plugin.";
  radar2world_trans_.Init(tf_child_frame_id_);
  radar2novatel_trans_.Init(tf_child_frame_id_);
  localization_subscriber_.Init(
      odometry_channel_name_,
      odometry_channel_name_ + '_' + comp_config.radar_name());
  return true;
}

bool RadarDetectionComponent::Proc(const std::shared_ptr<ContiRadar>& message) {
  AINFO << "Enter radar preprocess, message timestamp: "
        << std::to_string(message->header().timestamp_sec())
        << " current timestamp " << lib::TimeUtil::GetCurrentTime();
  std::shared_ptr<SensorFrameMessage> out_message(new (std::nothrow)
                                                      SensorFrameMessage);
  int status = InternalProc(message, out_message);
  if (status) {
    writer_->Write(out_message);
    AINFO << "Send radar processing output message.";
  }
  return status;
}

bool RadarDetectionComponent::InitAlgorithmPlugin() {
  AINFO << "onboard radar_preprocessor: " << preprocessor_method_;
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_ = map::HDMapInput::Instance();
    CHECK(hdmap_input_->Init()) << "Failed to init hdmap input.";
  }
  radar::BasePreprocessor* preprocessor =
      radar::BasePreprocessorRegisterer::GetInstanceByName(
          preprocessor_method_);
  CHECK_NOTNULL(preprocessor);
  radar_preprocessor_.reset(preprocessor);
  CHECK(radar_preprocessor_->Init()) << "Failed to init radar preprocessor.";
  radar::BaseRadarObstaclePerception* radar_perception =
      radar::BaseRadarObstaclePerceptionRegisterer::GetInstanceByName(
          perception_method_);
  CHECK(radar_perception != nullptr)
      << "No radar obstacle perception named: " << perception_method_;
  radar_perception_.reset(radar_perception);
  CHECK(radar_perception_->Init(pipeline_name_))
      << "Failed to init radar perception.";
  AINFO << "Init algorithm plugin successfully.";
  return true;
}

bool RadarDetectionComponent::InternalProc(
    const std::shared_ptr<ContiRadar>& in_message,
    std::shared_ptr<SensorFrameMessage> out_message) {
  PERCEPTION_PERF_FUNCTION_WITH_INDICATOR(radar_info_.name);
  ContiRadar raw_obstacles = *in_message;
  {
    std::unique_lock<std::mutex> lock(_mutex);
    ++seq_num_;
  }
  double timestamp = in_message->header().timestamp_sec();
  const double cur_time = lib::TimeUtil::GetCurrentTime();
  const double start_latency = (cur_time - timestamp) * 1e3;
  AINFO << "FRAME_STATISTICS:Radar:Start:msg_time[" << std::to_string(timestamp)
        << "]:cur_time[" << std::to_string(cur_time) << "]:cur_latency["
        << start_latency << "]";
  PERCEPTION_PERF_BLOCK_START();
  // Init preprocessor_options
  radar::PreprocessorOptions preprocessor_options;
  ContiRadar corrected_obstacles;
  radar_preprocessor_->Preprocess(raw_obstacles, preprocessor_options,
                                  &corrected_obstacles);
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_preprocessor");
  timestamp = corrected_obstacles.header().timestamp_sec();

  out_message->timestamp_ = timestamp;
  out_message->seq_num_ = seq_num_;
  out_message->process_stage_ = ProcessStage::LONG_RANGE_RADAR_DETECTION;
  out_message->sensor_id_ = radar_info_.name;

  // Init radar perception options
  radar::RadarPerceptionOptions options;
  options.sensor_name = radar_info_.name;
  // Init detector_options
  Eigen::Affine3d radar_trans;
  if (!radar2world_trans_.GetSensor2worldTrans(timestamp, &radar_trans)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get pose at time: " << timestamp;
    return true;
  }
  Eigen::Affine3d radar2novatel_trans;
  if (!radar2novatel_trans_.GetTrans(timestamp, &radar2novatel_trans, "novatel",
                                     tf_child_frame_id_)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get radar2novatel trans at time: " << timestamp;
    return true;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetSensor2worldTrans");
  Eigen::Matrix4d radar2world_pose = radar_trans.matrix();
  options.detector_options.radar2world_pose = &radar2world_pose;
  Eigen::Matrix4d radar2novatel_trans_m = radar2novatel_trans.matrix();
  options.detector_options.radar2novatel_trans = &radar2novatel_trans_m;
  if (!GetCarLocalizationSpeed(timestamp,
                               &(options.detector_options.car_linear_speed),
                               &(options.detector_options.car_angular_speed))) {
    AERROR << "Failed to call get_car_speed. [timestamp: "
           << std::to_string(timestamp);
    // return false;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name, "GetCarSpeed");
  // Init roi_filter_options
  base::PointD position;
  position.x = radar_trans(0, 3);
  position.y = radar_trans(1, 3);
  position.z = radar_trans(2, 3);
  options.roi_filter_options.roi.reset(new base::HdmapStruct());
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_->GetRoiHDMapStruct(position, radar_forward_distance_,
                                    options.roi_filter_options.roi);
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetRoiHDMapStruct");
  // Init object_filter_options
  // Init track_options
  // Init object_builder_options
  std::vector<base::ObjectPtr> radar_objects;
  if (!radar_perception_->Perceive(corrected_obstacles, options,
                                   &radar_objects)) {
    out_message->error_code_ =
        apollo::common::ErrorCode::PERCEPTION_ERROR_PROCESS;
    AERROR << "RadarDetector Proc failed.";
    return true;
  }
  out_message->frame_.reset(new base::Frame());
  out_message->frame_->sensor_info = radar_info_;
  out_message->frame_->timestamp = timestamp;
  out_message->frame_->sensor2world_pose = radar_trans;
  out_message->frame_->objects = radar_objects;

  const double end_timestamp = lib::TimeUtil::GetCurrentTime();
  const double end_latency =
      (end_timestamp - in_message->header().timestamp_sec()) * 1e3;
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_perception");
  AINFO << "FRAME_STATISTICS:Radar:End:msg_time["
        << std::to_string(in_message->header().timestamp_sec()) << "]:cur_time["
        << std::to_string(end_timestamp) << "]:cur_latency[" << end_latency
        << "]";

  return true;
}

bool RadarDetectionComponent::GetCarLocalizationSpeed(
    double timestamp, Eigen::Vector3f* car_linear_speed,
    Eigen::Vector3f* car_angular_speed) {
  CHECK_NOTNULL(car_linear_speed);
  (*car_linear_speed) = Eigen::Vector3f::Zero();
  CHECK_NOTNULL(car_angular_speed);
  (*car_angular_speed) = Eigen::Vector3f::Zero();
  std::shared_ptr<LocalizationEstimate const> loct_ptr;
  if (!localization_subscriber_.LookupNearest(timestamp, &loct_ptr)) {
    AERROR << "Cannot get car speed.";
    return false;
  }
  (*car_linear_speed)[0] =
      static_cast<float>(loct_ptr->pose().linear_velocity().x());
  (*car_linear_speed)[1] =
      static_cast<float>(loct_ptr->pose().linear_velocity().y());
  (*car_linear_speed)[2] =
      static_cast<float>(loct_ptr->pose().linear_velocity().z());
  (*car_angular_speed)[0] =
      static_cast<float>(loct_ptr->pose().angular_velocity().x());
  (*car_angular_speed)[1] =
      static_cast<float>(loct_ptr->pose().angular_velocity().y());
  (*car_angular_speed)[2] =
      static_cast<float>(loct_ptr->pose().angular_velocity().z());

  return true;
}

}  // namespace onboard
}  // namespace perception
}  // namespace apollo
<commit_msg>fix return code mismatching<commit_after>/******************************************************************************
 * Copyright 2018 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/perception/onboard/component/radar_detection_component.h"
#include "modules/perception/common/sensor_manager/sensor_manager.h"
#include "modules/perception/lib/utils/perf.h"

namespace apollo {
namespace perception {
namespace onboard {

bool RadarDetectionComponent::Init() {
  RadarComponentConfig comp_config;
  if (!GetProtoConfig(&comp_config)) {
    return false;
  }
  AINFO << "Radar Component Configs: " << comp_config.DebugString();

  // To load component configs
  tf_child_frame_id_ = comp_config.tf_child_frame_id();
  radar_forward_distance_ = comp_config.radar_forward_distance();
  preprocessor_method_ = comp_config.radar_preprocessor_method();
  perception_method_ = comp_config.radar_perception_method();
  pipeline_name_ = comp_config.radar_pipeline_name();
  odometry_channel_name_ = comp_config.odometry_channel_name();

  if (!common::SensorManager::Instance()->GetSensorInfo(
          comp_config.radar_name(), &radar_info_)) {
    AERROR << "Failed to get sensor info, sensor name: "
           << comp_config.radar_name();
    return false;
  }

  writer_ = node_->CreateWriter<SensorFrameMessage>(
      comp_config.output_channel_name());

  // Init algorithm plugin
  CHECK(InitAlgorithmPlugin()) << "Failed to init algorithm plugin.";
  radar2world_trans_.Init(tf_child_frame_id_);
  radar2novatel_trans_.Init(tf_child_frame_id_);
  localization_subscriber_.Init(
      odometry_channel_name_,
      odometry_channel_name_ + '_' + comp_config.radar_name());
  return true;
}

bool RadarDetectionComponent::Proc(const std::shared_ptr<ContiRadar>& message) {
  AINFO << "Enter radar preprocess, message timestamp: "
        << std::to_string(message->header().timestamp_sec())
        << " current timestamp " << lib::TimeUtil::GetCurrentTime();
  std::shared_ptr<SensorFrameMessage> out_message(new (std::nothrow)
                                                      SensorFrameMessage);
  bool status = InternalProc(message, out_message);
  if (status) {
    writer_->Write(out_message);
    AINFO << "Send radar processing output message.";
  }
  return status;
}

bool RadarDetectionComponent::InitAlgorithmPlugin() {
  AINFO << "onboard radar_preprocessor: " << preprocessor_method_;
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_ = map::HDMapInput::Instance();
    CHECK(hdmap_input_->Init()) << "Failed to init hdmap input.";
  }
  radar::BasePreprocessor* preprocessor =
      radar::BasePreprocessorRegisterer::GetInstanceByName(
          preprocessor_method_);
  CHECK_NOTNULL(preprocessor);
  radar_preprocessor_.reset(preprocessor);
  CHECK(radar_preprocessor_->Init()) << "Failed to init radar preprocessor.";
  radar::BaseRadarObstaclePerception* radar_perception =
      radar::BaseRadarObstaclePerceptionRegisterer::GetInstanceByName(
          perception_method_);
  CHECK(radar_perception != nullptr)
      << "No radar obstacle perception named: " << perception_method_;
  radar_perception_.reset(radar_perception);
  CHECK(radar_perception_->Init(pipeline_name_))
      << "Failed to init radar perception.";
  AINFO << "Init algorithm plugin successfully.";
  return true;
}

bool RadarDetectionComponent::InternalProc(
    const std::shared_ptr<ContiRadar>& in_message,
    std::shared_ptr<SensorFrameMessage> out_message) {
  PERCEPTION_PERF_FUNCTION_WITH_INDICATOR(radar_info_.name);
  ContiRadar raw_obstacles = *in_message;
  {
    std::unique_lock<std::mutex> lock(_mutex);
    ++seq_num_;
  }
  double timestamp = in_message->header().timestamp_sec();
  const double cur_time = lib::TimeUtil::GetCurrentTime();
  const double start_latency = (cur_time - timestamp) * 1e3;
  AINFO << "FRAME_STATISTICS:Radar:Start:msg_time[" << std::to_string(timestamp)
        << "]:cur_time[" << std::to_string(cur_time) << "]:cur_latency["
        << start_latency << "]";
  PERCEPTION_PERF_BLOCK_START();
  // Init preprocessor_options
  radar::PreprocessorOptions preprocessor_options;
  ContiRadar corrected_obstacles;
  radar_preprocessor_->Preprocess(raw_obstacles, preprocessor_options,
                                  &corrected_obstacles);
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_preprocessor");
  timestamp = corrected_obstacles.header().timestamp_sec();

  out_message->timestamp_ = timestamp;
  out_message->seq_num_ = seq_num_;
  out_message->process_stage_ = ProcessStage::LONG_RANGE_RADAR_DETECTION;
  out_message->sensor_id_ = radar_info_.name;

  // Init radar perception options
  radar::RadarPerceptionOptions options;
  options.sensor_name = radar_info_.name;
  // Init detector_options
  Eigen::Affine3d radar_trans;
  if (!radar2world_trans_.GetSensor2worldTrans(timestamp, &radar_trans)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get pose at time: " << timestamp;
    return true;
  }
  Eigen::Affine3d radar2novatel_trans;
  if (!radar2novatel_trans_.GetTrans(timestamp, &radar2novatel_trans, "novatel",
                                     tf_child_frame_id_)) {
    out_message->error_code_ = apollo::common::ErrorCode::PERCEPTION_ERROR_TF;
    AERROR << "Failed to get radar2novatel trans at time: " << timestamp;
    return true;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetSensor2worldTrans");
  Eigen::Matrix4d radar2world_pose = radar_trans.matrix();
  options.detector_options.radar2world_pose = &radar2world_pose;
  Eigen::Matrix4d radar2novatel_trans_m = radar2novatel_trans.matrix();
  options.detector_options.radar2novatel_trans = &radar2novatel_trans_m;
  if (!GetCarLocalizationSpeed(timestamp,
                               &(options.detector_options.car_linear_speed),
                               &(options.detector_options.car_angular_speed))) {
    AERROR << "Failed to call get_car_speed. [timestamp: "
           << std::to_string(timestamp);
    // return false;
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name, "GetCarSpeed");
  // Init roi_filter_options
  base::PointD position;
  position.x = radar_trans(0, 3);
  position.y = radar_trans(1, 3);
  position.z = radar_trans(2, 3);
  options.roi_filter_options.roi.reset(new base::HdmapStruct());
  if (FLAGS_obs_enable_hdmap_input) {
    hdmap_input_->GetRoiHDMapStruct(position, radar_forward_distance_,
                                    options.roi_filter_options.roi);
  }
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "GetRoiHDMapStruct");
  // Init object_filter_options
  // Init track_options
  // Init object_builder_options
  std::vector<base::ObjectPtr> radar_objects;
  if (!radar_perception_->Perceive(corrected_obstacles, options,
                                   &radar_objects)) {
    out_message->error_code_ =
        apollo::common::ErrorCode::PERCEPTION_ERROR_PROCESS;
    AERROR << "RadarDetector Proc failed.";
    return true;
  }
  out_message->frame_.reset(new base::Frame());
  out_message->frame_->sensor_info = radar_info_;
  out_message->frame_->timestamp = timestamp;
  out_message->frame_->sensor2world_pose = radar_trans;
  out_message->frame_->objects = radar_objects;

  const double end_timestamp = lib::TimeUtil::GetCurrentTime();
  const double end_latency =
      (end_timestamp - in_message->header().timestamp_sec()) * 1e3;
  PERCEPTION_PERF_BLOCK_END_WITH_INDICATOR(radar_info_.name,
                                           "radar_perception");
  AINFO << "FRAME_STATISTICS:Radar:End:msg_time["
        << std::to_string(in_message->header().timestamp_sec()) << "]:cur_time["
        << std::to_string(end_timestamp) << "]:cur_latency[" << end_latency
        << "]";

  return true;
}

bool RadarDetectionComponent::GetCarLocalizationSpeed(
    double timestamp, Eigen::Vector3f* car_linear_speed,
    Eigen::Vector3f* car_angular_speed) {
  CHECK_NOTNULL(car_linear_speed);
  (*car_linear_speed) = Eigen::Vector3f::Zero();
  CHECK_NOTNULL(car_angular_speed);
  (*car_angular_speed) = Eigen::Vector3f::Zero();
  std::shared_ptr<LocalizationEstimate const> loct_ptr;
  if (!localization_subscriber_.LookupNearest(timestamp, &loct_ptr)) {
    AERROR << "Cannot get car speed.";
    return false;
  }
  (*car_linear_speed)[0] =
      static_cast<float>(loct_ptr->pose().linear_velocity().x());
  (*car_linear_speed)[1] =
      static_cast<float>(loct_ptr->pose().linear_velocity().y());
  (*car_linear_speed)[2] =
      static_cast<float>(loct_ptr->pose().linear_velocity().z());
  (*car_angular_speed)[0] =
      static_cast<float>(loct_ptr->pose().angular_velocity().x());
  (*car_angular_speed)[1] =
      static_cast<float>(loct_ptr->pose().angular_velocity().y());
  (*car_angular_speed)[2] =
      static_cast<float>(loct_ptr->pose().angular_velocity().z());

  return true;
}

}  // namespace onboard
}  // namespace perception
}  // namespace apollo
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:enc=utf-8:
/*
The MIT License

Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Rüdiger Sonderfeld

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 "flusspferd/array.hpp"

#include "flusspferd/create.hpp"
#include "flusspferd/value.hpp"
#include "test_environment.hpp"

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( array ) {
  std::size_t const array_size = 10;
  flusspferd::array a = flusspferd::create_array(array_size);
  BOOST_CHECK_EQUAL(a.length(), array_size);
  BOOST_CHECK_EQUAL(a.size(), a.length());
  int const value0 = 10;
  a.set_element(0, flusspferd::value(value0));
  BOOST_CHECK(a.get_element(0).is_int());
  BOOST_CHECK_EQUAL(a.get_element(0).get_int(), value0);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>added test for iterator<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:enc=utf-8:
/*
The MIT License

Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Rüdiger Sonderfeld

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 "flusspferd/array.hpp"

#include "flusspferd/create.hpp"
#include "flusspferd/value.hpp"
#include "test_environment.hpp"

BOOST_TEST_DONT_PRINT_LOG_VALUE(flusspferd::array::iterator) //FIXME?

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( array ) {
  std::size_t const array_size = 10;
  flusspferd::array a = flusspferd::create_array(array_size);
  BOOST_CHECK_EQUAL(a.length(), array_size);
  BOOST_CHECK_EQUAL(a.size(), a.length());
  int const value0 = 10;
  a.set_element(0, flusspferd::value(value0));
  BOOST_CHECK(a.get_element(0).is_int());
  BOOST_CHECK_EQUAL(a.get_element(0).get_int(), value0);
}

BOOST_AUTO_TEST_CASE( array_iterator ) {
  std::size_t const array_size = 10;
  flusspferd::array a = flusspferd::create_array(array_size);
  for(std::size_t i = 0; i < array_size; ++i) {
    a.set_element(i, flusspferd::value(static_cast<int>(i)));
  }

  flusspferd::array::iterator i = a.begin();
  flusspferd::array::iterator const end = a.end();
  BOOST_REQUIRE_NE(i, end);
  BOOST_REQUIRE_EQUAL(end - i, array_size);
  int j = 0;
  for(; i != end; ++i, ++j) {
    BOOST_REQUIRE(i->is_int());
    BOOST_CHECK_EQUAL(i->get_int(), j);
  }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Copyright (c) 2022 by Apex.AI Inc. 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/cxx/filesystem.hpp"
#include "iceoryx_hoofs/log/logstream.hpp"
#include <iostream>
#include <type_traits>

namespace iox
{
namespace cxx
{
perms operator|(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) | static_cast<T>(rhs));
}

perms operator&(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) & static_cast<T>(rhs));
}

perms operator^(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) ^ static_cast<T>(rhs));
}

perms operator~(const perms& value) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(~static_cast<T>(value));
}

perms operator|=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs | rhs;
}

perms operator&=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs & rhs;
}

perms operator^=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs ^ rhs;
}

template <typename StreamType>
StreamType& operator<<(StreamType& stream, perms value) noexcept
{
    if (value == perms::unknown)
    {
        stream << "unknown permissions";
        return stream;
    }

    bool hasPreceedingEntry = false;
    auto outputToStream = [&](const char* text) {
        if (hasPreceedingEntry)
        {
            stream << ", ";
        }
        hasPreceedingEntry = true;

        stream << text;
    };

    auto finishEntry = [&](bool isLastEntry = false) {
        if (hasPreceedingEntry)
        {
            stream << "}";
        }
        else
        {
            stream << "none}";
        }

        if (!isLastEntry)
        {
            stream << ",  ";
        }
        hasPreceedingEntry = false;
    };

    // owner
    stream << "owner: {";

    if ((value & perms::owner_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::owner_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::owner_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // group
    stream << "group: {";

    if ((value & perms::group_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::group_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::group_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // other
    stream << "others: {";

    if ((value & perms::others_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::others_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::others_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // special bits
    stream << "special bits: {";
    if ((value & perms::set_uid) != perms::none)
    {
        outputToStream("set_uid");
    }

    if ((value & perms::set_gid) != perms::none)
    {
        outputToStream("set_git");
    }

    if ((value & perms::sticky_bit) != perms::none)
    {
        outputToStream("sticky_bit");
    }

    constexpr bool IS_LAST_ENTRY = true;
    finishEntry(IS_LAST_ENTRY);

    return stream;
}

template std::ostream& operator<<(std::ostream&, perms) noexcept;
template log::LogStream& operator<<(log::LogStream&, perms) noexcept;
} // namespace cxx
} // namespace iox
<commit_msg>iox-#1059 Spell correction in variable<commit_after>// Copyright (c) 2022 by Apex.AI Inc. 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/cxx/filesystem.hpp"
#include "iceoryx_hoofs/log/logstream.hpp"
#include <iostream>
#include <type_traits>

namespace iox
{
namespace cxx
{
perms operator|(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) | static_cast<T>(rhs));
}

perms operator&(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) & static_cast<T>(rhs));
}

perms operator^(const perms& lhs, const perms& rhs) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(static_cast<T>(lhs) ^ static_cast<T>(rhs));
}

perms operator~(const perms& value) noexcept
{
    using T = std::underlying_type<perms>::type;
    return static_cast<perms>(~static_cast<T>(value));
}

perms operator|=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs | rhs;
}

perms operator&=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs & rhs;
}

perms operator^=(perms& lhs, const perms& rhs) noexcept
{
    return lhs = lhs ^ rhs;
}

template <typename StreamType>
StreamType& operator<<(StreamType& stream, perms value) noexcept
{
    if (value == perms::unknown)
    {
        stream << "unknown permissions";
        return stream;
    }

    bool hasPrecedingEntry = false;
    auto outputToStream = [&](const char* text) {
        if (hasPrecedingEntry)
        {
            stream << ", ";
        }
        hasPrecedingEntry = true;

        stream << text;
    };

    auto finishEntry = [&](bool isLastEntry = false) {
        if (hasPrecedingEntry)
        {
            stream << "}";
        }
        else
        {
            stream << "none}";
        }

        if (!isLastEntry)
        {
            stream << ",  ";
        }
        hasPrecedingEntry = false;
    };

    // owner
    stream << "owner: {";

    if ((value & perms::owner_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::owner_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::owner_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // group
    stream << "group: {";

    if ((value & perms::group_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::group_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::group_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // other
    stream << "others: {";

    if ((value & perms::others_read) != perms::none)
    {
        outputToStream("read");
    }

    if ((value & perms::others_write) != perms::none)
    {
        outputToStream("write");
    }

    if ((value & perms::others_exec) != perms::none)
    {
        outputToStream("execute");
    }

    finishEntry();

    // special bits
    stream << "special bits: {";
    if ((value & perms::set_uid) != perms::none)
    {
        outputToStream("set_uid");
    }

    if ((value & perms::set_gid) != perms::none)
    {
        outputToStream("set_git");
    }

    if ((value & perms::sticky_bit) != perms::none)
    {
        outputToStream("sticky_bit");
    }

    constexpr bool IS_LAST_ENTRY = true;
    finishEntry(IS_LAST_ENTRY);

    return stream;
}

template std::ostream& operator<<(std::ostream&, perms) noexcept;
template log::LogStream& operator<<(log::LogStream&, perms) noexcept;
} // namespace cxx
} // namespace iox
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImage3dDilateErodeFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkImage3dDilateErodeFilter.h"

//----------------------------------------------------------------------------
// Description:
// Construct an instance of vtkImage3dDilateErodeFilter fitler.
// By default zero values are dilated.
vtkImage3dDilateErodeFilter::vtkImage3dDilateErodeFilter()
{
  this->DilateValue = 0.0;
  this->ErodeValue = 255.0;
  this->HandleBoundariesOn();
  this->Mask = NULL;
  this->SetKernelSize(1,1,1);
}

//----------------------------------------------------------------------------
void vtkImage3dDilateErodeFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSpatialFilter::PrintSelf(os,indent);
  os << indent << "Dilate Value: " << this->DilateValue << "\n";
  os << indent << "Erode Value: " << this->ErodeValue << "\n";
}

//----------------------------------------------------------------------------
// Description:
// This method sets the size of the 3d neighborhood.  It also sets the
// default mask/footprint (an elipse).
void
vtkImage3dDilateErodeFilter::SetKernelSize(int size0, int size1, int size2)
{
  unsigned char *ptr0, *ptr1, *ptr2;
  int inc0, inc1, inc2;
  int idx0, idx1, idx2;
  double f0, f1, f2, radius0, radius1, radius2;

  this->Modified();

  this->KernelSize[0] = size0;
  this->KernelSize[1] = size1;
  this->KernelSize[2] = size2;

  this->KernelMiddle[0] = size0 / 2;
  this->KernelMiddle[1] = size1 / 2;
  this->KernelMiddle[2] = size2 / 2;

  // Create the eliptical mask
  if (this->Mask)
    {
    this->Mask->Delete();
    }
  this->Mask = new vtkImageRegion;
  this->Mask->SetDataType(VTK_IMAGE_UNSIGNED_CHAR);
  this->Mask->SetAxes(this->GetAxes());
  this->Mask->SetBounds3d(0, size0-1, 0, size1-1, 0, size2-1);
  this->Mask->Allocate();
  if ( ! this->Mask->IsAllocated())
    {
    this->Mask->Delete();
    this->Mask = NULL;
    vtkErrorMacro(<< "SetKernelSize: Allocation of mask failed.");
    return;
    }

  radius0 = (double)(size0) / 2.0;
  radius1 = (double)(size1) / 2.0;
  radius2 = (double)(size2) / 2.0;

  this->Mask->GetIncrements3d(inc0, inc1, inc2);
  ptr2 = (unsigned char *)(this->Mask->GetVoidPointer());
  for (idx2 = 0; idx2 < size2; ++idx2)
    {
    ptr1 = ptr2;
    for (idx1 = 0; idx1 < size1; ++idx1)
      {
      ptr0 = ptr1;
      for (idx0 = 0; idx0 < size0; ++idx0)
	{
	// convert xyz to values in the range of [-1,1]
	f0 = ((double)(idx0) - radius0 + 0.5) / (radius0);
	f1 = ((double)(idx1) - radius1 + 0.5) / (radius1);
	f2 = ((double)(idx2) - radius2 + 0.5) / (radius2);

	if (f0*f0 + f1*f1 + f2*f2 <= 1.0)
	  {
	  *ptr0 = 255;
	  }
	else
	  {
	  *ptr0 = 0;
	  }

	ptr0 += inc0;
	}
      ptr1 += inc1;
      }
    ptr2 += inc2;
    }
}

//----------------------------------------------------------------------------
// Description:
// This templated function executes the filter on any region,
// whether it needs boundary checking or not.
// If the filter needs to be faster, the function could be duplicated
// for strictly center (no boundary ) processing.
template <class T>
void vtkImage3dDilateErodeFilterExecute(vtkImage3dDilateErodeFilter *self,
					vtkImageRegion *inRegion, T *inPtr,
					vtkImageRegion *outRegion, T *outPtr,
					int boundaryFlag)
{
  T erodeValue, dilateValue;
  int *kernelMiddle, *kernelSize;
  // For looping though output (and input) pixels.
  int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
  int outIdx0, outIdx1, outIdx2;
  int inInc0, inInc1, inInc2;
  int outInc0, outInc1, outInc2;
  T *inPtr0, *inPtr1, *inPtr2;
  T *outPtr0, *outPtr1, *outPtr2;
  // For looping through hood pixels
  int hoodMin0, hoodMax0, hoodMin1, hoodMax1, hoodMin2, hoodMax2;
  int hoodIdx0, hoodIdx1, hoodIdx2;
  T *hoodPtr0, *hoodPtr1, *hoodPtr2;
  // For looping through the mask.
  unsigned char *maskPtr, *maskPtr0, *maskPtr1, *maskPtr2;
  int maskInc0, maskInc1, maskInc2;
  vtkImageRegion *mask;
  // The bounds of the whole input image
  int inImageMin0, inImageMin1, inImageMin2;
  int inImageMax0, inImageMax1, inImageMax2;

  // Get information to march through data
  inRegion->GetIncrements3d(inInc0, inInc1, inInc2);
  inRegion->GetImageBounds3d(inImageMin0, inImageMax0, inImageMin1,
			     inImageMax1, inImageMin2, inImageMax2);
  outRegion->GetIncrements3d(outInc0, outInc1, outInc2);
  outRegion->GetBounds3d(outMin0, outMax0, outMin1, outMax1, outMin2, outMax2);

  // Get ivars of this object (easier than making friends)
  erodeValue = (T)(self->GetErodeValue());
  dilateValue = (T)(self->GetDilateValue());
  kernelSize = self->GetKernelSize();
  kernelMiddle = self->GetKernelMiddle();
  hoodMin0 = - kernelMiddle[0];
  hoodMin1 = - kernelMiddle[1];
  hoodMin2 = - kernelMiddle[2];
  hoodMax0 = hoodMin0 + kernelSize[0] - 1;
  hoodMax1 = hoodMin1 + kernelSize[1] - 1;
  hoodMax2 = hoodMin2 + kernelSize[2] - 1;

  // Setup mask info
  mask = self->GetMask();
  maskPtr = (unsigned char *)(mask->GetVoidPointer3d());
  mask->GetIncrements3d(maskInc0, maskInc1, maskInc2);

  // in and out should be marching through corresponding pixels.
  inPtr = (T *)(inRegion->GetVoidPointer3d(outMin0, outMin1, outMin2));

  // loop through pixels of output
  outPtr2 = outPtr;
  inPtr2 = inPtr;
  for (outIdx2 = outMin2; outIdx2 <= outMax2; ++outIdx2)
    {
    outPtr1 = outPtr2;
    inPtr1 = inPtr2;
    for (outIdx1 = outMin1; outIdx1 <= outMax1; ++outIdx1)
      {
      outPtr0 = outPtr1;
      inPtr0 = inPtr1;
      for (outIdx0 = outMin0; outIdx0 <= outMax0; ++outIdx0)
	{

	// Default behavior (copy input pixel)
	*outPtr0 = *inPtr0;
	if (*inPtr0 == erodeValue)
	  {
	  // loop through neighborhood pixels
	  // as sort of a hack to handle boundaries,
	  // input pointer will be marching through data that does not exist.
	  hoodPtr2 = inPtr0 - kernelMiddle[0] * inInc0
	    - kernelMiddle[1] * inInc1 - kernelMiddle[2] * inInc2;
	  maskPtr2 = maskPtr;
	  for (hoodIdx2 = hoodMin2; hoodIdx2 <= hoodMax2; ++hoodIdx2)
	    {
	    hoodPtr1 = hoodPtr2;
	    maskPtr1 = maskPtr2;
	    for (hoodIdx1 = hoodMin1; hoodIdx1 <= hoodMax1; ++hoodIdx1)
	      {
	      hoodPtr0 = hoodPtr1;
	      maskPtr0 = maskPtr1;
	      for (hoodIdx0 = hoodMin0; hoodIdx0 <= hoodMax0; ++hoodIdx0)
		{
		// A quick but rather expensive way to handle boundaries
		if ( ! boundaryFlag ||
		    (outIdx0 + hoodIdx0 >= inImageMin0 &&
		     outIdx0 + hoodIdx0 <= inImageMax0 &&
		     outIdx1 + hoodIdx1 >= inImageMin1 &&
		     outIdx1 + hoodIdx1 <= inImageMax1 &&
		     outIdx2 + hoodIdx2 >= inImageMin2 &&
		     outIdx2 + hoodIdx2 <= inImageMax2))
		  {
		  if (*hoodPtr0 == dilateValue && *maskPtr0)
		    {
		    *outPtr0 = dilateValue;
		    }
		  }

		hoodPtr0 += inInc0;
		maskPtr0 += maskInc0;
		}
	      hoodPtr1 += inInc1;
	      maskPtr1 += maskInc1;
	      }
	    hoodPtr2 += inInc2;
	    maskPtr2 += maskInc2;
	    }
	  }

	inPtr0 += inInc0;
	outPtr0 += outInc0;
	}
      inPtr1 += inInc1;
      outPtr1 += outInc1;
      }
    inPtr2 += inInc2;
    outPtr2 += outInc2;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method contains the first switch statement that calls the correct
// templated function for the input and output region types.
// This function deals with regions that are in the center of the image and
// need no boundary checking.
void vtkImage3dDilateErodeFilter::ExecuteCenter3d(vtkImageRegion *inRegion,
						  vtkImageRegion *outRegion)
{
  void *inPtr = inRegion->GetVoidPointer3d();
  void *outPtr = outRegion->GetVoidPointer3d();

  vtkDebugMacro(<< "Execute: inRegion = " << inRegion
		<< ", outRegion = " << outRegion);

  // Error checking on mask
  if ( ! this->Mask || (this->Mask->GetDataType() != VTK_IMAGE_UNSIGNED_CHAR))
    {
    vtkErrorMacro(<< "Execute3d: Bad Mask");
    return;
    }

  // this filter expects that input is the same type as output.
  if (inRegion->GetDataType() != outRegion->GetDataType())
    {
    vtkErrorMacro(<< "Execute: input DataType, " << inRegion->GetDataType()
                  << ", must match out DataType " << outRegion->GetDataType());
    return;
    }

  switch (inRegion->GetDataType())
    {
    case VTK_IMAGE_FLOAT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (float *)(inPtr),
			  outRegion, (float *)(outPtr), 0);
      break;
    case VTK_IMAGE_INT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (int *)(inPtr),
			  outRegion, (int *)(outPtr), 0);
      break;
    case VTK_IMAGE_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (short *)(inPtr),
			  outRegion, (short *)(outPtr), 0);
      break;
    case VTK_IMAGE_UNSIGNED_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned short *)(inPtr),
			  outRegion, (unsigned short *)(outPtr), 0);
      break;
    case VTK_IMAGE_UNSIGNED_CHAR:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned char *)(inPtr),
			  outRegion, (unsigned char *)(outPtr), 0);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown DataType");
      return;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method contains the first switch statement that calls the correct
// templated function for the input and output region types.
// It hanldes image boundaries, so the image does not shrink.
void vtkImage3dDilateErodeFilter::ExecuteBoundary3d(vtkImageRegion *inRegion,
						    vtkImageRegion *outRegion)
{
  void *inPtr = inRegion->GetVoidPointer3d();
  void *outPtr = outRegion->GetVoidPointer3d();

  vtkDebugMacro(<< "Execute: inRegion = " << inRegion
		<< ", outRegion = " << outRegion);

  // Error checking on mask
  if ( ! this->Mask || (this->Mask->GetDataType() != VTK_IMAGE_UNSIGNED_CHAR))
    {
    vtkErrorMacro(<< "Execute3d: Bad Mask");
    return;
    }

  // this filter expects that input is the same type as output.
  if (inRegion->GetDataType() != outRegion->GetDataType())
    {
    vtkErrorMacro(<< "Execute: input DataType, " << inRegion->GetDataType()
                  << ", must match out DataType " << outRegion->GetDataType());
    return;
    }

  switch (inRegion->GetDataType())
    {
    case VTK_IMAGE_FLOAT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (float *)(inPtr),
			  outRegion, (float *)(outPtr), 1);
      break;
    case VTK_IMAGE_INT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (int *)(inPtr),
			  outRegion, (int *)(outPtr), 1);
      break;
    case VTK_IMAGE_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (short *)(inPtr),
			  outRegion, (short *)(outPtr), 1);
      break;
    case VTK_IMAGE_UNSIGNED_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned short *)(inPtr),
			  outRegion, (unsigned short *)(outPtr), 1);
      break;
    case VTK_IMAGE_UNSIGNED_CHAR:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned char *)(inPtr),
			  outRegion, (unsigned char *)(outPtr), 1);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown DataType");
      return;
    }
}
<commit_msg>ERR: Added this=>Modified () in SetKernelSize.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImage3dDilateErodeFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkImage3dDilateErodeFilter.h"

//----------------------------------------------------------------------------
// Description:
// Construct an instance of vtkImage3dDilateErodeFilter fitler.
// By default zero values are dilated.
vtkImage3dDilateErodeFilter::vtkImage3dDilateErodeFilter()
{
  this->DilateValue = 0.0;
  this->ErodeValue = 255.0;
  this->HandleBoundariesOn();
  this->Mask = NULL;
  this->SetKernelSize(1,1,1);
}

//----------------------------------------------------------------------------
void vtkImage3dDilateErodeFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSpatialFilter::PrintSelf(os,indent);
  os << indent << "Dilate Value: " << this->DilateValue << "\n";
  os << indent << "Erode Value: " << this->ErodeValue << "\n";
}

//----------------------------------------------------------------------------
// Description:
// This method sets the size of the 3d neighborhood.  It also sets the
// default mask/footprint (an elipse).
void
vtkImage3dDilateErodeFilter::SetKernelSize(int size0, int size1, int size2)
{
  unsigned char *ptr0, *ptr1, *ptr2;
  int inc0, inc1, inc2;
  int idx0, idx1, idx2;
  double f0, f1, f2, radius0, radius1, radius2;

  this->Modified();

  this->KernelSize[0] = size0;
  this->KernelSize[1] = size1;
  this->KernelSize[2] = size2;

  this->KernelMiddle[0] = size0 / 2;
  this->KernelMiddle[1] = size1 / 2;
  this->KernelMiddle[2] = size2 / 2;

  // Create the eliptical mask
  if (this->Mask)
    {
    this->Mask->Delete();
    }
  this->Mask = new vtkImageRegion;
  this->Mask->SetDataType(VTK_IMAGE_UNSIGNED_CHAR);
  this->Mask->SetAxes(this->GetAxes());
  this->Mask->SetBounds3d(0, size0-1, 0, size1-1, 0, size2-1);
  this->Mask->Allocate();
  if ( ! this->Mask->IsAllocated())
    {
    this->Mask->Delete();
    this->Mask = NULL;
    vtkErrorMacro(<< "SetKernelSize: Allocation of mask failed.");
    return;
    }

  radius0 = (double)(size0) / 2.0;
  radius1 = (double)(size1) / 2.0;
  radius2 = (double)(size2) / 2.0;

  this->Mask->GetIncrements3d(inc0, inc1, inc2);
  ptr2 = (unsigned char *)(this->Mask->GetVoidPointer());
  for (idx2 = 0; idx2 < size2; ++idx2)
    {
    ptr1 = ptr2;
    for (idx1 = 0; idx1 < size1; ++idx1)
      {
      ptr0 = ptr1;
      for (idx0 = 0; idx0 < size0; ++idx0)
	{
	// convert xyz to values in the range of [-1,1]
	f0 = ((double)(idx0) - radius0 + 0.5) / (radius0);
	f1 = ((double)(idx1) - radius1 + 0.5) / (radius1);
	f2 = ((double)(idx2) - radius2 + 0.5) / (radius2);

	if (f0*f0 + f1*f1 + f2*f2 <= 1.0)
	  {
	  *ptr0 = 255;
	  }
	else
	  {
	  *ptr0 = 0;
	  }

	ptr0 += inc0;
	}
      ptr1 += inc1;
      }
    ptr2 += inc2;
    }
    this->Modified ();
}

//----------------------------------------------------------------------------
// Description:
// This templated function executes the filter on any region,
// whether it needs boundary checking or not.
// If the filter needs to be faster, the function could be duplicated
// for strictly center (no boundary ) processing.
template <class T>
void vtkImage3dDilateErodeFilterExecute(vtkImage3dDilateErodeFilter *self,
					vtkImageRegion *inRegion, T *inPtr,
					vtkImageRegion *outRegion, T *outPtr,
					int boundaryFlag)
{
  T erodeValue, dilateValue;
  int *kernelMiddle, *kernelSize;
  // For looping though output (and input) pixels.
  int outMin0, outMax0, outMin1, outMax1, outMin2, outMax2;
  int outIdx0, outIdx1, outIdx2;
  int inInc0, inInc1, inInc2;
  int outInc0, outInc1, outInc2;
  T *inPtr0, *inPtr1, *inPtr2;
  T *outPtr0, *outPtr1, *outPtr2;
  // For looping through hood pixels
  int hoodMin0, hoodMax0, hoodMin1, hoodMax1, hoodMin2, hoodMax2;
  int hoodIdx0, hoodIdx1, hoodIdx2;
  T *hoodPtr0, *hoodPtr1, *hoodPtr2;
  // For looping through the mask.
  unsigned char *maskPtr, *maskPtr0, *maskPtr1, *maskPtr2;
  int maskInc0, maskInc1, maskInc2;
  vtkImageRegion *mask;
  // The bounds of the whole input image
  int inImageMin0, inImageMin1, inImageMin2;
  int inImageMax0, inImageMax1, inImageMax2;

  // Get information to march through data
  inRegion->GetIncrements3d(inInc0, inInc1, inInc2);
  inRegion->GetImageBounds3d(inImageMin0, inImageMax0, inImageMin1,
			     inImageMax1, inImageMin2, inImageMax2);
  outRegion->GetIncrements3d(outInc0, outInc1, outInc2);
  outRegion->GetBounds3d(outMin0, outMax0, outMin1, outMax1, outMin2, outMax2);

  // Get ivars of this object (easier than making friends)
  erodeValue = (T)(self->GetErodeValue());
  dilateValue = (T)(self->GetDilateValue());
  kernelSize = self->GetKernelSize();
  kernelMiddle = self->GetKernelMiddle();
  hoodMin0 = - kernelMiddle[0];
  hoodMin1 = - kernelMiddle[1];
  hoodMin2 = - kernelMiddle[2];
  hoodMax0 = hoodMin0 + kernelSize[0] - 1;
  hoodMax1 = hoodMin1 + kernelSize[1] - 1;
  hoodMax2 = hoodMin2 + kernelSize[2] - 1;

  // Setup mask info
  mask = self->GetMask();
  maskPtr = (unsigned char *)(mask->GetVoidPointer3d());
  mask->GetIncrements3d(maskInc0, maskInc1, maskInc2);

  // in and out should be marching through corresponding pixels.
  inPtr = (T *)(inRegion->GetVoidPointer3d(outMin0, outMin1, outMin2));

  // loop through pixels of output
  outPtr2 = outPtr;
  inPtr2 = inPtr;
  for (outIdx2 = outMin2; outIdx2 <= outMax2; ++outIdx2)
    {
    outPtr1 = outPtr2;
    inPtr1 = inPtr2;
    for (outIdx1 = outMin1; outIdx1 <= outMax1; ++outIdx1)
      {
      outPtr0 = outPtr1;
      inPtr0 = inPtr1;
      for (outIdx0 = outMin0; outIdx0 <= outMax0; ++outIdx0)
	{

	// Default behavior (copy input pixel)
	*outPtr0 = *inPtr0;
	if (*inPtr0 == erodeValue)
	  {
	  // loop through neighborhood pixels
	  // as sort of a hack to handle boundaries,
	  // input pointer will be marching through data that does not exist.
	  hoodPtr2 = inPtr0 - kernelMiddle[0] * inInc0
	    - kernelMiddle[1] * inInc1 - kernelMiddle[2] * inInc2;
	  maskPtr2 = maskPtr;
	  for (hoodIdx2 = hoodMin2; hoodIdx2 <= hoodMax2; ++hoodIdx2)
	    {
	    hoodPtr1 = hoodPtr2;
	    maskPtr1 = maskPtr2;
	    for (hoodIdx1 = hoodMin1; hoodIdx1 <= hoodMax1; ++hoodIdx1)
	      {
	      hoodPtr0 = hoodPtr1;
	      maskPtr0 = maskPtr1;
	      for (hoodIdx0 = hoodMin0; hoodIdx0 <= hoodMax0; ++hoodIdx0)
		{
		// A quick but rather expensive way to handle boundaries
		if ( ! boundaryFlag ||
		    (outIdx0 + hoodIdx0 >= inImageMin0 &&
		     outIdx0 + hoodIdx0 <= inImageMax0 &&
		     outIdx1 + hoodIdx1 >= inImageMin1 &&
		     outIdx1 + hoodIdx1 <= inImageMax1 &&
		     outIdx2 + hoodIdx2 >= inImageMin2 &&
		     outIdx2 + hoodIdx2 <= inImageMax2))
		  {
		  if (*hoodPtr0 == dilateValue && *maskPtr0)
		    {
		    *outPtr0 = dilateValue;
		    }
		  }

		hoodPtr0 += inInc0;
		maskPtr0 += maskInc0;
		}
	      hoodPtr1 += inInc1;
	      maskPtr1 += maskInc1;
	      }
	    hoodPtr2 += inInc2;
	    maskPtr2 += maskInc2;
	    }
	  }

	inPtr0 += inInc0;
	outPtr0 += outInc0;
	}
      inPtr1 += inInc1;
      outPtr1 += outInc1;
      }
    inPtr2 += inInc2;
    outPtr2 += outInc2;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method contains the first switch statement that calls the correct
// templated function for the input and output region types.
// This function deals with regions that are in the center of the image and
// need no boundary checking.
void vtkImage3dDilateErodeFilter::ExecuteCenter3d(vtkImageRegion *inRegion,
						  vtkImageRegion *outRegion)
{
  void *inPtr = inRegion->GetVoidPointer3d();
  void *outPtr = outRegion->GetVoidPointer3d();

  vtkDebugMacro(<< "Execute: inRegion = " << inRegion
		<< ", outRegion = " << outRegion);

  // Error checking on mask
  if ( ! this->Mask || (this->Mask->GetDataType() != VTK_IMAGE_UNSIGNED_CHAR))
    {
    vtkErrorMacro(<< "Execute3d: Bad Mask");
    return;
    }

  // this filter expects that input is the same type as output.
  if (inRegion->GetDataType() != outRegion->GetDataType())
    {
    vtkErrorMacro(<< "Execute: input DataType, " << inRegion->GetDataType()
                  << ", must match out DataType " << outRegion->GetDataType());
    return;
    }

  switch (inRegion->GetDataType())
    {
    case VTK_IMAGE_FLOAT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (float *)(inPtr),
			  outRegion, (float *)(outPtr), 0);
      break;
    case VTK_IMAGE_INT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (int *)(inPtr),
			  outRegion, (int *)(outPtr), 0);
      break;
    case VTK_IMAGE_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (short *)(inPtr),
			  outRegion, (short *)(outPtr), 0);
      break;
    case VTK_IMAGE_UNSIGNED_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned short *)(inPtr),
			  outRegion, (unsigned short *)(outPtr), 0);
      break;
    case VTK_IMAGE_UNSIGNED_CHAR:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned char *)(inPtr),
			  outRegion, (unsigned char *)(outPtr), 0);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown DataType");
      return;
    }
}

//----------------------------------------------------------------------------
// Description:
// This method contains the first switch statement that calls the correct
// templated function for the input and output region types.
// It hanldes image boundaries, so the image does not shrink.
void vtkImage3dDilateErodeFilter::ExecuteBoundary3d(vtkImageRegion *inRegion,
						    vtkImageRegion *outRegion)
{
  void *inPtr = inRegion->GetVoidPointer3d();
  void *outPtr = outRegion->GetVoidPointer3d();

  vtkDebugMacro(<< "Execute: inRegion = " << inRegion
		<< ", outRegion = " << outRegion);

  // Error checking on mask
  if ( ! this->Mask || (this->Mask->GetDataType() != VTK_IMAGE_UNSIGNED_CHAR))
    {
    vtkErrorMacro(<< "Execute3d: Bad Mask");
    return;
    }

  // this filter expects that input is the same type as output.
  if (inRegion->GetDataType() != outRegion->GetDataType())
    {
    vtkErrorMacro(<< "Execute: input DataType, " << inRegion->GetDataType()
                  << ", must match out DataType " << outRegion->GetDataType());
    return;
    }

  switch (inRegion->GetDataType())
    {
    case VTK_IMAGE_FLOAT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (float *)(inPtr),
			  outRegion, (float *)(outPtr), 1);
      break;
    case VTK_IMAGE_INT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (int *)(inPtr),
			  outRegion, (int *)(outPtr), 1);
      break;
    case VTK_IMAGE_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (short *)(inPtr),
			  outRegion, (short *)(outPtr), 1);
      break;
    case VTK_IMAGE_UNSIGNED_SHORT:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned short *)(inPtr),
			  outRegion, (unsigned short *)(outPtr), 1);
      break;
    case VTK_IMAGE_UNSIGNED_CHAR:
      vtkImage3dDilateErodeFilterExecute(this,
			  inRegion, (unsigned char *)(inPtr),
			  outRegion, (unsigned char *)(outPtr), 1);
      break;
    default:
      vtkErrorMacro(<< "Execute: Unknown DataType");
      return;
    }
}
<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * 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.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Handle.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <spawn.h>
#   include <sys/wait.h>
#   if defined(CORECAT_OS_MACOS)
#       include <crt_externs.h>
#       define environ (*_NSGetEnviron())
#   else
#       include <unistd.h>
#   endif
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

struct ProcessOption {

    const char* file = nullptr;
    const char* const* argument = nullptr;
    const char* const* environment = nullptr;
    const char* directory = nullptr;

    ProcessOption(const char* file_, const char* const* argument_ = nullptr, const char* const* environment_ = nullptr, const char* directory_ = nullptr) :
        file(file_), argument(argument_), environment(environment_), directory(directory_) {}

};

class Process {

private:

    template <typename T>
    static Array<T> toNullTerminated(ArrayView<const T> arr) {

        Array<T> ret(arr.getSize() + 1);
        std::copy(arr.begin(), arr.end(), ret.begin());
        ret[arr.getSize()] = T();
        return ret;

    }

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getFullPath(const WString& file) {

        HMODULE module = ::LoadLibraryW(file.getData());
        if(!module) return {};
        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD pathLength = ::GetModuleFileNameW(module, path.getData(), DWORD(path.getLength() + 1));
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!pathLength) {

                ::FreeLibrary(module);
                return {};

            }
            path.setLength(pathLength);
            break;

        }
        ::FreeLibrary(module);
        return path;

    }

    static WString findFullPath(const WString& file) {

        WString path;
        path = getFullPath(file + L'.');
        if(!path.isEmpty()) return path;
        path = getFullPath(file + L".exe.");
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

private:
#if defined(CORECAT_OS_WINDOWS)
    Handle handle;
#else
    pid_t pid;
#endif

public:

    Process(const ProcessOption& option) {
#if defined(CORECAT_OS_WINDOWS)
        WString argument;
        if(option.argument) {

            for(auto p = option.argument; *p; ++p) {

                if(!argument.isEmpty()) argument += L' ';
                argument += L'"';
                for(auto&& c : WString(*p)) {

                    if(c == L'"') argument += L"\\\"";
                    else if(c == L'\\') argument += L"\\\\";
                    else argument += c;

                }
                argument += L'"';

            }

        }
        WString environment;
        if(option.environment) {

            for(auto p = option.environment; *p; ++p) {

                environment += WString(*p);
                environment += wchar_t();

            }

        }
        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        si.wShowWindow = SW_SHOWDEFAULT;
        PROCESS_INFORMATION pi = {};
        auto path = findFullPath(WString(option.file));
        if(!::CreateProcessW(
            path.getData(),
            option.argument ? argument.getData() : nullptr,
            nullptr,
            nullptr,
            true,
            CREATE_UNICODE_ENVIRONMENT,
            option.environment ? environment.getData() : nullptr,
            option.directory ? WString(option.directory).getData() : nullptr,
            &si,
            &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hThread);
        handle = pi.hProcess;
#else
        if(::posix_spawnp(
            &pid,
            option.file,
            nullptr,
            nullptr,
            const_cast<char* const*>(option.argument),
            option.environment ? const_cast<char* const*>(option.environment) : environ))
            throw SystemException("::posix_spawn failed");
#endif
    }
    Process(const char* file, const char* const* argument = nullptr, const char* const* environment = nullptr, const char* directory = nullptr) :
        Process(ProcessOption(file, argument, environment, directory)) {}
    Process(const char* file, const char* directory) :
        Process(file, nullptr, nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, ArrayView<const char* const> environment, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), toNullTerminated(environment).getData(), directory) {}
    Process(const Process& src) = delete;
    ~Process() = default;

    Process& operator =(const Process& src) = delete;

    std::int64_t wait() {
#if defined(CORECAT_OS_WINDOWS)
        if(::WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
            throw SystemException("::WaitForSingleObject failed");
        DWORD ret;
        if(!::GetExitCodeProcess(handle, &ret))
            throw SystemException("::GetExitCodeProcess failed");
        handle.close();
        return ret;
#else
        int ret;
        if(::waitpid(pid, &ret, 0) < 0)
            throw SystemException("::waitpid failed");
        pid = 0;
        return ret;
#endif
    }

};

}
}
}

#endif
<commit_msg>Update Process<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * 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.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Handle.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <spawn.h>
#   include <sys/wait.h>
#   if defined(CORECAT_OS_MACOS)
#       include <crt_externs.h>
#       define environ (*_NSGetEnviron())
#   else
#       include <unistd.h>
#   endif
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

struct ProcessOption {

    const char* file = nullptr;
    const char* const* argument = nullptr;
    const char* const* environment = nullptr;
    const char* directory = nullptr;

    ProcessOption(const char* file_, const char* const* argument_ = nullptr, const char* const* environment_ = nullptr, const char* directory_ = nullptr) :
        file(file_), argument(argument_), environment(environment_), directory(directory_) {}

};

class Process {

private:

    template <typename T>
    static Array<T> toNullTerminated(ArrayView<const T> arr) {

        Array<T> ret(arr.getSize() + 1);
        std::copy(arr.begin(), arr.end(), ret.begin());
        ret[arr.getSize()] = T();
        return ret;

    }

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getFullPath(const WString& file) {

        HMODULE module = ::LoadLibraryW(file.getData());
        if(!module) return {};
        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD pathLength = ::GetModuleFileNameW(module, path.getData(), DWORD(path.getLength() + 1));
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!pathLength) {

                ::FreeLibrary(module);
                return {};

            }
            path.setLength(pathLength);
            break;

        }
        ::FreeLibrary(module);
        return path;

    }

    static WString findFullPath(const WString& file) {

        WString path;
        path = getFullPath(file + L'.');
        if(!path.isEmpty()) return path;
        path = getFullPath(file + L".exe.");
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

private:
#if defined(CORECAT_OS_WINDOWS)
    Handle handle;
#else
    pid_t pid;
#endif

public:

    Process(const ProcessOption& option) {
#if defined(CORECAT_OS_WINDOWS)
        WString argument;
        if(option.argument) {

            for(auto p = option.argument; *p; ++p) {

                if(!argument.isEmpty()) argument += L' ';
                argument += L'"';
                for(auto&& c : WString(*p)) {

                    if(c == L'"') argument += L"\\\"";
                    else if(c == L'\\') argument += L"\\\\";
                    else argument += c;

                }
                argument += L'"';

            }

        }
        WString environment;
        if(option.environment) {

            for(auto p = option.environment; *p; ++p) {

                environment += WString(*p);
                environment += wchar_t();

            }

        }
        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        si.wShowWindow = SW_SHOWDEFAULT;
        PROCESS_INFORMATION pi = {};
        auto path = findFullPath(WString(option.file));
        if(!::CreateProcessW(
            path.getData(),
            option.argument ? argument.getData() : nullptr,
            nullptr,
            nullptr,
            true,
            CREATE_UNICODE_ENVIRONMENT,
            option.environment ? environment.getData() : nullptr,
            option.directory ? WString(option.directory).getData() : nullptr,
            &si,
            &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hThread);
        handle = pi.hProcess;
#else
        pid = ::fork();
        if(pid < 0)
            throw SystemException("::fork failed");
        if(pid > 0) {

            // Parent process

        } else {

            // Child process
            if(option.environment) environ = const_cast<char**>(option.environment);
            ::execvp(option.file, const_cast<char* const*>(option.argument));
            std::exit(127);

        }
#endif
    }
    Process(const char* file, const char* const* argument = nullptr, const char* const* environment = nullptr, const char* directory = nullptr) :
        Process(ProcessOption(file, argument, environment, directory)) {}
    Process(const char* file, const char* directory) :
        Process(file, nullptr, nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, ArrayView<const char* const> environment, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), toNullTerminated(environment).getData(), directory) {}
    Process(const Process& src) = delete;
    ~Process() = default;

    Process& operator =(const Process& src) = delete;

    std::int64_t wait() {
#if defined(CORECAT_OS_WINDOWS)
        if(::WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
            throw SystemException("::WaitForSingleObject failed");
        DWORD ret;
        if(!::GetExitCodeProcess(handle, &ret))
            throw SystemException("::GetExitCodeProcess failed");
        handle.close();
        return ret;
#else
        int ret;
        if(::waitpid(pid, &ret, 0) < 0)
            throw SystemException("::waitpid failed");
        pid = 0;
        return ret;
#endif
    }

};

}
}
}

#endif
<|endoftext|>