<commit_before>#include "writer/verilog/shared_reg.h"

#include "iroha/i_design.h"
#include "iroha/logging.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/connection.h"
#include "writer/module_template.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"

namespace iroha {
namespace writer {
namespace verilog {

SharedReg::SharedReg(const IResource &res, const Table &table)
  : Resource(res, table), has_default_output_value_(false),
    default_output_value_(0), writers_(nullptr),
    need_write_arbitration_(false) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    auto *params = res_.GetParams();
    string unused;
    params->GetExtOutputPort(&unused, &width_);
    has_default_output_value_ =
      params->GetDefaultValue(&default_output_value_);
    writers_ = table.GetModule()->GetConnection().GetSharedRegWriters(&res_);
    if (writers_ != nullptr || has_default_output_value_) {
      need_write_arbitration_ = true;
    }
  } else if (resource::IsSharedRegWriter(*klass)) {
    auto *params = res_.GetSharedReg()->GetParams();
    string unused;
    params->GetExtOutputPort(&unused, &width_);
  } else {
    width_ = 0;
  }
}

void SharedReg::BuildResource() {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    BuildSharedRegResource();
  }
  if (resource::IsSharedRegWriter(*klass)) {
    ostream &rs = tmpl_->GetStream(kRegisterSection);
    rs << "  // shared-reg-writer\n";
    rs << "  reg ";
    if (width_ > 0) {
      rs << "[" << width_ - 1 << ":0]";
    }
    rs << " " << WriterName(res_) << ";\n";
    rs << "  reg " << WriterEnName(res_) << ";\n";
    // Reset value
    ostream &is = tab_.InitialValueSectionStream();
    is << "      " << WriterName(res_) << " <= 0;\n"
       << "      " << WriterEnName(res_) << " <= 0;\n";
    // Write en signal.
    ostream &os = tab_.StateOutputSectionStream();
    map<IState *, IInsn *> callers;
    CollectResourceCallers("", &callers);
    os << "      " << WriterEnName(res_) << " <= ";
    WriteStateUnion(callers, os);
    os << ";\n";
  }
}

void SharedReg::BuildSharedRegResource() {
  ostream &rs = tmpl_->GetStream(kRegisterSection);
  rs << "  // shared-reg\n";
  rs << "  reg ";
  if (width_ > 0) {
    rs << "[" << width_ - 1 << ":0]";
  }
  rs << " " << RegName(res_) << ";\n";
  if (need_write_arbitration_) {
    // Priorities are
    // (1) Writers in this table
    // (2) Writers in other table
    // (3) Default output value
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegName(res_) << " <= ";
    string value;
    if (has_default_output_value_) {
      value = Util::Itoa(default_output_value_);
    } else {
      value = RegName(res_);
    }
    for (auto *res : *writers_) {
      value = WriterEnName(*res) + " ? " + WriterName(*res) + " : (" + value + ")";
    }
    os << SelectValueByState(value);
    os << ";\n";
  }
  // Reset value
  ostream &is = tab_.InitialValueSectionStream();
  is << "      " << RegName(res_) << " <= ";
  if (has_default_output_value_) {
    is << default_output_value_;
  } else {
    is << 0;
  }
  is << ";\n";
}

void SharedReg::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    if (!need_write_arbitration_ &&
	insn->inputs_.size() == 1) {
      ostream &os = st->StateBodySectionStream();
      os << "          " << RegName(res_) << " <= "
	 << InsnWriter::RegisterName(*insn->inputs_[0])
	 << ";\n";
    }
    if (insn->outputs_.size() == 1) {
      // Read from self.
      ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
      ws << "  assign "
	 << InsnWriter::InsnOutputWireName(*insn, 0)
	 << " = "
	 << RegName(res_) << ";\n";
    }
  }
  if (resource::IsSharedRegReader(*klass)) {
    // Read from another table.
    IResource *source = res_.GetSharedReg();
    ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
    ws << "  assign "
       << InsnWriter::InsnOutputWireName(*insn, 0)
       << " = "
       << RegName(*source) << ";\n";
  }
  if (resource::IsSharedRegWriter(*klass)) {
    ostream &os = st->StateBodySectionStream();
    os << "          " << WriterName(res_) << " <= "
       << InsnWriter::RegisterName(*insn->inputs_[0]) << ";\n";
  }
}

string SharedReg::WriterName(const IResource &res) {
  return RegName(res) + "_w";
}

string SharedReg::WriterEnName(const IResource &res) {
  return WriterName(res) + "_en";
}

string SharedReg::RegName(const IResource &res) {
  auto *params = res.GetParams();
  int unused_width;
  string port_name;
  params->GetExtOutputPort(&port_name, &unused_width);
  ITable *tab = res.GetTable();
  IModule *mod = tab->GetModule();
  return "shared_reg_" +
    Util::Itoa(mod->GetId()) + "_" +
    Util::Itoa(tab->GetId()) + "_" + Util::Itoa(res.GetId()) +
    "_" + port_name;
}

void SharedReg::BuildReaderPorts(const SharedRegConnectionInfo &pi,
				 Ports *ports) {
  for (IResource *res : pi.has_upward_port) {
    int width = res->GetParams()->GetWidth();
    ports->AddPort(RegName(*res), Port::OUTPUT_WIRE, width);
  }
  for (IResource *res : pi.has_downward_port) {
    int width = res->GetParams()->GetWidth();
    ports->AddPort(RegName(*res), Port::INPUT, width);
  }
}

void SharedReg::BuildWriterPorts(const SharedRegConnectionInfo &pi,
				 Ports *ports) {
  for (IResource *res : pi.has_upward_port) {
    int width = res->GetSharedReg()->GetParams()->GetWidth();
    ports->AddPort(WriterName(*res), Port::OUTPUT_WIRE, width);
    ports->AddPort(WriterEnName(*res), Port::OUTPUT_WIRE, 0);
  }
  for (IResource *res : pi.has_downward_port) {
    int width = res->GetSharedReg()->GetParams()->GetWidth();
    ports->AddPort(WriterName(*res), Port::INPUT, width);
    ports->AddPort(WriterEnName(*res), Port::INPUT, 0);
  }
}

void SharedReg::BuildReaderChildWire(const SharedRegConnectionInfo &pi,
				     ostream &os) {
  for (IResource *res : pi.has_upward_port) {
    AddChildWire(res, false, os);
  }
  for (IResource *res : pi.has_downward_port) {
    AddChildWire(res, false, os);
  }
}

void SharedReg::BuildWriterChildWire(const SharedRegConnectionInfo &pi,
				     ostream &os) {
  for (IResource *res : pi.has_upward_port) {
    AddChildWire(res, true, os);
  }
  for (IResource *res : pi.has_downward_port) {
    AddChildWire(res, true, os);
  }
}

