<commit_before>#include "mlfe/operators_v2/basic_arithmetic.h"
#include "mlfe/core/op_kernel.h"
#include "mlfe/math/activations.h"
#include "mlfe/device_context/cpu_context.h"

namespace mlfe{
namespace operators_v2{
namespace {

#define DEFINE_ELEMENTWISE_OP(name, expr)                  \
template <typename T>                                      \
void name##_fwd_impl(Tensor a, Tensor b, Tensor y){        \
    auto a_ptr = a.device_data<T>();                       \
    auto b_ptr = b.device_data<T>();                       \
    auto y_ptr = y.mutable_device_data<T>();               \
    int size = y.size();                                   \
    for(int n = 0; n < size; ++n){                         \
        y_ptr[n] = a_ptr[n] expr b_ptr[n];                 \
    }                                                      \
}

DEFINE_ELEMENTWISE_OP(eltwise_add, +)
DEFINE_ELEMENTWISE_OP(eltwise_sub, -)
DEFINE_ELEMENTWISE_OP(eltwise_mul, *)
DEFINE_ELEMENTWISE_OP(eltwise_div, /)

template <typename T>
void eltwise_add_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_add_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_sub_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_sub_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += -dy_ptr[n];
    }
}

template <typename T>
void eltwise_mul_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto b_ptr = b.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += b_ptr[n] * dy_ptr[n];
    }
}

template <typename T>
void eltwise_mul_right_bwd_impl(Tensor a, Tensor dy, Tensor db){
    auto a_ptr = a.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += a_ptr[n] * dy_ptr[n];
    }
}

template <typename T>
void eltwise_div_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto b_ptr = b.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n] / b_ptr[n];
    }
}

template <typename T>
void eltwise_div_right_bwd_impl(Tensor b, Tensor y, Tensor dy, Tensor db){
    auto b_ptr = b.device_data<T>();
    auto y_ptr = y.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += -dy_ptr[n] * y_ptr[n] / b_ptr[n];
    }
}

#define DEFINE_SCALAR_OP(name, expr)                       \
template <typename T>                                      \
void name##_fwd_impl(Tensor a, Tensor b, Tensor y){        \
    auto a_ptr = a.device_data<T>();                       \
    auto scalar = b.device_data<T>()[0];                   \
    auto y_ptr = y.mutable_device_data<T>();               \
    int size = y.size();                                   \
    for(int n = 0; n < size; ++n){                         \
        y_ptr[n] = a_ptr[n] expr scalar;                   \
    }                                                      \
}

DEFINE_SCALAR_OP(scalar_add, +)
DEFINE_SCALAR_OP(scalar_sub, -)
DEFINE_SCALAR_OP(scalar_mul, *)
DEFINE_SCALAR_OP(scalar_div, /)

template <typename T>
void scalar_add_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void scalar_add_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_sub_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void scalar_sub_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += -dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_mul_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto scalar_b = b.device_data<T>()[0];
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += scalar_b * dy_ptr[n];
    }
}

template <typename T>
void scalar_mul_right_bwd_impl(Tensor a, Tensor dy, Tensor db){
    auto a_ptr = a.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += a_ptr[n] * dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_div_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto b_ptr = b.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += b_ptr[n] * dy_ptr[n];
    }
}

template <typename T>
void scalar_div_right_bwd_impl(Tensor b, Tensor y, Tensor dy, Tensor db){
    auto scalar_b = b.device_data<T>()[0];
    auto y_ptr = y.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += -dy_ptr[n] * y_ptr[n] / scalar_b;
    }
    db_ptr[0] += sum;
}

} // namespace anonymous

REGIST_OP_KERNEL(eltwise_add_fwd, arithmetic_fwd_fn_t, eltwise_add_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_add_left_bwd, add_left_bwd_fn_t, eltwise_add_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_add_right_bwd, add_right_bwd_fn_t, eltwise_add_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_sub_fwd, arithmetic_fwd_fn_t, eltwise_sub_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_sub_left_bwd, sub_left_bwd_fn_t, eltwise_sub_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_sub_right_bwd, sub_right_bwd_fn_t, eltwise_sub_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_mul_fwd, arithmetic_fwd_fn_t, eltwise_mul_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_mul_left_bwd, mul_left_bwd_fn_t, eltwise_mul_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_mul_right_bwd, mul_right_bwd_fn_t, eltwise_mul_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_div_fwd, arithmetic_fwd_fn_t, eltwise_div_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_div_left_bwd, div_left_bwd_fn_t, eltwise_div_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_div_right_bwd, div_right_bwd_fn_t, eltwise_div_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_add_fwd, arithmetic_fwd_fn_t, scalar_add_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_add_left_bwd, add_left_bwd_fn_t, scalar_add_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_add_right_bwd, add_right_bwd_fn_t, scalar_add_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_sub_fwd, arithmetic_fwd_fn_t, scalar_sub_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_sub_left_bwd, sub_left_bwd_fn_t, scalar_sub_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_sub_right_bwd, sub_right_bwd_fn_t, scalar_sub_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_mul_fwd, arithmetic_fwd_fn_t, scalar_mul_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_mul_left_bwd, mul_left_bwd_fn_t, scalar_mul_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_mul_right_bwd, mul_right_bwd_fn_t, scalar_mul_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_div_fwd, arithmetic_fwd_fn_t, scalar_div_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_div_left_bwd, div_left_bwd_fn_t, scalar_div_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_div_right_bwd, div_right_bwd_fn_t, scalar_div_right_bwd_impl<float>);

namespace{

template <typename T>
void set_zeros_fwd_impl(Tensor x){
    auto x_ptr = x.mutable_device_data<T>();
    for(int i = 0; i < x.size(); ++i){ x_ptr[i] = T(0); }
}

template <typename T>
void set_ones_fwd_impl(Tensor x){
    auto x_ptr = x.mutable_device_data<T>();
    for(int i = 0; i < x.size(); ++i){ x_ptr[i] = T(1); }
}

} // namespace anonymous

REGIST_OP_KERNEL(set_zeros_fwd, set_x_fwd_fn_t, set_zeros_fwd_impl<float>);
REGIST_OP_KERNEL(set_ones_fwd, set_x_fwd_fn_t, set_ones_fwd_impl<float>);

} // namespace operators
} // namespace mlfe
<commit_msg>Fix scalar vector divide grad<commit_after>#include "mlfe/operators_v2/basic_arithmetic.h"
#include "mlfe/core/op_kernel.h"
#include "mlfe/math/activations.h"
#include "mlfe/device_context/cpu_context.h"

namespace mlfe{
namespace operators_v2{
namespace {

#define DEFINE_ELEMENTWISE_OP(name, expr)                  \
template <typename T>                                      \
void name##_fwd_impl(Tensor a, Tensor b, Tensor y){        \
    auto a_ptr = a.device_data<T>();                       \
    auto b_ptr = b.device_data<T>();                       \
    auto y_ptr = y.mutable_device_data<T>();               \
    int size = y.size();                                   \
    for(int n = 0; n < size; ++n){                         \
        y_ptr[n] = a_ptr[n] expr b_ptr[n];                 \
    }                                                      \
}

DEFINE_ELEMENTWISE_OP(eltwise_add, +)
DEFINE_ELEMENTWISE_OP(eltwise_sub, -)
DEFINE_ELEMENTWISE_OP(eltwise_mul, *)
DEFINE_ELEMENTWISE_OP(eltwise_div, /)

template <typename T>
void eltwise_add_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_add_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_sub_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void eltwise_sub_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += -dy_ptr[n];
    }
}

template <typename T>
void eltwise_mul_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto b_ptr = b.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += b_ptr[n] * dy_ptr[n];
    }
}

template <typename T>
void eltwise_mul_right_bwd_impl(Tensor a, Tensor dy, Tensor db){
    auto a_ptr = a.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += a_ptr[n] * dy_ptr[n];
    }
}

template <typename T>
void eltwise_div_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto b_ptr = b.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n] / b_ptr[n];
    }
}

template <typename T>
void eltwise_div_right_bwd_impl(Tensor b, Tensor y, Tensor dy, Tensor db){
    auto b_ptr = b.device_data<T>();
    auto y_ptr = y.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        db_ptr[n] += -dy_ptr[n] * y_ptr[n] / b_ptr[n];
    }
}

#define DEFINE_SCALAR_OP(name, expr)                       \
template <typename T>                                      \
void name##_fwd_impl(Tensor a, Tensor b, Tensor y){        \
    auto a_ptr = a.device_data<T>();                       \
    auto scalar = b.device_data<T>()[0];                   \
    auto y_ptr = y.mutable_device_data<T>();               \
    int size = y.size();                                   \
    for(int n = 0; n < size; ++n){                         \
        y_ptr[n] = a_ptr[n] expr scalar;                   \
    }                                                      \
}

DEFINE_SCALAR_OP(scalar_add, +)
DEFINE_SCALAR_OP(scalar_sub, -)
DEFINE_SCALAR_OP(scalar_mul, *)
DEFINE_SCALAR_OP(scalar_div, /)

template <typename T>
void scalar_add_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void scalar_add_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_sub_left_bwd_impl(Tensor dy, Tensor da){
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += dy_ptr[n];
    }
}

template <typename T>
void scalar_sub_right_bwd_impl(Tensor dy, Tensor db){
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += -dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_mul_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto scalar_b = b.device_data<T>()[0];
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += scalar_b * dy_ptr[n];
    }
}

template <typename T>
void scalar_mul_right_bwd_impl(Tensor a, Tensor dy, Tensor db){
    auto a_ptr = a.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += a_ptr[n] * dy_ptr[n];
    }
    db_ptr[0] += sum;
}

template <typename T>
void scalar_div_left_bwd_impl(Tensor b, Tensor dy, Tensor da){
    auto scalar = T(1) / b.device_data<T>()[0];
    auto dy_ptr = dy.device_data<T>();
    auto da_ptr = da.mutable_device_data<T>();
    auto size = dy.size();
    for(int n = 0; n < size; ++n){
        da_ptr[n] += scalar * dy_ptr[n];
    }
}

template <typename T>
void scalar_div_right_bwd_impl(Tensor b, Tensor y, Tensor dy, Tensor db){
    auto scalar_b = b.device_data<T>()[0];
    auto y_ptr = y.device_data<T>();
    auto dy_ptr = dy.device_data<T>();
    auto db_ptr = db.mutable_device_data<T>();
    auto size = dy.size();
    T sum = T(0);
    for(int n = 0; n < size; ++n){
        sum += -dy_ptr[n] * y_ptr[n] / scalar_b;
    }
    db_ptr[0] += sum;
}

} // namespace anonymous

