<commit_before>//  Copyright (c) 2015-2015 The KID Authors. All rights reserved.
//  Created on: 2017/1/10 Author: zjc

#include "stock_group.h"

#include <stdlib.h>
#include <sstream>

#include "logic/logic_comm.h"
#include "strade_share/strade_share_engine.h"

namespace strade_user {

SSEngine* StockGroup::engine_ = NULL;

StockGroup::StockGroup() {
  data_ = new Data();
}

StockGroup::StockGroup(UserId user_id,
                       GroupId id,
                       const std::string& name) {
  data_ = new Data();
  data_->id_ = id;
  data_->user_id_ = user_id;
  data_->name_ = name;
}

REFCOUNT_DEFINE(StockGroup)

std::string StockGroup::GetUserGroupSql(UserId user_id) {
  std::ostringstream oss;
  oss << "SELECT `groupId`, `groupName`, `status`, "
      "`availableCapital`, `frozenCapital`, `initCapital` "
      "FROM `group_info` "
      "WHERE "
      << "`userId` = " << user_id << " AND " << "`status` != 0";
  return oss.str();
}

std::string StockGroup::GetGroupStockSql(UserId group_id) {
  std::ostringstream oss;
  oss << "SELECT `stockCode`, `addTime` FROM `group_stock` "
      "WHERE `groupId` = " << group_id;
  return oss.str();
}

GroupId StockGroup::CreateGroup(UserId user_id,
                                const std::string& name,
                                Status status) {
  std::ostringstream oss;
  oss << "CALL `proc_CreateStockGroup`("
      << user_id << ","
      << "'" << name << "'" << ","
      << (int)status << ")";

  MYSQL_ROWS_VEC row;
  if (!engine_->ExcuteStorage(1, oss.str(), row)) {
    LOG_ERROR2("user:%d create stock group error", user_id);
    return INVALID_GROUPID;
  }

  assert(!row.empty());
  GroupId id = atoi(row[0][0].data());
  LOG_MSG2("user:%d create stock group, id:%d, name:%s",
           user_id, id, name.data());
  return id;
}

void StockGroup::Deserialize() {
  int t = 0;
  GetInteger(0, data_->id_);
  GetString(1, data_->name_);
  GetInteger(2, t);
  data_->status_ = (Status) t;

  GetReal(3, data_->available_capital_);
  GetReal(4, data_->frozen_capital_);
  GetReal(5, data_->init_capital_);

  data_->initialized_ = true;
}

bool StockGroup::InitStockList() {
  SSEngine* engine = GetStradeShareEngine();
  MYSQL_ROWS_VEC stocks;
  if (!engine->ExcuteStorage(2, GetGroupStockSql(data_->id_), stocks)) {
    LOG_ERROR("init user stock list error");
    return false;
  }

  for (size_t i = 0; i < stocks.size(); ++i) {
    std::string& stock = stocks[i][0];
    if (stock.empty()) {
      LOG_ERROR("init user group stock error");
      continue;
    }
    data_->stock_list_.push_back(stock);
    data_->stock_set_.insert(stock);
  }
  LOG_MSG2("user:%d group:%s init %d stocks",
           data_->user_id_, data_->name_.data(), stocks.size());
  return true;
}

bool StockGroup::AddStocks(StockCodeList& stocks) {
  bool rc = true;
  size_t n = stocks.size();
  StockCodeList s;
  for (size_t i = 0; i < stocks.size(); ++i) {
    if (data_->stock_set_.count(stocks[i])) {
      LOG_ERROR2("stock:%s exist in group:%s",
                 stocks[i].data(), data_->name_.data());
      continue;
    }
    data_->stock_set_.insert(stocks[i]);
    data_->stock_list_.push_back(stocks[i]);
    s.push_back(stocks[i]);
  }

  if (s.empty()) {
    return true;
  }

  // update mysql
  std::ostringstream oss;
  oss << "REPLACE INTO `group_stock`(`groupId`, `stockCode`, `addTime`) VALUES";
  for (size_t i = 0; i < s.size(); ++i) {
    oss << "(" << data_->id_ << ",'" << s[i] << "', NOW()),";
  }
  std::string sql = oss.str();
  sql.erase(sql.size()-1);
  LOG_DEBUG2("add stock list sql: %s", sql.data());

//  SSEngine* engine = GetStradeShareEngine();
  if (!engine_->WriteData(sql)) {
    rc = false;
    LOG_ERROR2("user:%d add stock to group:%s error",
               data_->user_id_, data_->name_.data());
  }

  stocks.swap(s);
  return rc;
}

bool StockGroup::DelStocks(StockCodeList& stocks) {
  size_t n = stocks.size();
  StockCodeList s;
  for (size_t i = 0; i < stocks.size(); ++i) {
    if (!data_->stock_set_.count(stocks[i])) {
      LOG_ERROR2("stock:%s not exist in group:%s",
                 stocks[i].data(), data_->name_.data());
      continue;
    }
    data_->stock_set_.erase(stocks[i]);
    s.push_back(stocks[i]);
  }

  StockCodeList t;
  for (size_t i = 0; i < data_->stock_list_.size(); ++i) {
    bool find = false;
    for (size_t j = 0; j < s.size(); ++j) {
      if (s[j] == data_->stock_list_[i]) {
        find = true;
      }
    }
    if (!find) {
      t.push_back(data_->stock_list_[i]);
    }
  }

  // update mysql
  // update mysql
  std::ostringstream oss;
  oss << "REPLACE INTO `group_stock`(`groupId`, `stockCode`, `status`) VALUES";
  for (size_t i = 0; i < s.size(); ++i) {
    oss << "(" << data_->id_ << ","
        << "'" << s[i] << "'" << ","
        << int(INVALID) << "),";
  }
  std::string sql = oss.str();
  sql.erase(sql.size()-1);
  LOG_DEBUG2("del stock list sql: %s", sql.data());

//  SSEngine* engine = GetStradeShareEngine();
  if (!engine_->WriteData(sql)) {
    LOG_ERROR2("user:%d del stock to group:%s error",
               data_->user_id_, data_->name_.data());
  }

  stocks.swap(s);
  data_->stock_list_.swap(t);
  return stocks.size() == n;
}

} /* namespace strade_user */
<commit_msg>解决删除股票为空时 sql 执行出错 bug<commit_after>//  Copyright (c) 2015-2015 The KID Authors. All rights reserved.
//  Created on: 2017/1/10 Author: zjc

#include "stock_group.h"

#include <stdlib.h>
#include <sstream>

#include "logic/logic_comm.h"
#include "strade_share/strade_share_engine.h"

