<commit_before>/*
 * 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.
 */

/*!
 * \file mkldnn_fully_connected.cc
 * \brief
 * \author Da Zheng
*/

#include "../fully_connected-inl.h"
#include "./mkldnn_base-inl.h"

#if MXNET_USE_MKLDNN == 1
namespace mxnet {
namespace op {

inline static mkldnn::inner_product_forward::primitive_desc GetIPFwd(
    const NDArray &data, const NDArray &weight, const NDArray *bias,
    const mkldnn::memory::desc &out_md) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto engine = CpuEngine::Get()->get_engine();
  if (bias) {
    auto bias_md = GetMemDesc(*bias);
    mkldnn::inner_product_forward::desc ipFwd_desc(mkldnn::prop_kind::forward_training,
        data_md, weight_md, bias_md, out_md);
    return mkldnn::inner_product_forward::primitive_desc(ipFwd_desc, engine);
  } else {
    mkldnn::inner_product_forward::desc ipFwd_desc(mkldnn::prop_kind::forward_training,
        data_md, weight_md, out_md);
    return mkldnn::inner_product_forward::primitive_desc(ipFwd_desc, engine);
  }
}

inline static mkldnn::inner_product_backward_data::primitive_desc GetIpBwdData(
    const NDArray &data, const NDArray &weight, const NDArray &output,
    mkldnn::inner_product_forward::primitive_desc ipFwd_pd) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto out_md = GetMemDesc(output);
  auto engine = CpuEngine::Get()->get_engine();
  mkldnn::inner_product_backward_data::desc desc(data_md, weight_md, out_md);
  return mkldnn::inner_product_backward_data::primitive_desc(desc, engine, ipFwd_pd);
}

inline static mkldnn::inner_product_backward_weights::primitive_desc GetIPBwdWeights(
    const NDArray &data, const NDArray &weight, const NDArray *bias,
    const NDArray &output, mkldnn::inner_product_forward::primitive_desc ipFwd_pd) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto out_md = GetMemDesc(output);
  auto engine = CpuEngine::Get()->get_engine();
  if (bias) {
    auto bias_md = GetMemDesc(*bias);
    mkldnn::inner_product_backward_weights::desc ipBwdWeights_desc(data_md,
        weight_md, bias_md, out_md);
    return mkldnn::inner_product_backward_weights::primitive_desc(
        ipBwdWeights_desc, engine, ipFwd_pd);
  } else {
    mkldnn::inner_product_backward_weights::desc ipBwdWeights_desc(data_md,
        weight_md, out_md);
    return mkldnn::inner_product_backward_weights::primitive_desc(
        ipBwdWeights_desc, engine, ipFwd_pd);
  }
}

void MKLDNNFCForward(const nnvm::NodeAttrs& attrs, const OpContext &ctx,
                     const std::vector<NDArray> &in_data,
                     const std::vector<OpReqType> &req,
                     const std::vector<NDArray> &out_data) {
  TmpMemMgr::Get()->Init(ctx.requested[fullc::kTempSpace]);
  const FullyConnectedParam& param = nnvm::get<FullyConnectedParam>(attrs.parsed);
  const TShape& ishape = in_data[fullc::kData].shape();
  const TShape& oshape = out_data[fullc::kOut].shape();
  NDArray weight = in_data[fullc::kWeight];
  NDArray data = in_data[fullc::kData];
  // If the input data is a view of an MKLDNN array, we should create a new
  // NDArray with reordered data.
  if (data.IsMKLDNNData() && data.IsView())
    data = in_data[fullc::kData].Reorder2Default();

  auto out_md = GetMemDesc(out_data[fullc::kOut]);
  if (data.shape().ndim() != 2 && !param.flatten) {
    data = data.MKLDNNDataReshape(Shape2(ishape.ProdShape(0, ishape.ndim()-1),
                                     ishape[ishape.ndim()-1]));
    mkldnn::memory::dims out_dims{static_cast<int>(oshape.ProdShape(0, oshape.ndim()-1)),
      static_cast<int>(oshape[ishape.ndim()-1])};
    out_md = mkldnn::memory::desc(out_dims, get_mkldnn_type(out_data[fullc::kOut].dtype()),
      mkldnn::memory::format::any);
  } else if (data.shape().ndim() != 2) {
    data = data.MKLDNNDataReshape(Shape2(ishape[0], ishape.ProdShape(1, ishape.ndim())));
    mkldnn::memory::dims out_dims{static_cast<int>(oshape[0]),
      static_cast<int>(oshape.ProdShape(1, oshape.ndim()))};
    out_md = mkldnn::memory::desc(out_dims, get_mkldnn_type(out_data[fullc::kOut].dtype()),
      mkldnn::memory::format::any);
  }

  mkldnn::inner_product_forward::primitive_desc ipFwd_pd = GetIPFwd(data, weight,
      param.no_bias ? nullptr : &in_data[fullc::kBias], out_md);
  auto data_mem = data.GetMKLDNNDataReorder(ipFwd_pd.src_primitive_desc());
  auto weight_mem = weight.GetMKLDNNDataReorder(ipFwd_pd.weights_primitive_desc());
  auto out_mem = CreateMKLDNNMem(out_data[fullc::kOut],
      ipFwd_pd.dst_primitive_desc(), req[fullc::kOut]);
  if (param.no_bias) {
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_forward(
          ipFwd_pd, *data_mem, *weight_mem, *out_mem.second));
  } else {
    auto bias_mem = in_data[fullc::kBias].GetMKLDNNDataReorder(ipFwd_pd.bias_primitive_desc());
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_forward(ipFwd_pd,
          *data_mem, *weight_mem, *bias_mem, *out_mem.second));
  }
  CommitOutput(out_data[fullc::kOut], out_mem);
  MKLDNNStream::Get()->Submit();
}

void MKLDNNFCBackward(const nnvm::NodeAttrs& attrs, const OpContext &ctx,
                      const std::vector<NDArray> &inputs,
                      const std::vector<OpReqType> &req,
                      const std::vector<NDArray> &outputs) {
  TmpMemMgr::Get()->Init(ctx.requested[fullc::kTempSpace]);
  const std::vector<NDArray> &in_grad = outputs;
  const FullyConnectedParam& param = nnvm::get<FullyConnectedParam>(attrs.parsed);
  const TShape& ishape = inputs[fullc::kData + 1].shape();
  const TShape& oshape = inputs[fullc::kOut].shape();

  NDArray weight = inputs[fullc::kWeight + 1];
  NDArray data = inputs[fullc::kData + 1];
  if (data.shape().ndim() != 2 && !param.flatten)
    data = data.MKLDNNDataReshape(Shape2(ishape.ProdShape(0, ishape.ndim()-1),
                                     ishape[ishape.ndim()-1]));
  else if (data.shape().ndim() != 2)
    data = data.MKLDNNDataReshape(Shape2(ishape[0],
                                     ishape.ProdShape(1, ishape.ndim())));
  NDArray out_grad = inputs[fullc::kOut];
  if (out_grad.shape().ndim() != 2 && !param.flatten)
    out_grad = out_grad.MKLDNNDataReshape(Shape2(oshape.ProdShape(0, oshape.ndim()-1),
                                             oshape[oshape.ndim()-1]));
  else if (out_grad.shape().ndim() != 2)
    out_grad = out_grad.MKLDNNDataReshape(Shape2(oshape[0],
                                             oshape.ProdShape(1, oshape.ndim())));

  mkldnn::inner_product_forward::primitive_desc ipFwd_pd = GetIPFwd(data, weight,
      param.no_bias ? nullptr : &in_grad[fullc::kBias], GetMemDesc(out_grad));

  CHECK_NE(req[fullc::kWeight], kWriteInplace) << "cannot write weight inplace";
  if (req[fullc::kData]) {
    mkldnn::inner_product_backward_data::primitive_desc ipBwdData_pd = GetIpBwdData(
        data, weight, out_grad, ipFwd_pd);
    auto out_grad_mem = out_grad.GetMKLDNNDataReorder(
        ipBwdData_pd.diff_dst_primitive_desc());
    auto weight_mem = weight.GetMKLDNNDataReorder(ipBwdData_pd.weights_primitive_desc());
    auto in_grad_mem = CreateMKLDNNMem(in_grad[fullc::kData],
                                       ipBwdData_pd.diff_src_primitive_desc(),
                                       req[fullc::kData]);
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_data(
          ipBwdData_pd, *out_grad_mem, *weight_mem, *in_grad_mem.second));
    CommitOutput(in_grad[fullc::kData], in_grad_mem);
  }
  if (req[fullc::kWeight]) {
    mkldnn::inner_product_backward_weights::primitive_desc ipBwdWeights_pd
      = GetIPBwdWeights(data, weight, param.no_bias ? nullptr : &in_grad[fullc::kBias],
          out_grad, ipFwd_pd);
    auto out_grad_mem = out_grad.GetMKLDNNDataReorder(
        ipBwdWeights_pd.diff_dst_primitive_desc());
    auto data_mem = data.GetMKLDNNDataReorder(ipBwdWeights_pd.src_primitive_desc());
    auto in_grad_weight = CreateMKLDNNWeightGrad(in_grad[fullc::kWeight],
                                                 ipBwdWeights_pd.diff_weights_primitive_desc(),
                                                 req[fullc::kWeight]);
    mkldnn_output_t in_grad_bias;
    if (param.no_bias) {
      MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_weights(
            ipBwdWeights_pd, *data_mem, *out_grad_mem, *in_grad_weight.second));
    } else {
      in_grad_bias = CreateMKLDNNMem(in_grad[fullc::kBias],
                                     ipBwdWeights_pd.diff_bias_primitive_desc(),
                                     req[fullc::kBias]);
      MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_weights(
            ipBwdWeights_pd, *data_mem, *out_grad_mem, *in_grad_weight.second,
            *in_grad_bias.second));
    }
    CommitOutput(in_grad[fullc::kWeight], in_grad_weight);
    CommitOutput(in_grad[fullc::kBias], in_grad_bias);
  }
  MKLDNNStream::Get()->Submit();
}

}  // namespace op
}  // namespace mxnet
#endif  // MXNET_USE_MKLDNN == 1
<commit_msg>use correct prop_kind for mkl-dnn FC layer (#10442)<commit_after>/*
 * 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.
 */

/*!
 * \file mkldnn_fully_connected.cc
 * \brief
 * \author Da Zheng
*/

#include "../fully_connected-inl.h"
#include "./mkldnn_base-inl.h"

#if MXNET_USE_MKLDNN == 1
namespace mxnet {
namespace op {

inline static mkldnn::inner_product_forward::primitive_desc GetIPFwd(
    const NDArray &data, const NDArray &weight, const NDArray *bias,
    const mkldnn::memory::desc &out_md, const bool is_train) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto engine = CpuEngine::Get()->get_engine();
  auto propagation =
    is_train ? mkldnn::prop_kind::forward_training : mkldnn::prop_kind::forward_scoring;
  if (bias) {
    auto bias_md = GetMemDesc(*bias);
    mkldnn::inner_product_forward::desc ipFwd_desc(propagation,
        data_md, weight_md, bias_md, out_md);
    return mkldnn::inner_product_forward::primitive_desc(ipFwd_desc, engine);
  } else {
    mkldnn::inner_product_forward::desc ipFwd_desc(propagation,
        data_md, weight_md, out_md);
    return mkldnn::inner_product_forward::primitive_desc(ipFwd_desc, engine);
  }
}

inline static mkldnn::inner_product_backward_data::primitive_desc GetIpBwdData(
    const NDArray &data, const NDArray &weight, const NDArray &output,
    mkldnn::inner_product_forward::primitive_desc ipFwd_pd) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto out_md = GetMemDesc(output);
  auto engine = CpuEngine::Get()->get_engine();
  mkldnn::inner_product_backward_data::desc desc(data_md, weight_md, out_md);
  return mkldnn::inner_product_backward_data::primitive_desc(desc, engine, ipFwd_pd);
}

inline static mkldnn::inner_product_backward_weights::primitive_desc GetIPBwdWeights(
    const NDArray &data, const NDArray &weight, const NDArray *bias,
    const NDArray &output, mkldnn::inner_product_forward::primitive_desc ipFwd_pd) {
  auto data_md = GetMemDesc(data);
  auto weight_md = GetMemDesc(weight);
  auto out_md = GetMemDesc(output);
  auto engine = CpuEngine::Get()->get_engine();
  if (bias) {
    auto bias_md = GetMemDesc(*bias);
    mkldnn::inner_product_backward_weights::desc ipBwdWeights_desc(data_md,
        weight_md, bias_md, out_md);
    return mkldnn::inner_product_backward_weights::primitive_desc(
        ipBwdWeights_desc, engine, ipFwd_pd);
  } else {
    mkldnn::inner_product_backward_weights::desc ipBwdWeights_desc(data_md,
        weight_md, out_md);
    return mkldnn::inner_product_backward_weights::primitive_desc(
        ipBwdWeights_desc, engine, ipFwd_pd);
  }
}

void MKLDNNFCForward(const nnvm::NodeAttrs& attrs, const OpContext &ctx,
                     const std::vector<NDArray> &in_data,
                     const std::vector<OpReqType> &req,
                     const std::vector<NDArray> &out_data) {
  TmpMemMgr::Get()->Init(ctx.requested[fullc::kTempSpace]);
  const FullyConnectedParam& param = nnvm::get<FullyConnectedParam>(attrs.parsed);
  const TShape& ishape = in_data[fullc::kData].shape();
  const TShape& oshape = out_data[fullc::kOut].shape();
  NDArray weight = in_data[fullc::kWeight];
  NDArray data = in_data[fullc::kData];
  // If the input data is a view of an MKLDNN array, we should create a new
  // NDArray with reordered data.
  if (data.IsMKLDNNData() && data.IsView())
    data = in_data[fullc::kData].Reorder2Default();

  auto out_md = GetMemDesc(out_data[fullc::kOut]);
  if (data.shape().ndim() != 2 && !param.flatten) {
    data = data.MKLDNNDataReshape(Shape2(ishape.ProdShape(0, ishape.ndim()-1),
                                     ishape[ishape.ndim()-1]));
    mkldnn::memory::dims out_dims{static_cast<int>(oshape.ProdShape(0, oshape.ndim()-1)),
      static_cast<int>(oshape[ishape.ndim()-1])};
    out_md = mkldnn::memory::desc(out_dims, get_mkldnn_type(out_data[fullc::kOut].dtype()),
      mkldnn::memory::format::any);
  } else if (data.shape().ndim() != 2) {
    data = data.MKLDNNDataReshape(Shape2(ishape[0], ishape.ProdShape(1, ishape.ndim())));
    mkldnn::memory::dims out_dims{static_cast<int>(oshape[0]),
      static_cast<int>(oshape.ProdShape(1, oshape.ndim()))};
    out_md = mkldnn::memory::desc(out_dims, get_mkldnn_type(out_data[fullc::kOut].dtype()),
      mkldnn::memory::format::any);
  }

  mkldnn::inner_product_forward::primitive_desc ipFwd_pd = GetIPFwd(data, weight,
      param.no_bias ? nullptr : &in_data[fullc::kBias], out_md, ctx.is_train);
  auto data_mem = data.GetMKLDNNDataReorder(ipFwd_pd.src_primitive_desc());
  auto weight_mem = weight.GetMKLDNNDataReorder(ipFwd_pd.weights_primitive_desc());
  auto out_mem = CreateMKLDNNMem(out_data[fullc::kOut],
      ipFwd_pd.dst_primitive_desc(), req[fullc::kOut]);
  if (param.no_bias) {
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_forward(
          ipFwd_pd, *data_mem, *weight_mem, *out_mem.second));
  } else {
    auto bias_mem = in_data[fullc::kBias].GetMKLDNNDataReorder(ipFwd_pd.bias_primitive_desc());
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_forward(ipFwd_pd,
          *data_mem, *weight_mem, *bias_mem, *out_mem.second));
  }
  CommitOutput(out_data[fullc::kOut], out_mem);
  MKLDNNStream::Get()->Submit();
}