REGIST_OP_KERNEL(eltwise_add_fwd, arithmetic_fwd_fn_t, eltwise_add_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_add_left_bwd, add_left_bwd_fn_t, eltwise_add_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_add_right_bwd, add_right_bwd_fn_t, eltwise_add_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_sub_fwd, arithmetic_fwd_fn_t, eltwise_sub_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_sub_left_bwd, sub_left_bwd_fn_t, eltwise_sub_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_sub_right_bwd, sub_right_bwd_fn_t, eltwise_sub_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_mul_fwd, arithmetic_fwd_fn_t, eltwise_mul_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_mul_left_bwd, mul_left_bwd_fn_t, eltwise_mul_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_mul_right_bwd, mul_right_bwd_fn_t, eltwise_mul_right_bwd_impl<float>);

REGIST_OP_KERNEL(eltwise_div_fwd, arithmetic_fwd_fn_t, eltwise_div_fwd_impl<float>);
REGIST_OP_KERNEL(eltwise_div_left_bwd, div_left_bwd_fn_t, eltwise_div_left_bwd_impl<float>);
REGIST_OP_KERNEL(eltwise_div_right_bwd, div_right_bwd_fn_t, eltwise_div_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_add_fwd, arithmetic_fwd_fn_t, scalar_add_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_add_left_bwd, add_left_bwd_fn_t, scalar_add_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_add_right_bwd, add_right_bwd_fn_t, scalar_add_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_sub_fwd, arithmetic_fwd_fn_t, scalar_sub_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_sub_left_bwd, sub_left_bwd_fn_t, scalar_sub_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_sub_right_bwd, sub_right_bwd_fn_t, scalar_sub_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_mul_fwd, arithmetic_fwd_fn_t, scalar_mul_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_mul_left_bwd, mul_left_bwd_fn_t, scalar_mul_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_mul_right_bwd, mul_right_bwd_fn_t, scalar_mul_right_bwd_impl<float>);

REGIST_OP_KERNEL(scalar_div_fwd, arithmetic_fwd_fn_t, scalar_div_fwd_impl<float>);
REGIST_OP_KERNEL(scalar_div_left_bwd, div_left_bwd_fn_t, scalar_div_left_bwd_impl<float>);
REGIST_OP_KERNEL(scalar_div_right_bwd, div_right_bwd_fn_t, scalar_div_right_bwd_impl<float>);

namespace{

template <typename T>
void set_zeros_fwd_impl(Tensor x){
    auto x_ptr = x.mutable_device_data<T>();
    for(int i = 0; i < x.size(); ++i){ x_ptr[i] = T(0); }
}

template <typename T>
void set_ones_fwd_impl(Tensor x){
    auto x_ptr = x.mutable_device_data<T>();
    for(int i = 0; i < x.size(); ++i){ x_ptr[i] = T(1); }
}

} // namespace anonymous

REGIST_OP_KERNEL(set_zeros_fwd, set_x_fwd_fn_t, set_zeros_fwd_impl<float>);
REGIST_OP_KERNEL(set_ones_fwd, set_x_fwd_fn_t, set_ones_fwd_impl<float>);

} // namespace operators
} // namespace mlfe
<|endoftext|>


<commit_before>#include <omp.h>
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <cstdint>

using namespace std;

int* global_queens;
int size = 8;
int level = 6;
bool stop = false;
int depth = 0;
int maxDepth = 10000;

std::string getRunTimeString(chrono::steady_clock::time_point beginTime, chrono::steady_clock::time_point endTime) {
  std::string res;
  std::chrono::steady_clock::duration diff = endTime - beginTime;
  auto h = std::chrono::duration_cast<std::chrono::hours> (diff);
  auto min = std::chrono::duration_cast<std::chrono::minutes> (diff);
  auto sec = std::chrono::duration_cast<std::chrono::seconds> (diff);
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds> (diff);
  auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (diff);
  if (h.count() > 0) {
    res.append(std::to_string(h.count()));
    res.append("h ");
  }
  if (min.count() > 0) {
    res.append(std::to_string(min.count() % 60));
    res.append(" min ");
  }
  res.append(std::to_string(sec.count() % 60));
  res.append(".");
  if (ms.count() % 1000 < 100)
    res.append("0");
  if (ms.count() % 1000 < 10)
    res.append("0");
  res.append(std::to_string(ms.count() % 1000));
  if (ms.count() == 0) {
    if (ns.count() % 1000 < 100)
      res.append("0");
    if (ns.count() % 1000 < 10)
      res.append("0");
    res.append(std::to_string(ns.count() % 1000));
  }
  res.append(" sec");
  return res;
}

void printBoard(int* queens) {
  for (int z = 0; z < size; z++) cout << queens[z] << " ";
  cout << endl;
}

void generateBoard(int* queens) {
  omp_set_num_threads(size);
  cout << "Generating board of size=" << size << endl;
  //#pragma omp parallel
  for (int i = 0; i < size; i++)
  {
    //int i = omp_get_thread_num();
    queens[i] = i;
  }
}

/**
 * @return true if the specified queen doesn't have any conflict.
 */
bool checkQueen(int q, int* queens) {
  for (int i = 0; i < size; i++)
  {
    if (i != q) {
      if (queens[i] == queens[q]) {
	return false;
      }

      int diff = abs(i - q);
      if (abs(queens[i] - queens[q]) == diff) {
	return false;
      }

    }
  }
  return true;
}

/**
 * @return true if the entire board is OK.
 */
bool checkBoard(int* queens) {
  for (int i = 0; i < size; i ++) {
    if (!checkQueen(i, queens)) {
      return false;
    }
  }
  return true;
}

void shuffleBoard(int* queens) {
  omp_set_num_threads(size);
#pragma omp parallel
  //for (int i = 0; i < size; i++)
  {
    int i = omp_get_thread_num();
    queens[i] = rand() % size;
  }
}

void shuffleQueen(int q, int* queens) {
  queens[q] = rand() % size;
}

void swap(int q1, int q2, int* queens) {
  int tmp = queens[q1];
  queens[q1] = queens[q2];
  queens[q2] = tmp;
}

int* copyBoard(int* queens) {
  int* nuBoard = new int[size];
  for (int i = 0; i < size; i++) {
    nuBoard[i] = queens[i];
  }
  return nuBoard;
}

void search_exhaustive(int* queens, int q) {
  if (q == size) {
    //stop
    if (checkBoard(queens)) {
      cout << "FINAL STOP:\t";
      printBoard(queens);
    }
  } else {
    for (int i = 0; i < size; i++) {
      if (stop) return;
      queens[q] = i;
      if (!checkBoard(queens)) {
	if (q < level) {
	  int* nuBoard = copyBoard(queens);
#pragma omp task
	  search_exhaustive(nuBoard, q+1);
	} else {
	  search_exhaustive(queens, q+1);
	}
      } else {
	cout << "REGULAR STOP:\t";
	printBoard(queens);
	delete[] global_queens;
	global_queens = queens;
	stop = true;
      }
    }
  }
}

int64_t  lineConflict(int iValue, int jValue) {
  if (iValue == jValue){
    return 1;
  }
  return 0;
}

int64_t  diagConflict(int difference, int iValue, int jValue) {
  if (difference == abs(iValue - jValue)) {
    return 1;
  }
  return 0;
}

int64_t calculateCost(int* queens, int* conflicts = NULL) {
  int64_t  cost = 0;
  int c_i = 0;
  for(int i = 0; i < size; i++){
    for (int j = i + 1 ; j < size ; j++){
      cost += diagConflict(j-i, queens[i], queens[j]) ;
      cost += lineConflict(queens[i], queens[j]);
      if (conflicts != NULL && (c_i == 0 || conflicts[c_i - 1] != i)) {
	conflicts[c_i] = i;
	c_i++;
      }
    }
  }
  return cost;
}

bool shouldWeStop() {
  return depth >= maxDepth;
}

void descent(int* queens) {
  int cost = calculateCost(queens);
  if (cost > 0 && !stop) {
    int q1 = rand() % size;
    int q2 = rand() % size;
    while (q2 == q1)  q2 = rand() % size;
    swap(q1, q2, queens);
    int tempCost = calculateCost(queens);
    if (tempCost > cost) {
      swap(q1, q2, queens);
    } else {
      cost = tempCost;
    }
    depth++;
    stop = shouldWeStop();
    //cout << "depth=" << depth << "; cost=" << cost << endl;
    #pragma omp task
    descent(queens);
  }
}

int64_t  updated_cost(int * queens, int index1, int index2) {
  int64_t  toReturn = 0;
  for(int i = 0; i < size; i++) {
    if (i!=index1) {
      toReturn+= diagConflict(abs(i-index1), queens[index1], queens[i]);
      toReturn+=lineConflict(queens[index1], queens[i]);
    }
    if (i!=index2) {
      toReturn+= diagConflict(abs(i-index2), queens[index2], queens[i]);
      toReturn+=lineConflict(queens[index2], queens[i]);
    }
  }

  return toReturn;
}