namespace strade_user {

SSEngine* StockGroup::engine_ = NULL;

StockGroup::StockGroup() {
  data_ = new Data();
}

StockGroup::StockGroup(UserId user_id,
                       GroupId id,
                       const std::string& name) {
  data_ = new Data();
  data_->id_ = id;
  data_->user_id_ = user_id;
  data_->name_ = name;
}

REFCOUNT_DEFINE(StockGroup)

std::string StockGroup::GetUserGroupSql(UserId user_id) {
  std::ostringstream oss;
  oss << "SELECT `groupId`, `groupName`, `status`, "
      "`availableCapital`, `frozenCapital`, `initCapital` "
      "FROM `group_info` "
      "WHERE "
      << "`userId` = " << user_id << " AND " << "`status` != 0";
  return oss.str();
}

std::string StockGroup::GetGroupStockSql(UserId group_id) {
  std::ostringstream oss;
  oss << "SELECT `stockCode`, `addTime` FROM `group_stock` "
      "WHERE `groupId` = " << group_id;
  return oss.str();
}

GroupId StockGroup::CreateGroup(UserId user_id,
                                const std::string& name,
                                Status status) {
  std::ostringstream oss;
  oss << "CALL `proc_CreateStockGroup`("
      << user_id << ","
      << "'" << name << "'" << ","
      << (int)status << ")";

  MYSQL_ROWS_VEC row;
  if (!engine_->ExcuteStorage(1, oss.str(), row)) {
    LOG_ERROR2("user:%d create stock group error", user_id);
    return INVALID_GROUPID;
  }

  assert(!row.empty());
  GroupId id = atoi(row[0][0].data());
  LOG_MSG2("user:%d create stock group, id:%d, name:%s",
           user_id, id, name.data());
  return id;
}

void StockGroup::Deserialize() {
  int t = 0;
  GetInteger(0, data_->id_);
  GetString(1, data_->name_);
  GetInteger(2, t);
  data_->status_ = (Status) t;

  GetReal(3, data_->available_capital_);
  GetReal(4, data_->frozen_capital_);
  GetReal(5, data_->init_capital_);

  data_->initialized_ = true;
}

bool StockGroup::InitStockList() {
  SSEngine* engine = GetStradeShareEngine();
  MYSQL_ROWS_VEC stocks;
  if (!engine->ExcuteStorage(2, GetGroupStockSql(data_->id_), stocks)) {
    LOG_ERROR("init user stock list error");
    return false;
  }

  for (size_t i = 0; i < stocks.size(); ++i) {
    std::string& stock = stocks[i][0];
    if (stock.empty()) {
      LOG_ERROR("init user group stock error");
      continue;
    }
    data_->stock_list_.push_back(stock);
    data_->stock_set_.insert(stock);
  }
  LOG_MSG2("user:%d group:%s init %d stocks",
           data_->user_id_, data_->name_.data(), stocks.size());
  return true;
}

bool StockGroup::AddStocks(StockCodeList& stocks) {
  bool rc = true;
  size_t n = stocks.size();
  StockCodeList s;
  for (size_t i = 0; i < stocks.size(); ++i) {
    if (data_->stock_set_.count(stocks[i])) {
      LOG_ERROR2("stock:%s exist in group:%s",
                 stocks[i].data(), data_->name_.data());
      continue;
    }
    data_->stock_set_.insert(stocks[i]);
    data_->stock_list_.push_back(stocks[i]);
    s.push_back(stocks[i]);
  }

  if (s.empty()) {
    return true;
  }

  // update mysql
  std::ostringstream oss;
  oss << "REPLACE INTO `group_stock`(`groupId`, `stockCode`, `addTime`) VALUES";
  for (size_t i = 0; i < s.size(); ++i) {
    oss << "(" << data_->id_ << ",'" << s[i] << "', NOW()),";
  }
  std::string sql = oss.str();
  sql.erase(sql.size()-1);
  LOG_DEBUG2("add stock list sql: %s", sql.data());

//  SSEngine* engine = GetStradeShareEngine();
  if (!engine_->WriteData(sql)) {
    rc = false;
    LOG_ERROR2("user:%d add stock to group:%s error",
               data_->user_id_, data_->name_.data());
  }

  stocks.swap(s);
  return rc;
}

bool StockGroup::DelStocks(StockCodeList& stocks) {
  size_t n = stocks.size();
  StockCodeList s;
  for (size_t i = 0; i < stocks.size(); ++i) {
    if (!data_->stock_set_.count(stocks[i])) {
      LOG_ERROR2("stock:%s not exist in group:%s",
                 stocks[i].data(), data_->name_.data());
      continue;
    }
    data_->stock_set_.erase(stocks[i]);
    s.push_back(stocks[i]);
  }

  StockCodeList t;
  for (size_t i = 0; i < data_->stock_list_.size(); ++i) {
    bool find = false;
    for (size_t j = 0; j < s.size(); ++j) {
      if (s[j] == data_->stock_list_[i]) {
        find = true;
      }
    }
    if (!find) {
      t.push_back(data_->stock_list_[i]);
    }
  }

  if (!s.empty()) {
    std::ostringstream oss;
    oss << "REPLACE INTO `group_stock`(`groupId`, `stockCode`, `status`) VALUES";
    for (size_t i = 0; i < s.size(); ++i) {
      oss << "(" << data_->id_ << "," << "'" << s[i] << "'" << ","
          << int(INVALID) << "),";
    }
    std::string sql = oss.str();
    sql.erase(sql.size() - 1);
    LOG_DEBUG2("del stock list sql: %s", sql.data());

//  SSEngine* engine = GetStradeShareEngine();
    if (!engine_->WriteData(sql)) {
      LOG_ERROR2("user:%d del stock to group:%s error",
          data_->user_id_, data_->name_.data());
    }
  }
  stocks.swap(s);
  data_->stock_list_.swap(t);
  return stocks.size() == n;
}

} /* namespace strade_user */
<|endoftext|>


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

#include "core/providers/cpu/math/top_k.h"
#include "core/providers/common.h"
#include "core/common/common.h"
#include "core/common/exceptions.h"
#include "core/framework/op_kernel.h"
#include "core/framework/tensor.h"
#include "core/util/math_cpuonly.h"
#include <queue>
using namespace std;
namespace onnxruntime {
// spec https://github.com/onnx/onnx/blob/master/docs/Operators.md#TopK
ONNX_CPU_OPERATOR_KERNEL(
    TopK,
    1,
    KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<float>()).TypeConstraint("I", DataTypeImpl::GetTensorType<int64_t>()),
    TopK<float>);

static int64_t SizeToDim(size_t k, const vector<int64_t>& dims) {
  ORT_ENFORCE(k <= dims.size());
  int64_t r = 1;
  for (size_t i = 0; i < k; ++i) {
    r *= dims[i];
  }
  return r;
}

static int64_t SizeFromDim(size_t k, const vector<int64_t>& dims) {
  ORT_ENFORCE(k <= dims.size());
  int64_t r = 1;
  for (size_t i = k; i < dims.size(); ++i) {
    r *= dims[i];
  }
  return r;
}

// Define these two names to allow lookup into the 2d tensors like
// mytensor(i, j)
template <typename T>
using EigenMatrixMapRowMajor = Eigen::Map<
    Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>;

template <typename T>
using ConstEigenMatrixMapRowMajor = Eigen::Map<
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>;

template <typename T>
struct ValueCmp {
  bool operator()(
      const pair<T, int64_t>& lhs,
      const pair<T, int64_t>& rhs) {
    return (
        lhs.first > rhs.first ||
        (lhs.first == rhs.first && lhs.second < rhs.second));
  }
};

template <>
Status TopK<float>::Compute(OpKernelContext* p_op_kernel_context) const {
  const Tensor* X = p_op_kernel_context->Input<Tensor>(0);
  if (X == nullptr) return Status(common::ONNXRUNTIME, common::FAIL, "input count mismatch");
  const vector<int64_t>& in_dims = X->Shape().GetDims();
  // Will return axis_ as is if positive or fixes it in case it is negative
  auto axis_parsed = HandleNegativeAxis(axis_, in_dims.size());
  // Check to ensure k_ is within the bounds of what is available in that specific axis
  if (in_dims.at(axis_parsed) < k_) {
    ostringstream err_msg;
    err_msg << "k argment [" << k_ << "] should not be greater than specified axis dim value [" << in_dims.at(axis_parsed) << "]";
    return Status(common::ONNXRUNTIME, common::FAIL, err_msg.str());
  }

  const int64_t rows = SizeToDim(axis_parsed, in_dims);
  const int64_t cols = X->Shape().Size() / rows;
  auto input_map = ConstEigenMatrixMapRowMajor<float>(
      static_cast<const float*>(X->template Data<float>()),
      rows,
      cols);

  // Resize output tensors to be the same shape as the input except
  // for the specified dimension ((i.e.) axis_parsed), which will be of size k_. E.x. for an input tensor
  // of shape [3, 4, 5] and k_=2 with axis_parsed=1, both of these will be shape [3, 2, 5]
  vector<int64_t> output_linear_shape = in_dims;
  output_linear_shape[axis_parsed] = k_;
  auto* Values = p_op_kernel_context->Output(0, output_linear_shape);
  auto* Indices = p_op_kernel_context->Output(1, output_linear_shape);

  // Use Eigen maps to allow indexing into the 2d tensors like Values_map(i,j)
  auto reduced_cols = SizeFromDim(axis_parsed, output_linear_shape);
  auto Values_map = EigenMatrixMapRowMajor<float>(
      Values->template MutableData<float>(), rows, reduced_cols);
  auto Indices_map = EigenMatrixMapRowMajor<int64_t>(
      Indices->template MutableData<int64_t>(), rows, reduced_cols);

  // This is basically the number of elements within each of the "k_" rows
  const int64_t block_slice = reduced_cols / k_;
  // Sort preserving Indices
  for (int64_t i = 0; i < rows; ++i) {
	  for (int64_t j = 0; j < block_slice; ++j) {
		// Build a min-heap, the heap element is pair of (value, idx)
		// the top of the heap is the smallest value
		priority_queue<
			pair<float, int64_t>,
			vector<pair<float, int64_t>>,
			ValueCmp<float>>
			min_heap;
		// Maintain the size of heap to be less or equal to k_, so the
		// heap will hold the k_ largest Values
		for (int64_t k = 0; k < in_dims[axis_parsed]; ++k) {
			const auto value = input_map(i, k * block_slice + j);
			if (min_heap.size() < k_ || value > min_heap.top().first) {
				min_heap.push({value, k});
			}
			if (min_heap.size() > k_) {
				min_heap.pop();
			}
		}
		// Extract these k_ elements and place them in the results placeholder
		for (int64_t l = 0; l < k_; ++l) {
			auto& pqElem = min_heap.top();
			auto col_index = (k_ - l -1) * block_slice + j;
			Values_map(i, col_index) = pqElem.first;
			Indices_map(i, col_index) = pqElem.second;
			min_heap.pop();
		}
	  }
  }

  return Status::OK();
}
}  // namespace onnxruntime
<commit_msg>Minor cleanup in TopK operator (#478)<commit_after>/**
* Copyright (c) 2016-present, Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "core/providers/cpu/math/top_k.h"
#include "core/providers/common.h"
#include "core/common/common.h"
#include "core/common/exceptions.h"
#include "core/framework/op_kernel.h"
#include "core/framework/tensor.h"
#include "core/util/math_cpuonly.h"
#include <queue>
using namespace std;
namespace onnxruntime {
// spec https://github.com/onnx/onnx/blob/master/docs/Operators.md#TopK
ONNX_CPU_OPERATOR_KERNEL(
    TopK,
    1,
    KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType<float>()).TypeConstraint("I", DataTypeImpl::GetTensorType<int64_t>()),
    TopK<float>);

static int64_t SizeToDim(size_t k, const vector<int64_t>& dims) {
  ORT_ENFORCE(k <= dims.size());
  int64_t r = 1;
  for (size_t i = 0; i < k; ++i) {
    r *= dims[i];
  }
  return r;
}

static int64_t SizeFromDim(size_t k, const vector<int64_t>& dims) {
  ORT_ENFORCE(k <= dims.size());
  int64_t r = 1;
  for (size_t i = k; i < dims.size(); ++i) {
    r *= dims[i];
  }
  return r;
}

template <typename T>
struct ValueCmp {
  bool operator()(
      const pair<T, int64_t>& lhs,
      const pair<T, int64_t>& rhs) {
    return (
        lhs.first > rhs.first ||
        (lhs.first == rhs.first && lhs.second < rhs.second));
  }
};

template <>
Status TopK<float>::Compute(OpKernelContext* p_op_kernel_context) const {
  const Tensor* X = p_op_kernel_context->Input<Tensor>(0);
  if (X == nullptr) return Status(common::ONNXRUNTIME, common::FAIL, "input count mismatch");
  const vector<int64_t>& in_dims = X->Shape().GetDims();
  // Will return axis_ as is if positive or fixes it in case it is negative
  auto axis_parsed = HandleNegativeAxis(axis_, in_dims.size());
  // Check to ensure k_ is within the bounds of what is available in that specific axis
  if (in_dims.at(axis_parsed) < k_) {
    ostringstream err_msg;
    err_msg << "k argment [" << k_ << "] should not be greater than specified axis dim value [" << in_dims.at(axis_parsed) << "]";
    return Status(common::ONNXRUNTIME, common::FAIL, err_msg.str());
  }

  const int64_t rows = SizeToDim(axis_parsed, in_dims);
  const int64_t cols = X->Shape().Size() / rows;
  auto input_map = ConstEigenMatrixMapRowMajor<float>(
      static_cast<const float*>(X->template Data<float>()),
      rows,
      cols);

  // Resize output tensors to be the same shape as the input except
  // for the specified dimension ((i.e.) axis_parsed), which will be of size k_. E.x. for an input tensor
  // of shape [3, 4, 5] and k_=2 with axis_parsed=1, both of these will be shape [3, 2, 5]
  vector<int64_t> output_linear_shape = in_dims;
  output_linear_shape[axis_parsed] = k_;
  auto* Values = p_op_kernel_context->Output(0, output_linear_shape);
  auto* Indices = p_op_kernel_context->Output(1, output_linear_shape);

  // Use Eigen maps to allow indexing into the 2d tensors like Values_map(i,j)
  const int64_t reduced_cols = SizeFromDim(axis_parsed, output_linear_shape);
  auto Values_map = EigenMatrixMapRowMajor<float>(
      Values->template MutableData<float>(), rows, reduced_cols);
  auto Indices_map = EigenMatrixMapRowMajor<int64_t>(
      Indices->template MutableData<int64_t>(), rows, reduced_cols);

  // This is basically the number of elements within each of the "k_" rows
  const int64_t block_slice = reduced_cols / k_;
  // Sort preserving Indices
  for (int64_t i = 0; i < rows; ++i) {
	  for (int64_t j = 0; j < block_slice; ++j) {
		// Build a min-heap, the heap element is pair of (value, idx)
		// the top of the heap is the smallest value
		priority_queue<
			pair<float, int64_t>,
			vector<pair<float, int64_t>>,
			ValueCmp<float>>
			min_heap;
		// Maintain the size of heap to be less or equal to k_, so the
		// heap will hold the k_ largest Values
		for (int64_t k = 0; k < in_dims[axis_parsed]; ++k) {
			const auto value = input_map(i, k * block_slice + j);
			if (min_heap.size() < k_ || value > min_heap.top().first) {
				min_heap.push({value, k});
			}
			if (min_heap.size() > k_) {
				min_heap.pop();
			}
		}
		// Extract these k_ elements and place them in the results placeholder
		for (int64_t l = 0; l < k_; ++l) {
			auto& pqElem = min_heap.top();
			auto col_index = (k_ - l -1) * block_slice + j;
			Values_map(i, col_index) = pqElem.first;
			Indices_map(i, col_index) = pqElem.second;
			min_heap.pop();
		}
	  }
  }

  return Status::OK();
}
}  // namespace onnxruntime
<|endoftext|>