void MKLDNNFCBackward(const nnvm::NodeAttrs& attrs, const OpContext &ctx,
                      const std::vector<NDArray> &inputs,
                      const std::vector<OpReqType> &req,
                      const std::vector<NDArray> &outputs) {
  TmpMemMgr::Get()->Init(ctx.requested[fullc::kTempSpace]);
  const std::vector<NDArray> &in_grad = outputs;
  const FullyConnectedParam& param = nnvm::get<FullyConnectedParam>(attrs.parsed);
  const TShape& ishape = inputs[fullc::kData + 1].shape();
  const TShape& oshape = inputs[fullc::kOut].shape();

  NDArray weight = inputs[fullc::kWeight + 1];
  NDArray data = inputs[fullc::kData + 1];
  if (data.shape().ndim() != 2 && !param.flatten)
    data = data.MKLDNNDataReshape(Shape2(ishape.ProdShape(0, ishape.ndim()-1),
                                     ishape[ishape.ndim()-1]));
  else if (data.shape().ndim() != 2)
    data = data.MKLDNNDataReshape(Shape2(ishape[0],
                                     ishape.ProdShape(1, ishape.ndim())));
  NDArray out_grad = inputs[fullc::kOut];
  if (out_grad.shape().ndim() != 2 && !param.flatten)
    out_grad = out_grad.MKLDNNDataReshape(Shape2(oshape.ProdShape(0, oshape.ndim()-1),
                                             oshape[oshape.ndim()-1]));
  else if (out_grad.shape().ndim() != 2)
    out_grad = out_grad.MKLDNNDataReshape(Shape2(oshape[0],
                                             oshape.ProdShape(1, oshape.ndim())));

  mkldnn::inner_product_forward::primitive_desc ipFwd_pd = GetIPFwd(data, weight,
      param.no_bias ? nullptr : &in_grad[fullc::kBias], GetMemDesc(out_grad), ctx.is_train);

  CHECK_NE(req[fullc::kWeight], kWriteInplace) << "cannot write weight inplace";
  if (req[fullc::kData]) {
    mkldnn::inner_product_backward_data::primitive_desc ipBwdData_pd = GetIpBwdData(
        data, weight, out_grad, ipFwd_pd);
    auto out_grad_mem = out_grad.GetMKLDNNDataReorder(
        ipBwdData_pd.diff_dst_primitive_desc());
    auto weight_mem = weight.GetMKLDNNDataReorder(ipBwdData_pd.weights_primitive_desc());
    auto in_grad_mem = CreateMKLDNNMem(in_grad[fullc::kData],
                                       ipBwdData_pd.diff_src_primitive_desc(),
                                       req[fullc::kData]);
    MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_data(
          ipBwdData_pd, *out_grad_mem, *weight_mem, *in_grad_mem.second));
    CommitOutput(in_grad[fullc::kData], in_grad_mem);
  }
  if (req[fullc::kWeight]) {
    mkldnn::inner_product_backward_weights::primitive_desc ipBwdWeights_pd
      = GetIPBwdWeights(data, weight, param.no_bias ? nullptr : &in_grad[fullc::kBias],
          out_grad, ipFwd_pd);
    auto out_grad_mem = out_grad.GetMKLDNNDataReorder(
        ipBwdWeights_pd.diff_dst_primitive_desc());
    auto data_mem = data.GetMKLDNNDataReorder(ipBwdWeights_pd.src_primitive_desc());
    auto in_grad_weight = CreateMKLDNNWeightGrad(in_grad[fullc::kWeight],
                                                 ipBwdWeights_pd.diff_weights_primitive_desc(),
                                                 req[fullc::kWeight]);
    mkldnn_output_t in_grad_bias;
    if (param.no_bias) {
      MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_weights(
            ipBwdWeights_pd, *data_mem, *out_grad_mem, *in_grad_weight.second));
    } else {
      in_grad_bias = CreateMKLDNNMem(in_grad[fullc::kBias],
                                     ipBwdWeights_pd.diff_bias_primitive_desc(),
                                     req[fullc::kBias]);
      MKLDNNStream::Get()->RegisterPrim(mkldnn::inner_product_backward_weights(
            ipBwdWeights_pd, *data_mem, *out_grad_mem, *in_grad_weight.second,
            *in_grad_bias.second));
    }
    CommitOutput(in_grad[fullc::kWeight], in_grad_weight);
    CommitOutput(in_grad[fullc::kBias], in_grad_bias);
  }
  MKLDNNStream::Get()->Submit();
}

}  // namespace op
}  // namespace mxnet
#endif  // MXNET_USE_MKLDNN == 1
<|endoftext|>


<commit_before>
#include "config_interrogatedb.cxx"
#include "indexRemapper.cxx"
#include "interrogateComponent.cxx"
#include "interrogateElement.cxx"
#include "interrogateFunction.cxx"
#include "interrogateFunctionWrapper.cxx"
#include "interrogate_datafile.cxx"
#include "interrogate_interface.cxx"
#include "vector_int.cxx"

<commit_msg>*** empty log message ***<commit_after>
#include "vector_int.cxx"
#include "config_interrogatedb.cxx"
#include "indexRemapper.cxx"
#include "interrogateComponent.cxx"
#include "interrogateElement.cxx"
#include "interrogateFunction.cxx"
#include "interrogateFunctionWrapper.cxx"
#include "interrogate_datafile.cxx"
#include "interrogate_interface.cxx"

<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <test/models/model_test_fixture.hpp>

class Models_BasicEstimators_NormalMixture :
  public Model_Test_Fixture<Models_BasicEstimators_NormalMixture> {
protected:
  virtual void SetUp() {
  }
public:
  static std::vector<std::string> get_model_path() {
    std::vector<std::string> model_path;
    model_path.push_back("models");
    model_path.push_back("basic_estimators");
    model_path.push_back("normal_mixture");
    return model_path;
  }
  static bool has_data() {
    return true;
  }

  static bool has_init() {
    return false;

  }
  static int num_iterations() {
    //return 8000;
    return 200;
  }

  static std::vector<int> skip_chains_test() {
    std::vector<int> params_to_skip;
    return params_to_skip;
  }

  static void populate_chains() {
    if (chains->num_kept_samples() == 0) {
      for (int chain = 0; chain < num_chains; chain++) {
  std::ifstream ifstream;
  stan::io::stan_csv stan_csv;
  ifstream.open(get_csv_file(chain).c_str());
  stan_csv = stan::io::stan_csv_reader::parse(ifstream);
  ifstream.close();

  int theta = 3;
  int mu1 = 4;
  int mu2 = 5;
  int log_theta = 6;
  int log_1mtheta = 7;
  // if theta > 0.5, swap values
  if (stan_csv.samples.col(theta).mean() > 0.5) {
    stan_csv.samples.col(theta) = 1.0 - stan_csv.samples.col(theta).array();

    Eigen::VectorXd tmp;
    tmp = stan_csv.samples.col(mu1);
    stan_csv.samples.col(mu1) = stan_csv.samples.col(mu2);
    stan_csv.samples.col(mu2) = tmp;

    tmp = stan_csv.samples.col(log_theta);
    stan_csv.samples.col(log_theta) = stan_csv.samples.col(log_1mtheta);
    stan_csv.samples.col(log_1mtheta) = tmp;
  }

  chains->add(stan_csv);
      }
    }
  }

  static std::vector<std::pair<int, double> >
  get_expected_values() {
    using std::make_pair;
    std::vector<std::pair<int, double> > expected_values;

    expected_values.push_back(make_pair(chains->index("theta"), 0.2916));
    expected_values.push_back(make_pair(chains->index("mu[1]"), -10.001));
    expected_values.push_back(make_pair(chains->index("mu[2]"), 10.026));

    return expected_values;
  }

};

INSTANTIATE_TYPED_TEST_CASE_P(Models_BasicEstimators_NormalMixture,
            Model_Test_Fixture,
            Models_BasicEstimators_NormalMixture);
<commit_msg>fixes issue #63.<commit_after>#include <gtest/gtest.h>
#include <test/models/model_test_fixture.hpp>