/*
void descent_it(int* queens) {
 // int cost = calculateCost(queens);

  for (int k = 0; k < 50; k++) {
  //for (int i = 0; i < 50 * 380; i++)
    int cost = calculateCost(queens);
    int cost2 = cost;
   // cout << cost2 << " " << cost << endl;
     if (cost == 0) break;
    omp_set_num_threads(380);
#pragma omp parallel
    {
      int i = omp_get_thread_num();
      //int cost = calculateCost(queens);
      if (cost > 0 && !stop) {
      	int q1 = rand() % size;
      	int q2 = rand() % size;
      	while (q2 == q1)  q2 = rand() % size;
        cost2 = cost;

        cost2 -=updated_cost(queens, q1, q2);
      	swap(q1, q2, queens);
        cost2 +=updated_cost(queens, q1, q2);
      	int tempCost = calculateCost(queens);
        //cout << tempCost << " " << cost2 << endl;
    //    if (tempCost != cost2) cout << " not" << endl;
      	if (tempCost > cost) {
      	  swap(q1, q2, queens);
          cost2 = cost;
      	} else {
      	  cost = tempCost;
      	}
      	depth++;
	//stop = shouldWeStop();
	//cout << "depth=" << depth << "; cost=" << cost << endl;
      } else {
	//break;
      }
    }
  }
}
*/
int64_t descent_it_it(int* queens) {

  int64_t cost = calculateCost(queens);

  for (int i = 0; i < 50 * 380; i++) {
    if (cost > 0 && !stop) {
      int q1 = rand() % size;
      int q2 = rand() % size;
      while (q2 == q1)  q2 = rand() % size;
      int64_t tempCost = cost;
      tempCost -= updated_cost(queens, q1, q2);
      swap(q1, q2, queens);
      tempCost += updated_cost(queens, q1, q2);

      if (tempCost > cost) {
        	swap(q1, q2, queens);
      } else {
      	cost = tempCost;
      }
      depth++;
    } else {
      break;
    }
  }
  return cost;
}
/*
void descent_it_conf(int* queens) {
  for (int k = 0; k < 50; k++) {
  //for (int i = 0; i < 50 * 380; i++)
    omp_set_num_threads(380);
#pragma omp parallel
    {
      int i = omp_get_thread_num();
      int* conflicts = new int[size];
      int cost = calculateCost(queens, conflicts);
      if (cost > 0 && !stop) {
	int q1 = conflicts[rand() % cost];
	int q2 = rand() % size;
	while (q2 == q1)  q2 = rand() % size;
	swap(q1, q2, queens);
	int tempCost = calculateCost(queens);
	if (tempCost > cost) {
	  swap(q1, q2, queens);
	} else {
	  cost = tempCost;
	}
	depth++;
	//stop = shouldWeStop();
	//cout << "depth=" << depth << "; cost=" << cost << endl;
      } else {
	//break;
      }
    }
  }
}
*/

int main(int argc, char** argv) {
 // srand(1);
  if (argc > 1) {
    size = atoi(argv[1]);
  }
  global_queens = new int[size];
  generateBoard(global_queens);

  std::chrono::steady_clock clock;
  chrono::steady_clock::time_point begin;
  chrono::steady_clock::time_point end;
  double time;
  begin = clock.now();

  //search_exhaustive(global_queens, 0);
  int64_t cost =  descent_it_it(global_queens);

  end = clock.now();

  //time = (double) (end - begin) / CLOCKS_PER_SEC;

  cout << "\n\n\n";
  printBoard(global_queens);
  cout << "Final board with cost=" << cost << ":\n";
  cout << "Runtime: " << getRunTimeString(begin, end) << endl;

  delete[] global_queens;
}
<commit_msg>code clean up<commit_after>#include <omp.h>
#include <cstdlib>
#include <iostream>
#include <cstdint>

using namespace std;

int* global_queens;
int size = 8;
int level = 6;

void printBoard(int* queens) {
  for (int z = 0; z < size; z++) cout << queens[z] << " ";
  cout << endl;
}

void generateBoard(int* queens) {
  omp_set_num_threads(size);
  cout << "Generating board of size=" << size << endl;
  //#pragma omp parallel
  for (int i = 0; i < size; i++)
  {
    //int i = omp_get_thread_num();
    queens[i] = i;
  }
}

/**
 * @return true if the specified queen doesn't have any conflict.
 */
bool checkQueen(int q, int* queens) {
  for (int i = 0; i < size; i++)
  {
    if (i != q) {
      if (queens[i] == queens[q]) {
	return false;
      }

      int diff = abs(i - q);
      if (abs(queens[i] - queens[q]) == diff) {
	return false;
      }

    }
  }
  return true;
}

/**
 * @return true if the entire board is OK.
 */
bool checkBoard(int* queens) {
  for (int i = 0; i < size; i ++) {
    if (!checkQueen(i, queens)) {
      return false;
    }
  }
  return true;
}

void shuffleBoard(int* queens) {
  omp_set_num_threads(size);
#pragma omp parallel
  //for (int i = 0; i < size; i++)
  {
    int i = omp_get_thread_num();
    queens[i] = rand() % size;
  }
}

void shuffleQueen(int q, int* queens) {
  queens[q] = rand() % size;
}

void swap(int q1, int q2, int* queens) {
  int tmp = queens[q1];
  queens[q1] = queens[q2];
  queens[q2] = tmp;
}

int* copyBoard(int* queens) {
  int* nuBoard = new int[size];
  for (int i = 0; i < size; i++) {
    nuBoard[i] = queens[i];
  }
  return nuBoard;
}

int64_t  lineConflict(int iValue, int jValue) {
  if (iValue == jValue){
    return 1;
  }
  return 0;
}

int64_t  diagConflict(int difference, int iValue, int jValue) {
  if (difference == abs(iValue - jValue)) {
    return 1;
  }
  return 0;
}

int64_t calculateCost(int* queens, int* conflicts = NULL) {
  int64_t  cost = 0;
  int c_i = 0;
  for(int i = 0; i < size; i++){
    for (int j = i + 1 ; j < size ; j++){
      cost += diagConflict(j-i, queens[i], queens[j]) ;
      cost += lineConflict(queens[i], queens[j]);
      if (conflicts != NULL && (c_i == 0 || conflicts[c_i - 1] != i)) {
	conflicts[c_i] = i;
	c_i++;
      }
    }
  }
  return cost;
}

int64_t  updated_cost(int * queens, int index1, int index2) {
  int64_t  toReturn = 0;
  for(int i = 0; i < size; i++) {
    if (i!=index1) {
      toReturn+= diagConflict(abs(i-index1), queens[index1], queens[i]);
      toReturn+=lineConflict(queens[index1], queens[i]);
    }
    if (i!=index2) {
      toReturn+= diagConflict(abs(i-index2), queens[index2], queens[i]);
      toReturn+=lineConflict(queens[index2], queens[i]);
    }
  }

  return toReturn;
}

int64_t descent_it_it(int* queens) {

  int64_t cost = calculateCost(queens);

  for (int i = 0; i < 50 * 380; i++) {
    if (cost > 0) {
      int q1 = rand() % size;
      int q2 = rand() % size;
      while (q2 == q1)  q2 = rand() % size;
      int64_t tempCost = cost;
      tempCost -= updated_cost(queens, q1, q2);
      swap(q1, q2, queens);
      tempCost += updated_cost(queens, q1, q2);

      if (tempCost > cost) {
        	swap(q1, q2, queens);
      } else {
      	cost = tempCost;
      }
    } else {
      break;
    }
  }
  return cost;
}

int main(int argc, char** argv) {
 // srand(1);
  if (argc > 1) {
    size = atoi(argv[1]);
  }

  global_queens = new int[size];

  generateBoard(global_queens);

  int64_t cost =  descent_it_it(global_queens);

  cout << "\n\n\n";
  printBoard(global_queens);
  cout << "Final board with cost=" << cost << ":\n";

  delete[] global_queens;
}
<|endoftext|>


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

#include "modules/common/util/down_sampler.h"

#include "modules/common/math/vec2d.h"

#include <vector>

#include "gtest/gtest.h"

namespace apollo {
namespace common {
namespace util {

TEST(DownSamplerTest, DownSampleByAngle) {
    using ::apollo::common::math::Vec2d;

    std::vector<Vec2d> points;
    points.emplace_back(-405.778, -134.969);
    points.emplace_back(-403.919, -127.696);
    points.emplace_back(-400.635, -115.407);
    points.emplace_back(-397.997, -105.291);
    points.emplace_back(-395.801, -96.8637);
    points.emplace_back(-392.889, -86.1015);
    points.emplace_back(-388.054, -67.9935);
    points.emplace_back(-385.994, -60.1831);
    points.emplace_back(-378.213, -30.2776);
    points.emplace_back(-376.702, -24.5804);
    points.emplace_back(-373.825, -13.3855);
    points.emplace_back(-367.583, 10.4028);
    points.emplace_back(-363.025, 27.4212);

    std::vector<int> sampled_indices;

    EXPECT_TRUE(DownSampleByAngle(points, 0.1, &sampled_indices));
    EXPECT_EQ(2, sampled_indices.size());
    EXPECT_EQ(0, sampled_indices[0]);
    EXPECT_EQ(12, sampled_indices[1]);
}

}  // namespace util
}  // namespace common
}  // namespace apollo

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

#include "modules/common/util/points_downsampler.h"

#include "modules/common/math/vec2d.h"

#include <vector>

#include "gtest/gtest.h"

namespace apollo {
namespace common {
namespace util {

TEST(DownSamplerTest, DownSampleByAngle) {
  using ::apollo::common::math::Vec2d;

  std::vector<Vec2d> points;
  points.emplace_back(-405.778, -134.969);
  points.emplace_back(-403.919, -127.696);
  points.emplace_back(-400.635, -115.407);
  points.emplace_back(-397.997, -105.291);
  points.emplace_back(-395.801, -96.8637);
  points.emplace_back(-392.889, -86.1015);
  points.emplace_back(-388.054, -67.9935);
  points.emplace_back(-385.994, -60.1831);
  points.emplace_back(-378.213, -30.2776);
  points.emplace_back(-376.702, -24.5804);
  points.emplace_back(-373.825, -13.3855);
  points.emplace_back(-367.583, 10.4028);
  points.emplace_back(-363.025, 27.4212);

  std::vector<int> sampled_indices;

  EXPECT_TRUE(DownSampleByAngle(points, 0.1, &sampled_indices));
  EXPECT_EQ(2, sampled_indices.size());
  EXPECT_EQ(0, sampled_indices[0]);
  EXPECT_EQ(12, sampled_indices[1]);
}

}  // namespace util
}  // namespace common
}  // namespace apollo
<|endoftext|>


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

#include <cmath>

#include "modules/prediction/common/prediction_gflags.h"

// System gflags
DEFINE_string(prediction_module_name, "prediction",
              "Default prediciton module name");
DEFINE_string(prediction_conf_file,
              "modules/prediction/conf/prediction_conf.pb.txt",
              "Default conf file for prediction");
DEFINE_string(prediction_adapter_config_filename,
              "modules/prediction/conf/adapter.conf",
              "Default conf file for prediction");
DEFINE_bool(prediction_test_mode, false, "Set prediction to test mode");
DEFINE_double(
    prediction_test_duration, -1.0,
    "The runtime duration in test mode (in seconds). Negative value will not "
    "restrict the runtime duration.");

DEFINE_double(prediction_duration, 5.0, "Prediction duration (in seconds)");
DEFINE_double(prediction_period, 0.1, "Prediction period (in seconds");
DEFINE_double(double_precision, 1e-6, "precision of double");
DEFINE_double(min_prediction_length, 50.0,
              "Minimal length of prediction trajectory");