<commit_before>#include "OSMC_driver.hpp"

#include <algorithm>

const int OSMC_driver::_max_speed_ = 130;
const int OSMC_driver::MINREQSPEED = 30;

OSMC_driver::OSMC_driver()
{
	lvgoal = 0;
	rvgoal = 0;
	m_connected = false;
	encoder = NULL;
	#ifndef MOTOR_SIMULATE
	ai.initLink(OSMC_IF_BOARD);
	encoder = new quadCoderDriver();
	#endif
	m_connected = true;
	set_motors(0, 0);
}

OSMC_driver::OSMC_driver(byte motor_iface, byte encoder_iface)
{
	lvgoal = 0;
	rvgoal = 0;
	m_connected = false;
	encoder = NULL;
	#ifndef MOTOR_SIMULATE
	ai.initLink(motor_iface);
	encoder = new quadCoderDriver(encoder_iface);
	#endif
	m_connected = true;
	set_motors(0, 0);
}
OSMC_driver::~OSMC_driver()
{
	delete encoder;
}
#if 0
OSMC_driver::connect()
{
	ai.initLink(OSMC_IF_BOARD);
	m_connected = true;
}
#endif
bool OSMC_driver::getEncoderData(new_encoder_pk_t& pk)
{
	return encoder->getEncoderState(pk);
}

bool OSMC_driver::getEncoderVel(double& rvel, double& lvel)
{
	return encoder->getEncoderVel(rvel, lvel);
}

current_reply_t OSMC_driver::getCurrentData()
{
	ai.sendCommand(MC_GET_RL_CURR_VAL, NULL, 0);

	byte retcmd = 0;
	byte* data = NULL;
	ai.recvCommand(retcmd, data);

	current_reply_t out;

	memcpy(&out, data, sizeof(current_reply_t));
	delete[] data;
	return out;
}

bool OSMC_driver::set_motors(int leftVelocity, int rightVelocity)
{
	byte leftDutyCycle = std::min(abs(leftVelocity), 255);
	byte leftDir = (leftVelocity < 0) ? MC_MOTOR_REVERSE : MC_MOTOR_FORWARD;

	byte rightDutyCycle = std::min(abs(rightVelocity), 255);
	byte rightDir = (rightVelocity < 0) ? MC_MOTOR_REVERSE : MC_MOTOR_FORWARD;

	return setmotorPWM(rightDir, rightDutyCycle, leftDir, leftDutyCycle);
}

int OSMC_driver::set_heading(int iFwdVelocity, int iRotation)
{
	// convert
	int left  = iFwdVelocity + iRotation ;
	int right = iFwdVelocity - iRotation ;

	if (true)
	{
		// scale speed
		left  = int( float(left)  * float(_max_speed_) / float(255) ) ;
		right = int( float(right) * float(_max_speed_) / float(255) ) ;
	}
	else
	{
		// cap speed
		if (left  > _max_speed_) left  = _max_speed_ ;
		if (right > _max_speed_) right = _max_speed_ ;
	}

	// motors don't respond until certain output is reached
	if (right != 0) right += MINREQSPEED ;
	if (left  != 0) left  += MINREQSPEED ;

	// do it!
	return this->set_motors( left , right );
}

#ifndef MOTOR_SIMULATE
bool OSMC_driver::setmotorPWM(byte rightDir, byte rightDutyCycle, byte leftDir, byte leftDutyCycle)
{
	speed_set_t cmdpk;
	cmdpk.sr = rightDutyCycle;
	cmdpk.rightDir = rightDir;
	cmdpk.sl = leftDutyCycle;
	cmdpk.leftDir = leftDir;

	std::cout << "r: " << (int)rightDutyCycle << "l: " << (int)leftDutyCycle << std::endl;

	if(ai.sendCommand(MC_SET_RL_DUTY_CYCLE, &cmdpk, sizeof(speed_set_t)))
	{
		return true;
	}

	byte cmdresp;
	byte* data = NULL;

	if(ai.recvCommand(cmdresp, data))
	{
		return true;
	}

	if(data != NULL)
	{
		delete[] data;
	}

	ldir = leftDir;
	lpwm = leftDutyCycle;
	rdir = rightDir;
	rpwm = rightDutyCycle;

	return false;
}
#else
bool OSMC_driver::setmotorPWM(byte rightDir, byte rightDutyCycle, byte leftDir, byte leftDutyCycle)
{
	int sr = (rightDir == MC_MOTOR_FORWARD) ? int(rightDutyCycle) : -int(rightDutyCycle);
	int sl = (leftDir == MC_MOTOR_FORWARD) ? int(leftDutyCycle) : -int(leftDutyCycle);

	std::cout << "right: " << sr << "\tleft: " << sl << std::endl;

	if((rightDir == MC_MOTOR_REVERSE) || (leftDir == MC_MOTOR_REVERSE))
	{
		//atach dbg here
		std::cout << "robot is moving backwards!!!" << std::endl;
	}

	return false;
}
#endif
joystick_reply_t OSMC_driver::getJoystickData()
{

	ai.sendCommand(MC_GET_JOYSTICK, NULL, 0);

	byte retcmd = 0;
	byte* data = NULL;
	ai.recvCommand(retcmd, data);

	joystick_reply_t out;

	memcpy(&out, data, sizeof(current_reply_t));
	delete[] data;
	return out;
}

// start dumb + hysteresis control code
void OSMC_driver::getNewVel_dumb(const double rtarget, const double ltarget, const double rvel, const double lvel, const int rmset, const int lmset,  int& out_rmset, int& out_lmset)
{
	int posstep = 1;
	int negstep = -1;

	double thresh = .03;

	double lerror = ltarget - lvel;
	double rerror = rtarget - rvel;

	if(lerror > thresh)
	{
		out_lmset = lmset + posstep;
	}
	else if(lerror < -thresh)
	{
		out_lmset = lmset + negstep;
	}
	else
	{
		out_lmset = lmset;
	}

	if(rerror > thresh)
	{
		out_rmset = rmset + posstep;
	}
	else if(rerror < -thresh)
	{
		out_rmset = rmset + negstep;
	}
	else
	{
		out_rmset = rmset;
	}
}