class Models_BasicEstimators_NormalMixture :
  public Model_Test_Fixture<Models_BasicEstimators_NormalMixture> {
protected:
  virtual void SetUp() {
  }
public:
  static std::vector<std::string> get_model_path() {
    std::vector<std::string> model_path;
    model_path.push_back("models");
    model_path.push_back("basic_estimators");
    model_path.push_back("normal_mixture");
    return model_path;
  }
  static bool has_data() {
    return true;
  }

  static bool has_init() {
    return false;

  }
  static int num_iterations() {
    //return 8000;
    return 200;
  }

  static std::vector<int> skip_chains_test() {
    std::vector<int> params_to_skip;
    return params_to_skip;
  }

  static int find(const Eigen::Matrix<std::string,Eigen::Dynamic,1>& header,
                  const std::string& var) {
    for (int i = 0; i < header.size(); i++)
      if (header(i) == var)
        return i;
    return -1;
  }

  static void populate_chains() {
    if (chains->num_kept_samples() == 0) {
      for (int chain = 1; chain <= num_chains; chain++) {
        std::ifstream ifstream;
        stan::io::stan_csv stan_csv;
        ifstream.open(get_csv_file(chain).c_str());
        stan_csv = stan::io::stan_csv_reader::parse(ifstream);
        ifstream.close();

        int theta = find(stan_csv.header, "theta");
        int mu1 = find(stan_csv.header, "mu[1]");
        int mu2 = find(stan_csv.header, "mu[2]");
        int log_theta = find(stan_csv.header, "log_theta");
        int log_1mtheta = find(stan_csv.header, "log_one_minus_theta");

        // if theta > 0.5, swap values
        if (stan_csv.samples.col(theta).mean() > 0.5) {
          stan_csv.samples.col(theta) = 1.0 - stan_csv.samples.col(theta).array();

          Eigen::VectorXd tmp;
          tmp = stan_csv.samples.col(mu1);
          stan_csv.samples.col(mu1) = stan_csv.samples.col(mu2);
          stan_csv.samples.col(mu2) = tmp;

          tmp = stan_csv.samples.col(log_theta);
          stan_csv.samples.col(log_theta) = stan_csv.samples.col(log_1mtheta);
          stan_csv.samples.col(log_1mtheta) = tmp;
        }
        chains->add(stan_csv);
      }
    }
  }

  static std::vector<std::pair<int, double> >
  get_expected_values() {
    using std::make_pair;
    std::vector<std::pair<int, double> > expected_values;

    expected_values.push_back(make_pair(chains->index("theta"), 0.2916));
    expected_values.push_back(make_pair(chains->index("mu[1]"), -10.001));
    expected_values.push_back(make_pair(chains->index("mu[2]"), 10.026));

    return expected_values;
  }

};

INSTANTIATE_TYPED_TEST_CASE_P(Models_BasicEstimators_NormalMixture,
                              Model_Test_Fixture,
                              Models_BasicEstimators_NormalMixture);
<|endoftext|>


<commit_before>/*
 * InputStreamMgr.cpp
 *
 *  Created on: Mar 21, 2013
 *      Author: nek3d
 */

#include "InputStreamMgr.h"
#include <cstring> //for memset
#include "gzstream.h"
#include "CompressionTools.h"

const char *InputStreamMgr::FIFO_STRING_LITERAL = "/dev/fd";

InputStreamMgr::InputStreamMgr(const string &filename, bool buildScanBuffer)
:
 _filename(filename),
 _pushBackStreamBuf(NULL),
 _inputFileStream(NULL),
 _infStreamBuf(NULL),
 _oldInputStream(NULL),
 _isStdin(false),
 _isGzipped(false),
 _isBam(false),
 _isBgzipped(false),
 _tmpZipBuf(NULL),
 _bamRuledOut(false),
 _streamFinished(false),
 _numBytesInBuffer(0),
 _bamReader(NULL),
 _bgStream(NULL),
 _eofHit(false)
{
	_possibleBamCode.resize(4, 0);
}

InputStreamMgr::~InputStreamMgr() {
	delete _pushBackStreamBuf;
	_pushBackStreamBuf = NULL;

	delete _inputFileStream;
	_inputFileStream = NULL;

	delete _oldInputStream;
	_oldInputStream = NULL;

	delete _infStreamBuf;
	_infStreamBuf = NULL;

	if(_bamReader) _bamReader->Close();
	delete _bamReader;

	delete _bgStream;
	_bgStream = NULL;

	delete _finalInputStream;
	_finalInputStream = NULL;

	delete [] _tmpZipBuf;
	_tmpZipBuf = NULL;
}

bool InputStreamMgr::init()
{
	if (_filename == "-" || _filename == "stdin") { //stdin
		_isStdin = true;
		//peek at the first char of stdin to see if this is gzipped.
		if ((unsigned char)cin.peek()  == 0x1f) {
			_isGzipped = true;
		}
		_pushBackStreamBuf = new PushBackStreamBuf(cin.rdbuf());
	} else {
		if (strncmp(_filename.c_str(), FIFO_STRING_LITERAL, strlen(FIFO_STRING_LITERAL)) == 0) {
			_isStdin = true;
		}
		_inputFileStream = new ifstream(_filename.c_str());
		if (_inputFileStream->fail()) {
			cerr << "Error: Unable to open file " << _filename << ". Exiting." << endl;
			delete _inputFileStream;
			_inputFileStream = NULL;
			exit(1);
		}
		//peek at the first char of stdin to see if this is gzipped.
		if ((unsigned char)_inputFileStream->peek()  == 0x1f) {
			_isGzipped = true;
		}
		_pushBackStreamBuf = new PushBackStreamBuf(_inputFileStream->rdbuf());
	}
	//now we have a PushBackStreamBuf. Make a new stream.
	_finalInputStream = new istream(_pushBackStreamBuf);
	populateScanBuffer();
	return true;
}

int InputStreamMgr::read(char *data, size_t dataSize)
{
	size_t origRead = 0;
	if (!_saveDataStr.empty()) {
		//must first copy contents of savedData into requested data read buffer.
		if (dataSize >= _saveDataStr.size()) {
			//They asked for the same amount of data or more than we saved. Give them all the saved data,
			//then decrement the requested data size accordingly.
			origRead = _saveDataStr.size();
			memcpy(data, _saveDataStr.c_str(), origRead);
			data += origRead;
			dataSize -= origRead;
			_saveDataStr.clear();
		} else {
			//This part is tricky. They want less data than we saved. Give them what they
			//requested, then delete from the front of the saveDataStr by using it's substr method.
			memcpy(data, _saveDataStr.c_str(), dataSize);
			string newDataStr;
			newDataStr = _saveDataStr.substr(dataSize, _saveDataStr.size() - dataSize);
			_saveDataStr = newDataStr;
			return dataSize;
		}
	}
	if (_streamFinished) {
		return origRead;
	}
	if (_isBgzipped) {
		ssize_t rc;
		if((rc = bgzf_read(_bgStream, data, dataSize)) < 0)
			return -1;

		return (int)(origRead + rc);
	}
	_finalInputStream->read(data, dataSize);
	return origRead + _finalInputStream->gcount();
}

bool InputStreamMgr::populateScanBuffer()
{
	_scanBuffer.clear();
	_saveDataStr.clear();
	int numChars=0;
	int currChar = 0;
	while (1) {
		if (_isGzipped && _bamRuledOut) {
			return readZipChunk();
		}
		currChar = _pushBackStreamBuf->sbumpc();
		//Stop when EOF hit.
		if (currChar == EOF) {
			_eofHit = true;
			break;
		}
		numChars++;
		_scanBuffer.push_back(currChar);
		if (_isGzipped) {
			if (!_bamRuledOut && detectBamOrBgzip(numChars, currChar)) {
				//we now know the file is in bgzipped format
				return true;
			}
			if (numChars == 0) {
				continue; //this will only happen when we've just discovered that this
				//is definitely not BAM, and want to start over.
			}
		}

		//Stop if we have the minimum number of bytes and newline is hit.
		//For gzip, stop at SCAN_BUFFER_SIZE.
		if (currChar == '\n' && numChars >= MIN_SCAN_BUFFER_SIZE ){
			break;
		}
	}
	_numBytesInBuffer = _scanBuffer.size();
	//append it to the savedDataStr.
 	_scanBuffer.toStr(_saveDataStr, true);
	if (_numBytesInBuffer == 0) return false;
	return true;
}

bool InputStreamMgr::detectBamOrBgzip(int &numChars, int currChar)
{
	//Look for the BAM magic string "BAM\1" in the first fouur characters of the input stream.
	//In compressed form, the first char is the gzip signifier, which was already found.
	//The next three are the integers 139, 8, and 4.
	if (numChars < 5) {
		_possibleBamCode[numChars -1] = currChar;
		//special: test for BAM
		if (numChars == 4 && _possibleBamCode[1] == 139 && _possibleBamCode[2] == 8 && _possibleBamCode[3] == 4) {
			//BAM magic string detected.This is either a BAM or bgzip file. To find out which, we have to try and
			//open the file as BAM, with a BAM reader, and see if the header and references are both non-empty.
			//However, if they are empty, we will have had to save all bytes consumed in the attempt, meaning still
			//fill the scanBuffer and push it back onto the pushBackStream as normal.
			for (; numChars < BAM_SCAN_BUFFER_SIZE; numChars++) {
				currChar = _pushBackStreamBuf->sbumpc();
				//Stop when EOF hit.
				if (currChar == EOF) {
					_eofHit = true;
					break;
				}
				_scanBuffer.push_back(currChar);

			}
			_pushBackStreamBuf->pushBack(_scanBuffer);

			//ok, now all the data read so far is saved in the scan buffer, and pushbackstream is reset.
			//now we make a BamReader and try to open the file.

			_bamReader = new BamTools::BamReader();
			if (!_bamReader->OpenStream(_finalInputStream)) {
				//This is NOT a bam file, but it is bgzipped.
				_pushBackStreamBuf->clear();
				//Put all bytes read so far back onto the scan buffer, then reset
				//everything so that we're effectively starting over.
				_pushBackStreamBuf->pushBack(_scanBuffer);
				_scanBuffer.clear();
				numChars = 0;
				_isBam = false;
				_isBgzipped = true;
				_bamRuledOut = true;
				_numBytesInBuffer = 0;
				delete _bamReader;
				_bamReader = NULL;
				_finalInputStream->clear();

				BamTools::stream_data_t* cb_data = new BamTools::stream_data_t(*_finalInputStream);
				hFILE_callback_ops ops;
				memset(&ops, 0, sizeof(ops));
				ops.read = BamTools::stream_data_t::read;
				ops.close = BamTools::stream_data_t::close;
				ops.cb_data = cb_data;
				hFILE* hp = hopen_callback(ops, "rb");
				if(nullptr == hp) return false;
				if(nullptr == (_bgStream = bgzf_hopen(hp, "rb")))
					return false;

				return false;
			}
			//This is a BAM file.
			_isBam = true;
			_numBytesInBuffer = _scanBuffer.size();
			return true;
		} else if (numChars == 4) {
			//This is a gzipped file, and it is not bgzipped or BAM.
			_pushBackStreamBuf->clear();
			_pushBackStreamBuf->pushBack(_scanBuffer);
			_scanBuffer.clear();
			numChars = 0;
			_isBam = false;
			_isBgzipped = false;
			_bamRuledOut = true;
			_numBytesInBuffer = 0;
			_infStreamBuf = new InflateStreamBuf(_finalInputStream);
			delete _oldInputStream;
			_oldInputStream = _finalInputStream;
			_finalInputStream = new istream(_infStreamBuf);
			return false;
		}
	}
	return false;
}

bool InputStreamMgr::readZipChunk()
{
	if (_tmpZipBuf == NULL) {
		_tmpZipBuf = new char[SCAN_BUFFER_SIZE +1];
	}
	memset(_tmpZipBuf, 0, SCAN_BUFFER_SIZE +1);
	size_t numCharsRead = read(_tmpZipBuf, (size_t)SCAN_BUFFER_SIZE);
	_saveDataStr.append(_tmpZipBuf);
	_numBytesInBuffer = _saveDataStr.size();
	if ((int)numCharsRead < SCAN_BUFFER_SIZE) {
		_streamFinished = true;
	}
	if (numCharsRead == 0) return false;
	return true;
}