// Bag replay timestamp gap
DEFINE_double(replay_timestamp_gap, 10.0,
              "Max timestamp gap for rosbag replay");

// Map
DEFINE_double(lane_search_radius, 3.0, "Search radius for a candidate lane");
DEFINE_double(junction_search_radius, 1.0, "Search radius for a junction");

// Obstacle features
DEFINE_bool(enable_kf_tracking, false, "Use measurements with KF tracking");
DEFINE_double(max_acc, 4.0, "Upper bound of acceleration");
DEFINE_double(min_acc, -4.0, "Lower bound of deceleration");
DEFINE_double(max_speed, 35.0, "Max speed");
DEFINE_double(q_var, 0.01, "Processing noise covariance");
DEFINE_double(r_var, 0.25, "Measurement noise covariance");
DEFINE_double(p_var, 0.1, "Error covariance");
DEFINE_double(go_approach_rate, 0.995,
              "The rate to approach to the reference line of going straight");
DEFINE_double(cutin_approach_rate, 0.9,
              "The rate to approach to the reference line of lane change");
DEFINE_int32(still_obstacle_history_length, 10,
             "Min # historical frames for still obstacles");
DEFINE_double(still_obstacle_speed_threshold, 2.0,
              "Speed threshold for still obstacles");
DEFINE_double(still_pedestrian_speed_threshold, 0.5,
              "Speed threshold for still pedestrians");
DEFINE_double(still_obstacle_position_std, 1.0,
              "Position standard deviation for still obstacles");
DEFINE_double(max_history_time, 7.0, "Obstacles' maximal historical time.");
DEFINE_double(target_lane_gap, 2.0, "gap between two lane points.");
DEFINE_int32(max_num_current_lane, 1, "Max number to search current lanes");
DEFINE_int32(max_num_nearby_lane, 2, "Max number to search nearby lanes");
DEFINE_double(max_lane_angle_diff, M_PI / 2.0,
              "Max angle difference for a candiate lane");
DEFINE_bool(enable_pedestrian_acc, false, "Enable calculating speed by acc");
DEFINE_double(coeff_mul_sigma, 2.0, "coefficient multiply standard deviation");
DEFINE_double(pedestrian_max_speed, 10.0, "speed upper bound for pedestrian");
DEFINE_double(pedestrian_max_acc, 2.0, "maximum pedestrian acceleration");
DEFINE_double(prediction_pedestrian_total_time, 10.0,
              "Total prediction time for pedestrians");
DEFINE_double(still_speed, 0.01, "speed considered to be still");
DEFINE_string(evaluator_vehicle_mlp_file,
              "modules/prediction/data/mlp_vehicle_model.bin",
              "mlp model file for vehicle evaluator");
DEFINE_string(evaluator_vehicle_rnn_file,
              "modules/prediction/data/rnn_vehicle_model.bin",
              "rnn model file for vehicle evaluator");
DEFINE_int32(max_num_obstacles, 100,
             "maximal number of obstacles stored in obstacles container.");
DEFINE_double(valid_position_diff_threshold, 0.5,
              "threshold of valid position difference");
DEFINE_double(valid_position_diff_rate_threshold, 0.075,
              "threshold of valid position difference rate");
DEFINE_double(split_rate, 0.5,
              "obstacle split rate for adjusting velocity");
DEFINE_double(rnn_min_lane_relatice_s, 5.0,
              "Minimal relative s for RNN model.");
DEFINE_bool(enable_adjust_velocity_heading, false,
            "adjust velocity heading to lane heading");
DEFINE_double(heading_filter_param, 0.99, "heading filter parameter");

// Obstacle trajectory
DEFINE_double(lane_sequence_threshold, 0.5,
              "Threshold for trimming lane sequence trajectories");
DEFINE_double(lane_change_dist, 10.0, "Lane change distance with ADC");
DEFINE_bool(enable_lane_sequence_acc, false,
            "If use acceleration in lane sequence.");
DEFINE_bool(enable_trim_prediction_trajectory, false,
            "If trim the prediction trajectory to avoid crossing"
            "protected adc planning trajectory.");
DEFINE_double(distance_beyond_junction, 0.5,
              "If the obstacle is in junction more than this threshold,"
              "consider it in junction.");
DEFINE_double(adc_trajectory_search_length, 10.0,
              "How far to search junction along adc planning trajectory");
DEFINE_double(virtual_lane_radius, 0.5, "Radius to search virtual lanes");
DEFINE_double(default_lateral_approach_speed, 0.5,
              "Default lateral speed approaching to center of lane");

// move sequence prediction
DEFINE_double(time_upper_bound_to_lane_center, 5.0,
              "Upper bound of time to get to the lane center");
DEFINE_double(time_lower_bound_to_lane_center, 1.0,
              "Lower bound of time to get to the lane center");
DEFINE_double(sample_time_gap, 0.2,
              "Gap of time to sample time to get to the lane center");
DEFINE_double(cost_alpha, 100.0,
              "The coefficient of lateral acceleration in cost function");
DEFINE_double(default_time_to_lane_center, 5.0,
              "The default time to lane center");
<commit_msg>Prediction: modify min_prediction_length to 20.0<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include <cmath>

#include "modules/prediction/common/prediction_gflags.h"

// System gflags
DEFINE_string(prediction_module_name, "prediction",
              "Default prediciton module name");
DEFINE_string(prediction_conf_file,
              "modules/prediction/conf/prediction_conf.pb.txt",
              "Default conf file for prediction");
DEFINE_string(prediction_adapter_config_filename,
              "modules/prediction/conf/adapter.conf",
              "Default conf file for prediction");
DEFINE_bool(prediction_test_mode, false, "Set prediction to test mode");
DEFINE_double(
    prediction_test_duration, -1.0,
    "The runtime duration in test mode (in seconds). Negative value will not "
    "restrict the runtime duration.");

DEFINE_double(prediction_duration, 5.0, "Prediction duration (in seconds)");
DEFINE_double(prediction_period, 0.1, "Prediction period (in seconds");
DEFINE_double(double_precision, 1e-6, "precision of double");
DEFINE_double(min_prediction_length, 20.0,
              "Minimal length of prediction trajectory");

// Bag replay timestamp gap
DEFINE_double(replay_timestamp_gap, 10.0,
              "Max timestamp gap for rosbag replay");

// Map
DEFINE_double(lane_search_radius, 3.0, "Search radius for a candidate lane");
DEFINE_double(junction_search_radius, 1.0, "Search radius for a junction");

// Obstacle features
DEFINE_bool(enable_kf_tracking, false, "Use measurements with KF tracking");
DEFINE_double(max_acc, 4.0, "Upper bound of acceleration");
DEFINE_double(min_acc, -4.0, "Lower bound of deceleration");
DEFINE_double(max_speed, 35.0, "Max speed");
DEFINE_double(q_var, 0.01, "Processing noise covariance");
DEFINE_double(r_var, 0.25, "Measurement noise covariance");
DEFINE_double(p_var, 0.1, "Error covariance");
DEFINE_double(go_approach_rate, 0.995,
              "The rate to approach to the reference line of going straight");
DEFINE_double(cutin_approach_rate, 0.9,
              "The rate to approach to the reference line of lane change");
DEFINE_int32(still_obstacle_history_length, 10,
             "Min # historical frames for still obstacles");
DEFINE_double(still_obstacle_speed_threshold, 2.0,
              "Speed threshold for still obstacles");
DEFINE_double(still_pedestrian_speed_threshold, 0.5,
              "Speed threshold for still pedestrians");
DEFINE_double(still_obstacle_position_std, 1.0,
              "Position standard deviation for still obstacles");
DEFINE_double(max_history_time, 7.0, "Obstacles' maximal historical time.");
DEFINE_double(target_lane_gap, 2.0, "gap between two lane points.");
DEFINE_int32(max_num_current_lane, 1, "Max number to search current lanes");
DEFINE_int32(max_num_nearby_lane, 2, "Max number to search nearby lanes");
DEFINE_double(max_lane_angle_diff, M_PI / 2.0,
              "Max angle difference for a candiate lane");
DEFINE_bool(enable_pedestrian_acc, false, "Enable calculating speed by acc");
DEFINE_double(coeff_mul_sigma, 2.0, "coefficient multiply standard deviation");
DEFINE_double(pedestrian_max_speed, 10.0, "speed upper bound for pedestrian");
DEFINE_double(pedestrian_max_acc, 2.0, "maximum pedestrian acceleration");
DEFINE_double(prediction_pedestrian_total_time, 10.0,
              "Total prediction time for pedestrians");
DEFINE_double(still_speed, 0.01, "speed considered to be still");
DEFINE_string(evaluator_vehicle_mlp_file,
              "modules/prediction/data/mlp_vehicle_model.bin",
              "mlp model file for vehicle evaluator");
DEFINE_string(evaluator_vehicle_rnn_file,
              "modules/prediction/data/rnn_vehicle_model.bin",
              "rnn model file for vehicle evaluator");
DEFINE_int32(max_num_obstacles, 100,
             "maximal number of obstacles stored in obstacles container.");
DEFINE_double(valid_position_diff_threshold, 0.5,
              "threshold of valid position difference");
DEFINE_double(valid_position_diff_rate_threshold, 0.075,
              "threshold of valid position difference rate");
DEFINE_double(split_rate, 0.5,
              "obstacle split rate for adjusting velocity");
DEFINE_double(rnn_min_lane_relatice_s, 5.0,
              "Minimal relative s for RNN model.");
DEFINE_bool(enable_adjust_velocity_heading, false,
            "adjust velocity heading to lane heading");
DEFINE_double(heading_filter_param, 0.99, "heading filter parameter");

// Obstacle trajectory
DEFINE_double(lane_sequence_threshold, 0.5,
              "Threshold for trimming lane sequence trajectories");
DEFINE_double(lane_change_dist, 10.0, "Lane change distance with ADC");
DEFINE_bool(enable_lane_sequence_acc, false,
            "If use acceleration in lane sequence.");
DEFINE_bool(enable_trim_prediction_trajectory, false,
            "If trim the prediction trajectory to avoid crossing"
            "protected adc planning trajectory.");
DEFINE_double(distance_beyond_junction, 0.5,
              "If the obstacle is in junction more than this threshold,"
              "consider it in junction.");