void SharedReg::AddChildWire(IResource *res, bool is_write, ostream &os) {
  string name;
  if (is_write) {
    name = WriterName(*res);
  } else {
    name = RegName(*res);
  }
  os << ", ." << name << "(" << name << ")";
  if (is_write) {
    name = WriterEnName(*res);
    os << ", ." << name << "(" << name << ")";
  }
}

void SharedReg::BuildReaderRootWire(const SharedRegConnectionInfo &pi,
				    Module *module) {
  BuildRootWire(pi, false, module);
}

void SharedReg::BuildWriterRootWire(const SharedRegConnectionInfo &pi,
				    Module *module) {
  BuildRootWire(pi, true, module);
}

void SharedReg::BuildRootWire(const SharedRegConnectionInfo &pi,
			      bool is_write,
			      Module *module) {
  ModuleTemplate *tmpl = module->GetModuleTemplate();
  ostream &ws = tmpl->GetStream(kInsnWireDeclSection);
  for (IResource *res : pi.has_wire) {
    ws << "  wire ";
    int width;
    if (is_write) {
      width = res->GetSharedReg()->GetParams()->GetWidth();
    } else {
      width = res->GetParams()->GetWidth();
    }
    if (width > 0) {
      ws << "[" << width - 1 << ":0] ";
    }
    if (is_write) {
      ws << WriterName(*res) << ";\n";
    } else {
      ws << RegName(*res) << ";\n";
    }
    if (is_write) {
      ws << "  wire " << WriterEnName(*res) << ";\n";
    }
  }
}

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<commit_msg>Fix not to access writers of shared-reg if it is null.<commit_after>#include "writer/verilog/shared_reg.h"

#include "iroha/i_design.h"
#include "iroha/logging.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/connection.h"
#include "writer/module_template.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/module.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"

namespace iroha {
namespace writer {
namespace verilog {

SharedReg::SharedReg(const IResource &res, const Table &table)
  : Resource(res, table), has_default_output_value_(false),
    default_output_value_(0), writers_(nullptr),
    need_write_arbitration_(false) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    auto *params = res_.GetParams();
    string unused;
    params->GetExtOutputPort(&unused, &width_);
    has_default_output_value_ =
      params->GetDefaultValue(&default_output_value_);
    writers_ = table.GetModule()->GetConnection().GetSharedRegWriters(&res_);
    if (writers_ != nullptr || has_default_output_value_) {
      need_write_arbitration_ = true;
    }
  } else if (resource::IsSharedRegWriter(*klass)) {
    auto *params = res_.GetSharedReg()->GetParams();
    string unused;
    params->GetExtOutputPort(&unused, &width_);
  } else {
    width_ = 0;
  }
}

void SharedReg::BuildResource() {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    BuildSharedRegResource();
  }
  if (resource::IsSharedRegWriter(*klass)) {
    ostream &rs = tmpl_->GetStream(kRegisterSection);
    rs << "  // shared-reg-writer\n";
    rs << "  reg ";
    if (width_ > 0) {
      rs << "[" << width_ - 1 << ":0]";
    }
    rs << " " << WriterName(res_) << ";\n";
    rs << "  reg " << WriterEnName(res_) << ";\n";
    // Reset value
    ostream &is = tab_.InitialValueSectionStream();
    is << "      " << WriterName(res_) << " <= 0;\n"
       << "      " << WriterEnName(res_) << " <= 0;\n";
    // Write en signal.
    ostream &os = tab_.StateOutputSectionStream();
    map<IState *, IInsn *> callers;
    CollectResourceCallers("", &callers);
    os << "      " << WriterEnName(res_) << " <= ";
    WriteStateUnion(callers, os);
    os << ";\n";
  }
}

void SharedReg::BuildSharedRegResource() {
  ostream &rs = tmpl_->GetStream(kRegisterSection);
  rs << "  // shared-reg\n";
  rs << "  reg ";
  if (width_ > 0) {
    rs << "[" << width_ - 1 << ":0]";
  }
  rs << " " << RegName(res_) << ";\n";
  if (need_write_arbitration_) {
    // Priorities are
    // (1) Writers in this table
    // (2) Writers in other table
    // (3) Default output value
    ostream &os = tab_.StateOutputSectionStream();
    os << "      " << RegName(res_) << " <= ";
    string value;
    if (has_default_output_value_) {
      value = Util::Itoa(default_output_value_);
    } else {
      value = RegName(res_);
    }
    if (writers_ != nullptr) {
      for (auto *res : *writers_) {
	value = WriterEnName(*res) + " ? " + WriterName(*res) + " : (" + value + ")";
      }
    }
    os << SelectValueByState(value);
    os << ";\n";
  }
  // Reset value
  ostream &is = tab_.InitialValueSectionStream();
  is << "      " << RegName(res_) << " <= ";
  if (has_default_output_value_) {
    is << default_output_value_;
  } else {
    is << 0;
  }
  is << ";\n";
}

void SharedReg::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsSharedReg(*klass)) {
    if (!need_write_arbitration_ &&
	insn->inputs_.size() == 1) {
      ostream &os = st->StateBodySectionStream();
      os << "          " << RegName(res_) << " <= "
	 << InsnWriter::RegisterName(*insn->inputs_[0])
	 << ";\n";
    }
    if (insn->outputs_.size() == 1) {
      // Read from self.
      ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
      ws << "  assign "
	 << InsnWriter::InsnOutputWireName(*insn, 0)
	 << " = "
	 << RegName(res_) << ";\n";
    }
  }
  if (resource::IsSharedRegReader(*klass)) {
    // Read from another table.
    IResource *source = res_.GetSharedReg();
    ostream &ws = tmpl_->GetStream(kInsnWireValueSection);
    ws << "  assign "
       << InsnWriter::InsnOutputWireName(*insn, 0)
       << " = "
       << RegName(*source) << ";\n";
  }
  if (resource::IsSharedRegWriter(*klass)) {
    ostream &os = st->StateBodySectionStream();
    os << "          " << WriterName(res_) << " <= "
       << InsnWriter::RegisterName(*insn->inputs_[0]) << ";\n";
  }
}

string SharedReg::WriterName(const IResource &res) {
  return RegName(res) + "_w";
}

string SharedReg::WriterEnName(const IResource &res) {
  return WriterName(res) + "_en";
}

string SharedReg::RegName(const IResource &res) {
  auto *params = res.GetParams();
  int unused_width;
  string port_name;
  params->GetExtOutputPort(&port_name, &unused_width);
  ITable *tab = res.GetTable();
  IModule *mod = tab->GetModule();
  return "shared_reg_" +
    Util::Itoa(mod->GetId()) + "_" +
    Util::Itoa(tab->GetId()) + "_" + Util::Itoa(res.GetId()) +
    "_" + port_name;
}