bool InputStreamMgr::resetStream()
{
	_saveDataStr.clear();
	if (!_isBam && !_isStdin && !_isGzipped) {
		//For non-compressed, non-stdin file input, just re-open the file.
		delete _finalInputStream;
		_finalInputStream = new ifstream(_filename.c_str());
		return true;
	}
	return false;
}

<commit_msg>Cram support<commit_after>/*
 * InputStreamMgr.cpp
 *
 *  Created on: Mar 21, 2013
 *      Author: nek3d
 */

#include "InputStreamMgr.h"
#include <cstring> //for memset
#include "gzstream.h"
#include "CompressionTools.h"

const char *InputStreamMgr::FIFO_STRING_LITERAL = "/dev/fd";

InputStreamMgr::InputStreamMgr(const string &filename, bool buildScanBuffer)
:
 _filename(filename),
 _pushBackStreamBuf(NULL),
 _inputFileStream(NULL),
 _infStreamBuf(NULL),
 _oldInputStream(NULL),
 _isStdin(false),
 _isGzipped(false),
 _isBam(false),
 _isBgzipped(false),
 _tmpZipBuf(NULL),
 _bamRuledOut(false),
 _streamFinished(false),
 _numBytesInBuffer(0),
 _bamReader(NULL),
 _bgStream(NULL),
 _eofHit(false)
{
	_possibleBamCode.resize(4, 0);
}

InputStreamMgr::~InputStreamMgr() {
	delete _pushBackStreamBuf;
	_pushBackStreamBuf = NULL;

	delete _inputFileStream;
	_inputFileStream = NULL;

	delete _oldInputStream;
	_oldInputStream = NULL;

	delete _infStreamBuf;
	_infStreamBuf = NULL;

	if(_bamReader) _bamReader->Close();
	delete _bamReader;

	delete _bgStream;
	_bgStream = NULL;

	delete _finalInputStream;
	_finalInputStream = NULL;

	delete [] _tmpZipBuf;
	_tmpZipBuf = NULL;
}

bool InputStreamMgr::init()
{
	if (_filename == "-" || _filename == "stdin") { //stdin
		_isStdin = true;
		//peek at the first char of stdin to see if this is gzipped.
		if ((unsigned char)cin.peek()  == 0x1f) {
			_isGzipped = true;
		}
		_pushBackStreamBuf = new PushBackStreamBuf(cin.rdbuf());
	} else {
		if (strncmp(_filename.c_str(), FIFO_STRING_LITERAL, strlen(FIFO_STRING_LITERAL)) == 0) {
			_isStdin = true;
		}
		_inputFileStream = new ifstream(_filename.c_str());
		if (_inputFileStream->fail()) {
			cerr << "Error: Unable to open file " << _filename << ". Exiting." << endl;
			delete _inputFileStream;
			_inputFileStream = NULL;
			exit(1);
		}
		//peek at the first char of stdin to see if this is gzipped.
		if ((unsigned char)_inputFileStream->peek()  == 0x1f) {
			_isGzipped = true;
		}
		_pushBackStreamBuf = new PushBackStreamBuf(_inputFileStream->rdbuf());
	}
	//now we have a PushBackStreamBuf. Make a new stream.
	_finalInputStream = new istream(_pushBackStreamBuf);
	populateScanBuffer();
	return true;
}

int InputStreamMgr::read(char *data, size_t dataSize)
{
	size_t origRead = 0;
	if (!_saveDataStr.empty()) {
		//must first copy contents of savedData into requested data read buffer.
		if (dataSize >= _saveDataStr.size()) {
			//They asked for the same amount of data or more than we saved. Give them all the saved data,
			//then decrement the requested data size accordingly.
			origRead = _saveDataStr.size();
			memcpy(data, _saveDataStr.c_str(), origRead);
			data += origRead;
			dataSize -= origRead;
			_saveDataStr.clear();
		} else {
			//This part is tricky. They want less data than we saved. Give them what they
			//requested, then delete from the front of the saveDataStr by using it's substr method.
			memcpy(data, _saveDataStr.c_str(), dataSize);
			string newDataStr;
			newDataStr = _saveDataStr.substr(dataSize, _saveDataStr.size() - dataSize);
			_saveDataStr = newDataStr;
			return dataSize;
		}
	}
	if (_streamFinished) {
		return origRead;
	}
	if (_isBgzipped) {
		ssize_t rc;
		if((rc = bgzf_read(_bgStream, data, dataSize)) < 0)
			return -1;

		return (int)(origRead + rc);
	}
	_finalInputStream->read(data, dataSize);
	return origRead + _finalInputStream->gcount();
}

bool InputStreamMgr::populateScanBuffer()
{
	_scanBuffer.clear();
	_saveDataStr.clear();
	int numChars=0;
	int currChar = 0;
	char cram_code[4];
	while (1) {
		if (_isGzipped && _bamRuledOut) {
			return readZipChunk();
		}
		currChar = _pushBackStreamBuf->sbumpc();
		//Stop when EOF hit.
		if (currChar == EOF) {
			_eofHit = true;
			break;
		}
		numChars++;
		_scanBuffer.push_back(currChar);
		if (_isGzipped) {
			if (!_bamRuledOut && detectBamOrBgzip(numChars, currChar)) {
				//we now know the file is in bgzipped format
				return true;
			}
			if (numChars == 0) {
				continue; //this will only happen when we've just discovered that this
				//is definitely not BAM, and want to start over.
			}
		}
	   else
	   {
			if(numChars <= 4) cram_code[numChars-1] = currChar;
			if(numChars == 4 && memcmp(cram_code, "CRAM", 4) == 0)
			{
				for (; numChars < BAM_SCAN_BUFFER_SIZE; numChars++) {
					currChar = _pushBackStreamBuf->sbumpc();
					//Stop when EOF hit.
					if (currChar == EOF) {
						_eofHit = true;
						break;
					}
					_scanBuffer.push_back(currChar);

				}
				_pushBackStreamBuf->pushBack(_scanBuffer);

				_bamReader = new BamTools::BamReader();
				if (_bamReader->OpenStream(_finalInputStream))
				{
					_isBam = true;
					_numBytesInBuffer = _scanBuffer.size();
					return true;
				}
				else return false;
			}
		}

		//Stop if we have the minimum number of bytes and newline is hit.
		//For gzip, stop at SCAN_BUFFER_SIZE.
		if (currChar == '\n' && numChars >= MIN_SCAN_BUFFER_SIZE ){
			break;
		}
	}
	_numBytesInBuffer = _scanBuffer.size();
	//append it to the savedDataStr.
 	_scanBuffer.toStr(_saveDataStr, true);
	if (_numBytesInBuffer == 0) return false;
	return true;
}

bool InputStreamMgr::detectBamOrBgzip(int &numChars, int currChar)
{
	//Look for the BAM magic string "BAM\1" in the first fouur characters of the input stream.
	//In compressed form, the first char is the gzip signifier, which was already found.
	//The next three are the integers 139, 8, and 4.
	if (numChars < 5) {
		_possibleBamCode[numChars -1] = currChar;
		//special: test for BAM
		if (numChars == 4 && _possibleBamCode[1] == 139 && _possibleBamCode[2] == 8 && _possibleBamCode[3] == 4) {
			//BAM magic string detected.This is either a BAM or bgzip file. To find out which, we have to try and
			//open the file as BAM, with a BAM reader, and see if the header and references are both non-empty.
			//However, if they are empty, we will have had to save all bytes consumed in the attempt, meaning still
			//fill the scanBuffer and push it back onto the pushBackStream as normal.
			for (; numChars < BAM_SCAN_BUFFER_SIZE; numChars++) {
				currChar = _pushBackStreamBuf->sbumpc();
				//Stop when EOF hit.
				if (currChar == EOF) {
					_eofHit = true;
					break;
				}
				_scanBuffer.push_back(currChar);

			}
			_pushBackStreamBuf->pushBack(_scanBuffer);

			//ok, now all the data read so far is saved in the scan buffer, and pushbackstream is reset.
			//now we make a BamReader and try to open the file.

			_bamReader = new BamTools::BamReader();
			if (!_bamReader->OpenStream(_finalInputStream)) {
				//This is NOT a bam file, but it is bgzipped.
				_pushBackStreamBuf->clear();
				//Put all bytes read so far back onto the scan buffer, then reset
				//everything so that we're effectively starting over.
				_pushBackStreamBuf->pushBack(_scanBuffer);
				_scanBuffer.clear();
				numChars = 0;
				_isBam = false;
				_isBgzipped = true;
				_bamRuledOut = true;
				_numBytesInBuffer = 0;
				delete _bamReader;
				_bamReader = NULL;
				_finalInputStream->clear();

				BamTools::stream_data_t* cb_data = new BamTools::stream_data_t(*_finalInputStream);
				hFILE_callback_ops ops;
				memset(&ops, 0, sizeof(ops));
				ops.read = BamTools::stream_data_t::read;
				ops.close = BamTools::stream_data_t::close;
				ops.cb_data = cb_data;
				hFILE* hp = hopen_callback(ops, "rb");
				if(nullptr == hp) return false;
				if(nullptr == (_bgStream = bgzf_hopen(hp, "rb")))
					return false;

				return false;
			}
			//This is a BAM file.
			_isBam = true;
			_numBytesInBuffer = _scanBuffer.size();
			return true;
		} else if (numChars == 4) {
			//This is a gzipped file, and it is not bgzipped or BAM.
			_pushBackStreamBuf->clear();
			_pushBackStreamBuf->pushBack(_scanBuffer);
			_scanBuffer.clear();
			numChars = 0;
			_isBam = false;
			_isBgzipped = false;
			_bamRuledOut = true;
			_numBytesInBuffer = 0;
			_infStreamBuf = new InflateStreamBuf(_finalInputStream);
			delete _oldInputStream;
			_oldInputStream = _finalInputStream;
			_finalInputStream = new istream(_infStreamBuf);
			return false;
		}
	}
	return false;
}

bool InputStreamMgr::readZipChunk()
{
	if (_tmpZipBuf == NULL) {
		_tmpZipBuf = new char[SCAN_BUFFER_SIZE +1];
	}
	memset(_tmpZipBuf, 0, SCAN_BUFFER_SIZE +1);
	size_t numCharsRead = read(_tmpZipBuf, (size_t)SCAN_BUFFER_SIZE);
	_saveDataStr.append(_tmpZipBuf);
	_numBytesInBuffer = _saveDataStr.size();
	if ((int)numCharsRead < SCAN_BUFFER_SIZE) {
		_streamFinished = true;
	}
	if (numCharsRead == 0) return false;
	return true;
}

bool InputStreamMgr::resetStream()
{
	_saveDataStr.clear();
	if (!_isBam && !_isStdin && !_isGzipped) {
		//For non-compressed, non-stdin file input, just re-open the file.
		delete _finalInputStream;
		_finalInputStream = new ifstream(_filename.c_str());
		return true;
	}
	return false;
}

<|endoftext|>


<commit_before>#include "Particle3DBuilder.h"
#include "PackParticle3D.h"
#include "PackNodeFactory.h"
#include "P3dSprBuilder.h"

#include <ee/Visitor.h>

#include <easyparticle3d.h>

#include <ps_3d.h>

namespace erespacker
{

Particle3DBuilder::Particle3DBuilder()
{
}

Particle3DBuilder::~Particle3DBuilder()
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::iterator
		itr = m_map_data.begin();
	for ( ; itr != m_map_data.end(); ++itr) {
		delete itr->second;
	}
}

void Particle3DBuilder::Traverse(ee::Visitor& visitor) const
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::const_iterator
		itr = m_map_data.begin();
	for ( ; itr != m_map_data.end(); ++itr) {
		bool has_next;
		visitor.Visit(const_cast<PackParticle3D*>(itr->second), has_next);
		if (!has_next) {
			break;
		}
	}
}

const IPackNode* Particle3DBuilder::Create(const eparticle3d::Symbol* symbol, P3dSprBuilder* spr_builder)
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::iterator
		itr = m_map_data.find(symbol);
	if (itr != m_map_data.end()) {
		return itr->second;
	}

	PackParticle3D* node = new PackParticle3D;
	Load(symbol, node);
	m_map_data.insert(std::make_pair(symbol, node));
	spr_builder->Create(symbol, node);
	return node;
}