DEFINE_double(adc_trajectory_search_length, 10.0,
              "How far to search junction along adc planning trajectory");
DEFINE_double(virtual_lane_radius, 0.5, "Radius to search virtual lanes");
DEFINE_double(default_lateral_approach_speed, 0.5,
              "Default lateral speed approaching to center of lane");

// move sequence prediction
DEFINE_double(time_upper_bound_to_lane_center, 5.0,
              "Upper bound of time to get to the lane center");
DEFINE_double(time_lower_bound_to_lane_center, 1.0,
              "Lower bound of time to get to the lane center");
DEFINE_double(sample_time_gap, 0.2,
              "Gap of time to sample time to get to the lane center");
DEFINE_double(cost_alpha, 100.0,
              "The coefficient of lateral acceleration in cost function");
DEFINE_double(default_time_to_lane_center, 5.0,
              "The default time to lane center");
<|endoftext|>


<commit_before>/*************************************************************************/
/*  audio_stream_ogg_vorbis.cpp                                          */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "audio_stream_ogg_vorbis.h"

#include "core/os/file_access.h"

void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
	ERR_FAIL_COND(!active);

	int todo = p_frames;

	int start_buffer = 0;

	while (todo && active) {
		float *buffer = (float *)p_buffer;
		if (start_buffer > 0) {
			buffer = (buffer + start_buffer * 2);
		}
		int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, buffer, todo * 2);
		if (vorbis_stream->channels == 1 && mixed > 0) {
			//mix mono to stereo
			for (int i = start_buffer; i < mixed; i++) {
				p_buffer[i].r = p_buffer[i].l;
			}
		}
		todo -= mixed;
		frames_mixed += mixed;

		if (todo) {
			//end of file!
			bool is_not_empty = mixed > 0 || stb_vorbis_stream_length_in_samples(ogg_stream) > 0;
			if (vorbis_stream->loop && is_not_empty) {
				//loop
				seek(vorbis_stream->loop_offset);
				loops++;
				// we still have buffer to fill, start from this element in the next iteration.
				start_buffer = p_frames - todo;
			} else {
				for (int i = p_frames - todo; i < p_frames; i++) {
					p_buffer[i] = AudioFrame(0, 0);
				}
				active = false;
				todo = 0;
			}
		}
	}
}

float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
	return vorbis_stream->sample_rate;
}

void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
	active = true;
	seek(p_from_pos);
	loops = 0;
	_begin_resample();
}

void AudioStreamPlaybackOGGVorbis::stop() {
	active = false;
}

bool AudioStreamPlaybackOGGVorbis::is_playing() const {
	return active;
}

int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
	return loops;
}

float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
	return float(frames_mixed) / vorbis_stream->sample_rate;
}

void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
	if (!active) {
		return;
	}

	if (p_time >= vorbis_stream->get_length()) {
		p_time = 0;
	}
	frames_mixed = uint32_t(vorbis_stream->sample_rate * p_time);

	stb_vorbis_seek(ogg_stream, frames_mixed);
}

AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
	if (ogg_alloc.alloc_buffer) {
		stb_vorbis_close(ogg_stream);
		memfree(ogg_alloc.alloc_buffer);
	}
}

Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
	Ref<AudioStreamPlaybackOGGVorbis> ovs;

	ERR_FAIL_COND_V_MSG(data == nullptr, ovs,
			"This AudioStreamOGGVorbis does not have an audio file assigned "
			"to it. AudioStreamOGGVorbis should not be created from the "
			"inspector or with `.new()`. Instead, load an audio file.");

	ovs.instance();
	ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
	ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size);
	ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size;
	ovs->frames_mixed = 0;
	ovs->active = false;
	ovs->loops = 0;
	int error;
	ovs->ogg_stream = stb_vorbis_open_memory((const unsigned char *)data, data_len, &error, &ovs->ogg_alloc);
	if (!ovs->ogg_stream) {
		memfree(ovs->ogg_alloc.alloc_buffer);
		ovs->ogg_alloc.alloc_buffer = nullptr;
		ERR_FAIL_COND_V(!ovs->ogg_stream, Ref<AudioStreamPlaybackOGGVorbis>());
	}

	return ovs;
}

String AudioStreamOGGVorbis::get_stream_name() const {
	return ""; //return stream_name;
}

void AudioStreamOGGVorbis::clear_data() {
	if (data) {
		memfree(data);
		data = nullptr;
		data_len = 0;
	}
}

void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
	int src_data_len = p_data.size();
	uint32_t alloc_try = 1024;
	Vector<char> alloc_mem;
	char *w;
	stb_vorbis *ogg_stream = nullptr;
	stb_vorbis_alloc ogg_alloc;

	// Vorbis comments may be up to UINT32_MAX, but that's arguably pretty rare.
	// Let's go with 2^30 so we don't risk going out of bounds.
	const uint32_t MAX_TEST_MEM = 1 << 30;

	while (alloc_try < MAX_TEST_MEM) {
		alloc_mem.resize(alloc_try);
		w = alloc_mem.ptrw();

		ogg_alloc.alloc_buffer = w;
		ogg_alloc.alloc_buffer_length_in_bytes = alloc_try;

		const uint8_t *src_datar = p_data.ptr();

		int error;
		ogg_stream = stb_vorbis_open_memory((const unsigned char *)src_datar, src_data_len, &error, &ogg_alloc);

		if (!ogg_stream && error == VORBIS_outofmem) {
			alloc_try *= 2;
		} else {
			ERR_FAIL_COND(alloc_try == MAX_TEST_MEM);
			ERR_FAIL_COND(ogg_stream == nullptr);

			stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);

			channels = info.channels;
			sample_rate = info.sample_rate;
			decode_mem_size = alloc_try;
			//does this work? (it's less mem..)
			//decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size;

			length = stb_vorbis_stream_length_in_seconds(ogg_stream);
			stb_vorbis_close(ogg_stream);

			// free any existing data
			clear_data();

			data = memalloc(src_data_len);
			copymem(data, src_datar, src_data_len);
			data_len = src_data_len;

			break;
		}
	}

	ERR_FAIL_COND_MSG(alloc_try == MAX_TEST_MEM, vformat("Couldn't set vorbis data even with an alloc buffer of %d bytes, report bug.", MAX_TEST_MEM));
}

Vector<uint8_t> AudioStreamOGGVorbis::get_data() const {
	Vector<uint8_t> vdata;

	if (data_len && data) {
		vdata.resize(data_len);
		{
			uint8_t *w = vdata.ptrw();
			copymem(w, data, data_len);
		}
	}

	return vdata;
}

void AudioStreamOGGVorbis::set_loop(bool p_enable) {
	loop = p_enable;
}

bool AudioStreamOGGVorbis::has_loop() const {
	return loop;
}

void AudioStreamOGGVorbis::set_loop_offset(float p_seconds) {
	loop_offset = p_seconds;
}

float AudioStreamOGGVorbis::get_loop_offset() const {
	return loop_offset;
}

float AudioStreamOGGVorbis::get_length() const {
	return length;
}

void AudioStreamOGGVorbis::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamOGGVorbis::set_data);
	ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamOGGVorbis::get_data);

	ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOGGVorbis::set_loop);
	ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOGGVorbis::has_loop);

	ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset);
	ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset);

	ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset");
}

AudioStreamOGGVorbis::AudioStreamOGGVorbis() {}

AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {
	clear_data();
}
<commit_msg>Fix mono->stereo conversion for oggs (see #40630)<commit_after>/*************************************************************************/
/*  audio_stream_ogg_vorbis.cpp                                          */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "audio_stream_ogg_vorbis.h"

#include "core/os/file_access.h"

void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
	ERR_FAIL_COND(!active);

	int todo = p_frames;

	int start_buffer = 0;

	while (todo && active) {
		float *buffer = (float *)p_buffer;
		if (start_buffer > 0) {
			buffer = (buffer + start_buffer * 2);
		}
		int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, buffer, todo * 2);
		if (vorbis_stream->channels == 1 && mixed > 0) {
			//mix mono to stereo
			for (int i = start_buffer; i < start_buffer + mixed; i++) {
				p_buffer[i].r = p_buffer[i].l;
			}
		}
		todo -= mixed;
		frames_mixed += mixed;

		if (todo) {
			//end of file!
			bool is_not_empty = mixed > 0 || stb_vorbis_stream_length_in_samples(ogg_stream) > 0;
			if (vorbis_stream->loop && is_not_empty) {
				//loop
				seek(vorbis_stream->loop_offset);
				loops++;
				// we still have buffer to fill, start from this element in the next iteration.
				start_buffer = p_frames - todo;
			} else {
				for (int i = p_frames - todo; i < p_frames; i++) {
					p_buffer[i] = AudioFrame(0, 0);
				}
				active = false;
				todo = 0;
			}
		}
	}
}

float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
	return vorbis_stream->sample_rate;
}

void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
	active = true;
	seek(p_from_pos);
	loops = 0;
	_begin_resample();
}

void AudioStreamPlaybackOGGVorbis::stop() {
	active = false;
}

bool AudioStreamPlaybackOGGVorbis::is_playing() const {
	return active;
}

int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
	return loops;
}

float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
	return float(frames_mixed) / vorbis_stream->sample_rate;
}

void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
	if (!active) {
		return;
	}

	if (p_time >= vorbis_stream->get_length()) {
		p_time = 0;
	}
	frames_mixed = uint32_t(vorbis_stream->sample_rate * p_time);

	stb_vorbis_seek(ogg_stream, frames_mixed);
}

AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
	if (ogg_alloc.alloc_buffer) {
		stb_vorbis_close(ogg_stream);
		memfree(ogg_alloc.alloc_buffer);
	}
}

Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
	Ref<AudioStreamPlaybackOGGVorbis> ovs;

	ERR_FAIL_COND_V_MSG(data == nullptr, ovs,
			"This AudioStreamOGGVorbis does not have an audio file assigned "
			"to it. AudioStreamOGGVorbis should not be created from the "
			"inspector or with `.new()`. Instead, load an audio file.");

	ovs.instance();
	ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
	ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size);
	ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size;
	ovs->frames_mixed = 0;
	ovs->active = false;
	ovs->loops = 0;
	int error;
	ovs->ogg_stream = stb_vorbis_open_memory((const unsigned char *)data, data_len, &error, &ovs->ogg_alloc);
	if (!ovs->ogg_stream) {
		memfree(ovs->ogg_alloc.alloc_buffer);
		ovs->ogg_alloc.alloc_buffer = nullptr;
		ERR_FAIL_COND_V(!ovs->ogg_stream, Ref<AudioStreamPlaybackOGGVorbis>());
	}

	return ovs;
}