void OSMC_driver::setVel_pd(double left, double right)
{
	lvgoal = left;
	rvgoal = right;
}

bool OSMC_driver::updateVel_pd()
{
	double now_rvel, now_lvel;
	timeval now_t;
	gettimeofday(&now_t, NULL);

	encoder->getEncoderVel(now_rvel, now_lvel);

	double now_t_d = double(now_t.tv_sec) + double(1e-6)*double(now_t.tv_usec);
	double dt = now_t_d - t;

	int out_lmset, out_rmset;
	getNewVel_pd(now_lvel, now_rvel, dt, out_rmset, out_lmset);

	t = now_t_d;

	return set_motors(out_lmset, out_rmset);
}

void OSMC_driver::getNewVel_pd(const double now_lvel, const double now_rvel, const double dt, int& out_r, int& out_l)
{
	const double kp = .1;
	const double kd = .1;

	double lerror = lvgoal - now_lvel;
	double rerror = rvgoal - now_rvel;

	double lerror_slope = (lerror - last_l_error) / dt;
	double rerror_slope = (rerror - last_r_error) / dt;

	out_l = -kp*lerror + -kd*lerror_slope;
	out_r = -kp*rerror + -kd*rerror_slope;

	//persist the stuff that needs to be saved
	last_l_error = lerror;
	last_r_error = rerror;
}

void OSMC_driver::getLastPWMSent(byte& r, byte& l)
{
	r = rpwm;
	l = lpwm;
}
<commit_msg><commit_after>#include "OSMC_driver.hpp"

#include <algorithm>

const int OSMC_driver::_max_speed_ = 130;
const int OSMC_driver::MINREQSPEED = 30;

OSMC_driver::OSMC_driver()
{
	lvgoal = 0;
	rvgoal = 0;
	m_connected = false;
	encoder = NULL;
	#ifndef MOTOR_SIMULATE
	ai.initLink(OSMC_IF_BOARD);
	encoder = new quadCoderDriver();
	#endif
	m_connected = true;
	set_motors(0, 0);
}

OSMC_driver::OSMC_driver(byte motor_iface, byte encoder_iface)
{
	lvgoal = 0;
	rvgoal = 0;
	m_connected = false;
	encoder = NULL;
	#ifndef MOTOR_SIMULATE
	ai.initLink(motor_iface);
	encoder = new quadCoderDriver(encoder_iface);
	#endif
	m_connected = true;
	set_motors(0, 0);
}
OSMC_driver::~OSMC_driver()
{
	delete encoder;
}
#if 0
OSMC_driver::connect()
{
	ai.initLink(OSMC_IF_BOARD);
	m_connected = true;
}
#endif
bool OSMC_driver::getEncoderData(new_encoder_pk_t& pk)
{
	return encoder->getEncoderState(pk);
}

bool OSMC_driver::getEncoderVel(double& rvel, double& lvel)
{
	return encoder->getEncoderVel(rvel, lvel);
}

current_reply_t OSMC_driver::getCurrentData()
{
	ai.sendCommand(MC_GET_RL_CURR_VAL, NULL, 0);

	byte retcmd = 0;
	byte* data = NULL;
	ai.recvCommand(retcmd, data);

	current_reply_t out;

	memcpy(&out, data, sizeof(current_reply_t));
	delete[] data;
	return out;
}

bool OSMC_driver::set_motors(int leftVelocity, int rightVelocity)
{
	byte leftDutyCycle = std::min(abs(leftVelocity), 255);
	byte leftDir = (leftVelocity < 0) ? MC_MOTOR_REVERSE : MC_MOTOR_FORWARD;

	byte rightDutyCycle = std::min(abs(rightVelocity), 255);
	byte rightDir = (rightVelocity < 0) ? MC_MOTOR_REVERSE : MC_MOTOR_FORWARD;

	return setmotorPWM(rightDir, rightDutyCycle, leftDir, leftDutyCycle);
}

int OSMC_driver::set_heading(int iFwdVelocity, int iRotation)
{
	// convert
	int left  = iFwdVelocity + iRotation ;
	int right = iFwdVelocity - iRotation ;

	if (true)
	{
		// scale speed
		left  = int( float(left)  * float(_max_speed_) / float(255) ) ;
		right = int( float(right) * float(_max_speed_) / float(255) ) ;
	}
	else
	{
		// cap speed
		if (left  > _max_speed_) left  = _max_speed_ ;
		if (right > _max_speed_) right = _max_speed_ ;
	}

	// motors don't respond until certain output is reached
	if (right != 0) right += MINREQSPEED ;
	if (left  != 0) left  += MINREQSPEED ;

	// do it!
	return this->set_motors( left , right );
}

#ifndef MOTOR_SIMULATE
bool OSMC_driver::setmotorPWM(byte rightDir, byte rightDutyCycle, byte leftDir, byte leftDutyCycle)
{
	speed_set_t cmdpk;
	cmdpk.sr = rightDutyCycle;
	cmdpk.rightDir = rightDir;
	cmdpk.sl = leftDutyCycle;
	cmdpk.leftDir = leftDir;

	std::cout << "r: " << (int)rightDutyCycle << "l: " << (int)leftDutyCycle << std::endl;

	if(ai.sendCommand(MC_SET_RL_DUTY_CYCLE, &cmdpk, sizeof(speed_set_t)))
	{
		return true;
	}

	byte cmdresp;
	byte* data = NULL;

	if(ai.recvCommand(cmdresp, data))
	{
		return true;
	}

	if(data != NULL)
	{
		delete[] data;
	}

	ldir = leftDir;
	lpwm = leftDutyCycle;
	rdir = rightDir;
	rpwm = rightDutyCycle;

	return false;
}
#else
bool OSMC_driver::setmotorPWM(byte rightDir, byte rightDutyCycle, byte leftDir, byte leftDutyCycle)
{
	int sr = (rightDir == MC_MOTOR_FORWARD) ? int(rightDutyCycle) : -int(rightDutyCycle);
	int sl = (leftDir == MC_MOTOR_FORWARD) ? int(leftDutyCycle) : -int(leftDutyCycle);

	std::cout << "right: " << sr << "\tleft: " << sl << std::endl;

	if((rightDir == MC_MOTOR_REVERSE) || (leftDir == MC_MOTOR_REVERSE))
	{
		//atach dbg here
		std::cout << "robot is moving backwards!!!" << std::endl;
	}

	return false;
}
#endif
joystick_reply_t OSMC_driver::getJoystickData()
{

	ai.sendCommand(MC_GET_JOYSTICK, NULL, 0);

	byte retcmd = 0;
	byte* data = NULL;
	ai.recvCommand(retcmd, data);

	joystick_reply_t out;

	memcpy(&out, data, sizeof(current_reply_t));
	delete[] data;
	return out;
}

// start dumb + hysteresis control code
void OSMC_driver::getNewVel_dumb(const double rtarget, const double ltarget, const double rvel, const double lvel, const int rmset, const int lmset,  int& out_rmset, int& out_lmset)
{
	int posstep = 1;
	int negstep = -1;

	double thresh = .03;

	double lerror = ltarget - lvel;
	double rerror = rtarget - rvel;

	if(lerror > thresh)
	{
		out_lmset = lmset + posstep;
	}
	else if(lerror < -thresh)
	{
		out_lmset = lmset + negstep;
	}
	else
	{
		out_lmset = lmset;
	}

	if(rerror > thresh)
	{
		out_rmset = rmset + posstep;
	}
	else if(rerror < -thresh)
	{
		out_rmset = rmset + negstep;
	}
	else
	{
		out_rmset = rmset;
	}
}

void OSMC_driver::setVel_pd(double left, double right)
{
	lvgoal = left;
	rvgoal = right;
}

bool OSMC_driver::updateVel_pd()
{
	double now_rvel, now_lvel;
	timeval now_t;
	gettimeofday(&now_t, NULL);

	encoder->getEncoderVel(now_rvel, now_lvel);

	double now_t_d = double(now_t.tv_sec) + double(1e-6)*double(now_t.tv_usec);
	double dt = now_t_d - t;

	int out_lmset, out_rmset;
	getNewVel_pd(now_lvel, now_rvel, dt, out_rmset, out_lmset);

	t = now_t_d;

	return set_motors(out_lmset, out_rmset);
}

//this won't change the sign of the pwm freq
void OSMC_driver::getNewVel_pd(const double now_lvel, const double now_rvel, const double dt, int& out_r, int& out_l)
{
	const double kp = .1;
	const double kd = .1;

	double lerror = lvgoal - now_lvel;
	double rerror = rvgoal - now_rvel;

	double lerror_slope = (lerror - last_l_error) / dt;
	double rerror_slope = (rerror - last_r_error) / dt;

	out_l = lpwm + -kp*lerror + -kd*lerror_slope;
	out_r = rpwm + -kp*rerror + -kd*rerror_slope;

	//persist the stuff that needs to be saved
	last_l_error = lerror;
	last_r_error = rerror;
}

void OSMC_driver::getLastPWMSent(byte& r, byte& l)
{
	r = rpwm;
	l = lpwm;
}
<|endoftext|>