void Particle3DBuilder::Load(const eparticle3d::Symbol* symbol, PackParticle3D* ps)
{
	const p3d_emitter_cfg* cfg = symbol->GetEmitterCfg();

	ps->static_mode = cfg->static_mode;

	ps->emission_time = cfg->emission_time;
	ps->count = cfg->count;

	ps->life = cfg->life;
	ps->life_var = cfg->life_var;

	ps->hori = cfg->hori;
	ps->hori_var = cfg->hori_var;
	ps->vert = cfg->vert;
	ps->vert_var = cfg->vert_var;

	ps->radial_spd = cfg->radial_spd;
	ps->radial_spd_var = cfg->radial_spd_var;
	ps->tangential_spd = cfg->tangential_spd;
	ps->tangential_spd_var = cfg->tangential_spd_var;
	ps->angular_spd = cfg->angular_spd;
	ps->angular_spd_var = cfg->angular_spd_var;

	ps->dis_region = cfg->dis_region;
	ps->dis_region_var = cfg->dis_region_var;
	ps->dis_spd = cfg->dis_spd;
	ps->dis_spd_var = cfg->dis_spd_var;

	ps->gravity = cfg->gravity;

	ps->linear_acc = cfg->linear_acc;
	ps->linear_acc_var = cfg->linear_acc_var;

	ps->fadeout_time = cfg->fadeout_time;

	ps->ground = cfg->ground;

	ps->start_radius = cfg->start_radius;
	ps->start_height = cfg->start_height;

	ps->orient_to_movement = cfg->orient_to_movement;

	ps->components.reserve(cfg->symbol_count);
	for (int i = 0; i < cfg->symbol_count; ++i)
	{
		const p3d_symbol& p_symbol = cfg->symbols[i];

		PackParticle3D::Component comp;

		comp.count = p_symbol.count;

		comp.scale_start = p_symbol.scale_start;
		comp.scale_end = p_symbol.scale_end;

		comp.angle = p_symbol.angle;
		comp.angle_var = p_symbol.angle_var;

		comp.col_mul = s2::Color((int)(p_symbol.col_mul.r * 255), (int)(p_symbol.col_mul.g * 255),
			(int)(p_symbol.col_mul.b * 255), (int)(p_symbol.col_mul.a * 255)).ToABGR();
		comp.col_add = s2::Color((int)(p_symbol.col_add.r * 255), (int)(p_symbol.col_add.g * 255),
			(int)(p_symbol.col_add.b * 255), (int)(p_symbol.col_add.a * 255)).ToABGR();
		comp.alpha_start = p_symbol.alpha_start * 255.0f + 0.5f;
		comp.alpha_end = p_symbol.alpha_end * 255.0f + 0.5f;

		ee::Symbol* symbol = static_cast<ee::Symbol*>(p_symbol.ud);
		comp.node = PackNodeFactory::Instance()->Create(symbol);

		ps->components.push_back(comp);
	}
}

}<commit_msg>[FIXED] pack p3d color, use argb format<commit_after>#include "Particle3DBuilder.h"
#include "PackParticle3D.h"
#include "PackNodeFactory.h"
#include "P3dSprBuilder.h"

#include <ee/Visitor.h>
#include <ee/trans_color.h>

#include <easyparticle3d.h>

#include <ps_3d.h>

namespace erespacker
{

Particle3DBuilder::Particle3DBuilder()
{
}

Particle3DBuilder::~Particle3DBuilder()
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::iterator
		itr = m_map_data.begin();
	for ( ; itr != m_map_data.end(); ++itr) {
		delete itr->second;
	}
}

void Particle3DBuilder::Traverse(ee::Visitor& visitor) const
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::const_iterator
		itr = m_map_data.begin();
	for ( ; itr != m_map_data.end(); ++itr) {
		bool has_next;
		visitor.Visit(const_cast<PackParticle3D*>(itr->second), has_next);
		if (!has_next) {
			break;
		}
	}
}

const IPackNode* Particle3DBuilder::Create(const eparticle3d::Symbol* symbol, P3dSprBuilder* spr_builder)
{
	std::map<const eparticle3d::Symbol*, const PackParticle3D*>::iterator
		itr = m_map_data.find(symbol);
	if (itr != m_map_data.end()) {
		return itr->second;
	}

	PackParticle3D* node = new PackParticle3D;
	Load(symbol, node);
	m_map_data.insert(std::make_pair(symbol, node));
	spr_builder->Create(symbol, node);
	return node;
}

void Particle3DBuilder::Load(const eparticle3d::Symbol* symbol, PackParticle3D* ps)
{
	const p3d_emitter_cfg* cfg = symbol->GetEmitterCfg();

	ps->static_mode = cfg->static_mode;

	ps->emission_time = cfg->emission_time;
	ps->count = cfg->count;

	ps->life = cfg->life;
	ps->life_var = cfg->life_var;

	ps->hori = cfg->hori;
	ps->hori_var = cfg->hori_var;
	ps->vert = cfg->vert;
	ps->vert_var = cfg->vert_var;

	ps->radial_spd = cfg->radial_spd;
	ps->radial_spd_var = cfg->radial_spd_var;
	ps->tangential_spd = cfg->tangential_spd;
	ps->tangential_spd_var = cfg->tangential_spd_var;
	ps->angular_spd = cfg->angular_spd;
	ps->angular_spd_var = cfg->angular_spd_var;

	ps->dis_region = cfg->dis_region;
	ps->dis_region_var = cfg->dis_region_var;
	ps->dis_spd = cfg->dis_spd;
	ps->dis_spd_var = cfg->dis_spd_var;

	ps->gravity = cfg->gravity;

	ps->linear_acc = cfg->linear_acc;
	ps->linear_acc_var = cfg->linear_acc_var;

	ps->fadeout_time = cfg->fadeout_time;

	ps->ground = cfg->ground;

	ps->start_radius = cfg->start_radius;
	ps->start_height = cfg->start_height;

	ps->orient_to_movement = cfg->orient_to_movement;

	ps->components.reserve(cfg->symbol_count);
	for (int i = 0; i < cfg->symbol_count; ++i)
	{
		const p3d_symbol& p_symbol = cfg->symbols[i];

		PackParticle3D::Component comp;

		comp.count = p_symbol.count;

		comp.scale_start = p_symbol.scale_start;
		comp.scale_end = p_symbol.scale_end;

		comp.angle = p_symbol.angle;
		comp.angle_var = p_symbol.angle_var;

		s2::Color mul((int)(p_symbol.col_mul.r * 255), (int)(p_symbol.col_mul.g * 255),
			(int)(p_symbol.col_mul.b * 255), (int)(p_symbol.col_mul.a * 255));
		s2::Color add((int)(p_symbol.col_add.r * 255), (int)(p_symbol.col_add.g * 255),
			(int)(p_symbol.col_add.b * 255), (int)(p_symbol.col_add.a * 255));
		comp.col_mul = ee::color2int(mul, ee::PT_ARGB);
		comp.col_add = ee::color2int(add, ee::PT_ARGB);
		comp.alpha_start = p_symbol.alpha_start * 255.0f + 0.5f;
		comp.alpha_end = p_symbol.alpha_end * 255.0f + 0.5f;

		ee::Symbol* symbol = static_cast<ee::Symbol*>(p_symbol.ud);
		comp.node = PackNodeFactory::Instance()->Create(symbol);

		ps->components.push_back(comp);
	}
}

}<|endoftext|>


<commit_before>// WlanTest.cpp : Defines the entry point for the console application.
//

// #include "stdafx.h"
#include <stdio.h>
#include <tchar.h>

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <wlanapi.h>

#define WLAN_CLIENT_VERSION_VISTA 2

void SetInterface(WLAN_INTF_OPCODE opcode, PVOID* pData, GUID* InterfaceGuid)
{
	DWORD dwResult = 0;
	HANDLE hClient = NULL;
	DWORD dwCurVersion = 0;
	DWORD outsize = 0;

	// Open Handle for the set operation
	dwResult = WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
	dwResult = WlanSetInterface(hClient, InterfaceGuid, opcode, sizeof(ULONG), pData, NULL);
	WlanCloseHandle(hClient, NULL);

}

// enumerate wireless interfaces
UINT EnumInterface(HANDLE hClient, WLAN_INTERFACE_INFO sInfo[64])
{
	DWORD dwError = ERROR_SUCCESS;
	PWLAN_INTERFACE_INFO_LIST pIntfList = NULL;
	UINT i = 0;

	__try
	{
		// enumerate wireless interfaces
		if ((dwError = WlanEnumInterfaces(
			hClient,
			NULL,               // reserved
			&pIntfList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print out interface information
		for (i = 0; i < pIntfList->dwNumberOfItems; i++)
		{
			memcpy(&sInfo[i], &pIntfList->InterfaceInfo[i], sizeof(WLAN_INTERFACE_INFO));
		}

		return pIntfList->dwNumberOfItems;
	}
	__finally
	{
		// clean up
		if (pIntfList != NULL)
		{
			WlanFreeMemory(pIntfList);
		}
	}
	return 0;
}

// open a WLAN client handle and check version
DWORD
OpenHandleAndCheckVersion(
PHANDLE phClient
)
{
	DWORD dwError = ERROR_SUCCESS;
	DWORD dwServiceVersion;
	HANDLE hClient = NULL;

	__try
	{
		*phClient = NULL;

		// open a handle to the service
		if ((dwError = WlanOpenHandle(
			WLAN_API_VERSION,
			NULL,               // reserved
			&dwServiceVersion,
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// check service version
		if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0))
		{
			// No-op, because the version check is for demonstration purpose only.
			// You can add your own logic here.
		}

		*phClient = hClient;

		// set hClient to NULL so it will not be closed
		hClient = NULL;
	}
	__finally
	{
		if (hClient != NULL)
		{
			// clean up
			WlanCloseHandle(
				hClient,
				NULL            // reserved
				);
		}
	}

	return dwError;
}

// get interface state string
LPWSTR
GetInterfaceStateString(__in WLAN_INTERFACE_STATE wlanInterfaceState)
{
	LPWSTR strRetCode;

	switch (wlanInterfaceState)
	{
	case wlan_interface_state_not_ready:
		strRetCode = L"\"not ready\"";
		break;
	case wlan_interface_state_connected:
		strRetCode = L"\"connected\"";
		break;
	case wlan_interface_state_ad_hoc_network_formed:
		strRetCode = L"\"ad hoc network formed\"";
		break;
	case wlan_interface_state_disconnecting:
		strRetCode = L"\"disconnecting\"";
		break;
	case wlan_interface_state_disconnected:
		strRetCode = L"\"disconnected\"";
		break;
	case wlan_interface_state_associating:
		strRetCode = L"\"associating\"";
		break;
	case wlan_interface_state_discovering:
		strRetCode = L"\"discovering\"";
		break;
	case wlan_interface_state_authenticating:
		strRetCode = L"\"authenticating\"";
		break;
	default:
		strRetCode = L"\"invalid interface state\"";
	}

	return strRetCode;
}

int main()
{
	HANDLE hClient = NULL;
	WLAN_INTERFACE_INFO sInfo[64];
	RPC_CSTR strGuid = NULL;

	TCHAR szBuffer[256];
	DWORD dwRead;
	if (OpenHandleAndCheckVersion(&hClient) != ERROR_SUCCESS)
		return -1;

	UINT nCount = EnumInterface(hClient, sInfo);
	for (UINT i = 0; i < nCount; ++i)
	{
		if (UuidToStringA(&sInfo[i].InterfaceGuid, &strGuid) == RPC_S_OK)
		{
			printf(("%d. %s\n\tDescription: %S\n\tState: %S\n"),
				i,
				strGuid,
				sInfo[i].strInterfaceDescription,
				GetInterfaceStateString(sInfo[i].isState));

			RpcStringFreeA(&strGuid);
		}
	}

	UINT nChoice = 0;
	printf("Enter the choice (0, 1,..) of the wireless card you want to operate on:\n");

	if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), szBuffer, _countof(szBuffer), &dwRead, NULL) == FALSE)
	{
		puts("Error input.");
		return -1;
	}
	szBuffer[dwRead] = 0;
	nChoice = _ttoi(szBuffer);

	if (nChoice > nCount)
	{
		puts("No such index.");
		return -1;
	}

	UINT nSTate = 0;
	//ULONG targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION;
	ULONG targetOperationMode = DOT11_OPERATION_MODE_NETWORK_MONITOR;
	printf("Enter the state (0, 1 or 2) you want to switch to for the chosen wireless card:\n");
	printf("0: Managed Mode (ExtSTA)\n1: Monitor Mode (NetMon)\n2: Master Mode (ExtAP)\n");

	if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), szBuffer, _countof(szBuffer), &dwRead, NULL) == FALSE)
	{
		puts("Error input.");
		return -1;
	}
	szBuffer[dwRead] = 0;
	nSTate = _ttoi(szBuffer);

	if (nSTate != 0 && nSTate != 1 && nSTate != 2)
	{
		puts("Only 0, 1 and 2 are valid inputs.");
		return -1;
	}
	if (nSTate == 0)
	{
		targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION;
	}
	if (nSTate == 1)
	{
		targetOperationMode = DOT11_OPERATION_MODE_NETWORK_MONITOR;
	}
	else // nSTate == 2
	{
		targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_AP;
	}

	SetInterface(wlan_intf_opcode_current_operation_mode, (PVOID*)&targetOperationMode, &sInfo[nChoice].InterfaceGuid);

	return 0;
}