String AudioStreamOGGVorbis::get_stream_name() const {
	return ""; //return stream_name;
}

void AudioStreamOGGVorbis::clear_data() {
	if (data) {
		memfree(data);
		data = nullptr;
		data_len = 0;
	}
}

void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
	int src_data_len = p_data.size();
	uint32_t alloc_try = 1024;
	Vector<char> alloc_mem;
	char *w;
	stb_vorbis *ogg_stream = nullptr;
	stb_vorbis_alloc ogg_alloc;

	// Vorbis comments may be up to UINT32_MAX, but that's arguably pretty rare.
	// Let's go with 2^30 so we don't risk going out of bounds.
	const uint32_t MAX_TEST_MEM = 1 << 30;

	while (alloc_try < MAX_TEST_MEM) {
		alloc_mem.resize(alloc_try);
		w = alloc_mem.ptrw();

		ogg_alloc.alloc_buffer = w;
		ogg_alloc.alloc_buffer_length_in_bytes = alloc_try;

		const uint8_t *src_datar = p_data.ptr();

		int error;
		ogg_stream = stb_vorbis_open_memory((const unsigned char *)src_datar, src_data_len, &error, &ogg_alloc);

		if (!ogg_stream && error == VORBIS_outofmem) {
			alloc_try *= 2;
		} else {
			ERR_FAIL_COND(alloc_try == MAX_TEST_MEM);
			ERR_FAIL_COND(ogg_stream == nullptr);

			stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);

			channels = info.channels;
			sample_rate = info.sample_rate;
			decode_mem_size = alloc_try;
			//does this work? (it's less mem..)
			//decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size;

			length = stb_vorbis_stream_length_in_seconds(ogg_stream);
			stb_vorbis_close(ogg_stream);

			// free any existing data
			clear_data();

			data = memalloc(src_data_len);
			copymem(data, src_datar, src_data_len);
			data_len = src_data_len;

			break;
		}
	}

	ERR_FAIL_COND_MSG(alloc_try == MAX_TEST_MEM, vformat("Couldn't set vorbis data even with an alloc buffer of %d bytes, report bug.", MAX_TEST_MEM));
}

Vector<uint8_t> AudioStreamOGGVorbis::get_data() const {
	Vector<uint8_t> vdata;

	if (data_len && data) {
		vdata.resize(data_len);
		{
			uint8_t *w = vdata.ptrw();
			copymem(w, data, data_len);
		}
	}

	return vdata;
}

void AudioStreamOGGVorbis::set_loop(bool p_enable) {
	loop = p_enable;
}

bool AudioStreamOGGVorbis::has_loop() const {
	return loop;
}

void AudioStreamOGGVorbis::set_loop_offset(float p_seconds) {
	loop_offset = p_seconds;
}

float AudioStreamOGGVorbis::get_loop_offset() const {
	return loop_offset;
}

float AudioStreamOGGVorbis::get_length() const {
	return length;
}

void AudioStreamOGGVorbis::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamOGGVorbis::set_data);
	ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamOGGVorbis::get_data);

	ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOGGVorbis::set_loop);
	ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOGGVorbis::has_loop);

	ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset);
	ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset);

	ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset");
}

AudioStreamOGGVorbis::AudioStreamOGGVorbis() {}

AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {
	clear_data();
}
<|endoftext|>


<commit_before>/* Copyright (C) 2004 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Utility program used to signal a safe_process it's time to shutdown

  Usage:
    safe_kill <pid>
*/

#include <windows.h>
#include <stdio.h>
#include <signal.h>

int main(int argc, const char** argv )
{
  DWORD pid= -1;
  HANDLE shutdown_event;
  char safe_process_name[32]= {0};
  int retry_open_event= 100;
  /* Ignore any signals */
  signal(SIGINT,   SIG_IGN);
  signal(SIGBREAK, SIG_IGN);
  signal(SIGTERM,  SIG_IGN);

  if (argc != 2) {
    fprintf(stderr, "safe_kill <pid>\n");
    exit(2);
  }
  pid= atoi(argv[1]);

  _snprintf(safe_process_name, sizeof(safe_process_name),
            "safe_process[%d]", pid);

  /* Open the event to signal */
  while ((shutdown_event=
          OpenEvent(EVENT_MODIFY_STATE, FALSE, safe_process_name)) == NULL)
  {
    if (retry_open_event--)
      Sleep(100);
    else
    {
      fprintf(stderr, "Failed to open shutdown_event '%s', error: %d\n",
            safe_process_name, GetLastError());
      exit(3);
    }
  }

  if(SetEvent(shutdown_event) == 0)
  {
    fprintf(stderr, "Failed to signal shutdown_event '%s', error: %d\n",
            safe_process_name, GetLastError());
    CloseHandle(shutdown_event);
    exit(4);
  }
  CloseHandle(shutdown_event);
  exit(0);
}

<commit_msg>WL#4189 NO need to retry OpenEvent if the process does not exist anymore<commit_after>/* Copyright (C) 2004 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Utility program used to signal a safe_process it's time to shutdown

  Usage:
    safe_kill <pid>
*/

#include <windows.h>
#include <stdio.h>
#include <signal.h>

int main(int argc, const char** argv )
{
  DWORD pid= -1;
  HANDLE shutdown_event;
  char safe_process_name[32]= {0};
  int retry_open_event= 100;
  /* Ignore any signals */
  signal(SIGINT,   SIG_IGN);
  signal(SIGBREAK, SIG_IGN);
  signal(SIGTERM,  SIG_IGN);

  if (argc != 2) {
    fprintf(stderr, "safe_kill <pid>\n");
    exit(2);
  }
  pid= atoi(argv[1]);

  _snprintf(safe_process_name, sizeof(safe_process_name),
            "safe_process[%d]", pid);

  /* Open the event to signal */
  while ((shutdown_event=
          OpenEvent(EVENT_MODIFY_STATE, FALSE, safe_process_name)) == NULL)
  {
     /*
      Check if the process is alive, otherwise there is really
      no idea to retry the open of the event
     */
    HANDLE process;
    if ((process= OpenProcess(SYNCHRONIZE, FALSE, pid)) == NULL)
    {
      fprintf(stderr, "Could not open event or process %d, error: %d\n",
            pid, GetLastError());
      exit(3);
    }
    CloseHandle(process);

    if (retry_open_event--)
      Sleep(100);
    else
    {
      fprintf(stderr, "Failed to open shutdown_event '%s', error: %d\n",
              safe_process_name, GetLastError());
      exit(3);
    }
  }

  if(SetEvent(shutdown_event) == 0)
  {
    fprintf(stderr, "Failed to signal shutdown_event '%s', error: %d\n",
            safe_process_name, GetLastError());
    CloseHandle(shutdown_event);
    exit(4);
  }
  CloseHandle(shutdown_event);
  exit(0);
}

<|endoftext|>


<commit_before>/* The following code example is taken from the book
 * "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
 * by Nicolai M. Josuttis, Addison-Wesley, 2012
 *
 * (C) Copyright Nicolai M. Josuttis 2012.
 * Permission to copy, use, modify, sell and distribute this software
 * is granted provided this copyright notice appears in all copies.
 * This software is provided "as is" without express or implied
 * warranty, and with no claim as to its suitability for any purpose.
 */
#include <string>
#include <fstream>   // for ofstream
#include <memory>    // for shared_ptr
#include <cstdio>    // for remove()

class FileDeleter
{
  private:
    std::string filename;
  public:
    FileDeleter (const std::string& fn)
     : filename(fn) {
    }
    void operator () (std::ofstream* fp) {
        delete fp;                     // close file
        std::remove(filename.c_str()); // delete file
    }
};

int main()
{
    // create and open temporary file:
    std::shared_ptr<std::ofstream> fp(new std::ofstream("tmpfile.txt"),
                                      FileDeleter("tmpfile.txt"));
    //...
}
<commit_msg>update util/shareptr2.cpp<commit_after>/* The following code example is taken from the book
 * "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
 * by Nicolai M. Josuttis, Addison-Wesley, 2012
 *
 * (C) Copyright Nicolai M. Josuttis 2012.
 * Permission to copy, use, modify, sell and distribute this software
 * is granted provided this copyright notice appears in all copies.
 * This software is provided "as is" without express or implied
 * warranty, and with no claim as to its suitability for any purpose.
 */
#include <string>
#include <fstream>   // for ofstream
#include <memory>    // for shared_ptr
#include <cstdio>    // for remove()
#include <iostream>

using namespace std;

class FileDeleter
{
  private:
    std::string filename;
  public:
    FileDeleter (const std::string& fn)
     : filename(fn) {
      cout << "FileDeleter constructor." << endl;
    }
    void operator () (std::ofstream* fp) {
        delete fp;                     // close file
        std::remove(filename.c_str()); // delete file
        cout << "delet file: " << filename << endl;
    }
};

int main()
{
    // create and open temporary file:
    std::shared_ptr<std::ofstream> fp(new std::ofstream("tmpfile.txt"),
                                      FileDeleter("tmpfile.txt"));
    //...
    cout << "===========================" << endl;

    auto deleter = FileDeleter("hello_world.cpp");
    deleter(new std::ofstream("hello_world.cpp"));
}
<|endoftext|>


<commit_before>#ifndef ITER_PERMUTATIONS_HPP_
#define ITER_PERMUTATIONS_HPP_

#include "internal/iterbase.hpp"
#include "internal/iteratoriterator.hpp"

#include <algorithm>
#include <initializer_list>
#include <vector>
#include <utility>
#include <iterator>

namespace iter {
  namespace impl {
    template <typename Container>
    class Permuter;
  }
  template <typename Container>
  impl::Permuter<Container> permutations(Container&&);

  template <typename T>
  impl::Permuter<std::initializer_list<T>> permutations(
      std::initializer_list<T>);
}

template <typename Container>
class iter::impl::Permuter {
 private:
  Container container;

  using IndexVector = std::vector<iterator_type<Container>>;
  using Permutable = IterIterWrapper<IndexVector>;

  friend Permuter iter::permutations<Container>(Container&&);
  template <typename T>
  friend Permuter<std::initializer_list<T>> iter::permutations(
      std::initializer_list<T>);

  Permuter(Container&& in_container)
      : container(std::forward<Container>(in_container)) {}