<commit_before>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;
static ID id_to_value_set;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    void* object = 0;
    Data_Get_Struct(self, void, object);
    return *reinterpret_cast<ValueSet*>(object);
}
static void value_set_mark(ValueSet const* set)
{ std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set)
{ delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for_each(set.begin(), set.end(), rb_yield);
    return self;
}
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}
static VALUE value_set_to_value_set(VALUE self) { return self; }
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
{
    set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
    if (seen.find(i) == seen.end())
    {
	seen.insert(i);
	return rb_yield(i);
    }
    else
	return Qnil;

}

static VALUE enumerable_each_uniq(VALUE self)
{
    set<VALUE> seen;
    rb_iterate(rb_each, self,
	    RUBY_METHOD_FUNC(enumerable_each_uniq_i), (VALUE)&seen);
    return self;
}

extern "C" void Init_faster()
{
    rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    id_to_value_set = rb_intern("to_value_set");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
}

<commit_msg>[value_set] define #==<commit_after>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;
static ID id_to_value_set;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    void* object = 0;
    Data_Get_Struct(self, void, object);
    return *reinterpret_cast<ValueSet*>(object);
}
static void value_set_mark(ValueSet const* set)
{ std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set)
{ delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for_each(set.begin(), set.end(), rb_yield);
    return self;
}
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}
static VALUE value_set_to_value_set(VALUE self) { return self; }
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

/* call-seq:
 *  set == other		=> true or false
 *
 * Equality
 */
static VALUE value_set_equal(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return (self == other) ? Qtrue : Qfalse;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
{
    set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
    if (seen.find(i) == seen.end())
    {
	seen.insert(i);
	return rb_yield(i);
    }
    else
	return Qnil;

}

static VALUE enumerable_each_uniq(VALUE self)
{
    set<VALUE> seen;
    rb_iterate(rb_each, self,
	    RUBY_METHOD_FUNC(enumerable_each_uniq_i), (VALUE)&seen);
    return self;
}

extern "C" void Init_faster()
{
    rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    id_to_value_set = rb_intern("to_value_set");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
}

<|endoftext|>


<commit_before>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;
static ID id_to_value_set;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    ValueSet* object = 0;
    Data_Get_Struct(self, ValueSet, object);
    return *object;
}

static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set) { delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
/* call-seq:
 *  set.empty?			    => true or false
 *
 * Checks if this set is empty
 */
static VALUE value_set_empty_p(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return set.empty() ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.size			    => size
 *
 * Returns this set size
 */
static VALUE value_set_size(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return INT2NUM(set.size());
}

/* call-seq:
 *  set.each { |obj| ... }	    => set
 *
 */
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for_each(set.begin(), set.end(), rb_yield);
    return self;
}
/* call-seq:
 *  set.include?(value)	    => true or false
 *
 * Checks if +value+ is in +set+
 */
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}

/* call-seq:
 *  set.to_value_set		    => set
 */
static VALUE value_set_to_value_set(VALUE self) { return self; }

/* call-seq:
 *  set.include_all?(other)		=> true or false
 *
 * Checks if all elements of +other+ are in +set+
 */
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.union(other)		=> union_set
 *  set | other			=> union_set
 *
 * Computes the union of +set+ and +other+. This operation is O(N + M)
 * is +other+ is a ValueSet
 */
static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}
/* call-seq:
 *   set.difference(other)	=> difference_set
 *   set - other		=> difference_set
 *
 * Computes the set of all elements of +set+ not in +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.insert(value)		=> true or false
 *
 * Inserts +value+ into +set+. Returns true if the value did not exist
 * in the set yet (it has actually been inserted), and false otherwise.
 * This operation is O(log N)
 */
static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
/* call-seq:
 *  set.delete(value)		=> true or false
 *
 * Removes +value+ from +set+. Returns true if the value did exist
 * in the set yet (it has actually been removed), and false otherwise.
 */
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

/* call-seq:
 *  set == other		=> true or false
 *
 * Equality
 */
static VALUE value_set_equal(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return (self == other) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.clear			=> set
 *
 * Remove all elements of this set
 */
static VALUE value_set_clear(VALUE self)
{
    get_wrapped_set(self).clear();
    return self;
}

static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
{
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    set<VALUE> new_set(other.begin(), other.end());
    get_wrapped_set(vself).swap(new_set);
    return vself;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}
/* call-seq:
 *  enum.to_value_set		=> value_set
 *
 * Builds a ValueSet object from this enumerable
 */
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
{
    set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
    if (seen.find(i) == seen.end())
    {
	seen.insert(i);
	return rb_yield(i);
    }
    else
	return Qnil;

}

/* :nodoc: */
static VALUE enumerable_each_uniq(VALUE self)
{
    set<VALUE> seen;
    rb_iterate(rb_each, self,
	    RUBY_METHOD_FUNC(enumerable_each_uniq_i), (VALUE)&seen);
    return self;
}

/*
 * Document-class: ValueSet
 *
 * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
 * for which union(), intersection() and difference() is done in linear time. For performance
 * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
 * their object_id.
 */

extern "C" void Init_faster()
{
    rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    id_to_value_set = rb_intern("to_value_set");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
    rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
    rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
    rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
    rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
}

<commit_msg>[value_set] make sure we call #to_value_set everywhere an argument is expected to be a ValueSet object<commit_after>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;
static ID id_to_value_set;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    ValueSet* object = 0;
    Data_Get_Struct(self, ValueSet, object);
    return *object;
}

static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set) { delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
/* call-seq:
 *  set.empty?			    => true or false
 *
 * Checks if this set is empty
 */
static VALUE value_set_empty_p(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return set.empty() ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.size			    => size
 *
 * Returns this set size
 */
static VALUE value_set_size(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return INT2NUM(set.size());
}

/* call-seq:
 *  set.each { |obj| ... }	    => set
 *
 */
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for_each(set.begin(), set.end(), rb_yield);
    return self;
}
/* call-seq:
 *  set.include?(value)	    => true or false
 *
 * Checks if +value+ is in +set+
 */
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}

/* call-seq:
 *  set.to_value_set		    => set
 */
static VALUE value_set_to_value_set(VALUE self) { return self; }

/* call-seq:
 *  set.include_all?(other)		=> true or false
 *
 * Checks if all elements of +other+ are in +set+
 */
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.union(other)		=> union_set
 *  set | other			=> union_set
 *
 * Computes the union of +set+ and +other+. This operation is O(N + M)
 * is +other+ is a ValueSet
 */
static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}
/* call-seq:
 *   set.difference(other)	=> difference_set
 *   set - other		=> difference_set
 *
 * Computes the set of all elements of +set+ not in +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.insert(value)		=> true or false
 *
 * Inserts +value+ into +set+. Returns true if the value did not exist
 * in the set yet (it has actually been inserted), and false otherwise.
 * This operation is O(log N)
 */
static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
/* call-seq:
 *  set.delete(value)		=> true or false
 *
 * Removes +value+ from +set+. Returns true if the value did exist
 * in the set yet (it has actually been removed), and false otherwise.
 */
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

/* call-seq:
 *  set == other		=> true or false
 *
 * Equality
 */
static VALUE value_set_equal(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    return (self == other) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.clear			=> set
 *
 * Remove all elements of this set
 */
static VALUE value_set_clear(VALUE self)
{
    get_wrapped_set(self).clear();
    return self;
}

static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
{
    ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
    set<VALUE> new_set(other.begin(), other.end());
    get_wrapped_set(vself).swap(new_set);
    return vself;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}
/* call-seq:
 *  enum.to_value_set		=> value_set
 *
 * Builds a ValueSet object from this enumerable
 */
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
{
    set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
    if (seen.find(i) == seen.end())
    {
	seen.insert(i);
	return rb_yield(i);
    }
    else
	return Qnil;

}

/* :nodoc: */
static VALUE enumerable_each_uniq(VALUE self)
{
    set<VALUE> seen;
    rb_iterate(rb_each, self,
	    RUBY_METHOD_FUNC(enumerable_each_uniq_i), (VALUE)&seen);
    return self;
}

/*
 * Document-class: ValueSet
 *
 * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
 * for which union(), intersection() and difference() is done in linear time. For performance
 * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
 * their object_id.
 */

extern "C" void Init_faster()
{
    rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    id_to_value_set = rb_intern("to_value_set");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
    rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
    rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
    rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
    rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
}

<|endoftext|>


<commit_before>//! @Alan @pezy
//!
//! Exercise 9.24:
//! Write a program that fetches the first element in a vector using at,
//! the subscript operator, front, and begin. Test your program on an empty vector.
//!
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    std::cout << v.at(0);       // terminating with uncaught exception of type std::out_of_range
    std::cout << v[0];          // Segmentation fault: 11
    std::cout << v.front();     // Segmentation fault: 11
    std::cout << *v.begin();    // Segmentation fault: 11
    return 0;
}
<commit_msg>Update ex9_24.cpp<commit_after>//! @Yue Wang @pezy
//!
//! Exercise 9.24:
//! Write a program that fetches the first element in a vector using at,
//! the subscript operator, front, and begin. Test your program on an empty vector.
//!
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    std::cout << v.at(0);       // terminating with uncaught exception of type std::out_of_range
    std::cout << v[0];          // Segmentation fault: 11
    std::cout << v.front();     // Segmentation fault: 11
    std::cout << *v.begin();    // Segmentation fault: 11
    return 0;
}
<|endoftext|>


<commit_before>// ASAN example: stack buffer overflow

#include <array>
#include <iostream>