void SharedReg::BuildReaderPorts(const SharedRegConnectionInfo &pi,
				 Ports *ports) {
  for (IResource *res : pi.has_upward_port) {
    int width = res->GetParams()->GetWidth();
    ports->AddPort(RegName(*res), Port::OUTPUT_WIRE, width);
  }
  for (IResource *res : pi.has_downward_port) {
    int width = res->GetParams()->GetWidth();
    ports->AddPort(RegName(*res), Port::INPUT, width);
  }
}

void SharedReg::BuildWriterPorts(const SharedRegConnectionInfo &pi,
				 Ports *ports) {
  for (IResource *res : pi.has_upward_port) {
    int width = res->GetSharedReg()->GetParams()->GetWidth();
    ports->AddPort(WriterName(*res), Port::OUTPUT_WIRE, width);
    ports->AddPort(WriterEnName(*res), Port::OUTPUT_WIRE, 0);
  }
  for (IResource *res : pi.has_downward_port) {
    int width = res->GetSharedReg()->GetParams()->GetWidth();
    ports->AddPort(WriterName(*res), Port::INPUT, width);
    ports->AddPort(WriterEnName(*res), Port::INPUT, 0);
  }
}

void SharedReg::BuildReaderChildWire(const SharedRegConnectionInfo &pi,
				     ostream &os) {
  for (IResource *res : pi.has_upward_port) {
    AddChildWire(res, false, os);
  }
  for (IResource *res : pi.has_downward_port) {
    AddChildWire(res, false, os);
  }
}

void SharedReg::BuildWriterChildWire(const SharedRegConnectionInfo &pi,
				     ostream &os) {
  for (IResource *res : pi.has_upward_port) {
    AddChildWire(res, true, os);
  }
  for (IResource *res : pi.has_downward_port) {
    AddChildWire(res, true, os);
  }
}

void SharedReg::AddChildWire(IResource *res, bool is_write, ostream &os) {
  string name;
  if (is_write) {
    name = WriterName(*res);
  } else {
    name = RegName(*res);
  }
  os << ", ." << name << "(" << name << ")";
  if (is_write) {
    name = WriterEnName(*res);
    os << ", ." << name << "(" << name << ")";
  }
}

void SharedReg::BuildReaderRootWire(const SharedRegConnectionInfo &pi,
				    Module *module) {
  BuildRootWire(pi, false, module);
}

void SharedReg::BuildWriterRootWire(const SharedRegConnectionInfo &pi,
				    Module *module) {
  BuildRootWire(pi, true, module);
}

void SharedReg::BuildRootWire(const SharedRegConnectionInfo &pi,
			      bool is_write,
			      Module *module) {
  ModuleTemplate *tmpl = module->GetModuleTemplate();
  ostream &ws = tmpl->GetStream(kInsnWireDeclSection);
  for (IResource *res : pi.has_wire) {
    ws << "  wire ";
    int width;
    if (is_write) {
      width = res->GetSharedReg()->GetParams()->GetWidth();
    } else {
      width = res->GetParams()->GetWidth();
    }
    if (width > 0) {
      ws << "[" << width - 1 << ":0] ";
    }
    if (is_write) {
      ws << WriterName(*res) << ";\n";
    } else {
      ws << RegName(*res) << ";\n";
    }
    if (is_write) {
      ws << "  wire " << WriterEnName(*res) << ";\n";
    }
  }
}

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_LOG_SUM_EXP_HPP
#define STAN_MATH_REV_FUN_LOG_SUM_EXP_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/fun/typedefs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/inv_logit.hpp>
#include <stan/math/prim/fun/log_sum_exp.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {
namespace internal {

class log_sum_exp_vv_vari : public op_vv_vari {
 public:
  log_sum_exp_vv_vari(vari* avi, vari* bvi)
      : op_vv_vari(log_sum_exp(avi->val_, bvi->val_), avi, bvi) {}
  void chain() {
    avi_->adj_ += adj_ * inv_logit(avi_->val_ - bvi_->val_);
    bvi_->adj_ += adj_ * inv_logit(bvi_->val_ - avi_->val_);
  }
};
class log_sum_exp_vd_vari : public op_vd_vari {
 public:
  log_sum_exp_vd_vari(vari* avi, double b)
      : op_vd_vari(log_sum_exp(avi->val_, b), avi, b) {}
  void chain() {
    if (val_ == NEGATIVE_INFTY) {
      avi_->adj_ += adj_;
    } else {
      avi_->adj_ += adj_ * inv_logit(avi_->val_ - bd_);
    }
  }
};

}  // namespace internal

/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(const var& a, const var& b) {
  return var(new internal::log_sum_exp_vv_vari(a.vi_, b.vi_));
}
/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(const var& a, double b) {
  return var(new internal::log_sum_exp_vd_vari(a.vi_, b));
}
/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(double a, const var& b) {
  return var(new internal::log_sum_exp_vd_vari(b.vi_, a));
}

/**
 * Returns the log sum of exponentials.
 *
 * @tparam T Type of input vector or matrix.
 * @param x matrix
 */