 public:
  Permuter(Permuter&&) = default;

  class Iterator : public std::iterator<std::input_iterator_tag, Permutable> {
   private:
    static constexpr const int COMPLETE = -1;
    static bool cmp_iters(const iterator_type<Container>& lhs,
        const iterator_type<Container>& rhs) noexcept {
      return *lhs < *rhs;
    }

    Permutable working_set;
    int steps{};

   public:
    Iterator(
        iterator_type<Container>&& sub_iter, iterator_type<Container>&& sub_end)
        : steps{sub_iter != sub_end ? 0 : COMPLETE} {
      // done like this instead of using vector ctor with
      // two iterators because that causes a substitution
      // failure when the iterator is minimal
      while (sub_iter != sub_end) {
        this->working_set.get().push_back(sub_iter);
        ++sub_iter;
      }
      std::sort(std::begin(working_set.get()), std::end(working_set.get()),
          cmp_iters);
    }

    Permutable& operator*() {
      return this->working_set;
    }

    Permutable* operator->() {
      return &this->working_set;
    }

    Iterator& operator++() {
      ++this->steps;
      if (!std::next_permutation(std::begin(working_set.get()),
              std::end(working_set.get()), cmp_iters)) {
        this->steps = COMPLETE;
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return !(*this == other);
    }

    bool operator==(const Iterator& other) const {
      return this->steps == other.steps;
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container)};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container)};
  }
};

template <typename Container>
iter::impl::Permuter<Container> iter::permutations(Container&& container) {
  return {std::forward<Container>(container)};
}

template <typename T>
iter::impl::Permuter<std::initializer_list<T>> iter::permutations(
    std::initializer_list<T> il) {
  return {std::move(il)};
}

#endif
<commit_msg>drops init list support from permutations<commit_after>#ifndef ITER_PERMUTATIONS_HPP_
#define ITER_PERMUTATIONS_HPP_

#include "internal/iterbase.hpp"
#include "internal/iteratoriterator.hpp"

#include <algorithm>
#include <vector>
#include <utility>
#include <iterator>

namespace iter {
  namespace impl {
    template <typename Container>
    class Permuter;
  }
  template <typename Container>
  impl::Permuter<Container> permutations(Container&&);
}

template <typename Container>
class iter::impl::Permuter {
 private:
  Container container;

  using IndexVector = std::vector<iterator_type<Container>>;
  using Permutable = IterIterWrapper<IndexVector>;

  friend Permuter iter::permutations<Container>(Container&&);

  Permuter(Container&& in_container)
      : container(std::forward<Container>(in_container)) {}

 public:
  Permuter(Permuter&&) = default;

  class Iterator : public std::iterator<std::input_iterator_tag, Permutable> {
   private:
    static constexpr const int COMPLETE = -1;
    static bool cmp_iters(const iterator_type<Container>& lhs,
        const iterator_type<Container>& rhs) noexcept {
      return *lhs < *rhs;
    }

    Permutable working_set;
    int steps{};

   public:
    Iterator(
        iterator_type<Container>&& sub_iter, iterator_type<Container>&& sub_end)
        : steps{sub_iter != sub_end ? 0 : COMPLETE} {
      // done like this instead of using vector ctor with
      // two iterators because that causes a substitution
      // failure when the iterator is minimal
      while (sub_iter != sub_end) {
        this->working_set.get().push_back(sub_iter);
        ++sub_iter;
      }
      std::sort(std::begin(working_set.get()), std::end(working_set.get()),
          cmp_iters);
    }

    Permutable& operator*() {
      return this->working_set;
    }

    Permutable* operator->() {
      return &this->working_set;
    }

    Iterator& operator++() {
      ++this->steps;
      if (!std::next_permutation(std::begin(working_set.get()),
              std::end(working_set.get()), cmp_iters)) {
        this->steps = COMPLETE;
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return !(*this == other);
    }

    bool operator==(const Iterator& other) const {
      return this->steps == other.steps;
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container)};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container)};
  }
};

template <typename Container>
iter::impl::Permuter<Container> iter::permutations(Container&& container) {
  return {std::forward<Container>(container)};
}

#endif
<|endoftext|>


<commit_before>/** @file

  This plugin allows retrying requests against different destinations.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <ts/ts.h>
#include <ts/remap.h>
#include <ts/experimental.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <string>
#include <iterator>
#include <map>

// Constants and some declarations
const char PLUGIN_NAME[] = "escalate";
static int EscalateResponse(TSCont, TSEvent, void *);

//////////////////////////////////////////////////////////////////////////////////////////
// Hold information about the escalation / retry states for a remap rule.
//
struct EscalationState {
  enum RetryType {
    RETRY_URL,
    RETRY_HOST,
  };

  struct RetryInfo {
    RetryType type;
    std::string target;
  };

  typedef std::map<unsigned, RetryInfo> StatusMapType;

  EscalationState()
  {
    cont = TSContCreate(EscalateResponse, NULL);
    TSContDataSet(cont, this);
  }

  ~EscalationState() { TSContDestroy(cont); }

  TSCont cont;
  StatusMapType status_map;
};

//////////////////////////////////////////////////////////////////////////////////////////
// Main continuation for the plugin, examining an origin response for a potential retry.
//
static int
EscalateResponse(TSCont cont, TSEvent event, void *edata)
{
  TSHttpTxn txn = (TSHttpTxn)edata;
  EscalationState *es = static_cast<EscalationState *>(TSContDataGet(cont));
  EscalationState::StatusMapType::const_iterator entry;
  TSMBuffer mbuf;
  TSMLoc hdrp, url;
  TSHttpStatus status;
  char *url_str = NULL;
  int url_len, tries;

  TSAssert(event == TS_EVENT_HTTP_READ_RESPONSE_HDR);

  // First, we need the server response ...
  if (TS_SUCCESS != TSHttpTxnServerRespGet(txn, &mbuf, &hdrp)) {
    goto no_action;
  }

  tries = TSHttpTxnRedirectRetries(txn);
  if (0 != tries) { // ToDo: Future support for more than one retry-URL
    goto no_action;
  }
  TSDebug(PLUGIN_NAME, "This is try %d, proceeding", tries);

  // Next, the response status ...
  status = TSHttpHdrStatusGet(mbuf, hdrp);
  TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdrp); // Don't need this any more

  // See if we have an escalation retry config for this response code
  entry = es->status_map.find((unsigned)status);
  if (entry == es->status_map.end()) {
    goto no_action;
  }

  TSDebug(PLUGIN_NAME, "Found an entry for HTTP status %u", (unsigned)status);
  if (EscalationState::RETRY_URL == entry->second.type) {
    url_str = TSstrdup(entry->second.target.c_str());
    url_len = entry->second.target.size();
    TSDebug(PLUGIN_NAME, "Setting new URL to %.*s", url_len, url_str);
  } else if (EscalationState::RETRY_HOST == entry->second.type) {
    if (TS_SUCCESS == TSHttpTxnClientReqGet(txn, &mbuf, &hdrp)) {
      if (TS_SUCCESS == TSHttpHdrUrlGet(mbuf, hdrp, &url)) {
        // Update the request URL with the new Host to try.
        TSUrlHostSet(mbuf, url, entry->second.target.c_str(), entry->second.target.size());
        url_str = TSUrlStringGet(mbuf, url, &url_len);
        TSDebug(PLUGIN_NAME, "Setting new Host: to %.*s", url_len, url_str);
      }
      // Release the request MLoc
      TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdrp);
    }
  }

  // Now update the Redirect URL, if set
  if (url_str) {
    TSHttpTxnRedirectUrlSet(txn, url_str, url_len); // Transfers ownership
  }

// Set the transaction free ...
no_action:
  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  return TS_EVENT_NONE;
}

TSReturnCode
TSRemapInit(TSRemapInterface * /* api */, char * /* errbuf */, int /* bufsz */)
{
  return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char *argv[], void **instance, char *errbuf, int errbuf_size)
{
  EscalationState *es = new EscalationState();

  // The first two arguments are the "from" and "to" URL string. We can just
  // skip those, since we only ever remap on the error path.
  for (int i = 2; i < argc; ++i) {
    char *sep, *token, *save;

    // Each token should be a status code then a URL, separated by ':'.
    sep = strchr(argv[i], ':');
    if (sep == NULL) {
      snprintf(errbuf, errbuf_size, "malformed status:target config: %s", argv[i]);
      goto fail;
    }

    *sep = '\0';
    ++sep; // Skip over the ':' (which is now \0)

    // OK, we have a valid status/URL pair.
    EscalationState::RetryInfo info;

    info.target = sep;
    if (std::string::npos != info.target.find('/')) {
      info.type = EscalationState::RETRY_URL;
      TSDebug(PLUGIN_NAME, "Creating Redirect rule with URL = %s", sep);
    } else {
      info.type = EscalationState::RETRY_HOST;
      TSDebug(PLUGIN_NAME, "Creating Redirect rule with Host = %s", sep);
    }

    for (token = strtok_r(argv[i], ",", &save); token; token = strtok_r(NULL, ",", &save)) {
      unsigned status = strtol(token, NULL, 10);

      if (status < 100 || status > 599) {
        snprintf(errbuf, errbuf_size, "invalid status code: %.*s", (int)std::distance(argv[i], sep), argv[i]);
        goto fail;
      }

      TSDebug(PLUGIN_NAME, "      added status = %d to rule", status);
      es->status_map[status] = info;
    }
  }

  *instance = es;
  return TS_SUCCESS;

fail:
  delete es;
  return TS_ERROR;
}

void
TSRemapDeleteInstance(void *instance)
{
  delete static_cast<EscalationState *>(instance);
}