int main(int argc, char** argv)
{
    std::array<const char*, 3> data{ "no", "one", "two" };
    std::cout << "You passed " << data[argc - 1] << " args(s)\n";
    return 0;
}
<commit_msg>replacing 'const char*' with 'std::string' to ensure data on the stack<commit_after>// ASAN example: stack buffer overflow

#include <array>
#include <iostream>

int main(int argc, char** argv)
{
    std::array<std::string, 3> data{ "no", "one", "two" };
    std::cout << "You passed " << data[argc - 1] << " args(s)\n";
    return 0;
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * 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 Google Inc. 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 <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Handle;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
  NanScope();
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  NanEscapableScope();
  if (buffer == NULL) {
    return NanEscapeScope(NanNull());
  }
  size_t length = grpc_byte_buffer_length(buffer);
  char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
  size_t offset = 0;
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice next;
  while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
    memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
    offset += GPR_SLICE_LENGTH(next);
  }
  return NanEscapeScope(MakeFastBuffer(NanNewBufferHandle(result, length)));
}

Handle<Value> MakeFastBuffer(Handle<Value> slowBuffer) {
  NanEscapableScope();
  Handle<Object> globalObj = NanGetCurrentContext()->Global();
  Handle<Function> bufferConstructor = Handle<Function>::Cast(
      globalObj->Get(NanNew("Buffer")));
  Handle<Value> consArgs[3] = {
    slowBuffer,
    NanNew<Number>(::node::Buffer::Length(slowBuffer)),
    NanNew<Number>(0)
  };
  Handle<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return NanEscapeScope(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<commit_msg>Changes to byte_buffer based on comments.<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * 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 Google Inc. 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 <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Handle;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
  NanScope();
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  NanEscapableScope();
  if (buffer == NULL) {
    return NanEscapeScope(NanNull());
  }
  size_t length = grpc_byte_buffer_length(buffer);
  char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
  size_t offset = 0;
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice next;
  while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
    memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
    offset += GPR_SLICE_LENGTH(next);
  }
  return NanEscapeScope(MakeFastBuffer(NanNewBufferHandle(result, length)));
}