<commit_msg>Added error code display when error occurs.<commit_after>// WlanHelper.cpp : Defines the entry point for the console application.
//

// #include "stdafx.h"
#include <stdio.h>
#include <tchar.h>

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <wlanapi.h>

#define WLAN_CLIENT_VERSION_VISTA 2

DWORD SetInterface(WLAN_INTF_OPCODE opcode, PVOID* pData, GUID* InterfaceGuid)
{
	DWORD dwResult = 0;
	HANDLE hClient = NULL;
	DWORD dwCurVersion = 0;
	DWORD outsize = 0;

	// Open Handle for the set operation
	dwResult = WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
	dwResult = WlanSetInterface(hClient, InterfaceGuid, opcode, sizeof(ULONG), pData, NULL);
	WlanCloseHandle(hClient, NULL);

	return dwResult;
}

// enumerate wireless interfaces
UINT EnumInterface(HANDLE hClient, WLAN_INTERFACE_INFO sInfo[64])
{
	DWORD dwError = ERROR_SUCCESS;
	PWLAN_INTERFACE_INFO_LIST pIntfList = NULL;
	UINT i = 0;

	__try
	{
		// enumerate wireless interfaces
		if ((dwError = WlanEnumInterfaces(
			hClient,
			NULL,               // reserved
			&pIntfList
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// print out interface information
		for (i = 0; i < pIntfList->dwNumberOfItems; i++)
		{
			memcpy(&sInfo[i], &pIntfList->InterfaceInfo[i], sizeof(WLAN_INTERFACE_INFO));
		}

		return pIntfList->dwNumberOfItems;
	}
	__finally
	{
		// clean up
		if (pIntfList != NULL)
		{
			WlanFreeMemory(pIntfList);
		}
	}
	return 0;
}

// open a WLAN client handle and check version
DWORD
OpenHandleAndCheckVersion(
PHANDLE phClient
)
{
	DWORD dwError = ERROR_SUCCESS;
	DWORD dwServiceVersion;
	HANDLE hClient = NULL;

	__try
	{
		*phClient = NULL;

		// open a handle to the service
		if ((dwError = WlanOpenHandle(
			WLAN_API_VERSION,
			NULL,               // reserved
			&dwServiceVersion,
			&hClient
			)) != ERROR_SUCCESS)
		{
			__leave;
		}

		// check service version
		if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0))
		{
			// No-op, because the version check is for demonstration purpose only.
			// You can add your own logic here.
		}

		*phClient = hClient;

		// set hClient to NULL so it will not be closed
		hClient = NULL;
	}
	__finally
	{
		if (hClient != NULL)
		{
			// clean up
			WlanCloseHandle(
				hClient,
				NULL            // reserved
				);
		}
	}

	return dwError;
}

// get interface state string
LPWSTR
GetInterfaceStateString(__in WLAN_INTERFACE_STATE wlanInterfaceState)
{
	LPWSTR strRetCode;

	switch (wlanInterfaceState)
	{
	case wlan_interface_state_not_ready:
		strRetCode = L"\"not ready\"";
		break;
	case wlan_interface_state_connected:
		strRetCode = L"\"connected\"";
		break;
	case wlan_interface_state_ad_hoc_network_formed:
		strRetCode = L"\"ad hoc network formed\"";
		break;
	case wlan_interface_state_disconnecting:
		strRetCode = L"\"disconnecting\"";
		break;
	case wlan_interface_state_disconnected:
		strRetCode = L"\"disconnected\"";
		break;
	case wlan_interface_state_associating:
		strRetCode = L"\"associating\"";
		break;
	case wlan_interface_state_discovering:
		strRetCode = L"\"discovering\"";
		break;
	case wlan_interface_state_authenticating:
		strRetCode = L"\"authenticating\"";
		break;
	default:
		strRetCode = L"\"invalid interface state\"";
	}

	return strRetCode;
}

int main()
{
	HANDLE hClient = NULL;
	WLAN_INTERFACE_INFO sInfo[64];
	RPC_CSTR strGuid = NULL;

	TCHAR szBuffer[256];
	DWORD dwRead;
	if (OpenHandleAndCheckVersion(&hClient) != ERROR_SUCCESS)
		return -1;

	UINT nCount = EnumInterface(hClient, sInfo);
	for (UINT i = 0; i < nCount; ++i)
	{
		if (UuidToStringA(&sInfo[i].InterfaceGuid, &strGuid) == RPC_S_OK)
		{
			printf(("%d. %s\n\tDescription: %S\n\tState: %S\n"),
				i,
				strGuid,
				sInfo[i].strInterfaceDescription,
				GetInterfaceStateString(sInfo[i].isState));

			RpcStringFreeA(&strGuid);
		}
	}

	UINT nChoice = 0;
	printf("Enter the choice (0, 1,..) of the wireless card you want to operate on:\n");

	if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), szBuffer, _countof(szBuffer), &dwRead, NULL) == FALSE)
	{
		puts("Error input.");
		return -1;
	}
	szBuffer[dwRead] = 0;
	nChoice = _ttoi(szBuffer);

	if (nChoice > nCount)
	{
		puts("No such index.");
		return -1;
	}

	UINT nSTate = 0;
	//ULONG targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION;
	ULONG targetOperationMode = DOT11_OPERATION_MODE_NETWORK_MONITOR;
	printf("Enter the state (0, 1 or 2) you want to switch to for the chosen wireless card:\n");
	printf("0: Managed Mode (ExtSTA)\n1: Monitor Mode (NetMon)\n2: Master Mode (ExtAP)\n");

	if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), szBuffer, _countof(szBuffer), &dwRead, NULL) == FALSE)
	{
		puts("Error input.");
		return -1;
	}
	szBuffer[dwRead] = 0;
	nSTate = _ttoi(szBuffer);

	if (nSTate != 0 && nSTate != 1 && nSTate != 2)
	{
		puts("Only 0, 1 and 2 are valid inputs.");
		return -1;
	}
	if (nSTate == 0)
	{
		targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_STATION;
	}
	else if (nSTate == 1)
	{
		targetOperationMode = DOT11_OPERATION_MODE_NETWORK_MONITOR;
	}
	else // nSTate == 2
	{
		targetOperationMode = DOT11_OPERATION_MODE_EXTENSIBLE_AP;
	}

	DWORD dwResult = SetInterface(wlan_intf_opcode_current_operation_mode, (PVOID*)&targetOperationMode, &sInfo[nChoice].InterfaceGuid);
	if (dwResult != ERROR_SUCCESS)
	{
		printf("SetInterface error, error code = %d\n", dwResult);
		system("PAUSE");
	}
	else
	{
		printf("SetInterface success!\n");
	}

	return 0;
}

<|endoftext|>


<commit_before>#include <stdlib.h> // malloc, free
#include <string.h> // memset

#include <apoapsis_stb_image.h>

#include "Common.h"
#include "PhysFS.h"
#include "OpenGL.h"
#include "Image.h"

bool CreateImage( Image* image, int width, int height, int bpp )
{
    memset(image, 0, sizeof(Image));

    image->width = width;
    image->height = height;
    image->bpp = bpp;

    switch(image->bpp)
    {
        case 1:
            image->format = GL_LUMINANCE;
            break;

        case 2:
            image->format = GL_LUMINANCE_ALPHA;
            break;

        case 3:
            image->format = GL_RGB;
            break;

        case 4:
            image->format = GL_RGBA;
            break;

        default:
            Error("Can't create image (Unknown BPP -> %d)", image->bpp);
            return false;
    }

    image->type = GL_UNSIGNED_BYTE;

    image->data = (char*)malloc(width*height*bpp);

    return true;
}

static int PhysFSRead( void* user, char* data, int size )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    return (int)PHYSFS_readBytes(file, data, size);
}

static void PhysFSSkip( void* user, int offset )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    const int currentPosition = PHYSFS_tell(file);
    assert(currentPosition >= 0);
    const int newPosition = currentPosition + offset;
    const int success = PHYSFS_seek(file, newPosition);
    assert(success);
}

static int PhysFSEOF( void* user )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    return PHYSFS_eof(file);
}

static const stbi_io_callbacks PhysFSCallbacks =
{
   PhysFSRead,
   PhysFSSkip,
   PhysFSEOF
};

bool LoadImage( Image* image, const char* vfsPath )
{
    memset(image, 0, sizeof(Image));

    PHYSFS_File* file = PHYSFS_openRead(vfsPath);
    if(!file)
    {
        Error("Can't load '%s': %s", vfsPath, PHYSFS_getLastError());
        return false;
    }

    image->data = (char*)stbi_load_from_callbacks(&PhysFSCallbacks,
                                                  file,
                                                  &image->width,
                                                  &image->height,
                                                  &image->bpp,
                                                  STBI_default);
    PHYSFS_close(file);
    if(!image->data)
    {
        Error("Can't load '%s': %s", vfsPath, stbi_failure_reason());
        return false;
    }

    switch(image->bpp)
    {
        case 1:
            image->format = GL_LUMINANCE;
            break;

        case 2:
            image->format = GL_LUMINANCE_ALPHA;
            break;

        case 3:
            image->format = GL_RGB;
            break;

        case 4:
            image->format = GL_RGBA;
            break;

        default:
            Error("Can't load '%s': Unknown BPP -> %d", vfsPath, image->bpp);
            free(image->data);
            return false;
    }

    image->type = GL_UNSIGNED_BYTE;

    return true;
}

void FreeImage( const Image* image )
{
    if(image->data)
        free(image->data);
}
<commit_msg>Flip images loaded by stb_image.<commit_after>#include <stdlib.h> // malloc, free
#include <string.h> // memset, memcpy

#include <apoapsis_stb_image.h>

#include "Common.h"
#include "PhysFS.h"
#include "OpenGL.h"
#include "Image.h"

bool CreateImage( Image* image, int width, int height, int bpp )
{
    memset(image, 0, sizeof(Image));

    image->width = width;
    image->height = height;
    image->bpp = bpp;

    switch(image->bpp)
    {
        case 1:
            image->format = GL_LUMINANCE;
            break;

        case 2:
            image->format = GL_LUMINANCE_ALPHA;
            break;

        case 3:
            image->format = GL_RGB;
            break;

        case 4:
            image->format = GL_RGBA;
            break;

        default:
            Error("Can't create image (Unknown BPP -> %d)", image->bpp);
            return false;
    }

    image->type = GL_UNSIGNED_BYTE;

    image->data = (char*)malloc(width*height*bpp);

    return true;
}

static int PhysFSRead( void* user, char* data, int size )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    return (int)PHYSFS_readBytes(file, data, size);
}

static void PhysFSSkip( void* user, int offset )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    const int currentPosition = PHYSFS_tell(file);
    assert(currentPosition >= 0);
    const int newPosition = currentPosition + offset;
    const int success = PHYSFS_seek(file, newPosition);
    assert(success);
}

static int PhysFSEOF( void* user )
{
    PHYSFS_File* file = (PHYSFS_File*)user;
    return PHYSFS_eof(file);
}