TSRemapStatus
TSRemapDoRemap(void *instance, TSHttpTxn txn, TSRemapRequestInfo * /* rri */)
{
  EscalationState *es = static_cast<EscalationState *>(instance);

  TSHttpTxnHookAdd(txn, TS_HTTP_READ_RESPONSE_HDR_HOOK, es->cont);
  return TSREMAP_NO_REMAP;
}
<commit_msg>TS-4081 Adds --pristine to use pristine URL on escalation<commit_after>/** @file

  This plugin allows retrying requests against different destinations.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <ts/ts.h>
#include <ts/remap.h>
#include <ts/experimental.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <string>
#include <iterator>
#include <map>

// Constants and some declarations
const char PLUGIN_NAME[] = "escalate";
static int EscalateResponse(TSCont, TSEvent, void *);

//////////////////////////////////////////////////////////////////////////////////////////
// Hold information about the escalation / retry states for a remap rule.
//
struct EscalationState {
  enum RetryType {
    RETRY_URL,
    RETRY_HOST,
  };

  struct RetryInfo {
    RetryType type;
    std::string target;
  };

  typedef std::map<unsigned, RetryInfo> StatusMapType;

  EscalationState() : use_pristine(false)
  {
    cont = TSContCreate(EscalateResponse, NULL);
    TSContDataSet(cont, this);
  }

  ~EscalationState() { TSContDestroy(cont); }

  TSCont cont;
  StatusMapType status_map;
  bool use_pristine;
};

// Little helper function, to update the Host portion of a URL, and stringify the result.
// Returns the URL string, and updates url_len with the length.
char *
MakeEscalateUrl(TSMBuffer mbuf, TSMLoc url, const char *host, size_t host_len, int &url_len)
{
  char *url_str = NULL;

  // Update the request URL with the new Host to try.
  TSUrlHostSet(mbuf, url, host, host_len);
  url_str = TSUrlStringGet(mbuf, url, &url_len);
  TSDebug(PLUGIN_NAME, "Setting new URL to %.*s", url_len, url_str);

  return url_str;
}

//////////////////////////////////////////////////////////////////////////////////////////
// Main continuation for the plugin, examining an origin response for a potential retry.
//
static int
EscalateResponse(TSCont cont, TSEvent event, void *edata)
{
  TSHttpTxn txn = (TSHttpTxn)edata;
  EscalationState *es = static_cast<EscalationState *>(TSContDataGet(cont));
  EscalationState::StatusMapType::const_iterator entry;
  TSMBuffer mbuf;
  TSMLoc hdrp, url;
  TSHttpStatus status;
  char *url_str = NULL;
  int url_len, tries;

  TSAssert(event == TS_EVENT_HTTP_READ_RESPONSE_HDR);

  // First, we need the server response ...
  if (TS_SUCCESS != TSHttpTxnServerRespGet(txn, &mbuf, &hdrp)) {
    goto no_action;
  }

  tries = TSHttpTxnRedirectRetries(txn);
  if (0 != tries) { // ToDo: Future support for more than one retry-URL
    goto no_action;
  }
  TSDebug(PLUGIN_NAME, "This is try %d, proceeding", tries);

  // Next, the response status ...
  status = TSHttpHdrStatusGet(mbuf, hdrp);
  TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdrp); // Don't need this any more

  // See if we have an escalation retry config for this response code
  entry = es->status_map.find((unsigned)status);
  if (entry == es->status_map.end()) {
    goto no_action;
  }

  TSDebug(PLUGIN_NAME, "Found an entry for HTTP status %u", (unsigned)status);
  if (EscalationState::RETRY_URL == entry->second.type) {
    url_str = TSstrdup(entry->second.target.c_str());
    url_len = entry->second.target.size();
    TSDebug(PLUGIN_NAME, "Setting new URL to %.*s", url_len, url_str);
  } else if (EscalationState::RETRY_HOST == entry->second.type) {
    if (es->use_pristine) {
      if (TS_SUCCESS == TSHttpTxnPristineUrlGet(txn, &mbuf, &url)) {
        url_str = MakeEscalateUrl(mbuf, url, entry->second.target.c_str(), entry->second.target.size(), url_len);
        printf("STRING is %.*s\n", url_len, url_str);
      }
    } else {
      if (TS_SUCCESS == TSHttpTxnClientReqGet(txn, &mbuf, &hdrp)) {
        if (TS_SUCCESS == TSHttpHdrUrlGet(mbuf, hdrp, &url)) {
          url_str = MakeEscalateUrl(mbuf, url, entry->second.target.c_str(), entry->second.target.size(), url_len);
          printf("Old code STRING is %.*s\n", url_len, url_str);
        }
        // Release the request MLoc
        TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdrp);
      }
    }
  }

  // Now update the Redirect URL, if set
  if (url_str) {
    TSHttpTxnRedirectUrlSet(txn, url_str, url_len); // Transfers ownership
  }

// Set the transaction free ...
no_action:
  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
  return TS_EVENT_NONE;
}

TSReturnCode
TSRemapInit(TSRemapInterface * /* api */, char * /* errbuf */, int /* bufsz */)
{
  return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char *argv[], void **instance, char *errbuf, int errbuf_size)
{
  EscalationState *es = new EscalationState();

  // The first two arguments are the "from" and "to" URL string. We can just
  // skip those, since we only ever remap on the error path.
  for (int i = 2; i < argc; ++i) {
    char *sep, *token, *save;

    // Ugly, but we set the precedence before with non-command line parsing of args
    if (0 == strncasecmp(argv[i], "--pristine", 10)) {
      es->use_pristine = true;
    } else {
      // Each token should be a status code then a URL, separated by ':'.
      sep = strchr(argv[i], ':');
      if (sep == NULL) {
        snprintf(errbuf, errbuf_size, "malformed status:target config: %s", argv[i]);
        goto fail;
      }

      *sep = '\0';
      ++sep; // Skip over the ':' (which is now \0)

      // OK, we have a valid status/URL pair.
      EscalationState::RetryInfo info;

      info.target = sep;
      if (std::string::npos != info.target.find('/')) {
        info.type = EscalationState::RETRY_URL;
        TSDebug(PLUGIN_NAME, "Creating Redirect rule with URL = %s", sep);
      } else {
        info.type = EscalationState::RETRY_HOST;
        TSDebug(PLUGIN_NAME, "Creating Redirect rule with Host = %s", sep);
      }

      for (token = strtok_r(argv[i], ",", &save); token; token = strtok_r(NULL, ",", &save)) {
        unsigned status = strtol(token, NULL, 10);

        if (status < 100 || status > 599) {
          snprintf(errbuf, errbuf_size, "invalid status code: %.*s", (int)std::distance(argv[i], sep), argv[i]);
          goto fail;
        }

        TSDebug(PLUGIN_NAME, "      added status = %d to rule", status);
        es->status_map[status] = info;
      }
    }
  }

  *instance = es;
  return TS_SUCCESS;

fail:
  delete es;
  return TS_ERROR;
}

void
TSRemapDeleteInstance(void *instance)
{
  delete static_cast<EscalationState *>(instance);
}

TSRemapStatus
TSRemapDoRemap(void *instance, TSHttpTxn txn, TSRemapRequestInfo * /* rri */)
{
  EscalationState *es = static_cast<EscalationState *>(instance);

  TSHttpTxnHookAdd(txn, TS_HTTP_READ_RESPONSE_HDR_HOOK, es->cont);
  return TSREMAP_NO_REMAP;
}
<|endoftext|>


<commit_before>//************************************************************************
//*	main.c
//*
//*	Arduino core files for PIC32
//*		Copyright (c) 2010, 2011 by Mark Sproul
//*
//*
//************************************************************************
//*	this code is based on code Copyright (c) 2005-2006 David A. Mellis
//*
//*	This library is free software; you can redistribute it and/or
//*	modify it under the terms of the GNU Lesser General Public
//*	License as published by the Free Software Foundation; either
//*	version 2.1 of the License, or (at your option) any later version.
//*
//*	This library is distributed in the hope that it will be useful,
//*	but WITHOUT ANY WARRANTY; without even the implied warranty of
//*	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.//*	See the GNU
//*	Lesser General Public License for more details.
//*
//*	You should have received a copy of the GNU Lesser General
//*	Public License along with this library; if not, write to the
//*	Free Software Foundation, Inc., 59 Temple Place, Suite 330,
//*	Boston, MA  02111-1307  USA
//*
//*
//************************************************************************
//*	Edit History
//************************************************************************
//*	Oct 12,	2010	Got MPLAB X working on MacOSX 1.6 for the first time
//* Dec 12, 2011 <GeneApperson> added call to _scheduleTask() before call
//*					to loop().
//************************************************************************

//!!! This section is a read only section !!!

#define OPT_SYSTEM_INTERNAL
#include <System_Defs.h>

#if (ARDUINO >= 100)
	#include <Arduino.h>
#else
	#include <WProgram.h>
#endif

#if !defined(__PIC32MZXX__)
extern "C" {
extern void __use_isr_install(void);
__attribute__((section(".comment"))) void (*__use_force_isr_install)(void) = &__use_isr_install;
}
#endif

//************************************************************************
int main(void)
{
	init();

	setup();

	while (1)
	{
		_scheduleTask();
		loop();
        if (serialEventRun != NULL) serialEventRun();
	}
	return 0;
}

<commit_msg>Removed if () check for serialEventRun based on reviewer feedback.<commit_after>//************************************************************************
//*	main.c
//*
//*	Arduino core files for PIC32
//*		Copyright (c) 2010, 2011 by Mark Sproul
//*
//*
//************************************************************************
//*	this code is based on code Copyright (c) 2005-2006 David A. Mellis
//*
//*	This library is free software; you can redistribute it and/or
//*	modify it under the terms of the GNU Lesser General Public
//*	License as published by the Free Software Foundation; either
//*	version 2.1 of the License, or (at your option) any later version.
//*
//*	This library is distributed in the hope that it will be useful,
//*	but WITHOUT ANY WARRANTY; without even the implied warranty of
//*	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.//*	See the GNU
//*	Lesser General Public License for more details.
//*
//*	You should have received a copy of the GNU Lesser General
//*	Public License along with this library; if not, write to the
//*	Free Software Foundation, Inc., 59 Temple Place, Suite 330,
//*	Boston, MA  02111-1307  USA
//*
//*
//************************************************************************
//*	Edit History
//************************************************************************
//*	Oct 12,	2010	Got MPLAB X working on MacOSX 1.6 for the first time
//* Dec 12, 2011 <GeneApperson> added call to _scheduleTask() before call
//*					to loop().
//************************************************************************

//!!! This section is a read only section !!!

#define OPT_SYSTEM_INTERNAL
#include <System_Defs.h>

#if (ARDUINO >= 100)
	#include <Arduino.h>
#else
	#include <WProgram.h>
#endif

#if !defined(__PIC32MZXX__)
extern "C" {
extern void __use_isr_install(void);
__attribute__((section(".comment"))) void (*__use_force_isr_install)(void) = &__use_isr_install;
}
#endif

//************************************************************************
int main(void)
{
	init();

	setup();

	while (1)
	{
		_scheduleTask();
		loop();
        serialEventRun();
	}
	return 0;
}

<|endoftext|>