template <typename T, require_container_st<is_var, T>* = nullptr>
inline auto log_sum_exp(const T& x) {
  return apply_vector_unary<T>::reduce(x, [](const auto& v) {
    arena_t<decltype(v)> arena_v = v;
    arena_t<decltype(v.val())> arena_v_val = v.val();
    var res = log_sum_exp(arena_v_val);

    reverse_pass_callback([arena_v, arena_v_val, res]() mutable {
      arena_v.adj()
          += res.adj() * (arena_v_val.array().val() - res.val()).exp().matrix();
    });

    return res;
  });
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>fix expression test failure<commit_after>#ifndef STAN_MATH_REV_FUN_LOG_SUM_EXP_HPP
#define STAN_MATH_REV_FUN_LOG_SUM_EXP_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/fun/typedefs.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/inv_logit.hpp>
#include <stan/math/prim/fun/log_sum_exp.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {
namespace internal {

class log_sum_exp_vv_vari : public op_vv_vari {
 public:
  log_sum_exp_vv_vari(vari* avi, vari* bvi)
      : op_vv_vari(log_sum_exp(avi->val_, bvi->val_), avi, bvi) {}
  void chain() {
    avi_->adj_ += adj_ * inv_logit(avi_->val_ - bvi_->val_);
    bvi_->adj_ += adj_ * inv_logit(bvi_->val_ - avi_->val_);
  }
};
class log_sum_exp_vd_vari : public op_vd_vari {
 public:
  log_sum_exp_vd_vari(vari* avi, double b)
      : op_vd_vari(log_sum_exp(avi->val_, b), avi, b) {}
  void chain() {
    if (val_ == NEGATIVE_INFTY) {
      avi_->adj_ += adj_;
    } else {
      avi_->adj_ += adj_ * inv_logit(avi_->val_ - bd_);
    }
  }
};

}  // namespace internal

/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(const var& a, const var& b) {
  return var(new internal::log_sum_exp_vv_vari(a.vi_, b.vi_));
}
/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(const var& a, double b) {
  return var(new internal::log_sum_exp_vd_vari(a.vi_, b));
}
/**
 * Returns the log sum of exponentials.
 */
inline var log_sum_exp(double a, const var& b) {
  return var(new internal::log_sum_exp_vd_vari(b.vi_, a));
}

/**
 * Returns the log sum of exponentials.
 *
 * @tparam T Type of input vector or matrix.
 * @param x matrix
 */
template <typename T, require_container_st<is_var, T>* = nullptr>
inline auto log_sum_exp(const T& x) {
  return apply_vector_unary<T>::reduce(x, [](const auto& v) {
    arena_t<decltype(v)> arena_v = v;
    arena_t<decltype(v.val())> arena_v_val = arena_v.val();
    var res = log_sum_exp(arena_v_val);

    reverse_pass_callback([arena_v, arena_v_val, res]() mutable {
      arena_v.adj()
          += res.adj() * (arena_v_val.array().val() - res.val()).exp().matrix();
    });

    return res;
  });
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
 * Teensy 3.2 SPI test to control Mirrorcle PicoAmp MEMS mirror driver board.
 * PicoAmp board is based on AD5664R quad 16 bit DAC with SPI input.
 * Michael Taylor
 * Aug 8th(ish) 2017
 *
 * This program generates a varying sinusoid in X and Y, initializes the SPI, initializes the DAC, sets a period
 * then plays back the sinusoid over the MEMS driver.
 */
#include <main.h>
#define BUFFER_LEN 1024
static float sine_wave[BUFFER_LEN]; // buffer to hold decimal value sine wave (scaled to uint16_t before sent to DAC)
static uint8_t DAC_write_word[3]; // DAC input register is 24 bits, SPI writes 8 bits at a time. Need to queue up 3 bytes (24 bits) to send every time you write to it
// Teensy 3.2 pinouts
const int slaveSelectPin = 43;
const int DRIVER_HV_EN_pin = 54;
const int LASER_EN_PIN = 22; // toggles laser on / off for modulation (PWM pin)
bool laser_state = LOW;
int count = 0;
int freq_x = 1;
int freq_y = 1;
float ampl_x = 1.0;
float ampl_y = 1.0;
int signal_x = 0;
int signal_y = 0;
uint16_t DAC_ch_A = 32768;
uint16_t DAC_ch_B = 32768;
uint16_t DAC_ch_C = 32768;
uint16_t DAC_ch_D = 32768;
float twopi = 2*3.14159265359; // good old pi
float phase = twopi/BUFFER_LEN; // phase increment for sinusoid
volatile uint32_t timeOfLastMirrorOutput = 0;

void mirrorDriverSetup() {
    // Setup Pins:
    pinMode (slaveSelectPin, OUTPUT); // SPI SS pin 10
    pinMode (DRIVER_HV_EN_pin, OUTPUT); // driver board high voltage output enable pin 8
    pinMode (LASER_EN_PIN, OUTPUT); // Laser diode switching pin 7, active low.
    // write pins low
    digitalWrite(slaveSelectPin,LOW);
    digitalWrite(DRIVER_HV_EN_pin,LOW);
    analogWrite(LASER_EN_PIN,0);
    // setup SPI
    debugPrintln("Setting up SPI");
    // initialize SPI:
    SPI2.begin();
    // setup DAC
    Serial.println("Setting up DAC");
    //  send the DAC write word one byte at a time:
    // 0x280001 FULL_RESET
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x28);
    SPI2.transfer(0x00);
    SPI2.transfer(0x01);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x380001 INT_REF_EN
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x38);
    SPI2.transfer(0x00);
    SPI2.transfer(0x01);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x20000F DAC_EN_ALL
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x20);
    SPI2.transfer(0x00);
    SPI2.transfer(0x0F);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x300000 LDAC_EN
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x30);
    SPI2.transfer(0x00);
    SPI2.transfer(0x00);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);

    // Fill the sine wave buffer with 1024 points
    // The 0.9 here prevents the driver from ever going over 150V! (It can do ~160 which can damage mirror)
    debugPrintln("Filling in sine wave");
    for (int i = 0; i < BUFFER_LEN; i++){
        sine_wave[i] = sin(i*phase); // fill 0 to twopi phase, output range -0.9 to 0.9 to limit HV output
    }
    // Start the LASER PWM timer
    // 50% duty cycle at desired frequency
    analogWriteFrequency(LASER_EN_PIN, 1000);
    analogWrite (LASER_EN_PIN,0);
}

void sendMirrorOutput(const mirrorOutput& out) {
    volatile uint32_t timeNow = millis();
    // millis() subject to overflow after 40 days, causes 1 assertion error
    assert(timeNow - timeOfLastMirrorOutput >= 10); // No more than 100Hz
    timeOfLastMirrorOutput = timeNow;
    int16_t x = out.x * 0.9; // Important: never max out the mirror
    int16_t y = out.y * 0.9;
    // figure out the sine wave output for each channel, from -1,1 to uint16_t centered at 32768
    // X = A - B
    DAC_ch_A = (uint16_t) (32768*(1 + (ampl_x * x / 2)));
    DAC_ch_B = (uint16_t) (32768*(1 - (ampl_x * x / 2)));
    // Y = C - D
    // 90 degree phase shift on Y for a circle>?
    DAC_ch_C = (uint16_t) (32768*(1 + (ampl_y * y / 2)));
    DAC_ch_D = (uint16_t) (32768*(1 - (ampl_y * y / 2)));

  /* HERE BE STUPID */
    // Write all 4 channels 1 at a time
    DAC_write_word[0] = 0b00011000; // write to and update (C = 011) channel A DAC (A = 000), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_A >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_A & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011001; // write to and update (C = 011) channel B DAC (B = 001), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_B >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_B & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011010; // write to and update (C = 011) channel C DAC (C = 010), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_C >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_C & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011011; // write to and update (C = 011) channel D DAC (D = 011), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_D >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_D & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
}

void highVoltageEnable(bool enable) {
    if (enable) {
        digitalWrite(DRIVER_HV_EN_pin,HIGH);
    } else {
        digitalWrite(DRIVER_HV_EN_pin,LOW);
    }
}

void laserEnable(bool enable) {
    if (enable) {
        laser_state = HIGH;
        analogWrite (LASER_EN_PIN, 128); // 50% duty cycle 1khz
    } else {
        laser_state = LOW;
        analogWrite (LASER_EN_PIN, 0);
    }
}
<commit_msg>Quick fix on frequency<commit_after>/*
 * Teensy 3.2 SPI test to control Mirrorcle PicoAmp MEMS mirror driver board.
 * PicoAmp board is based on AD5664R quad 16 bit DAC with SPI input.
 * Michael Taylor
 * Aug 8th(ish) 2017
 *
 * This program generates a varying sinusoid in X and Y, initializes the SPI, initializes the DAC, sets a period
 * then plays back the sinusoid over the MEMS driver.
 */