static const stbi_io_callbacks PhysFSCallbacks =
{
   PhysFSRead,
   PhysFSSkip,
   PhysFSEOF
};

static void FlipImageVertically( Image* image )
{
    const char* oldData = image->data;
    const int width  = image->width;
    const int height = image->height;
    const int bpp    = image->bpp;

    const int size = width * height * bpp;
    char* newData = (char*)malloc(size);

    const int lineLength = bpp * width;

    for(int y = 0; y < height; y++)
    {
              char* dstStart = &newData[lineLength * y];
        const char* srcStart = &oldData[lineLength * (height-y)];
        memcpy(dstStart, srcStart, lineLength);
    }

    free(image->data);
    image->data = newData;
}

bool LoadImage( Image* image, const char* vfsPath )
{
    memset(image, 0, sizeof(Image));

    PHYSFS_File* file = PHYSFS_openRead(vfsPath);
    if(!file)
    {
        Error("Can't load '%s': %s", vfsPath, PHYSFS_getLastError());
        return false;
    }

    image->data = (char*)stbi_load_from_callbacks(&PhysFSCallbacks,
                                                  file,
                                                  &image->width,
                                                  &image->height,
                                                  &image->bpp,
                                                  STBI_default);
    PHYSFS_close(file);
    if(!image->data)
    {
        Error("Can't load '%s': %s", vfsPath, stbi_failure_reason());
        return false;
    }

    FlipImageVertically(image);

    switch(image->bpp)
    {
        case 1:
            image->format = GL_LUMINANCE;
            break;

        case 2:
            image->format = GL_LUMINANCE_ALPHA;
            break;

        case 3:
            image->format = GL_RGB;
            break;

        case 4:
            image->format = GL_RGBA;
            break;

        default:
            Error("Can't load '%s': Unknown BPP -> %d", vfsPath, image->bpp);
            free(image->data);
            return false;
    }

    image->type = GL_UNSIGNED_BYTE;

    return true;
}

void FreeImage( const Image* image )
{
    if(image->data)
        free(image->data);
}
<|endoftext|>


<commit_before>#include <map>
#include <vector>
#include <thread>
#include <mutex>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#define BITCOIN_UA_LENGTH 24
#define BITCOIN_UA {'/', 'R', 'e', 'l', 'a', 'y', 'N', 'e', 't', 'w', 'o', 'r', 'k', 'C', 'l', 'i', 'e', 'n', 't', ':', '4', '2', '/', '\0'}

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"
#include "p2pclient.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient : public OutboundPersistentConnection {
private:
	RELAY_DECLARE_CLASS_VARS

	const std::function<void (std::vector<unsigned char>&)> provide_block;
	const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)> provide_transaction;
	const std::function<void (void)> on_connected;

	std::atomic_bool connected;

	RelayNodeCompressor compressor;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (std::vector<unsigned char>&)>& provide_block_in,
						const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in,
						const std::function<void (void)>& on_connected_in)
			: OutboundPersistentConnection(serverHostIn, 8336), RELAY_DECLARE_CONSTRUCTOR_EXTENDS,
			provide_block(provide_block_in), provide_transaction(provide_transaction_in), on_connected(on_connected_in),
			connected(false), compressor(false) {
		construction_done();
	}

private:
	void on_disconnect() {
		connected = false;
	}

	void net_process(const std::function<void(const char*)>& disconnect) {
		compressor.reset();

		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		maybe_do_send_bytes((char*)&version_header, sizeof(version_header));
		maybe_do_send_bytes(VERSION_STRING, strlen(VERSION_STRING));

		connected = true;

		while (true) {
			relay_msg_header header;
			if (read_all((char*)&header, 4*3) != 4*3)
				return disconnect("failed to read message header");

			if (header.magic != RELAY_MAGIC_BYTES)
				return disconnect("invalid magic bytes");

			uint32_t message_size = ntohl(header.length);

			if (message_size > 1000000)
				return disconnect("got message too large");

			if (header.type == VERSION_TYPE) {
				char data[message_size];
				if (read_all(data, message_size) < (int64_t)(message_size))
					return disconnect("failed to read version message");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					return disconnect("unknown version string");
				else {
					printf("Connected to relay node with protocol version %s\n", VERSION_STRING);
					on_connected();
				}
			} else if (header.type == MAX_VERSION_TYPE) {
				char data[message_size];
				if (read_all(data, message_size) < (int64_t)(message_size))
					return disconnect("failed to read max_version string");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					printf("Relay network is using a later version (PLEASE UPGRADE)\n");
				else
					return disconnect("got MAX_VERSION of same version as us");
			} else if (header.type == BLOCK_TYPE) {
				std::function<ssize_t(char*, size_t)> do_read = [&](char* buf, size_t count) { return this->read_all(buf, count); };
				auto res = compressor.decompress_relay_block(do_read, message_size, false);
				if (std::get<2>(res))
					return disconnect(std::get<2>(res));

				provide_block(*std::get<1>(res));

				auto fullhash = *std::get<3>(res).get();
				struct tm tm;
				time_t now = time(NULL);
				gmtime_r(&now, &tm);
				printf("[%d-%02d-%02d %02d:%02d:%02d+00] ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" recv'd, size %lu with %u bytes on the wire\n", (unsigned long)std::get<1>(res)->size() - sizeof(bitcoin_msg_header), std::get<0>(res));
			} else if (header.type == END_BLOCK_TYPE) {
			} else if (header.type == TRANSACTION_TYPE) {
				if (!compressor.maybe_recv_tx_of_size(message_size, true))
					return disconnect("got freely relayed transaction too large");

				auto tx = std::make_shared<std::vector<unsigned char> > (message_size);
				if (read_all((char*)&(*tx)[0], message_size) < (int64_t)(message_size))
					return disconnect("failed to read loose transaction data");

				compressor.recv_tx(tx);
				provide_transaction(tx);
				printf("Received transaction of size %u from relay server\n", message_size);
			} else
				return disconnect("got unknown message type");
		}
	}

public:
	void receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx, int token, bool send_oob) {
		if (!connected)
			return;

		std::shared_ptr<std::vector<unsigned char> > msgptr;
		if (send_oob)
			msgptr = compressor.tx_to_msg(tx, true);
		else
			msgptr = compressor.get_relay_transaction(tx);
		if (!msgptr.use_count())
			return;

		auto& msg = *msgptr.get();

		maybe_do_send_bytes((char*)&msg[0], msg.size(), token);
		printf("Sent transaction of size %lu%s to relay server\n", (unsigned long)tx->size(), send_oob ? " (out-of-band)" : "");
	}

	void receive_block(const std::vector<unsigned char>& block, int token) {
		if (!connected)
			return;

		std::vector<unsigned char> fullhash(32);
		getblockhash(fullhash, block, sizeof(struct bitcoin_msg_header));

		auto tuple = compressor.maybe_compress_block(fullhash, block, false);
		if (std::get<1>(tuple)) {
			printf("Failed to process block from bitcoind (%s)\n", std::get<1>(tuple));
			return;
		}
		auto compressed_block = std::get<0>(tuple);

		maybe_do_send_bytes((char*)&(*compressed_block)[0], compressed_block->size(), token);
		struct relay_msg_header header = { RELAY_MAGIC_BYTES, END_BLOCK_TYPE, 0 };
		maybe_do_send_bytes((char*)&header, sizeof(header), token);

		print_hash(&fullhash[0]);
		printf(" sent, size %lu with %lu bytes on the wire\n", (unsigned long)block.size(), (unsigned long)compressed_block->size());
	}
};

class P2PClient : public P2PRelayer {
public:
	P2PClient(const char* serverHostIn, uint16_t serverPortIn,
				const std::function<void (std::vector<unsigned char>&, const std::chrono::system_clock::time_point&)>& provide_block_in,
				const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in,
				const std::function<void (void)>& mempools_done_in) :
			P2PRelayer(serverHostIn, serverPortIn, provide_block_in, provide_transaction_in, NULL, mempools_done_in, NULL, true)
		{ construction_done(); }

private:
	std::vector<unsigned char> generate_version() {
		struct bitcoin_version_with_header version_msg;
		version_msg.version.start.timestamp = htole64(time(0));
		version_msg.version.start.user_agent_length = BITCOIN_UA_LENGTH; // Work around apparent gcc bug
		return std::vector<unsigned char>((unsigned char*)&version_msg, (unsigned char*)&version_msg + sizeof(version_msg));
	}
};

#define HOSTNAMES_TO_TEST 20
#define CONNECT_TESTS 20
std::chrono::milliseconds connect_durations[HOSTNAMES_TO_TEST];
void test_node(int node) {
	const char* relay = "public.%02d.relay.mattcorallo.com";
	char host[strlen(relay)];
	sprintf(host, relay, node);
	sockaddr_in6 addr;
	if (!lookup_address(host, &addr) ||
			(addr.sin6_addr.s6_addr[15] == 0 && addr.sin6_addr.s6_addr[14] == 0 && addr.sin6_addr.s6_addr[13] == 0 && addr.sin6_addr.s6_addr[12] == 0)) {
		connect_durations[node] = std::chrono::milliseconds::max();
		return;
	}

	addr.sin6_port = htons(8336);

	auto start = std::chrono::steady_clock::now();
	for (int i = 0; i < CONNECT_TESTS; i++) {
		int sock = socket(AF_INET6, SOCK_STREAM, 0);
		ALWAYS_ASSERT(sock > 0);

		int v6only = 0;
		setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		connect(sock, (struct sockaddr*)&addr, sizeof(addr));
		close(sock);
	}
	connect_durations[node] = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
}

int main(int argc, char** argv) {
	bool validPort = false;
	try { std::stoul(argv[2]); validPort = true; } catch (std::exception& e) {}
	if ((argc != 3 && argc != 4) || !validPort) {
		printf("USAGE: %s BITCOIND_ADDRESS BITCOIND_PORT [ server ]\n", argv[0]);
		printf("Relay server is automatically selected by pinging available servers, unless one is specified\n");
		return -1;
	}

#ifdef WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2), &wsaData))
		return -1;
#endif

	const char* relay = "public.%02d.relay.mattcorallo.com";
	char host[std::max(argc == 3 ? 0 : strlen(argv[3]), strlen(relay))];
	if (argc == 3) {
		while (true) {
			std::list<std::thread> threads;
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++)
				threads.emplace_back(test_node, i);
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++) {
				threads.front().join();
				threads.pop_front();
			}

			int min = -1; std::chrono::milliseconds min_duration(std::chrono::milliseconds::max());
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++) {
				if (connect_durations[i] != std::chrono::milliseconds::max()) {
					std::string aka;
					sprintf(host, relay, i);
					printf("Server %d (%s) took %lld ms to respond %d times.\n", i, lookup_cname(host, aka) ? aka.c_str() : "", (long long int)connect_durations[i].count(), CONNECT_TESTS);
				}
				if (connect_durations[i] < min_duration) {
					min_duration = connect_durations[i];
					min = i;
				}
			}

			std::this_thread::sleep_for(std::chrono::seconds(10)); // Wait for server to open up our slot again
			if (min == -1) {
				printf("No servers responded\n");
				continue;
			}

			sprintf(host, relay, min);
		}
	} else
		memcpy(host, argv[3], strlen(argv[3]) + 1);
	printf("Using server %s\n", host);

	std::atomic_int relayToken(0);
	RelayNetworkClient* relayClient;
	P2PClient p2p(argv[1], std::stoul(argv[2]),
					[&](std::vector<unsigned char>& bytes, const std::chrono::system_clock::time_point&) { relayClient->receive_block(bytes, relayToken); },
					[&](std::shared_ptr<std::vector<unsigned char> >& bytes) {
						relayClient->receive_transaction(bytes, relayToken, !p2p.maybe_supports_mempool());
					},
					[&]() {
						relayClient->release_send_mutex(relayToken);
						relayToken = 0;
						if (!p2p.maybe_supports_mempool())
							p2p.regularly_request_mempool_and_dont_fetch_loose_txn = false;
					});
	relayClient = new RelayNetworkClient(host,
										[&](std::vector<unsigned char>& bytes) { p2p.receive_block(bytes); },
										[&](std::shared_ptr<std::vector<unsigned char> >& bytes) {
											p2p.receive_transaction(bytes);
											if (!p2p.maybe_supports_mempool())
												relayClient->receive_transaction(bytes, relayToken, false);
										},
										[&]() {
											relayToken = relayClient->get_send_mutex();
											relayClient->do_throttle_outbound(relayToken);
											p2p.request_mempool();
										});

	while (true) { sleep(1000); }
}
<commit_msg>Fix client server search<commit_after>#include <map>
#include <vector>
#include <thread>
#include <mutex>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#ifdef WIN32
	#include <winsock2.h>
	#include <ws2tcpip.h>