Handle<Value> MakeFastBuffer(Handle<Value> slowBuffer) {
  NanEscapableScope();
  Handle<Object> globalObj = NanGetCurrentContext()->Global();
  Handle<Function> bufferConstructor = Handle<Function>::Cast(
      globalObj->Get(NanNew("Buffer")));
  Handle<Value> consArgs[3] = {
    slowBuffer,
    NanNew<Number>(::node::Buffer::Length(slowBuffer)),
    NanNew<Number>(0)
  };
  Handle<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return NanEscapeScope(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<|endoftext|>


<commit_before>/*
 * ImageFromMemoryBuffer.hpp
 *
 *  Created on: Oct 31, 2014
 *      Author: Pete Schultz
 *  Description of the class is in ImageFromMemoryBuffer.hpp
 */

#include "ImageFromMemoryBuffer.hpp"

namespace PV {

ImageFromMemoryBuffer::ImageFromMemoryBuffer(char const * name, HyPerCol * hc) {
   initialize_base();
   initialize(name, hc);
}

ImageFromMemoryBuffer::ImageFromMemoryBuffer() {
   initialize_base();
   // protected default constructor; initialize(name,hc) should be called by any derived class's initialization routine
}

int ImageFromMemoryBuffer::initialize_base() {
   buffer = NULL;
   return PV_SUCCESS;
}

int ImageFromMemoryBuffer::initialize(char const * name, HyPerCol * hc) {
   return Image::initialize(name, hc);
}

template <typename pixeltype>
int ImageFromMemoryBuffer::setMemoryBuffer(pixeltype const * externalBuffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, pixeltype zeroval, pixeltype oneval) {
   if (height<=0 || width<=0 || numbands<=0) {
      if (parent->columnId()==0) {
         fprintf(stderr, "ImageFromMemoryBuffer::setMemoryBuffer error: height, width, numbands arguments must be positive.\n");
      }
      return PV_FAILURE;
   }
   imageLoc.nx = height;
   imageLoc.ny = width;
   imageLoc.nf = numbands;
   imageLoc.nxGlobal = height;
   imageLoc.nyGlobal = width;
   imageLoc.kx0 = 0;
   imageLoc.ky0 = 0;
   memset(&imageLoc.halo, 0, sizeof(PVHalo));

   if (parent->columnId()==0) {
      int buffersize = height*width*numbands;
      buffer = (pvadata_t *) malloc((size_t) buffersize * sizeof(pvadata_t));
      if (buffer==NULL) {
         fprintf(stderr, "%s \"%s\": unable to allocate buffer for %d values of %zu chars each: %s\n",
               parent->parameters()->groupKeywordFromName(name), name, buffersize, sizeof(pvadata_t), strerror(errno));
         exit(EXIT_FAILURE);
      }
      for (int k=0; k<buffersize; k++) {
         int x=kxPos(k,width,height,numbands);
         int y=kyPos(k,width,height,numbands);
         int f=featureIndex(k,width,height,numbands);
         int externalIndex = f*bandstride + x*xstride + y*ystride;
         pixeltype q = externalBuffer[externalIndex];
         buffer[k] = pixelTypeConvert(q, zeroval, oneval);
      }
   }

   hasNewImageFlag = true;

   HyPerLayer::outputState(parent->simulationTime(), parent->getDeltaTime());

   return PV_SUCCESS;
}
template int ImageFromMemoryBuffer::setMemoryBuffer<uint8_t>(uint8_t const * buffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, uint8_t zeroval, uint8_t oneval);

template <typename pixeltype>
int ImageFromMemoryBuffer::setMemoryBuffer(pixeltype const * externalBuffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, pixeltype zeroval, pixeltype oneval, int offsetX, int offsetY, char const * offsetAnchor) {
   offsets[0] = offsetX;
   offsets[1] = offsetY;
   free(this->offsetAnchor);
   this->offsetAnchor = strdup(offsetAnchor);
   if (checkValidAnchorString()!=PV_SUCCESS) {
      if (parent->columnId()==0) {
         fprintf(stderr, "%s \"%s\" error: setMemoryBuffer called with invalid anchor string \"%s\"",
               parent->parameters()->groupKeywordFromName(name), name, offsetAnchor);
      }
      MPI_Barrier(parent->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   return setMemoryBuffer(externalBuffer, height, width, numbands, xstride, ystride, bandstride, zeroval, oneval);
}
template int ImageFromMemoryBuffer::setMemoryBuffer<uint8_t>(uint8_t const * buffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, uint8_t zeroval, uint8_t oneval, int offsetX, int offsetY, char const * offsetAnchor);

template <typename pixeltype>
pvadata_t ImageFromMemoryBuffer::pixelTypeConvert(pixeltype q, pixeltype zeroval, pixeltype oneval) {
   return ((pvadata_t) (q-zeroval))/((pvadata_t) (oneval-zeroval));
}

int ImageFromMemoryBuffer::initializeActivity() {
   return copyBuffer();
}

int ImageFromMemoryBuffer::updateState(double time, double dt) {
   return copyBuffer();
}

int ImageFromMemoryBuffer::copyBuffer() {
   int status = PV_SUCCESS;
   if (!hasNewImageFlag) { return status; }
   Communicator * icComm = parent->icCommunicator();
   if (parent->columnId()==0) {
      if (buffer == NULL) {
         fprintf(stderr, "%s \"%s\" error: moveBufferToData called without having called setMemoryBuffer.\n",
               parent->parameters()->groupKeywordFromName(name), name);
         exit(PV_FAILURE); // return PV_FAILURE;
      }
      for (int rank=1; rank<icComm->commSize(); rank++) {
         status = moveBufferToData(rank);
         assert(status == PV_SUCCESS);
         MPI_Send(data, getNumExtended(), MPI_FLOAT, rank, 31, icComm->communicator());
      }
      status = moveBufferToData(0);
      assert(status == PV_SUCCESS);
   }
   else {
      MPI_Recv(data, getNumExtended(), MPI_FLOAT, 0, 31, icComm->communicator(), MPI_STATUS_IGNORE);
   }
   hasNewImageFlag = false;
   return status;
}

int ImageFromMemoryBuffer::moveBufferToData(int rank) {
   if (autoResizeFlag) {
      fprintf(stderr, "autoResizeFlag not implemented for ImageFromMemoryBuffer yet :-(\n");
      exit(EXIT_FAILURE);
   }
   assert(parent->columnId()==0);
   assert(buffer != NULL);

   // The part of the buffer with x in [processcolumnnumber * nx, processcolumnnumber * (nx + 1) - 1]
   // and y in [processcolumnnumber * nx, processcolumnnumber * (nx + 1) - 1]
   // gets copied to the restricted space of the given rank.
   // If useImageBCflag is set, we also have to copy as much of the surrounding region as
   // will fit in both the halo and the image.
   // Are we also supposed to mirror any gap between the edge of the image and the edge of the halo?
   // The code doesn't do that at this point.
   // The code below assumes that all processes have the same getLayerLoc().
   Communicator * icComm = parent->icCommunicator();
   int column = columnFromRank(rank, icComm->numCommRows(), icComm->numCommColumns());
   int startxbuffer = getOffsetX(this->offsetAnchor, this->offsets[0]) + column * getLayerLoc()->nx;
   int startxdata = getLayerLoc()->halo.lt;
   int row = rowFromRank(rank, icComm->numCommRows(), icComm->numCommColumns());
   int startybuffer = getOffsetX(this->offsetAnchor, this->offsets[0]) + row * getLayerLoc()->ny;
   int startydata = getLayerLoc()->halo.up;
   int xsize = getLayerLoc()->nx;
   int ysize = getLayerLoc()->ny;
   int fsize = getLayerLoc()->nf;
   PVHalo const * halo = &getLayerLoc()->halo;
   if (useImageBCflag) {

      int moveleft = startxbuffer;
      if (halo->lt < moveleft) {
         moveleft = halo->lt;
      }
      if (moveleft > 0) {
         startxbuffer -= moveleft;
         startxdata -= moveleft;
         xsize += moveleft;
      }

      int moveright = imageLoc.nx - (startxbuffer + xsize);
      if (halo->rt < moveright) {
         moveright = halo->rt;
      }
      if (moveright > 0) {
         xsize += moveright;
      }

      int moveup = startybuffer;
      if (halo->up < moveup) {
         moveup = halo->up;
      }
      if (moveup > 0) {
         startybuffer -= moveup;
         startydata -= moveup;
         ysize += moveup;
      }

      int movedown = imageLoc.ny - (startybuffer + ysize);
      if (halo->dn < movedown) {
         movedown = halo->dn;
      }
      if (movedown > 0) {
         ysize += movedown;
      }
   }
   assert(startxbuffer >= 0 && startxbuffer + xsize <= imageLoc.nxGlobal);
   assert(startybuffer >= 0 && startybuffer + ysize <= imageLoc.nyGlobal);
   if (fsize != 1 && fsize != imageLoc.nf) {
      fprintf(stderr, "%s \"%s\": If nf is greater than 1, or numbands must be the same as nf\n", parent->parameters()->groupKeywordFromName(name), name);
      exit(EXIT_FAILURE);
   }
   if (fsize != imageLoc.nf) {
      assert(fsize == 1);
      // layer has one feature; convert memory buffer to grayscale
      for (int y=0; y<ysize; y++) {
         for (int x=0; x<xsize; x++) {
            int indexdata = kIndex(startxdata+x,startydata+y,0,getLayerLoc()->nx+halo->lt+halo->rt,getLayerLoc()->ny+halo->dn+halo->up,1);
            int indexbuffer = kIndex(startxdata+x,startydata+y,0,imageLoc.nx,imageLoc.ny,imageLoc.nf);
            pvdata_t val = (pvadata_t) 0;
            for (int f=0; f<imageLoc.nf; f++) {
               val += buffer[indexbuffer+f];
            }
            data[indexdata] = val/(pvadata_t) imageLoc.nf;
         }
      }
   }
   else {
      // layer and memory buffer have the same number of features
      for (int y=0; y<ysize; y++) {
         int linestartdata = kIndex(startxdata,startydata+y,0,getLayerLoc()->nx+halo->lt+halo->rt,getLayerLoc()->ny+halo->dn+halo->up,fsize);
         int linestartbuffer = kIndex(startxbuffer,startybuffer+y,0,imageLoc.nx,imageLoc.ny,fsize);
         memcpy(&data[linestartdata], &buffer[linestartbuffer], sizeof(pvadata_t) * xsize * fsize);
      }
   }
   return PV_SUCCESS;
}

ImageFromMemoryBuffer::~ImageFromMemoryBuffer() {
   free(buffer);
}

}  // namespace PV
<commit_msg>setMemoryBuffer shouldn't call outputState<commit_after>/*
 * ImageFromMemoryBuffer.hpp
 *
 *  Created on: Oct 31, 2014
 *      Author: Pete Schultz
 *  Description of the class is in ImageFromMemoryBuffer.hpp
 */

#include "ImageFromMemoryBuffer.hpp"

namespace PV {

ImageFromMemoryBuffer::ImageFromMemoryBuffer(char const * name, HyPerCol * hc) {
   initialize_base();
   initialize(name, hc);
}

ImageFromMemoryBuffer::ImageFromMemoryBuffer() {
   initialize_base();
   // protected default constructor; initialize(name,hc) should be called by any derived class's initialization routine
}

int ImageFromMemoryBuffer::initialize_base() {
   buffer = NULL;
   return PV_SUCCESS;
}

int ImageFromMemoryBuffer::initialize(char const * name, HyPerCol * hc) {
   return Image::initialize(name, hc);
}

template <typename pixeltype>
int ImageFromMemoryBuffer::setMemoryBuffer(pixeltype const * externalBuffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, pixeltype zeroval, pixeltype oneval) {
   if (height<=0 || width<=0 || numbands<=0) {
      if (parent->columnId()==0) {
         fprintf(stderr, "ImageFromMemoryBuffer::setMemoryBuffer error: height, width, numbands arguments must be positive.\n");
      }
      return PV_FAILURE;
   }
   imageLoc.nx = height;
   imageLoc.ny = width;
   imageLoc.nf = numbands;
   imageLoc.nxGlobal = height;
   imageLoc.nyGlobal = width;
   imageLoc.kx0 = 0;
   imageLoc.ky0 = 0;
   memset(&imageLoc.halo, 0, sizeof(PVHalo));

   if (parent->columnId()==0) {
      int buffersize = height*width*numbands;
      buffer = (pvadata_t *) malloc((size_t) buffersize * sizeof(pvadata_t));
      if (buffer==NULL) {
         fprintf(stderr, "%s \"%s\": unable to allocate buffer for %d values of %zu chars each: %s\n",
               parent->parameters()->groupKeywordFromName(name), name, buffersize, sizeof(pvadata_t), strerror(errno));
         exit(EXIT_FAILURE);
      }
      for (int k=0; k<buffersize; k++) {
         int x=kxPos(k,width,height,numbands);
         int y=kyPos(k,width,height,numbands);
         int f=featureIndex(k,width,height,numbands);
         int externalIndex = f*bandstride + x*xstride + y*ystride;
         pixeltype q = externalBuffer[externalIndex];
         buffer[k] = pixelTypeConvert(q, zeroval, oneval);
      }
   }

   hasNewImageFlag = true;

   return PV_SUCCESS;
}
template int ImageFromMemoryBuffer::setMemoryBuffer<uint8_t>(uint8_t const * buffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, uint8_t zeroval, uint8_t oneval);

template <typename pixeltype>
int ImageFromMemoryBuffer::setMemoryBuffer(pixeltype const * externalBuffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, pixeltype zeroval, pixeltype oneval, int offsetX, int offsetY, char const * offsetAnchor) {
   offsets[0] = offsetX;
   offsets[1] = offsetY;
   free(this->offsetAnchor);
   this->offsetAnchor = strdup(offsetAnchor);
   if (checkValidAnchorString()!=PV_SUCCESS) {
      if (parent->columnId()==0) {
         fprintf(stderr, "%s \"%s\" error: setMemoryBuffer called with invalid anchor string \"%s\"",
               parent->parameters()->groupKeywordFromName(name), name, offsetAnchor);
      }
      MPI_Barrier(parent->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   return setMemoryBuffer(externalBuffer, height, width, numbands, xstride, ystride, bandstride, zeroval, oneval);
}
template int ImageFromMemoryBuffer::setMemoryBuffer<uint8_t>(uint8_t const * buffer, int height, int width, int numbands, int xstride, int ystride, int bandstride, uint8_t zeroval, uint8_t oneval, int offsetX, int offsetY, char const * offsetAnchor);

template <typename pixeltype>
pvadata_t ImageFromMemoryBuffer::pixelTypeConvert(pixeltype q, pixeltype zeroval, pixeltype oneval) {
   return ((pvadata_t) (q-zeroval))/((pvadata_t) (oneval-zeroval));
}

int ImageFromMemoryBuffer::initializeActivity() {
   return copyBuffer();
}

int ImageFromMemoryBuffer::updateState(double time, double dt) {
   return copyBuffer();
}

int ImageFromMemoryBuffer::copyBuffer() {
   int status = PV_SUCCESS;
   if (!hasNewImageFlag) { return status; }
   Communicator * icComm = parent->icCommunicator();
   if (parent->columnId()==0) {
      if (buffer == NULL) {
         fprintf(stderr, "%s \"%s\" error: moveBufferToData called without having called setMemoryBuffer.\n",
               parent->parameters()->groupKeywordFromName(name), name);
         exit(PV_FAILURE); // return PV_FAILURE;
      }
      for (int rank=1; rank<icComm->commSize(); rank++) {
         status = moveBufferToData(rank);
         assert(status == PV_SUCCESS);
         MPI_Send(data, getNumExtended(), MPI_FLOAT, rank, 31, icComm->communicator());
      }
      status = moveBufferToData(0);
      assert(status == PV_SUCCESS);
   }
   else {
      MPI_Recv(data, getNumExtended(), MPI_FLOAT, 0, 31, icComm->communicator(), MPI_STATUS_IGNORE);
   }
   hasNewImageFlag = false;
   return status;
}

int ImageFromMemoryBuffer::moveBufferToData(int rank) {
   if (autoResizeFlag) {
      fprintf(stderr, "autoResizeFlag not implemented for ImageFromMemoryBuffer yet :-(\n");
      exit(EXIT_FAILURE);
   }
   assert(parent->columnId()==0);
   assert(buffer != NULL);

   // The part of the buffer with x in [processcolumnnumber * nx, processcolumnnumber * (nx + 1) - 1]
   // and y in [processcolumnnumber * nx, processcolumnnumber * (nx + 1) - 1]
   // gets copied to the restricted space of the given rank.
   // If useImageBCflag is set, we also have to copy as much of the surrounding region as
   // will fit in both the halo and the image.
   // Are we also supposed to mirror any gap between the edge of the image and the edge of the halo?
   // The code doesn't do that at this point.
   // The code below assumes that all processes have the same getLayerLoc().
   Communicator * icComm = parent->icCommunicator();
   int column = columnFromRank(rank, icComm->numCommRows(), icComm->numCommColumns());
   int startxbuffer = getOffsetX(this->offsetAnchor, this->offsets[0]) + column * getLayerLoc()->nx;
   int startxdata = getLayerLoc()->halo.lt;
   int row = rowFromRank(rank, icComm->numCommRows(), icComm->numCommColumns());
   int startybuffer = getOffsetX(this->offsetAnchor, this->offsets[0]) + row * getLayerLoc()->ny;
   int startydata = getLayerLoc()->halo.up;
   int xsize = getLayerLoc()->nx;
   int ysize = getLayerLoc()->ny;
   int fsize = getLayerLoc()->nf;
   PVHalo const * halo = &getLayerLoc()->halo;
   if (useImageBCflag) {

      int moveleft = startxbuffer;
      if (halo->lt < moveleft) {
         moveleft = halo->lt;
      }
      if (moveleft > 0) {
         startxbuffer -= moveleft;
         startxdata -= moveleft;
         xsize += moveleft;
      }

      int moveright = imageLoc.nx - (startxbuffer + xsize);
      if (halo->rt < moveright) {
         moveright = halo->rt;
      }
      if (moveright > 0) {
         xsize += moveright;
      }

      int moveup = startybuffer;
      if (halo->up < moveup) {
         moveup = halo->up;
      }
      if (moveup > 0) {
         startybuffer -= moveup;
         startydata -= moveup;
         ysize += moveup;
      }

      int movedown = imageLoc.ny - (startybuffer + ysize);
      if (halo->dn < movedown) {
         movedown = halo->dn;
      }
      if (movedown > 0) {
         ysize += movedown;
      }
   }
   assert(startxbuffer >= 0 && startxbuffer + xsize <= imageLoc.nxGlobal);
   assert(startybuffer >= 0 && startybuffer + ysize <= imageLoc.nyGlobal);
   if (fsize != 1 && fsize != imageLoc.nf) {
      fprintf(stderr, "%s \"%s\": If nf is greater than 1, or numbands must be the same as nf\n", parent->parameters()->groupKeywordFromName(name), name);
      exit(EXIT_FAILURE);
   }
   if (fsize != imageLoc.nf) {
      assert(fsize == 1);
      // layer has one feature; convert memory buffer to grayscale
      for (int y=0; y<ysize; y++) {
         for (int x=0; x<xsize; x++) {
            int indexdata = kIndex(startxdata+x,startydata+y,0,getLayerLoc()->nx+halo->lt+halo->rt,getLayerLoc()->ny+halo->dn+halo->up,1);
            int indexbuffer = kIndex(startxdata+x,startydata+y,0,imageLoc.nx,imageLoc.ny,imageLoc.nf);
            pvdata_t val = (pvadata_t) 0;
            for (int f=0; f<imageLoc.nf; f++) {
               val += buffer[indexbuffer+f];
            }
            data[indexdata] = val/(pvadata_t) imageLoc.nf;
         }
      }
   }
   else {
      // layer and memory buffer have the same number of features
      for (int y=0; y<ysize; y++) {
         int linestartdata = kIndex(startxdata,startydata+y,0,getLayerLoc()->nx+halo->lt+halo->rt,getLayerLoc()->ny+halo->dn+halo->up,fsize);
         int linestartbuffer = kIndex(startxbuffer,startybuffer+y,0,imageLoc.nx,imageLoc.ny,fsize);
         memcpy(&data[linestartdata], &buffer[linestartbuffer], sizeof(pvadata_t) * xsize * fsize);
      }
   }
   return PV_SUCCESS;
}

ImageFromMemoryBuffer::~ImageFromMemoryBuffer() {
   free(buffer);
}

}  // namespace PV
<|endoftext|>


<commit_before>class AmbientEnvironment {
        title = "    Ambient - Environment";
        values[]= {0};
        texts[]= {" "};
        default = 0;
};
class AmbientCivs {
        title = "        Enable Civilians";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 1;
};
class AmbientVehs {
        title = "        Enable Civilian Vehicles";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 0;
};
class AmbientAnimals {
        title = "        Enable Animals";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 0;
};
<commit_msg>[CRB_CIVILIANS] - Renabled Vehicles and Animals as testing shows no sustained impact<commit_after>class AmbientEnvironment {
        title = "    Ambient - Environment";
        values[]= {0};
        texts[]= {" "};
        default = 0;
};
class AmbientCivs {
        title = "        Enable Civilians";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 1;
};
class AmbientVehs {
        title = "        Enable Civilian Vehicles";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 1;
};
class AmbientAnimals {
        title = "        Enable Animals";
        values[]= {0,1};
        texts[]= {"Off", "On"};
        default = 1;
};
<|endoftext|>


<commit_before>#include "request_router.h"

#include "request.h"
#include "response.h"

rs::httpserver::RequestRouter::RequestRouter() :
    routes_({ {"GET",{}}, {"PUT",{}}, {"POST",{}}, {"DELETE",{}}, {"HEAD",{}} }) {
}

void rs::httpserver::RequestRouter::Add(const char* method, const char* re, Callback func) {
    std::vector<std::string> namedGroups;

    const char* namedGroupStart = re;
    while ((namedGroupStart = std::strstr(namedGroupStart, "(?<")) != nullptr) {
        namedGroupStart += 3;
        auto namedGroupPtr = namedGroupStart;
        while (*namedGroupPtr != '>' && *namedGroupPtr) {
            ++namedGroupPtr;
        }

        namedGroups.emplace_back(namedGroupStart, namedGroupPtr);
        namedGroupStart = namedGroupPtr + 1;
    }

    if (routes_.find(method) == routes_.cend()) {
        routes_[method] = {};
    }

    routes_[method].push_back(std::make_tuple(boost::basic_regex<char>(re), func, namedGroups));
}

bool rs::httpserver::RequestRouter::Match(request_ptr request, response_ptr response) const {
    auto method = request->getMethod();
    auto methodRoutes = routes_.find(method);

    for (auto route : methodRoutes->second) {
        boost::match_results<const char*> what;
        if (boost::regex_match(request->getUri().c_str(), what, std::get<0>(route))) {
            CallbackArgs groups;
            std::vector<std::string> heapValues;
            for (auto& name : std::get<2>(route)) {
                auto value = what[name];
                auto valueLength = value.second - value.first;
                if (valueLength < 128) {
                    auto valueBuffer = reinterpret_cast<char*>(alloca(valueLength + 1));
                    std::strncpy(valueBuffer, value.first, valueLength);
                    valueBuffer[valueLength] = '\0';
                    groups.emplace(name.c_str(), valueBuffer);
                } else {
                    heapValues.emplace_back(value.str());
                    groups.emplace(name.c_str(), heapValues.back().c_str());
                }
            }
            if ((std::get<1>(route))(request, groups, response)) {
                return true;
            }
        }
    }
    return false;
}   <commit_msg>Fixed a bug where when the router failed to match the http request method<commit_after>#include "request_router.h"

#include "request.h"
#include "response.h"

rs::httpserver::RequestRouter::RequestRouter() :
    routes_({ {"GET",{}}, {"PUT",{}}, {"POST",{}}, {"DELETE",{}}, {"HEAD",{}} }) {
}

void rs::httpserver::RequestRouter::Add(const char* method, const char* re, Callback func) {
    std::vector<std::string> namedGroups;

    const char* namedGroupStart = re;
    while ((namedGroupStart = std::strstr(namedGroupStart, "(?<")) != nullptr) {
        namedGroupStart += 3;
        auto namedGroupPtr = namedGroupStart;
        while (*namedGroupPtr != '>' && *namedGroupPtr) {
            ++namedGroupPtr;
        }

        namedGroups.emplace_back(namedGroupStart, namedGroupPtr);
        namedGroupStart = namedGroupPtr + 1;
    }

    if (routes_.find(method) == routes_.cend()) {
        routes_[method] = {};
    }

    routes_[method].push_back(std::make_tuple(boost::basic_regex<char>(re), func, namedGroups));
}

bool rs::httpserver::RequestRouter::Match(request_ptr request, response_ptr response) const {
    auto method = request->getMethod();
    auto methodRoutes = routes_.find(method);

    if (methodRoutes != routes_.cend()) {
        for (auto route : methodRoutes->second) {
            boost::match_results<const char*> what;
            if (boost::regex_match(request->getUri().c_str(), what, std::get<0>(route))) {
                CallbackArgs groups;
                std::vector<std::string> heapValues;
                for (auto& name : std::get<2>(route)) {
                    auto value = what[name];
                    auto valueLength = value.second - value.first;
                    if (valueLength < 128) {
                        auto valueBuffer = reinterpret_cast<char*>(alloca(valueLength + 1));
                        std::strncpy(valueBuffer, value.first, valueLength);
                        valueBuffer[valueLength] = '\0';
                        groups.emplace(name.c_str(), valueBuffer);
                    } else {
                        heapValues.emplace_back(value.str());
                        groups.emplace(name.c_str(), heapValues.back().c_str());
                    }
                }
                if ((std::get<1>(route))(request, groups, response)) {
                    return true;
                }
            }
        }
    }

    return false;
}   <|endoftext|>