#include <main.h>
#define BUFFER_LEN 1024
static float sine_wave[BUFFER_LEN]; // buffer to hold decimal value sine wave (scaled to uint16_t before sent to DAC)
static uint8_t DAC_write_word[3]; // DAC input register is 24 bits, SPI writes 8 bits at a time. Need to queue up 3 bytes (24 bits) to send every time you write to it
// Teensy 3.2 pinouts
const int slaveSelectPin = 43;
const int DRIVER_HV_EN_pin = 54;
const int LASER_EN_PIN = 22; // toggles laser on / off for modulation (PWM pin)
bool laser_state = LOW;
int count = 0;
int freq_x = 1;
int freq_y = 1;
float ampl_x = 1.0;
float ampl_y = 1.0;
int signal_x = 0;
int signal_y = 0;
uint16_t DAC_ch_A = 32768;
uint16_t DAC_ch_B = 32768;
uint16_t DAC_ch_C = 32768;
uint16_t DAC_ch_D = 32768;
float twopi = 2*3.14159265359; // good old pi
float phase = twopi/BUFFER_LEN; // phase increment for sinusoid
volatile uint32_t timeOfLastMirrorOutput = 0;

void mirrorDriverSetup() {
    // Setup Pins:
    pinMode (slaveSelectPin, OUTPUT); // SPI SS pin 10
    pinMode (DRIVER_HV_EN_pin, OUTPUT); // driver board high voltage output enable pin 8
    pinMode (LASER_EN_PIN, OUTPUT); // Laser diode switching pin 7, active low.
    // write pins low
    digitalWrite(slaveSelectPin,LOW);
    digitalWrite(DRIVER_HV_EN_pin,LOW);
    analogWrite(LASER_EN_PIN,0);
    // setup SPI
    debugPrintln("Setting up SPI");
    // initialize SPI:
    SPI2.begin();
    // setup DAC
    Serial.println("Setting up DAC");
    //  send the DAC write word one byte at a time:
    // 0x280001 FULL_RESET
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x28);
    SPI2.transfer(0x00);
    SPI2.transfer(0x01);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x380001 INT_REF_EN
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x38);
    SPI2.transfer(0x00);
    SPI2.transfer(0x01);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x20000F DAC_EN_ALL
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x20);
    SPI2.transfer(0x00);
    SPI2.transfer(0x0F);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);
    // 0x300000 LDAC_EN
    digitalWrite(slaveSelectPin,LOW);
    SPI2.transfer(0x30);
    SPI2.transfer(0x00);
    SPI2.transfer(0x00);
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(1);

    // Fill the sine wave buffer with 1024 points
    // The 0.9 here prevents the driver from ever going over 150V! (It can do ~160 which can damage mirror)
    debugPrintln("Filling in sine wave");
    for (int i = 0; i < BUFFER_LEN; i++){
        sine_wave[i] = sin(i*phase); // fill 0 to twopi phase, output range -0.9 to 0.9 to limit HV output
    }
    // Start the LASER PWM timer
    // 50% duty cycle at desired frequency
    analogWriteFrequency(LASER_EN_PIN, 1000);
    analogWrite (LASER_EN_PIN,0);
}

void sendMirrorOutput(const mirrorOutput& out) {
    volatile uint32_t timeNow = millis();
    // millis() subject to overflow after 40 days, causes 1 assertion error
    assert(timeNow - timeOfLastMirrorOutput >= 9); // No more than 100Hz
    timeOfLastMirrorOutput = timeNow;
    int16_t x = out.x * 0.9; // Important: never max out the mirror
    int16_t y = out.y * 0.9;
    // figure out the sine wave output for each channel, from -1,1 to uint16_t centered at 32768
    // X = A - B
    DAC_ch_A = (uint16_t) (32768*(1 + (ampl_x * x / 2)));
    DAC_ch_B = (uint16_t) (32768*(1 - (ampl_x * x / 2)));
    // Y = C - D
    // 90 degree phase shift on Y for a circle>?
    DAC_ch_C = (uint16_t) (32768*(1 + (ampl_y * y / 2)));
    DAC_ch_D = (uint16_t) (32768*(1 - (ampl_y * y / 2)));

  /* HERE BE STUPID */
    // Write all 4 channels 1 at a time
    DAC_write_word[0] = 0b00011000; // write to and update (C = 011) channel A DAC (A = 000), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_A >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_A & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011001; // write to and update (C = 011) channel B DAC (B = 001), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_B >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_B & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011010; // write to and update (C = 011) channel C DAC (C = 010), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_C >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_C & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
    DAC_write_word[0] = 0b00011011; // write to and update (C = 011) channel D DAC (D = 011), first 2 bits dont care.
    DAC_write_word[1] = DAC_ch_D >> 8;     // MSB
    DAC_write_word[2] = DAC_ch_D & 0x00FF; // LSB

    // manually toggle SS pin (blergh)
    digitalWrite(slaveSelectPin,LOW);
    //  send the DAC write word one byte at a time:
    SPI2.transfer(DAC_write_word[0]);
    SPI2.transfer(DAC_write_word[1]);
    SPI2.transfer(DAC_write_word[2]);
    // take the SS pin high to de-select the chip:
    digitalWrite(slaveSelectPin,HIGH);
    delayMicroseconds(10);
}

void highVoltageEnable(bool enable) {
    if (enable) {
        digitalWrite(DRIVER_HV_EN_pin,HIGH);
    } else {
        digitalWrite(DRIVER_HV_EN_pin,LOW);
    }
}

void laserEnable(bool enable) {
    if (enable) {
        laser_state = HIGH;
        analogWrite (LASER_EN_PIN, 128); // 50% duty cycle 1khz
    } else {
        laser_state = LOW;
        analogWrite (LASER_EN_PIN, 0);
    }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <libtorrent/kademlia/find_data.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/io.hpp>
#include <libtorrent/socket.hpp>
#include <libtorrent/socket_io.hpp>
#include <vector>

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_DECLARE_LOG(traversal);
#endif

using detail::read_v4_endpoint;
using detail::read_v6_endpoint;
using detail::read_endpoint_list;

void find_data_observer::reply(msg const& m)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	std::stringstream log_line;
	log_line << "[" << m_algorithm.get() << "] incoming get_peer response [ ";
#endif

	lazy_entry const* r = m.message.dict_find_dict("r");
	if (!r)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] missing response dict";
#endif
		return;
	}

	lazy_entry const* id = r->dict_find_string("id");
	if (!id || id->string_length() != 20)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response";