#else // WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netinet/tcp.h>
	#include <netdb.h>
	#include <fcntl.h>
#endif // !WIN32

#define BITCOIN_UA_LENGTH 24
#define BITCOIN_UA {'/', 'R', 'e', 'l', 'a', 'y', 'N', 'e', 't', 'w', 'o', 'r', 'k', 'C', 'l', 'i', 'e', 'n', 't', ':', '4', '2', '/', '\0'}

#include "crypto/sha2.h"
#include "flaggedarrayset.h"
#include "relayprocess.h"
#include "utils.h"
#include "p2pclient.h"

/***********************************************
 **** Relay network client processing class ****
 ***********************************************/
class RelayNetworkClient : public OutboundPersistentConnection {
private:
	RELAY_DECLARE_CLASS_VARS

	const std::function<void (std::vector<unsigned char>&)> provide_block;
	const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)> provide_transaction;
	const std::function<void (void)> on_connected;

	std::atomic_bool connected;

	RelayNodeCompressor compressor;

public:
	RelayNetworkClient(const char* serverHostIn,
						const std::function<void (std::vector<unsigned char>&)>& provide_block_in,
						const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in,
						const std::function<void (void)>& on_connected_in)
			: OutboundPersistentConnection(serverHostIn, 8336), RELAY_DECLARE_CONSTRUCTOR_EXTENDS,
			provide_block(provide_block_in), provide_transaction(provide_transaction_in), on_connected(on_connected_in),
			connected(false), compressor(false) {
		construction_done();
	}

private:
	void on_disconnect() {
		connected = false;
	}

	void net_process(const std::function<void(const char*)>& disconnect) {
		compressor.reset();

		relay_msg_header version_header = { RELAY_MAGIC_BYTES, VERSION_TYPE, htonl(strlen(VERSION_STRING)) };
		maybe_do_send_bytes((char*)&version_header, sizeof(version_header));
		maybe_do_send_bytes(VERSION_STRING, strlen(VERSION_STRING));

		connected = true;

		while (true) {
			relay_msg_header header;
			if (read_all((char*)&header, 4*3) != 4*3)
				return disconnect("failed to read message header");

			if (header.magic != RELAY_MAGIC_BYTES)
				return disconnect("invalid magic bytes");

			uint32_t message_size = ntohl(header.length);

			if (message_size > 1000000)
				return disconnect("got message too large");

			if (header.type == VERSION_TYPE) {
				char data[message_size];
				if (read_all(data, message_size) < (int64_t)(message_size))
					return disconnect("failed to read version message");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					return disconnect("unknown version string");
				else {
					printf("Connected to relay node with protocol version %s\n", VERSION_STRING);
					on_connected();
				}
			} else if (header.type == MAX_VERSION_TYPE) {
				char data[message_size];
				if (read_all(data, message_size) < (int64_t)(message_size))
					return disconnect("failed to read max_version string");

				if (strncmp(VERSION_STRING, data, std::min(sizeof(VERSION_STRING), size_t(message_size))))
					printf("Relay network is using a later version (PLEASE UPGRADE)\n");
				else
					return disconnect("got MAX_VERSION of same version as us");
			} else if (header.type == BLOCK_TYPE) {
				std::function<ssize_t(char*, size_t)> do_read = [&](char* buf, size_t count) { return this->read_all(buf, count); };
				auto res = compressor.decompress_relay_block(do_read, message_size, false);
				if (std::get<2>(res))
					return disconnect(std::get<2>(res));

				provide_block(*std::get<1>(res));

				auto fullhash = *std::get<3>(res).get();
				struct tm tm;
				time_t now = time(NULL);
				gmtime_r(&now, &tm);
				printf("[%d-%02d-%02d %02d:%02d:%02d+00] ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
				for (unsigned int i = 0; i < fullhash.size(); i++)
					printf("%02x", fullhash[fullhash.size() - i - 1]);
				printf(" recv'd, size %lu with %u bytes on the wire\n", (unsigned long)std::get<1>(res)->size() - sizeof(bitcoin_msg_header), std::get<0>(res));
			} else if (header.type == END_BLOCK_TYPE) {
			} else if (header.type == TRANSACTION_TYPE) {
				if (!compressor.maybe_recv_tx_of_size(message_size, true))
					return disconnect("got freely relayed transaction too large");

				auto tx = std::make_shared<std::vector<unsigned char> > (message_size);
				if (read_all((char*)&(*tx)[0], message_size) < (int64_t)(message_size))
					return disconnect("failed to read loose transaction data");

				compressor.recv_tx(tx);
				provide_transaction(tx);
				printf("Received transaction of size %u from relay server\n", message_size);
			} else
				return disconnect("got unknown message type");
		}
	}

public:
	void receive_transaction(const std::shared_ptr<std::vector<unsigned char> >& tx, int token, bool send_oob) {
		if (!connected)
			return;

		std::shared_ptr<std::vector<unsigned char> > msgptr;
		if (send_oob)
			msgptr = compressor.tx_to_msg(tx, true);
		else
			msgptr = compressor.get_relay_transaction(tx);
		if (!msgptr.use_count())
			return;

		auto& msg = *msgptr.get();

		maybe_do_send_bytes((char*)&msg[0], msg.size(), token);
		printf("Sent transaction of size %lu%s to relay server\n", (unsigned long)tx->size(), send_oob ? " (out-of-band)" : "");
	}

	void receive_block(const std::vector<unsigned char>& block, int token) {
		if (!connected)
			return;

		std::vector<unsigned char> fullhash(32);
		getblockhash(fullhash, block, sizeof(struct bitcoin_msg_header));

		auto tuple = compressor.maybe_compress_block(fullhash, block, false);
		if (std::get<1>(tuple)) {
			printf("Failed to process block from bitcoind (%s)\n", std::get<1>(tuple));
			return;
		}
		auto compressed_block = std::get<0>(tuple);

		maybe_do_send_bytes((char*)&(*compressed_block)[0], compressed_block->size(), token);
		struct relay_msg_header header = { RELAY_MAGIC_BYTES, END_BLOCK_TYPE, 0 };
		maybe_do_send_bytes((char*)&header, sizeof(header), token);

		print_hash(&fullhash[0]);
		printf(" sent, size %lu with %lu bytes on the wire\n", (unsigned long)block.size(), (unsigned long)compressed_block->size());
	}
};

class P2PClient : public P2PRelayer {
public:
	P2PClient(const char* serverHostIn, uint16_t serverPortIn,
				const std::function<void (std::vector<unsigned char>&, const std::chrono::system_clock::time_point&)>& provide_block_in,
				const std::function<void (std::shared_ptr<std::vector<unsigned char> >&)>& provide_transaction_in,
				const std::function<void (void)>& mempools_done_in) :
			P2PRelayer(serverHostIn, serverPortIn, provide_block_in, provide_transaction_in, NULL, mempools_done_in, NULL, true)
		{ construction_done(); }

private:
	std::vector<unsigned char> generate_version() {
		struct bitcoin_version_with_header version_msg;
		version_msg.version.start.timestamp = htole64(time(0));
		version_msg.version.start.user_agent_length = BITCOIN_UA_LENGTH; // Work around apparent gcc bug
		return std::vector<unsigned char>((unsigned char*)&version_msg, (unsigned char*)&version_msg + sizeof(version_msg));
	}
};

#define HOSTNAMES_TO_TEST 20
#define CONNECT_TESTS 20
std::chrono::milliseconds connect_durations[HOSTNAMES_TO_TEST];
void test_node(int node) {
	const char* relay = "public.%02d.relay.mattcorallo.com";
	char host[strlen(relay)];
	sprintf(host, relay, node);
	sockaddr_in6 addr;
	if (!lookup_address(host, &addr) ||
			(addr.sin6_addr.s6_addr[15] == 0 && addr.sin6_addr.s6_addr[14] == 0 && addr.sin6_addr.s6_addr[13] == 0 && addr.sin6_addr.s6_addr[12] == 0)) {
		connect_durations[node] = std::chrono::milliseconds::max();
		return;
	}

	addr.sin6_port = htons(8336);

	auto start = std::chrono::steady_clock::now();
	for (int i = 0; i < CONNECT_TESTS; i++) {
		int sock = socket(AF_INET6, SOCK_STREAM, 0);
		ALWAYS_ASSERT(sock > 0);

		int v6only = 0;
		setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof(v6only));

		connect(sock, (struct sockaddr*)&addr, sizeof(addr));
		close(sock);
	}
	connect_durations[node] = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
}

int main(int argc, char** argv) {
	bool validPort = false;
	try { std::stoul(argv[2]); validPort = true; } catch (std::exception& e) {}
	if ((argc != 3 && argc != 4) || !validPort) {
		printf("USAGE: %s BITCOIND_ADDRESS BITCOIND_PORT [ server ]\n", argv[0]);
		printf("Relay server is automatically selected by pinging available servers, unless one is specified\n");
		return -1;
	}

#ifdef WIN32
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2), &wsaData))
		return -1;
#endif

	const char* relay = "public.%02d.relay.mattcorallo.com";
	char host[std::max(argc == 3 ? 0 : strlen(argv[3]), strlen(relay))];
	if (argc == 3) {
		while (true) {
			std::list<std::thread> threads;
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++)
				threads.emplace_back(test_node, i);
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++) {
				threads.front().join();
				threads.pop_front();
			}

			int min = -1; std::chrono::milliseconds min_duration(std::chrono::milliseconds::max());
			for (int i = 0; i < HOSTNAMES_TO_TEST; i++) {
				if (connect_durations[i] != std::chrono::milliseconds::max()) {
					std::string aka;
					sprintf(host, relay, i);
					printf("Server %d (%s) took %lld ms to respond %d times.\n", i, lookup_cname(host, aka) ? aka.c_str() : "", (long long int)connect_durations[i].count(), CONNECT_TESTS);
				}
				if (connect_durations[i] < min_duration) {
					min_duration = connect_durations[i];
					min = i;
				}
			}

			std::this_thread::sleep_for(std::chrono::seconds(10)); // Wait for server to open up our slot again
			if (min == -1) {
				printf("No servers responded\n");
				continue;
			}

			sprintf(host, relay, min);
			break;
		}
	} else
		memcpy(host, argv[3], strlen(argv[3]) + 1);
	printf("Using server %s\n", host);

	std::atomic_int relayToken(0);
	RelayNetworkClient* relayClient;
	P2PClient p2p(argv[1], std::stoul(argv[2]),
					[&](std::vector<unsigned char>& bytes, const std::chrono::system_clock::time_point&) { relayClient->receive_block(bytes, relayToken); },
					[&](std::shared_ptr<std::vector<unsigned char> >& bytes) {
						relayClient->receive_transaction(bytes, relayToken, !p2p.maybe_supports_mempool());
					},
					[&]() {
						relayClient->release_send_mutex(relayToken);
						relayToken = 0;
						if (!p2p.maybe_supports_mempool())
							p2p.regularly_request_mempool_and_dont_fetch_loose_txn = false;
					});
	relayClient = new RelayNetworkClient(host,
										[&](std::vector<unsigned char>& bytes) { p2p.receive_block(bytes); },
										[&](std::shared_ptr<std::vector<unsigned char> >& bytes) {
											p2p.receive_transaction(bytes);
											if (!p2p.maybe_supports_mempool())
												relayClient->receive_transaction(bytes, relayToken, false);
										},
										[&]() {
											relayToken = relayClient->get_send_mutex();
											relayClient->do_throttle_outbound(relayToken);
											p2p.request_mempool();
										});

	while (true) { sleep(1000); }
}
<|endoftext|>