#endif
		return;
	}

	lazy_entry const* token = r->dict_find_string("token");
	if (token)
	{
		static_cast<find_data*>(m_algorithm.get())->got_write_token(
			node_id(id->string_ptr()), token->string_value());

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " token: " << to_hex(token->string_value());
#endif
	}

	// look for peers
	lazy_entry const* n = r->dict_find_list("values");
	if (n)
	{
		std::vector<tcp::endpoint> peer_list;
		if (n->list_size() == 1 && n->list_at(0)->type() == lazy_entry::string_t)
		{
			// assume it's mainline format
			char const* peers = n->list_at(0)->string_ptr();
			char const* end = peers + n->list_at(0)->string_length();

#ifdef TORRENT_DHT_VERBOSE_LOGGING
			log_line << " p: " << ((end - peers) / 6);
#endif
			while (end - peers >= 6)
				peer_list.push_back(read_v4_endpoint<tcp::endpoint>(peers));
		}
		else
		{
			// assume it's uTorrent/libtorrent format
			read_endpoint_list<tcp::endpoint>(n, peer_list);
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			log_line << " p: " << n->list_size();
#endif
		}
		static_cast<find_data*>(m_algorithm.get())->got_peers(peer_list);
	}

	// look for nodes
	n = r->dict_find_string("nodes");
	if (n)
	{
		std::vector<node_entry> node_list;
		char const* nodes = n->string_ptr();
		char const* end = nodes + n->string_length();

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " nodes: " << ((end - nodes) / 26);
#endif
		while (end - nodes >= 26)
		{
			node_id id;
			std::copy(nodes, nodes + 20, id.begin());
			nodes += 20;
			m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(nodes));
		}
	}

	n = r->dict_find_list("nodes2");
	if (n)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " nodes2: " << n->list_size();
#endif
		for (int i = 0; i < n->list_size(); ++i)
		{
			lazy_entry const* p = n->list_at(0);
			if (p->type() != lazy_entry::string_t) continue;
			if (p->string_length() < 6 + 20) continue;
			char const* in = p->string_ptr();

			node_id id;
			std::copy(in, in + 20, id.begin());
			in += 20;
			if (p->string_length() == 6 + 20)
				m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(in));
#if TORRENT_USE_IPV6
			else if (p->string_length() == 18 + 20)
				m_algorithm->traverse(id, read_v6_endpoint<udp::endpoint>(in));
#endif
		}
	}
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	log_line << " ]";
	TORRENT_LOG(traversal) << log_line.str();
#endif
	done();
}

find_data::find_data(
	node_impl& node
	, node_id target
	, data_callback const& dcallback
	, nodes_callback const& ncallback)
	: traversal_algorithm(node, target)
	, m_data_callback(dcallback)
	, m_nodes_callback(ncallback)
	, m_target(target)
	, m_done(false)
	, m_got_peers(false)
{
	for (routing_table::const_iterator i = node.m_table.begin()
		, end(node.m_table.end()); i != end; ++i)
	{
		add_entry(i->id, i->ep(), result::initial);
	}
}

bool find_data::invoke(udp::endpoint addr)
{
	if (m_done)
	{
		m_invoke_count = -1;
		return false;
	}

	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocator().malloc();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] failed to "
			"allocate memory for observer. aborting!";
#endif
		done();
		return false;
	}
	m_node.m_rpc.allocator().set_next_size(10);
	observer_ptr o(new (ptr) find_data_observer(this));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	entry e;
	e["y"] = "q";
	e["q"] = "get_peers";
	entry& a = e["a"];
	a["info_hash"] = m_target.to_string();
	return m_node.m_rpc.invoke(e, addr, o);
}

void find_data::got_peers(std::vector<tcp::endpoint> const& peers)
{
	if (!peers.empty()) m_got_peers = true;
	m_data_callback(peers);
}

void find_data::done()
{
	if (m_invoke_count != 0) return;

	m_done = true;

	std::vector<std::pair<node_entry, std::string> > results;
	int num_results = m_node.m_table.bucket_size();
	for (std::vector<result>::iterator i = m_results.begin()
		, end(m_results.end()); i != end && num_results > 0; ++i)
	{
		if (i->flags & result::no_id) continue;
		if ((i->flags & result::queried) == 0) continue;
		std::map<node_id, std::string>::iterator j = m_write_tokens.find(i->id);
		if (j == m_write_tokens.end()) continue;
		results.push_back(std::make_pair(node_entry(i->id, i->endpoint()), j->second));
		--num_results;
	}
	m_nodes_callback(results, m_got_peers);
}

} } // namespace libtorrent::dht

<commit_msg>USE_IPV6 fixes<commit_after>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <libtorrent/kademlia/find_data.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node.hpp>
#include <libtorrent/io.hpp>
#include <libtorrent/socket.hpp>
#include <libtorrent/socket_io.hpp>
#include <vector>

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	TORRENT_DECLARE_LOG(traversal);
#endif

using detail::read_endpoint_list;
using detail::read_v4_endpoint;
#if TORRENT_USE_IPV6
using detail::read_v6_endpoint;
#endif

void find_data_observer::reply(msg const& m)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	std::stringstream log_line;
	log_line << "[" << m_algorithm.get() << "] incoming get_peer response [ ";
#endif

	lazy_entry const* r = m.message.dict_find_dict("r");
	if (!r)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] missing response dict";
#endif
		return;
	}

	lazy_entry const* id = r->dict_find_string("id");
	if (!id || id->string_length() != 20)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response";
#endif
		return;
	}

	lazy_entry const* token = r->dict_find_string("token");
	if (token)
	{
		static_cast<find_data*>(m_algorithm.get())->got_write_token(
			node_id(id->string_ptr()), token->string_value());

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " token: " << to_hex(token->string_value());
#endif
	}

	// look for peers
	lazy_entry const* n = r->dict_find_list("values");
	if (n)
	{
		std::vector<tcp::endpoint> peer_list;
		if (n->list_size() == 1 && n->list_at(0)->type() == lazy_entry::string_t)
		{
			// assume it's mainline format
			char const* peers = n->list_at(0)->string_ptr();
			char const* end = peers + n->list_at(0)->string_length();

#ifdef TORRENT_DHT_VERBOSE_LOGGING
			log_line << " p: " << ((end - peers) / 6);
#endif
			while (end - peers >= 6)
				peer_list.push_back(read_v4_endpoint<tcp::endpoint>(peers));
		}
		else
		{
			// assume it's uTorrent/libtorrent format
			read_endpoint_list<tcp::endpoint>(n, peer_list);
#ifdef TORRENT_DHT_VERBOSE_LOGGING
			log_line << " p: " << n->list_size();
#endif
		}
		static_cast<find_data*>(m_algorithm.get())->got_peers(peer_list);
	}

	// look for nodes
	n = r->dict_find_string("nodes");
	if (n)
	{
		std::vector<node_entry> node_list;
		char const* nodes = n->string_ptr();
		char const* end = nodes + n->string_length();

#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " nodes: " << ((end - nodes) / 26);
#endif
		while (end - nodes >= 26)
		{
			node_id id;
			std::copy(nodes, nodes + 20, id.begin());
			nodes += 20;
			m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(nodes));
		}
	}

	n = r->dict_find_list("nodes2");
	if (n)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		log_line << " nodes2: " << n->list_size();
#endif
		for (int i = 0; i < n->list_size(); ++i)
		{
			lazy_entry const* p = n->list_at(0);
			if (p->type() != lazy_entry::string_t) continue;
			if (p->string_length() < 6 + 20) continue;
			char const* in = p->string_ptr();

			node_id id;
			std::copy(in, in + 20, id.begin());
			in += 20;
			if (p->string_length() == 6 + 20)
				m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(in));
#if TORRENT_USE_IPV6
			else if (p->string_length() == 18 + 20)
				m_algorithm->traverse(id, read_v6_endpoint<udp::endpoint>(in));
#endif
		}
	}
#ifdef TORRENT_DHT_VERBOSE_LOGGING
	log_line << " ]";
	TORRENT_LOG(traversal) << log_line.str();
#endif
	done();
}

find_data::find_data(
	node_impl& node
	, node_id target
	, data_callback const& dcallback
	, nodes_callback const& ncallback)
	: traversal_algorithm(node, target)
	, m_data_callback(dcallback)
	, m_nodes_callback(ncallback)
	, m_target(target)
	, m_done(false)
	, m_got_peers(false)
{
	for (routing_table::const_iterator i = node.m_table.begin()
		, end(node.m_table.end()); i != end; ++i)
	{
		add_entry(i->id, i->ep(), result::initial);
	}
}

bool find_data::invoke(udp::endpoint addr)
{
	if (m_done)
	{
		m_invoke_count = -1;
		return false;
	}

	TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer));
	void* ptr = m_node.m_rpc.allocator().malloc();
	if (ptr == 0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << "[" << this << "] failed to "
			"allocate memory for observer. aborting!";
#endif
		done();
		return false;
	}
	m_node.m_rpc.allocator().set_next_size(10);
	observer_ptr o(new (ptr) find_data_observer(this));
#ifdef TORRENT_DEBUG
	o->m_in_constructor = false;
#endif
	entry e;
	e["y"] = "q";
	e["q"] = "get_peers";
	entry& a = e["a"];
	a["info_hash"] = m_target.to_string();
	return m_node.m_rpc.invoke(e, addr, o);
}

void find_data::got_peers(std::vector<tcp::endpoint> const& peers)
{
	if (!peers.empty()) m_got_peers = true;
	m_data_callback(peers);
}

void find_data::done()
{
	if (m_invoke_count != 0) return;

	m_done = true;

	std::vector<std::pair<node_entry, std::string> > results;
	int num_results = m_node.m_table.bucket_size();
	for (std::vector<result>::iterator i = m_results.begin()
		, end(m_results.end()); i != end && num_results > 0; ++i)
	{
		if (i->flags & result::no_id) continue;
		if ((i->flags & result::queried) == 0) continue;
		std::map<node_id, std::string>::iterator j = m_write_tokens.find(i->id);
		if (j == m_write_tokens.end()) continue;
		results.push_back(std::make_pair(node_entry(i->id, i->endpoint()), j->second));
		--num_results;
	}
	m_nodes_callback(results, m_got_peers);
}

} } // namespace libtorrent::dht

<|endoftext|>


<commit_before>
/**
 * This file is part of the boostcache package.
 *
 * (c) Azat Khuzhin <a3at.mail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include "session.h"
#include "util/log.h"

#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <sstream>

using namespace boost::spirit::qi;

void Session::start()
{
    asyncRead();
}

void Session::asyncRead()
{
    m_socket.async_read_some(boost::asio::buffer(m_buffer, MAX_BUFFER_LENGTH),
                             boost::bind(&Session::handleRead, this,
                                         boost::asio::placeholders::error,
                                         boost::asio::placeholders::bytes_transferred));
}

void Session::asyncWrite(const std::string& message)
{
    boost::asio::async_write(m_socket,
                             boost::asio::buffer(message),
                             boost::bind(&Session::handleWrite, this,
                                         boost::asio::placeholders::error));
}

void Session::handleRead(const boost::system::error_code& error, size_t /* bytesTransferred */)
{
    if (error) {
        delete this;
        return;
    }

    handleReadParseCommand();
}

void Session::handleWrite(const boost::system::error_code& error)
{
    if (error) {
        delete this;
        return;
    }

    asyncRead();
}

/**
 * TODO: speedup parsing
 * TODO: more error-friendly parsing
 * TODO: add logging before every reset() call
 */
void Session::handleReadParseCommand()
{
    LOG(debug) << "Try to read/parser command " << m_buffer
               << "with " << m_numberOfArguments << " arguments, "
               "for " << this;
    m_commandString += m_buffer;

    std::string line;
    std::istringstream stream(m_commandString);
    stream.seekg(m_commandOffset);

    // Number of arguments
    if (m_numberOfArguments < 0) {
        std::getline(stream, line);
        parse(line.begin(), line.end(),
              '*' >> int_ >> "\r",
              m_numberOfArguments);

        if (m_numberOfArguments < 0) {
            LOG(debug) << "Don't have number of arguments, for " << this;

            reset();
            asyncRead();
            return;
        }

        commandArguments.reserve(m_numberOfArguments);
        m_numberOfArgumentsLeft = m_numberOfArguments;
        m_commandOffset = stream.tellg();

        LOG(info) << "Have " << m_numberOfArguments << " number of arguments, "
                  << "for " << this;
    }

    char crLf[2];
    char *argument = NULL;
    int argumentLength = 0;
    while (m_numberOfArgumentsLeft && std::getline(stream, line)) {
        if (!parse(line.begin(), line.end(),
                   '$' >> int_ >> "\r",
                   m_lastArgumentLength)
        ) {
            LOG(debug) << "Can't find valid argument length, for " << this;
            break;
        }
        LOG(debug) << "Reading " << m_lastArgumentLength << " bytes, for " << this;

        if (argumentLength < m_lastArgumentLength) {
            argument = (char *)realloc(argument, argumentLength + 1 /* NULL byte */
                                       + m_lastArgumentLength);
            argumentLength += m_lastArgumentLength;
        }
        stream.read(argument, m_lastArgumentLength);
        argument[m_lastArgumentLength] = 0;
        if (!stream.good()) {
            /**
             * TODO: add some internal counters for failover,
             * or smth like this
             */
            if (stream.bad()) {
                LOG(debug) << "Bad stream, for " << this;
                reset();
            }
            break;
        }
        // Read CRLF separator
        stream.read(crLf, 2);
        if (!stream.good()) {
            /**
             * TODO: add some internal counters for failover,
             * or smth like this
             */
            if (stream.bad()) {
                LOG(debug) << "Bad stream, for " << this;
                reset();
            }
            break;
        }
        if (memcmp(crLf, "\r\n", 2) != 0) {
            LOG(debug) << "Malfomed end of argument, for " << this;
            reset();
            break;
        }
        // Save command argument
        LOG(debug) << "Saving " << argument << " argument, for " << this;
        commandArguments.push_back(argument);
        m_lastArgumentLength = -1;

        // Update some counters/offsets
        --m_numberOfArgumentsLeft;
        m_commandOffset = stream.tellg();
    }

    if (!m_numberOfArgumentsLeft) {
        handleCommand();
        // Will be called asyncRead() in write callback
    } else {
        asyncRead();
    }
}

void Session::handleCommand()
{
    LOG(info) << "Handling new command, for " << this;

    writeCommand();

    reset();
}

void Session::writeCommand()
{
    std::string arguments;
    int i;
    for_each(commandArguments.begin(), commandArguments.end(),
             [&arguments, &i] (std::string argument)
             {
                  arguments += i++;
                  arguments += " ";
                  arguments += argument;
                  arguments += "\n";
             }
    );

    asyncWrite(arguments);
}

void Session::reset()
{
    m_commandString = "";
    m_commandOffset = 0;
    m_numberOfArguments = -1;
    m_numberOfArgumentsLeft = -1;
    m_lastArgumentLength = -1;

    commandArguments.clear();
}<commit_msg>[net/session] fix std::string::operator+() value to lvalue<commit_after>
/**
 * This file is part of the boostcache package.
 *
 * (c) Azat Khuzhin <a3at.mail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include "session.h"
#include "util/log.h"

#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <sstream>

using namespace boost::spirit::qi;

void Session::start()
{
    asyncRead();
}

void Session::asyncRead()
{
    m_socket.async_read_some(boost::asio::buffer(m_buffer, MAX_BUFFER_LENGTH),
                             boost::bind(&Session::handleRead, this,
                                         boost::asio::placeholders::error,
                                         boost::asio::placeholders::bytes_transferred));
}

void Session::asyncWrite(const std::string& message)
{
    boost::asio::async_write(m_socket,
                             boost::asio::buffer(message),
                             boost::bind(&Session::handleWrite, this,
                                         boost::asio::placeholders::error));
}

void Session::handleRead(const boost::system::error_code& error, size_t /* bytesTransferred */)
{
    if (error) {
        delete this;
        return;
    }

    handleReadParseCommand();
}

void Session::handleWrite(const boost::system::error_code& error)
{
    if (error) {
        delete this;
        return;
    }

    asyncRead();
}

/**
 * TODO: speedup parsing
 * TODO: more error-friendly parsing
 * TODO: add logging before every reset() call
 */
void Session::handleReadParseCommand()
{
    LOG(debug) << "Try to read/parser command " << m_buffer
               << "with " << m_numberOfArguments << " arguments, "
               "for " << this;
    m_commandString += m_buffer;

    std::string line;
    std::istringstream stream(m_commandString);
    stream.seekg(m_commandOffset);

    // Number of arguments
    if (m_numberOfArguments < 0) {
        std::getline(stream, line);
        parse(line.begin(), line.end(),
              '*' >> int_ >> "\r",
              m_numberOfArguments);

        if (m_numberOfArguments < 0) {
            LOG(debug) << "Don't have number of arguments, for " << this;

            reset();
            asyncRead();
            return;
        }

        commandArguments.reserve(m_numberOfArguments);
        m_numberOfArgumentsLeft = m_numberOfArguments;
        m_commandOffset = stream.tellg();

        LOG(info) << "Have " << m_numberOfArguments << " number of arguments, "
                  << "for " << this;
    }

    char crLf[2];
    char *argument = NULL;
    int argumentLength = 0;
    while (m_numberOfArgumentsLeft && std::getline(stream, line)) {
        if (!parse(line.begin(), line.end(),
                   '$' >> int_ >> "\r",
                   m_lastArgumentLength)
        ) {
            LOG(debug) << "Can't find valid argument length, for " << this;
            break;
        }
        LOG(debug) << "Reading " << m_lastArgumentLength << " bytes, for " << this;

        if (argumentLength < m_lastArgumentLength) {
            argument = (char *)realloc(argument, argumentLength + 1 /* NULL byte */
                                       + m_lastArgumentLength);
            argumentLength += m_lastArgumentLength;
        }
        stream.read(argument, m_lastArgumentLength);
        argument[m_lastArgumentLength] = 0;
        if (!stream.good()) {
            /**
             * TODO: add some internal counters for failover,
             * or smth like this
             */
            if (stream.bad()) {
                LOG(debug) << "Bad stream, for " << this;
                reset();
            }
            break;
        }
        // Read CRLF separator
        stream.read(crLf, 2);
        if (!stream.good()) {
            /**
             * TODO: add some internal counters for failover,
             * or smth like this
             */
            if (stream.bad()) {
                LOG(debug) << "Bad stream, for " << this;
                reset();
            }
            break;
        }
        if (memcmp(crLf, "\r\n", 2) != 0) {
            LOG(debug) << "Malfomed end of argument, for " << this;
            reset();
            break;
        }
        // Save command argument
        LOG(debug) << "Saving " << argument << " argument, for " << this;
        commandArguments.push_back(argument);
        m_lastArgumentLength = -1;

        // Update some counters/offsets
        --m_numberOfArgumentsLeft;
        m_commandOffset = stream.tellg();
    }

    if (!m_numberOfArgumentsLeft) {
        handleCommand();
        // Will be called asyncRead() in write callback
    } else {
        asyncRead();
    }
}

void Session::handleCommand()
{
    LOG(info) << "Handling new command, for " << this;

    writeCommand();

    reset();
}

void Session::writeCommand()
{
    std::string arguments;
    int i;
    for_each(commandArguments.begin(), commandArguments.end(),
             [&arguments, &i] (std::string argument)
             {
                  arguments += ++i;
                  arguments += " ";
                  arguments += argument;
                  arguments += "\n";
             }
    );

    asyncWrite(arguments);
}

void Session::reset()
{
    m_commandString = "";
    m_commandOffset = 0;
    m_numberOfArguments = -1;
    m_numberOfArgumentsLeft = -1;
    m_lastArgumentLength = -1;

    commandArguments.clear();
}<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry()
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t)
		: m_type(undefined_t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
		: m_type(undefined_t)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		switch(t)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(t == undefined_t);
		}
		m_type = t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		switch (e.type())
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			TORRENT_ASSERT(e.type() == undefined_t);
		}
		m_type = e.type();
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
		m_type = undefined_t;
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<commit_msg>fixed include issue in entry.cpp<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <iostream>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry()
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t)
		: m_type(undefined_t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
		: m_type(undefined_t)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		switch(t)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(t == undefined_t);
		}
		m_type = t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		switch (e.type())
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			TORRENT_ASSERT(e.type() == undefined_t);
		}
		m_type = e.type();
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
		m_type = undefined_t;
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<|endoftext|>