<commit_before>#include "tree.h"
#include "mpi_util.h"

#include <cstdlib>
#include <cmath>
#include <limits>
#include <utility>
#include <glog/logging.h>

Tree::Tree(unsigned int max_depth, unsigned int n_bins, unsigned int n_splits):
  max_depth_(max_depth), n_bins_(n_bins), n_splits_(n_splits),
  current_node_id_(0),
  current_depth_(0)
{
};

void Tree::Train(const DataMatrix& data) {
  Train(data, data.GetTargets());
};

void Tree::Train(const DataMatrix& data, const std::vector<double>& targets) {
  InitializeRootNode(data);
  while (current_depth_ < max_depth_) {
    ProcessCurrentNodes(data, targets);
    current_depth_ += 1;
  }
};

std::vector<double> Tree::Predict(const DataMatrix& data) const {
  std::vector<double> predictions;
  predictions.reserve(data.Size());
  for (unsigned int i = 0; i < data.Size(); ++i) {
  //LOG(INFO) << "Predicting for sample #" << i;
    predictions.push_back(Predict(data.GetRow(i)));
  }
  return predictions;
};

double Tree::Predict(const DataMatrix::SamplePoint& sample) const {
  return TraverseTree(sample);
};

void Tree::InitializeRootNode(const DataMatrix& data) {
  nodes_.resize(1 << (max_depth_+1));
  unsigned int root_id = current_node_id_++;
  Node& root = nodes_[root_id];
  root.samples.reserve(data.Size());
  root.depth = 0;
  // NOTE: Even if the almost unncessary label is to be filled, it has to be
  // determined by the master later.
  for (unsigned int i = 0; i < data.Size(); ++i) {
    root.samples.push_back(i);
  }
  current_queue_.push_back(root_id);
};

void Tree::ProcessCurrentNodes(const DataMatrix& data, const std::vector<double>& targets) {

  // Histograms are stored by features. In the distributed version, a message
  // completely covers a feature (over multiple nodes), so that the number of
  // messages sent does not grow with tree depth.
  // histograms[x][y]: Histogram for feature x at node y
  const std::vector<unsigned int> feature_keys = data.GetFeatureKeys();
  std::vector<std::vector<Histogram> > histograms(feature_keys.size(),
      std::vector<Histogram>(current_queue_.size(), Histogram(n_bins_)));

  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;

  //LOG(INFO) << "Rank: " << world.rank();
  //LOG(INFO) << "Environment intialized: " << env.initialized();

  // In case of slaves
  int total_reqs_push_histograms = histograms.size();
  mpi::request reqs_push_histograms[total_reqs_push_histograms];
  std::vector<HistogramsPerFeature> messages(total_reqs_push_histograms);

  for (unsigned int i = 0; i < feature_keys.size(); ++i) {
    unsigned int fkey = feature_keys[i];
    const auto& column = data.GetColumn(fkey);
    for (unsigned int j = 0; j < current_queue_.size(); ++j) {
      histograms[i][j] = ComputeHistogram(column, targets, nodes_[current_queue_[j]].samples);
    }
    messages[i].histograms = histograms[i];
    messages[i].feature_index = i; // TODO: i or fkey?
    if (world.rank() >= 1) {
      int tag = (world.rank()-1)*feature_keys.size() + i;
      //LOG(INFO) << "Push tag: " << tag;
      reqs_push_histograms[i] = world.isend(0, tag, messages[i]);
      // TODO: Need to run a dummy test() to kick start the process?
    }
  }

  if (world.rank() == 0 && world.size() > 1) {
    LOG(INFO) << "Pulling";
    MPI_PullHistograms(histograms);
  }
  else if (world.rank() >= 1) {
    LOG(INFO) << "Finalize pushing";
    mpi::wait_all(reqs_push_histograms, reqs_push_histograms + total_reqs_push_histograms);
    LOG(INFO) << "Pushed all histograms";
  }

  next_queue_.clear();

  // This way ordering of nodes in the next processing queue is defined by the
  // master process.
  std::vector<SplitResult> best_splits_by_nodes(current_queue_.size());

  if ( world.rank() == 0 ) {
    for (unsigned int j = 0; j < current_queue_.size(); ++j) {
      SplitResult best_result;
      best_result.can_split = false;
      best_result.cost = std::numeric_limits<double>::max();
      for (unsigned int i = 0; i < feature_keys.size(); ++i) {
        SplitResult result = FindBestSplit(histograms[i][j]);
        if (result.can_split && result.cost < best_result.cost) {
          // TODO: Options to check for number of observations per leaf, etc. Or
          // check for these within FindBestSplit using the histogram?
          best_result = result;
          best_result.feature_index = i;
        }
      }
      // TODO: Make a ref?
      best_splits_by_nodes[j] = best_result;
    }
    MPI_PushBestSplits(best_splits_by_nodes);
  }
  else {
    LOG(INFO) << "Receiving split results...";
    MPI_PullBestSplits(best_splits_by_nodes);
  }

  for (unsigned int j = 0; j < current_queue_.size(); ++j) {

    SplitResult& best_result = best_splits_by_nodes[j];

    if (!best_result.can_split) {
      return;
    }
    best_result.id_left = current_node_id_++;
    best_result.id_right = current_node_id_++;

    //LOG(INFO) << "Node [" << current_queue_[j] <<"]: Making a split on feature " << best_result.feature_index << " with threshold " << best_result.threshold << "; label_left: " << best_result.label_left << " label_right: " << best_result.label_right;

    FinalizeAndSplitNode(data, best_result, nodes_[current_queue_[j]]);

    //LOG(INFO) << "Done processing node " << current_queue_[j];
    next_queue_.push_back(best_result.id_left);
    next_queue_.push_back(best_result.id_right);
  }

  current_queue_.swap(next_queue_);
};

void Tree::MPI_PullHistograms(std::vector<std::vector<Histogram> >& histograms) const {
  // TODO: or pass in env and world?
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  int total_reqs = (world.size()-1) * histograms.size();
  //LOG(INFO) << "MPI_PullHistograms: # total reqs: " << total_reqs;
  mpi::request reqs[total_reqs];
  std::vector<HistogramsPerFeature> messages(total_reqs);
  for (unsigned int i = 0; i < histograms.size(); ++i) {
    for (int k = 1; k < world.size(); ++k) {
      int cur_idx = i*(world.size()-1) + (k-1);
      int tag = (k-1)*histograms.size() + i;
      //LOG(INFO) << "MPI_PullHistograms: Current message index to pull: " << cur_idx;
      reqs[cur_idx] = world.irecv(k, tag, messages[cur_idx]);
    }
  }
  LOG(INFO) << "MPI_PullHistograms: Start waiting for slave histograms";
  mpi::wait_all(reqs, reqs + total_reqs);
  LOG(INFO) << "MPI_PulHistograms: Finished waiting in pull";
  for (int i = 0; i < total_reqs; i++) {
    unsigned int feature_index = messages[i].feature_index;
    std::vector<Histogram>& h = messages[i].histograms;
    for (unsigned int j = 0; j < h.size(); ++j) {
      histograms[feature_index][j].Merge(h[j]);
    }
  }
};

void Tree::MPI_PushHistograms(const std::vector<std::vector<Histogram> >& histograms) const {
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
};

void Tree::MPI_PushBestSplits(const std::vector<SplitResult>& best_splits_by_nodes) const {
  LOG(INFO) << "MPI_PushBestSplits: Pushing best splits";
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  mpi::request reqs[world.size()-1];
  for (int k = 1; k < world.size(); ++k) {
    reqs[k-1] = world.isend(k, MPI_TagBestSplits(), best_splits_by_nodes);
  }
  mpi::wait_all(reqs, reqs + world.size() - 1);
  LOG(INFO) << "MPI_PushBestSplits: Pushes finalized";
};

void Tree::MPI_PullBestSplits(std::vector<SplitResult>& best_splits_by_nodes) const {
  LOG(INFO) << "MPI_PullBestSplits: Pulling best splits";
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  world.recv(0, MPI_TagBestSplits(), best_splits_by_nodes);
  LOG(INFO) << "MPI_PullBestSplits: Pull finalized";
};

int Tree::MPI_TagBestSplits() const {
  return 1001;
};

void Tree::FinalizeAndSplitNode(const DataMatrix& data, const SplitResult& result, Node& parent) {

  // Finalize current node
  parent.is_leaf = false;
  parent.feature_index = result.feature_index;
  parent.threshold = result.threshold;

  // Reference is OK since nodes_ will not be reallocated
  Node& next_left = nodes_[result.id_left];
  Node& next_right = nodes_[result.id_right];

  next_left.id = result.id_left;
  next_left.depth = parent.depth + 1;
  next_left.label = result.label_left;
  next_left.is_leaf = true;
  next_right.id = result.id_right;
  next_right.depth = parent.depth + 1;
  next_right.label = result.label_right;
  next_right.is_leaf = true;

  auto features = data.GetColumn(parent.feature_index);
  for(unsigned int i = 0; i < parent.samples.size(); ++i) {
    unsigned int sample_idx = parent.samples[i];
    if (features[sample_idx].value < parent.threshold) {
      next_left.samples.push_back(sample_idx);
    }
    else {
      next_right.samples.push_back(sample_idx);
    }
  }

  // After split is decided and samples divided to the children, no longer need
  // to retain the sample indices
  parent.samples.clear();

  // Link parent and childrens
  parent.left_id = result.id_left;
  parent.right_id = result.id_right;
  //LOG(INFO) << "Node " << nodes_[node_id].id << "'s left: " << nodes_[node_id].left_id << "; right: " << nodes_[node_id].right_id;
};

Tree::SplitResult Tree::FindBestSplit(const Histogram& histogram) const {
  //LOG(INFO) << "Finding best split";

  SplitResult best_split;
  best_split.cost = std::numeric_limits<double>::max();
  best_split.can_split = false;

  // Possible that the histogram is empty because of no sample at all (TO CHECK)
  if (histogram.get_num_bins() == 0) {
    return best_split;
  }

  std::vector<double> candidates = histogram.Uniform(n_splits_);
  //CHECK(candidates.size() > 0) << "Empty split (uniformed) candidates";
  Histogram::BinVal val_inf = histogram.InterpolateInf();
  double l_inf = val_inf.y;
  double m_inf = val_inf.m;

  // Minimum samples required to initiate a split
  if (m_inf <= 2) {
    return best_split;
  }

  for (unsigned int i = 0; i < candidates.size(); ++i) {
    double s = candidates[i];
    // TODO: Make sure that cache is in action
    Histogram::BinVal val_s = histogram.Interpolate(s);
    double l_s = val_s.y;
    double m_s = val_s.m;
    double y_left = l_s / m_s;
    double y_right = (l_inf - l_s) / (m_inf - m_s);
    // (Estimated) Minimum observations at leaf
    if (!(m_s > 0 && (m_inf-m_s) > 0)) {
      continue;
    }
    // No need to split if node is already pure
    // TODO: Can be checked out of this loop ?
    if (std::fabs(y_left - y_right) < 10e-6) {
      continue;
    }

    CHECK((m_inf - m_s) > 0) << "Deviding by zero in right side at s = " << s << ": i = " << i << "; m_inf: " << m_inf << "; m_s: " << m_s;
    double cost = - (l_s*l_s)/(m_s) - (l_inf-l_s)*(l_inf-l_s)/(m_inf-m_s);
    if (cost < best_split.cost) {
      best_split.cost = cost;
      best_split.threshold = s;
      best_split.label_left = y_left;
      best_split.label_right = y_right;
      best_split.can_split = true;
    }
  }
  //LOG(INFO) << "Done finding best split with cost: " << best_split.cost;
  return best_split;
};

Histogram Tree::ComputeHistogram(
    const std::vector<DataMatrix::FeaturePoint>& column,
    const std::vector<double>& targets,
    const std::vector<unsigned int>& samples) const {
  //TODO: What if samples is empty? Now in the next step find best split will
  //ignore the resulted empty histogram.

  //LOG(INFO) << "Computing histogram";
  Histogram histogram(n_bins_);
  for (unsigned int i = 0; i < samples.size(); ++i) {
    unsigned int sample_idx = samples[i];
    double fval = column[sample_idx].value;
    double tval = targets[sample_idx];
    histogram.Update(fval, tval);
  }
  //LOG(INFO) << "Done computing histogram";
  return histogram;
};

double Tree::TraverseTree(const DataMatrix::SamplePoint& sample) const {
  unsigned int id = 0;
  while (true) {
    //LOG(INFO) << "Traversing: Now at node " << id;
    if (nodes_[id].is_leaf) {
      return nodes_[id].label;
    }
    unsigned int fidx = nodes_[id].feature_index;
    //LOG(INFO) << "Considering feature " << fidx << " at node " << id;
    double thres = nodes_[id].threshold;
    if (sample.features.at(fidx) <= thres) {
      id = nodes_[id].left_id;
    }
    else {
      id = nodes_[id].right_id;
    }
  };
};
<commit_msg>Log when a tree level finishes<commit_after>#include "tree.h"
#include "mpi_util.h"

#include <cstdlib>
#include <cmath>
#include <limits>
#include <utility>
#include <glog/logging.h>

Tree::Tree(unsigned int max_depth, unsigned int n_bins, unsigned int n_splits):
  max_depth_(max_depth), n_bins_(n_bins), n_splits_(n_splits),
  current_node_id_(0),
  current_depth_(0)
{
};

void Tree::Train(const DataMatrix& data) {
  Train(data, data.GetTargets());
};

void Tree::Train(const DataMatrix& data, const std::vector<double>& targets) {
  InitializeRootNode(data);
  while (current_depth_ < max_depth_) {
    ProcessCurrentNodes(data, targets);
    current_depth_ += 1;
  }
};

std::vector<double> Tree::Predict(const DataMatrix& data) const {
  std::vector<double> predictions;
  predictions.reserve(data.Size());
  for (unsigned int i = 0; i < data.Size(); ++i) {
  //LOG(INFO) << "Predicting for sample #" << i;
    predictions.push_back(Predict(data.GetRow(i)));
  }
  return predictions;
};

double Tree::Predict(const DataMatrix::SamplePoint& sample) const {
  return TraverseTree(sample);
};

void Tree::InitializeRootNode(const DataMatrix& data) {
  nodes_.resize(1 << (max_depth_+1));
  unsigned int root_id = current_node_id_++;
  Node& root = nodes_[root_id];
  root.samples.reserve(data.Size());
  root.depth = 0;
  // NOTE: Even if the almost unncessary label is to be filled, it has to be
  // determined by the master later.
  for (unsigned int i = 0; i < data.Size(); ++i) {
    root.samples.push_back(i);
  }
  current_queue_.push_back(root_id);
};

void Tree::ProcessCurrentNodes(const DataMatrix& data, const std::vector<double>& targets) {

  // Histograms are stored by features. In the distributed version, a message
  // completely covers a feature (over multiple nodes), so that the number of
  // messages sent does not grow with tree depth.
  // histograms[x][y]: Histogram for feature x at node y
  const std::vector<unsigned int> feature_keys = data.GetFeatureKeys();
  std::vector<std::vector<Histogram> > histograms(feature_keys.size(),
      std::vector<Histogram>(current_queue_.size(), Histogram(n_bins_)));

  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;

  //LOG(INFO) << "Rank: " << world.rank();
  //LOG(INFO) << "Environment intialized: " << env.initialized();

  // In case of slaves
  int total_reqs_push_histograms = histograms.size();
  mpi::request reqs_push_histograms[total_reqs_push_histograms];
  std::vector<HistogramsPerFeature> messages(total_reqs_push_histograms);

  for (unsigned int i = 0; i < feature_keys.size(); ++i) {
    unsigned int fkey = feature_keys[i];
    const auto& column = data.GetColumn(fkey);
    for (unsigned int j = 0; j < current_queue_.size(); ++j) {
      histograms[i][j] = ComputeHistogram(column, targets, nodes_[current_queue_[j]].samples);
    }
    messages[i].histograms = histograms[i];
    messages[i].feature_index = i; // TODO: i or fkey?
    if (world.rank() >= 1) {
      int tag = (world.rank()-1)*feature_keys.size() + i;
      //LOG(INFO) << "Push tag: " << tag;
      reqs_push_histograms[i] = world.isend(0, tag, messages[i]);
      // TODO: Need to run a dummy test() to kick start the process?
    }
  }

  if (world.rank() == 0 && world.size() > 1) {
    LOG(INFO) << "Pulling";
    MPI_PullHistograms(histograms);
  }
  else if (world.rank() >= 1) {
    LOG(INFO) << "Finalize pushing";
    mpi::wait_all(reqs_push_histograms, reqs_push_histograms + total_reqs_push_histograms);
    LOG(INFO) << "Pushed all histograms";
  }

  next_queue_.clear();

  // This way ordering of nodes in the next processing queue is defined by the
  // master process.
  std::vector<SplitResult> best_splits_by_nodes(current_queue_.size());

  if ( world.rank() == 0 ) {
    for (unsigned int j = 0; j < current_queue_.size(); ++j) {
      SplitResult best_result;
      best_result.can_split = false;
      best_result.cost = std::numeric_limits<double>::max();
      for (unsigned int i = 0; i < feature_keys.size(); ++i) {
        SplitResult result = FindBestSplit(histograms[i][j]);
        if (result.can_split && result.cost < best_result.cost) {
          // TODO: Options to check for number of observations per leaf, etc. Or
          // check for these within FindBestSplit using the histogram?
          best_result = result;
          best_result.feature_index = i;
        }
      }
      // TODO: Make a ref?
      best_splits_by_nodes[j] = best_result;
    }
    MPI_PushBestSplits(best_splits_by_nodes);
  }
  else {
    LOG(INFO) << "Receiving split results...";
    MPI_PullBestSplits(best_splits_by_nodes);
  }

  for (unsigned int j = 0; j < current_queue_.size(); ++j) {

    SplitResult& best_result = best_splits_by_nodes[j];

    if (!best_result.can_split) {
      return;
    }
    best_result.id_left = current_node_id_++;
    best_result.id_right = current_node_id_++;

    //LOG(INFO) << "Node [" << current_queue_[j] <<"]: Making a split on feature " << best_result.feature_index << " with threshold " << best_result.threshold << "; label_left: " << best_result.label_left << " label_right: " << best_result.label_right;

    FinalizeAndSplitNode(data, best_result, nodes_[current_queue_[j]]);

    //LOG(INFO) << "Done processing node " << current_queue_[j];
    next_queue_.push_back(best_result.id_left);
    next_queue_.push_back(best_result.id_right);
  }

  current_queue_.swap(next_queue_);

  LOG(INFO) << "ProcessCurrentNodes: Done depth " << current_depth_;
};

void Tree::MPI_PullHistograms(std::vector<std::vector<Histogram> >& histograms) const {
  // TODO: or pass in env and world?
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  int total_reqs = (world.size()-1) * histograms.size();
  //LOG(INFO) << "MPI_PullHistograms: # total reqs: " << total_reqs;
  mpi::request reqs[total_reqs];
  std::vector<HistogramsPerFeature> messages(total_reqs);
  for (unsigned int i = 0; i < histograms.size(); ++i) {
    for (int k = 1; k < world.size(); ++k) {
      int cur_idx = i*(world.size()-1) + (k-1);
      int tag = (k-1)*histograms.size() + i;
      //LOG(INFO) << "MPI_PullHistograms: Current message index to pull: " << cur_idx;
      reqs[cur_idx] = world.irecv(k, tag, messages[cur_idx]);
    }
  }
  LOG(INFO) << "MPI_PullHistograms: Start waiting for slave histograms";
  mpi::wait_all(reqs, reqs + total_reqs);
  LOG(INFO) << "MPI_PulHistograms: Finished waiting in pull";
  for (int i = 0; i < total_reqs; i++) {
    unsigned int feature_index = messages[i].feature_index;
    std::vector<Histogram>& h = messages[i].histograms;
    for (unsigned int j = 0; j < h.size(); ++j) {
      histograms[feature_index][j].Merge(h[j]);
    }
  }
};

void Tree::MPI_PushHistograms(const std::vector<std::vector<Histogram> >& histograms) const {
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
};

void Tree::MPI_PushBestSplits(const std::vector<SplitResult>& best_splits_by_nodes) const {
  LOG(INFO) << "MPI_PushBestSplits: Pushing best splits";
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  mpi::request reqs[world.size()-1];
  for (int k = 1; k < world.size(); ++k) {
    reqs[k-1] = world.isend(k, MPI_TagBestSplits(), best_splits_by_nodes);
  }
  mpi::wait_all(reqs, reqs + world.size() - 1);
  LOG(INFO) << "MPI_PushBestSplits: Pushes finalized";
};

void Tree::MPI_PullBestSplits(std::vector<SplitResult>& best_splits_by_nodes) const {
  LOG(INFO) << "MPI_PullBestSplits: Pulling best splits";
  mpi::environment& env = MPIHandle::Get().env;
  mpi::communicator& world = MPIHandle::Get().world;
  world.recv(0, MPI_TagBestSplits(), best_splits_by_nodes);
  LOG(INFO) << "MPI_PullBestSplits: Pull finalized";
};

int Tree::MPI_TagBestSplits() const {
  return 1001;
};

void Tree::FinalizeAndSplitNode(const DataMatrix& data, const SplitResult& result, Node& parent) {

  // Finalize current node
  parent.is_leaf = false;
  parent.feature_index = result.feature_index;
  parent.threshold = result.threshold;

  // Reference is OK since nodes_ will not be reallocated
  Node& next_left = nodes_[result.id_left];
  Node& next_right = nodes_[result.id_right];

  next_left.id = result.id_left;
  next_left.depth = parent.depth + 1;
  next_left.label = result.label_left;
  next_left.is_leaf = true;
  next_right.id = result.id_right;
  next_right.depth = parent.depth + 1;
  next_right.label = result.label_right;
  next_right.is_leaf = true;

  auto features = data.GetColumn(parent.feature_index);
  for(unsigned int i = 0; i < parent.samples.size(); ++i) {
    unsigned int sample_idx = parent.samples[i];
    if (features[sample_idx].value < parent.threshold) {
      next_left.samples.push_back(sample_idx);
    }
    else {
      next_right.samples.push_back(sample_idx);
    }
  }

  // After split is decided and samples divided to the children, no longer need
  // to retain the sample indices
  parent.samples.clear();

  // Link parent and childrens
  parent.left_id = result.id_left;
  parent.right_id = result.id_right;
  //LOG(INFO) << "Node " << nodes_[node_id].id << "'s left: " << nodes_[node_id].left_id << "; right: " << nodes_[node_id].right_id;
};

Tree::SplitResult Tree::FindBestSplit(const Histogram& histogram) const {
  //LOG(INFO) << "Finding best split";

  SplitResult best_split;
  best_split.cost = std::numeric_limits<double>::max();
  best_split.can_split = false;

  // Possible that the histogram is empty because of no sample at all (TO CHECK)
  if (histogram.get_num_bins() == 0) {
    return best_split;
  }

  std::vector<double> candidates = histogram.Uniform(n_splits_);
  //CHECK(candidates.size() > 0) << "Empty split (uniformed) candidates";
  Histogram::BinVal val_inf = histogram.InterpolateInf();
  double l_inf = val_inf.y;
  double m_inf = val_inf.m;

  // Minimum samples required to initiate a split
  if (m_inf <= 2) {
    return best_split;
  }

  for (unsigned int i = 0; i < candidates.size(); ++i) {
    double s = candidates[i];
    // TODO: Make sure that cache is in action
    Histogram::BinVal val_s = histogram.Interpolate(s);
    double l_s = val_s.y;
    double m_s = val_s.m;
    double y_left = l_s / m_s;
    double y_right = (l_inf - l_s) / (m_inf - m_s);
    // (Estimated) Minimum observations at leaf
    if (!(m_s > 0 && (m_inf-m_s) > 0)) {
      continue;
    }
    // No need to split if node is already pure
    // TODO: Can be checked out of this loop ?
    if (std::fabs(y_left - y_right) < 10e-6) {
      continue;
    }

    CHECK((m_inf - m_s) > 0) << "Deviding by zero in right side at s = " << s << ": i = " << i << "; m_inf: " << m_inf << "; m_s: " << m_s;
    double cost = - (l_s*l_s)/(m_s) - (l_inf-l_s)*(l_inf-l_s)/(m_inf-m_s);
    if (cost < best_split.cost) {
      best_split.cost = cost;
      best_split.threshold = s;
      best_split.label_left = y_left;
      best_split.label_right = y_right;
      best_split.can_split = true;
    }
  }
  //LOG(INFO) << "Done finding best split with cost: " << best_split.cost;
  return best_split;
};

Histogram Tree::ComputeHistogram(
    const std::vector<DataMatrix::FeaturePoint>& column,
    const std::vector<double>& targets,
    const std::vector<unsigned int>& samples) const {
  //TODO: What if samples is empty? Now in the next step find best split will
  //ignore the resulted empty histogram.

  //LOG(INFO) << "Computing histogram";
  Histogram histogram(n_bins_);
  for (unsigned int i = 0; i < samples.size(); ++i) {
    unsigned int sample_idx = samples[i];
    double fval = column[sample_idx].value;
    double tval = targets[sample_idx];
    histogram.Update(fval, tval);
  }
  //LOG(INFO) << "Done computing histogram";
  return histogram;
};

double Tree::TraverseTree(const DataMatrix::SamplePoint& sample) const {
  unsigned int id = 0;
  while (true) {
    //LOG(INFO) << "Traversing: Now at node " << id;
    if (nodes_[id].is_leaf) {
      return nodes_[id].label;
    }
    unsigned int fidx = nodes_[id].feature_index;
    //LOG(INFO) << "Considering feature " << fidx << " at node " << id;
    double thres = nodes_[id].threshold;
    if (sample.features.at(fidx) <= thres) {
      id = nodes_[id].left_id;
    }
    else {
      id = nodes_[id].right_id;
    }
  };
};
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __xoutcell_hxx
#define __xoutcell_hxx

#include "xoutcell.h"

namespace xoutlibrary
{
using namespace std;

/**
 * ************************ Constructor *************************
 */

template< class charT, class traits >
xoutcell< charT, traits >::xoutcell()
{
  this->AddTargetCell( "InternalBuffer", &( this->m_InternalBuffer ) );

} // end Constructor

/**
 * ********************* Destructor *****************************
 */

template< class charT, class traits >
xoutcell< charT, traits >::~xoutcell()
{
  //nothing

} // end Destructor

/**
 * ******************** WriteBufferedData ***********************
 *
 * The buffered data is sent to the outputs.
 */

template< class charT, class traits >
void
xoutcell< charT, traits >::WriteBufferedData( void )
{
  /** Make sure all data is written to the string */
  this->m_InternalBuffer << flush;

  const std::string & strbuf = this->m_InternalBuffer.str();

  const char * charbuf = strbuf.c_str();

  /** Send the string to the outputs */
  for( CStreamMapIteratorType cit = this->m_COutputs.begin();
    cit != this->m_COutputs.end(); ++cit )
  {
    *( cit->second ) << charbuf << flush;
  }

  /** Send the string to the outputs */
  for( XStreamMapIteratorType xit = this->m_XOutputs.begin();
    xit != this->m_XOutputs.end(); ++xit )
  {
    *( xit->second ) << charbuf;
    xit->second->WriteBufferedData();
  }

  /** Empty the internal buffer */
  this->m_InternalBuffer.str( string( "" ) );

} // end WriteBufferedData

} // end namespace xoutlibrary

#endif // end #ifndef __xoutcell_hxx
<commit_msg>STYLE: Fix /analyze warning "Don't dereference 'strbuf'"<commit_after>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __xoutcell_hxx
#define __xoutcell_hxx

#include "xoutcell.h"

namespace xoutlibrary
{
using namespace std;

/**
 * ************************ Constructor *************************
 */

template< class charT, class traits >
xoutcell< charT, traits >::xoutcell()
{
  this->AddTargetCell( "InternalBuffer", &( this->m_InternalBuffer ) );

} // end Constructor

/**
 * ********************* Destructor *****************************
 */

template< class charT, class traits >
xoutcell< charT, traits >::~xoutcell()
{
  //nothing

} // end Destructor

/**
 * ******************** WriteBufferedData ***********************
 *
 * The buffered data is sent to the outputs.
 */

template< class charT, class traits >
void
xoutcell< charT, traits >::WriteBufferedData( void )
{
  /** Make sure all data is written to the string */
  this->m_InternalBuffer << flush;

  const std::string strbuf = this->m_InternalBuffer.str();

  const char * const charbuf = strbuf.c_str();

  /** Send the string to the outputs */
  for( CStreamMapIteratorType cit = this->m_COutputs.begin();
    cit != this->m_COutputs.end(); ++cit )
  {
    *( cit->second ) << charbuf << flush;
  }

  /** Send the string to the outputs */
  for( XStreamMapIteratorType xit = this->m_XOutputs.begin();
    xit != this->m_XOutputs.end(); ++xit )
  {
    *( xit->second ) << charbuf;
    xit->second->WriteBufferedData();
  }

  /** Empty the internal buffer */
  this->m_InternalBuffer.str( string( "" ) );

} // end WriteBufferedData

} // end namespace xoutlibrary

#endif // end #ifndef __xoutcell_hxx
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015
              Jonathan Hale <squareys@googlemail.com>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <memory.h>
#include <Corrade/Containers/Array.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/Mesh.h>
#include <Corrade/Utility/utilities.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Renderer.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Context.h>

#include "Types.h"
#include "HmdCamera.h"
#include "CubeDrawable.h"

#include <Magnum/LibOvrIntegration/LibOvrIntegration.h>
#include <Magnum/LibOvrIntegration/Context.h>
#include <Magnum/LibOvrIntegration/Hmd.h>
#include <Magnum/LibOvrIntegration/HmdEnum.h>

namespace Magnum { namespace Examples {

using namespace LibOvrIntegration;

/**
 * @brief The Application class of OvrExample.
 * @author Jonathan Hale (Squareys)
 */
class OvrExample: public Platform::Application {
    public:
        explicit OvrExample(const Arguments& arguments);
        virtual ~OvrExample();

    private:
        void drawEvent() override;

        LibOvrIntegration::Context _ovrContext;
        std::unique_ptr<Hmd> _hmd;

        std::unique_ptr<Buffer> _indexBuffer, _vertexBuffer;
        std::unique_ptr<Mesh> _mesh;
        std::unique_ptr<Shaders::Phong> _shader;

        Scene3D _scene;
        Object3D _cameraObject;
        Object3D _eyes[2];
        SceneGraph::DrawableGroup3D _drawables;
        std::unique_ptr<HmdCamera> _cameras[2];

        std::unique_ptr<Object3D> _cubes[4];
        std::unique_ptr<CubeDrawable> _cubeDrawables[4];

        std::unique_ptr<Framebuffer> _mirrorFramebuffer;
        Texture2D* _mirrorTexture;

        LayerEyeFov* _layer;
};

OvrExample::OvrExample(const Arguments& arguments) : Platform::Application(arguments, nullptr),
    _indexBuffer(nullptr), _vertexBuffer(nullptr), _mesh(nullptr),
    _shader(nullptr), _scene(), _cameraObject(&_scene)
{

    /* connect to an Hmd, or create a debug hmd with DK2 type in case none is connected. */
    _hmd = LibOvrIntegration::Context::get().createHmd(0, HmdType::DK2);

    /* get the hmd display resolution */
    Vector2i resolution = _hmd->resolution() / 2;

    /* create a context with the hmd display resolution */
    Configuration conf;
    conf.setTitle("Magnum OculusVR Example")
        .setSize(resolution)
        .setSampleCount(16);

    if(!tryCreateContext(conf))
        createContext(conf.setSampleCount(0));

    /* the oculus sdk compositor does some "magic" to reduce latency. For
     * that to work, vsync needs to be turned off. */
    if(!setSwapInterval(0))
        Error() << "Could not turn off vsync.";

    Renderer::enable(Renderer::Feature::DepthTest);

    _hmd->setEnabledCaps(HmdCapability::LowPersistence | HmdCapability::DynamicPrediction );
    _hmd->configureTracking(HmdTrackingCapability::Orientation | HmdTrackingCapability::MagYawCorrection |
                            HmdTrackingCapability::Position, {});
    _hmd->configureRendering();

    /* setup mirroring of oculus sdk compositor results to a texture which can later be blitted
     * onto the defaultFramebuffer. */
    _mirrorTexture = &_hmd->createMirrorTexture(TextureFormat::RGBA, resolution);
    _mirrorFramebuffer.reset(new Framebuffer(Range2Di::fromSize({}, resolution)));
    _mirrorFramebuffer->attachTexture(Framebuffer::ColorAttachment(0), *_mirrorTexture, 0)
                      .mapForRead(Framebuffer::ColorAttachment(0));

    /* Setup cube mesh. */
    const Trade::MeshData3D cube = Primitives::Cube::solid();

    _vertexBuffer.reset(new Buffer());
    _vertexBuffer->setData(
                MeshTools::interleave(cube.positions(0), cube.normals(0)),
                BufferUsage::StaticDraw);

    Containers::Array<char> indexData;
    Mesh::IndexType indexType;
    UnsignedInt indexStart, indexEnd;
    std::tie(indexData, indexType, indexStart, indexEnd) =
            MeshTools::compressIndices(cube.indices());

    _indexBuffer.reset(new Buffer());
    _indexBuffer->setData(indexData, BufferUsage::StaticDraw);

    _mesh.reset(new Mesh());
    _mesh->setPrimitive(cube.primitive()).setCount(cube.indices().size()).addVertexBuffer(
                *_vertexBuffer, 0, Shaders::Phong::Position {},
                Shaders::Phong::Normal {}).setIndexBuffer(*_indexBuffer, 0, indexType,
                                                          indexStart, indexEnd);

    /* setup shader */
    _shader.reset(new Shaders::Phong());

    /* setup scene */
    _cubes[0] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[0]->rotateY(Deg(45.0f));
    _cubes[0]->translate({0.0f, 0.0f, -3.0f});
    _cubeDrawables[0] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 1.0f, 0.0f}, _cubes[0].get(), &_drawables));

    _cubes[1] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[1]->rotateY(Deg(45.0f));
    _cubes[1]->translate({5.0f, 0.0f, 0.0f});
    _cubeDrawables[1] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 0.0f, 0.0f}, _cubes[1].get(), &_drawables));

    _cubes[2] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[2]->rotateY(Deg(45.0f));
    _cubes[2]->translate({-10.0f, 0.0f, 0.0f});
    _cubeDrawables[2] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 0.0f, 1.0f}, _cubes[2].get(), &_drawables));

    _cubes[3] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[3]->rotateY(Deg(45.0f));
    _cubes[3]->translate({0.0f, 0.0f, 7.0f});
    _cubeDrawables[3] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 1.0f, 1.0f}, _cubes[3].get(), &_drawables));

    /* setup compositor layers */
    _layer = &LibOvrIntegration::Context::get().compositor().addLayerEyeFov();
    _layer->setFov(*_hmd.get());
    _layer->setHighQuality(true);

    /* setup cameras */
    _eyes[0].setParent(&_cameraObject);
    _eyes[1].setParent(&_cameraObject);

    for(int eye = 0; eye < 2; ++eye) {
        /* projection matrix is set in the camera, since it requires some hmd-specific fov etc. */
        _cameras[eye].reset(new HmdCamera(*_hmd, eye, _eyes[eye]));

        _layer->setColorTexture(eye, _cameras[eye]->textureSet());
        _layer->setViewport(eye, {{}, _cameras[eye]->viewport()});
    }

}

OvrExample::~OvrExample() {
}

void OvrExample::drawEvent() {
    /* get orientation and position of the hmd. */
    std::array<DualQuaternion, 2> poses = _hmd->pollEyePoses().eyePoses();

    /* draw the scene for both cameras */
    for(int eye = 0; eye < 2; ++eye) {
        /* set the transformation according to rift trackers */
        _eyes[eye].setTransformation(poses[eye].toMatrix());
        /* render each eye. */
        _cameras[eye]->draw(_drawables);
    }

    /* set the layers eye poses to the poses chached in the _hmd. */
    _layer->setRenderPoses(*_hmd.get());

    /* let the libOVR sdk compositor do its magic! */
    LibOvrIntegration::Context::get().compositor().submitFrame(*_hmd.get());

    /* blit mirror texture to defaultFramebuffer. */
    const Vector2i size = _mirrorTexture->imageSize(0);
    Framebuffer::blit(*_mirrorFramebuffer,
                      defaultFramebuffer,
                      {{0, size.y()}, {size.x(), 0}},
                      {{}, size},
                      FramebufferBlit::Color, FramebufferBlitFilter::Nearest);

    if(_hmd->isDebugHmd()) {
        /* provide some rotation, but only without real devices to avoid vr sickness ;) */
        _cameraObject.rotateY(Deg(0.1f));
    }

    swapBuffers();
    redraw();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::OvrExample)
<commit_msg>ovr: Show the performance HUD with F11.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>
    Copyright © 2015
              Jonathan Hale <squareys@googlemail.com>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <memory.h>
#include <Corrade/Containers/Array.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector2.h>
#include <Magnum/Math/Vector3.h>
#include <Magnum/Mesh.h>
#include <Corrade/Utility/utilities.h>
#include <Magnum/Buffer.h>
#include <Magnum/DefaultFramebuffer.h>
#include <Magnum/Renderer.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/MeshTools/CompressIndices.h>
#include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/SceneGraph/Scene.h>
#include <Magnum/SceneGraph/Drawable.h>
#include <Magnum/SceneGraph/Camera.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>
#include <Magnum/Context.h>

#include "Types.h"
#include "HmdCamera.h"
#include "CubeDrawable.h"

#include <Magnum/LibOvrIntegration/LibOvrIntegration.h>
#include <Magnum/LibOvrIntegration/Context.h>
#include <Magnum/LibOvrIntegration/Hmd.h>
#include <Magnum/LibOvrIntegration/HmdEnum.h>

namespace Magnum { namespace Examples {

using namespace LibOvrIntegration;

/**
 * @brief The Application class of OvrExample.
 * @author Jonathan Hale (Squareys)
 */
class OvrExample: public Platform::Application {
    public:
        explicit OvrExample(const Arguments& arguments);
        virtual ~OvrExample();

    protected:
        virtual void keyPressEvent(KeyEvent& event) override;

    private:
        void drawEvent() override;

        LibOvrIntegration::Context _ovrContext;
        std::unique_ptr<Hmd> _hmd;

        std::unique_ptr<Buffer> _indexBuffer, _vertexBuffer;
        std::unique_ptr<Mesh> _mesh;
        std::unique_ptr<Shaders::Phong> _shader;

        Scene3D _scene;
        Object3D _cameraObject;
        Object3D _eyes[2];
        SceneGraph::DrawableGroup3D _drawables;
        std::unique_ptr<HmdCamera> _cameras[2];

        std::unique_ptr<Object3D> _cubes[4];
        std::unique_ptr<CubeDrawable> _cubeDrawables[4];

        std::unique_ptr<Framebuffer> _mirrorFramebuffer;
        Texture2D* _mirrorTexture;

        LayerEyeFov* _layer;

        PerformanceHudMode _curPerfHudMode;
};

OvrExample::OvrExample(const Arguments& arguments) : Platform::Application(arguments, nullptr),
    _indexBuffer(nullptr), _vertexBuffer(nullptr), _mesh(nullptr),
    _shader(nullptr), _scene(), _cameraObject(&_scene), _curPerfHudMode(PerformanceHudMode::Off)
{

    /* connect to an Hmd, or create a debug hmd with DK2 type in case none is connected. */
    _hmd = LibOvrIntegration::Context::get().createHmd(0, HmdType::DK2);

    /* get the hmd display resolution */
    Vector2i resolution = _hmd->resolution() / 2;

    /* create a context with the hmd display resolution */
    Configuration conf;
    conf.setTitle("Magnum OculusVR Example")
        .setSize(resolution)
        .setSampleCount(16);

    if(!tryCreateContext(conf))
        createContext(conf.setSampleCount(0));

    /* the oculus sdk compositor does some "magic" to reduce latency. For
     * that to work, vsync needs to be turned off. */
    if(!setSwapInterval(0))
        Error() << "Could not turn off vsync.";

    Renderer::enable(Renderer::Feature::DepthTest);

    _hmd->setEnabledCaps(HmdCapability::LowPersistence | HmdCapability::DynamicPrediction );
    _hmd->configureTracking(HmdTrackingCapability::Orientation | HmdTrackingCapability::MagYawCorrection |
                            HmdTrackingCapability::Position, {});
    _hmd->configureRendering();

    /* setup mirroring of oculus sdk compositor results to a texture which can later be blitted
     * onto the defaultFramebuffer. */
    _mirrorTexture = &_hmd->createMirrorTexture(TextureFormat::RGBA, resolution);
    _mirrorFramebuffer.reset(new Framebuffer(Range2Di::fromSize({}, resolution)));
    _mirrorFramebuffer->attachTexture(Framebuffer::ColorAttachment(0), *_mirrorTexture, 0)
                      .mapForRead(Framebuffer::ColorAttachment(0));

    /* Setup cube mesh. */
    const Trade::MeshData3D cube = Primitives::Cube::solid();

    _vertexBuffer.reset(new Buffer());
    _vertexBuffer->setData(
                MeshTools::interleave(cube.positions(0), cube.normals(0)),
                BufferUsage::StaticDraw);

    Containers::Array<char> indexData;
    Mesh::IndexType indexType;
    UnsignedInt indexStart, indexEnd;
    std::tie(indexData, indexType, indexStart, indexEnd) =
            MeshTools::compressIndices(cube.indices());

    _indexBuffer.reset(new Buffer());
    _indexBuffer->setData(indexData, BufferUsage::StaticDraw);

    _mesh.reset(new Mesh());
    _mesh->setPrimitive(cube.primitive()).setCount(cube.indices().size()).addVertexBuffer(
                *_vertexBuffer, 0, Shaders::Phong::Position {},
                Shaders::Phong::Normal {}).setIndexBuffer(*_indexBuffer, 0, indexType,
                                                          indexStart, indexEnd);

    /* setup shader */
    _shader.reset(new Shaders::Phong());

    /* setup scene */
    _cubes[0] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[0]->rotateY(Deg(45.0f));
    _cubes[0]->translate({0.0f, 0.0f, -3.0f});
    _cubeDrawables[0] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 1.0f, 0.0f}, _cubes[0].get(), &_drawables));

    _cubes[1] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[1]->rotateY(Deg(45.0f));
    _cubes[1]->translate({5.0f, 0.0f, 0.0f});
    _cubeDrawables[1] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {1.0f, 0.0f, 0.0f}, _cubes[1].get(), &_drawables));

    _cubes[2] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[2]->rotateY(Deg(45.0f));
    _cubes[2]->translate({-10.0f, 0.0f, 0.0f});
    _cubeDrawables[2] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 0.0f, 1.0f}, _cubes[2].get(), &_drawables));

    _cubes[3] = std::unique_ptr<Object3D>(new Object3D(&_scene));
    _cubes[3]->rotateY(Deg(45.0f));
    _cubes[3]->translate({0.0f, 0.0f, 7.0f});
    _cubeDrawables[3] = std::unique_ptr<CubeDrawable>(new CubeDrawable(_mesh.get(), _shader.get(), {0.0f, 1.0f, 1.0f}, _cubes[3].get(), &_drawables));

    /* setup compositor layers */
    _layer = &LibOvrIntegration::Context::get().compositor().addLayerEyeFov();
    _layer->setFov(*_hmd.get());
    _layer->setHighQuality(true);

    /* setup cameras */
    _eyes[0].setParent(&_cameraObject);
    _eyes[1].setParent(&_cameraObject);

    for(int eye = 0; eye < 2; ++eye) {
        /* projection matrix is set in the camera, since it requires some hmd-specific fov etc. */
        _cameras[eye].reset(new HmdCamera(*_hmd, eye, _eyes[eye]));

        _layer->setColorTexture(eye, _cameras[eye]->textureSet());
        _layer->setViewport(eye, {{}, _cameras[eye]->viewport()});
    }

}

OvrExample::~OvrExample() {
}

void OvrExample::drawEvent() {
    /* get orientation and position of the hmd. */
    std::array<DualQuaternion, 2> poses = _hmd->pollEyePoses().eyePoses();

    /* draw the scene for both cameras */
    for(int eye = 0; eye < 2; ++eye) {
        /* set the transformation according to rift trackers */
        _eyes[eye].setTransformation(poses[eye].toMatrix());
        /* render each eye. */
        _cameras[eye]->draw(_drawables);
    }

    /* set the layers eye poses to the poses chached in the _hmd. */
    _layer->setRenderPoses(*_hmd.get());

    /* let the libOVR sdk compositor do its magic! */
    LibOvrIntegration::Context::get().compositor().submitFrame(*_hmd.get());

    /* blit mirror texture to defaultFramebuffer. */
    const Vector2i size = _mirrorTexture->imageSize(0);
    Framebuffer::blit(*_mirrorFramebuffer,
                      defaultFramebuffer,
                      {{0, size.y()}, {size.x(), 0}},
                      {{}, size},
                      FramebufferBlit::Color, FramebufferBlitFilter::Nearest);

    if(_hmd->isDebugHmd()) {
        /* provide some rotation, but only without real devices to avoid vr sickness ;) */
        _cameraObject.rotateY(Deg(0.1f));
    }

    swapBuffers();
    redraw();
}

void OvrExample::keyPressEvent(KeyEvent& event) {
    if(event.key() == KeyEvent::Key::F11) {
        /* toggle through the performance hud modes */
        switch(_curPerfHudMode) {
            case PerformanceHudMode::Off:
                _curPerfHudMode = PerformanceHudMode::LatencyTiming;
                break;
            case PerformanceHudMode::LatencyTiming:
                _curPerfHudMode = PerformanceHudMode::RenderTiming;
                break;
            case PerformanceHudMode::RenderTiming:
                _curPerfHudMode = PerformanceHudMode::Off;
                break;
        }

        /** libovr has a bug where performance hud will block the app when using a debug hmd */
        if(!_hmd->isDebugHmd()) {
            _hmd->setPerformanceHudMode(_curPerfHudMode);
        }
    }
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::OvrExample)
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	robusttransaction.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::robusttransaction class.
 *   pqxx::robusttransaction is a slower but safer transaction class
 *
 * Copyright (c) 2002-2005, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <stdexcept>

#include "pqxx/connection_base"
#include "pqxx/result"
#include "pqxx/robusttransaction"

using namespace PGSTD;
using namespace pqxx::internal;

// TODO: Use two-phase transaction if backend supports it

#define SQL_COMMIT_WORK 	"COMMIT"
#define SQL_ROLLBACK_WORK 	"ROLLBACK"

pqxx::basic_robusttransaction::basic_robusttransaction(connection_base &C,
	const string &IsolationLevel,
	const string &TName) :
  dbtransaction(C,
      IsolationLevel,
      TName,
      "robusttransaction<"+IsolationLevel+">"),
  m_ID(oid_none),
  m_LogTable(),
  m_backendpid(-1)
{
  m_LogTable = string("PQXXLOG_") + conn().username();
}

pqxx::basic_robusttransaction::~basic_robusttransaction()
{
}

void pqxx::basic_robusttransaction::do_begin()
{
  start_backend_transaction();

  try
  {
    CreateTransactionRecord();
  }
  catch (const exception &)
  {
    // The problem here *may* be that the log table doesn't exist yet.  Create
    // one, start a new transaction, and try again.
    try { DirectExec(SQL_ROLLBACK_WORK); } catch (const exception &e) {}
    CreateLogTable();
    start_backend_transaction();
    m_backendpid = conn().backendpid();
    CreateTransactionRecord();
  }
}

void pqxx::basic_robusttransaction::do_commit()
{
  const IDType ID = m_ID;

  if (ID == oid_none)
    throw logic_error("libpqxx internal error: transaction "
		      "'" + name() + "' "
		     "has no ID");

  // Check constraints before sending the COMMIT to the database to reduce the
  // work being done inside our in-doubt window.  It also implicitly provides
  // one last check that our connection is really working before sending the
  // commit command.
  //
  // This may not be an entirely clear-cut 100% obvious unambiguous Good Thing.
  // If we lose our connection during the in-doubt window, it may be better if
  // the transaction didn't actually go though, and having constraints checked
  // first theoretically makes it more likely that it will once we get to that
  // stage.
  //
  // However, it seems reasonable to assume that most transactions will satisfy
  // their constraints.  Besides, the goal of robusttransaction is to weed out
  // indeterminacy, rather than to improve the odds of desirable behaviour when
  // all bets are off anyway.
  DirectExec("SET CONSTRAINTS ALL IMMEDIATE");

  // Here comes the critical part.  If we lose our connection here, we'll be
  // left clueless as to whether the backend got the message and is trying to
  // commit the transaction (let alone whether it will succeed if so).  This
  // case requires some special handling that makes robusttransaction what it
  // is.
  try
  {
    DirectExec(SQL_COMMIT_WORK);
  }
  catch (const exception &e)
  {
    // TODO: Can we limit this handler to broken_connection exceptions?
    m_ID = oid_none;
    if (!conn().is_open())
    {
      // We've lost the connection while committing.  We'll have to go back to
      // the backend and check our transaction log to see what happened.
      process_notice(e.what() + string("\n"));

      // See if transaction record ID exists; if yes, our transaction was
      // committed before the connection went down.  If not, the transaction
      // was aborted.
      bool Exists;
      try
      {
        Exists = CheckTransactionRecord(ID);
      }
      catch (const exception &f)
      {
	// Couldn't check for transaction record.  We're still in doubt as to
	// whether the transaction was performed.
        const string Msg = "WARNING: "
		    "Connection lost while committing transaction "
		    "'" + name() + "' (oid " + to_string(ID) + "). "
		    "Please check for this record in the "
		    "'" + m_LogTable + "' table.  "
		    "If the record exists, the transaction was executed. "
		    "If not, then it wasn't.\n";

        process_notice(Msg);
	process_notice("Could not verify existence of transaction record "
	    "because of the following error:\n");
	process_notice(string(f.what()) + "\n");

        throw in_doubt_error(Msg);
      }

      // Transaction record is gone, so all we have is a "normal" transaction
      // failure.
      if (!Exists) throw;
    }
    else
    {
      // Commit failed--probably due to a constraint violation or something
      // similar.  But we're still connected, so no worries from a consistency
      // point of view.

      // Try to delete transaction record ID, if it still exists (although it
      // really shouldn't)
      DeleteTransactionRecord(ID);
      throw;
    }
  }

  m_ID = oid_none;
  DeleteTransactionRecord(ID);
}

void pqxx::basic_robusttransaction::do_abort()
{
  m_ID = oid_none;

  // Rollback transaction.  Our transaction record will be dropped as a side
  // effect, which is what we want since "it never happened."
  DirectExec(SQL_ROLLBACK_WORK);
}

// Create transaction log table if it didn't already exist
void pqxx::basic_robusttransaction::CreateLogTable()
{
  // Create log table in case it doesn't already exist.  This code must only be
  // executed before the backend transaction has properly started.
  const string CrTab = "CREATE TABLE " + m_LogTable +
	               "("
	               "name VARCHAR(256), "
	               "date TIMESTAMP"
	               ")";

  try { DirectExec(CrTab.c_str(), 1); } catch (const exception &) { }
}

void pqxx::basic_robusttransaction::CreateTransactionRecord()
{
  // TODO: Might as well include real transaction ID and backend PID
  const string Insert = "INSERT INTO " + m_LogTable + " "
	                "(name, date) "
			"VALUES "
	                "(" +
			(name().empty() ? "null" : "'"+sqlesc(name())+"'") +
			", "
	                "CURRENT_TIMESTAMP"
	                ")";

  m_ID = DirectExec(Insert.c_str()).inserted_oid();

  if (m_ID == oid_none)
    throw runtime_error("Could not create transaction log record");
}

void pqxx::basic_robusttransaction::DeleteTransactionRecord(IDType ID) throw ()
{
  if (ID == oid_none) return;

  try
  {
    // Try very, very hard to delete record.  Specify an absurd retry count to
    // ensure that the server gets a chance to restart before we give up.
    const string Del = "DELETE FROM " + m_LogTable + " "
	               "WHERE oid=" + to_string(ID);

    DirectExec(Del.c_str(), 20);

    // Now that we've arrived here, we're almost sure that record is quite dead.
    ID = oid_none;
  }
  catch (const exception &)
  {
  }

  if (ID != oid_none) try
  {
    process_notice("WARNING: "
	           "Failed to delete obsolete transaction record with oid " +
		   to_string(ID) + " ('" + name() + "'). "
		   "Please delete it manually.  Thank you.\n");
  }
  catch (const exception &)
  {
  }
}

// Attempt to establish whether transaction record with given ID still exists
bool pqxx::basic_robusttransaction::CheckTransactionRecord(IDType ID)
{
  /* First, wait for the old backend (with the lost connection) to die.
   *
   * On 2004-09-18, Tom Lane wrote:
   *
   * I don't see any reason for guesswork.  Remember the PID of the backend
   * you were connected to.  On reconnect, look in pg_stat_activity to see
   * if that backend is still alive; if so, sleep till it's not.  Then check
   * to see if your transaction committed or not.  No need for anything so
   * dangerous as a timeout.
   */
  /* Actually, looking if the query has finished is only possible if the
   * stats_command_string has been set in postgresql.conf and we're running
   * as the postgres superuser.  If we get a string saying this option has not
   * been enabled, we must wait as if the query were still executing--and hope
   * that the backend dies.
   */
  // TODO: Tom says we need stats_start_collector, not stats_command_string!?
  /* Starting with PostgreSQL 7.4, we can use pg_locks.  The entry for the
   * zombied transaction will have a "relation" field of null, a "transaction"
   * field with the transaction ID (which we don't have--m_ID is the ID of our
   * own transaction record!), and "pid" set to our backendpid.  If the relation
   * exists but no such record is found, then the transaction is no longer
   * running.
   */
  // TODO: Support multiple means of detection for zombied transaction?
  bool hold = true;
  for (int c=20; hold && c; internal::sleep_seconds(5), --c)
  {
    const result R(DirectExec(("SELECT current_query "
	  "FROM pq_stat_activity "
	  "WHERE procpid=" + to_string(m_backendpid)).c_str()));
    hold = (!R.empty() &&
      !R[0][0].as(string()).empty() &&
      (R[0][0].as(string()) != "<IDLE>"));
  }

  if (hold)
    throw runtime_error("Old backend process stays alive too long to wait for");

  // Now look for our transaction record
  const string Find = "SELECT oid FROM " + m_LogTable + " "
	              "WHERE oid=" + to_string(ID);

  return !DirectExec(Find.c_str(), 20).empty();
}

<commit_msg>Transaction log table is now all lower-case everywhere; create table WITH OIDS if possible<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	robusttransaction.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::robusttransaction class.
 *   pqxx::robusttransaction is a slower but safer transaction class
 *
 * Copyright (c) 2002-2005, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler.h"

#include <stdexcept>

#include "pqxx/connection_base"
#include "pqxx/result"
#include "pqxx/robusttransaction"

using namespace PGSTD;
using namespace pqxx::internal;

// TODO: Use two-phase transaction if backend supports it

#define SQL_COMMIT_WORK 	"COMMIT"
#define SQL_ROLLBACK_WORK 	"ROLLBACK"

pqxx::basic_robusttransaction::basic_robusttransaction(connection_base &C,
	const string &IsolationLevel,
	const string &TName) :
  dbtransaction(C,
      IsolationLevel,
      TName,
      "robusttransaction<"+IsolationLevel+">"),
  m_ID(oid_none),
  m_LogTable(),
  m_backendpid(-1)
{
  m_LogTable = string("pqxxlog_") + conn().username();
}

pqxx::basic_robusttransaction::~basic_robusttransaction()
{
}

void pqxx::basic_robusttransaction::do_begin()
{
  start_backend_transaction();

  try
  {
    CreateTransactionRecord();
  }
  catch (const exception &)
  {
    // The problem here *may* be that the log table doesn't exist yet.  Create
    // one, start a new transaction, and try again.
    try { DirectExec(SQL_ROLLBACK_WORK); } catch (const exception &e) {}
    CreateLogTable();
    start_backend_transaction();
    m_backendpid = conn().backendpid();
    CreateTransactionRecord();
  }
}

void pqxx::basic_robusttransaction::do_commit()
{
  const IDType ID = m_ID;

  if (ID == oid_none)
    throw logic_error("libpqxx internal error: transaction "
		      "'" + name() + "' "
		     "has no ID");

  // Check constraints before sending the COMMIT to the database to reduce the
  // work being done inside our in-doubt window.  It also implicitly provides
  // one last check that our connection is really working before sending the
  // commit command.
  //
  // This may not be an entirely clear-cut 100% obvious unambiguous Good Thing.
  // If we lose our connection during the in-doubt window, it may be better if
  // the transaction didn't actually go though, and having constraints checked
  // first theoretically makes it more likely that it will once we get to that
  // stage.
  //
  // However, it seems reasonable to assume that most transactions will satisfy
  // their constraints.  Besides, the goal of robusttransaction is to weed out
  // indeterminacy, rather than to improve the odds of desirable behaviour when
  // all bets are off anyway.
  DirectExec("SET CONSTRAINTS ALL IMMEDIATE");

  // Here comes the critical part.  If we lose our connection here, we'll be
  // left clueless as to whether the backend got the message and is trying to
  // commit the transaction (let alone whether it will succeed if so).  This
  // case requires some special handling that makes robusttransaction what it
  // is.
  try
  {
    DirectExec(SQL_COMMIT_WORK);
  }
  catch (const exception &e)
  {
    m_ID = oid_none;
    if (!conn().is_open())
    {
      // We've lost the connection while committing.  We'll have to go back to
      // the backend and check our transaction log to see what happened.
      process_notice(e.what() + string("\n"));

      // See if transaction record ID exists; if yes, our transaction was
      // committed before the connection went down.  If not, the transaction
      // was aborted.
      bool Exists;
      try
      {
        Exists = CheckTransactionRecord(ID);
      }
      catch (const exception &f)
      {
	// Couldn't check for transaction record.  We're still in doubt as to
	// whether the transaction was performed.
        const string Msg = "WARNING: "
		    "Connection lost while committing transaction "
		    "'" + name() + "' (oid " + to_string(ID) + "). "
		    "Please check for this record in the "
		    "'" + m_LogTable + "' table.  "
		    "If the record exists, the transaction was executed. "
		    "If not, then it wasn't.\n";

        process_notice(Msg);
	process_notice("Could not verify existence of transaction record "
	    "because of the following error:\n");
	process_notice(string(f.what()) + "\n");

        throw in_doubt_error(Msg);
      }

      // Transaction record is gone, so all we have is a "normal" transaction
      // failure.
      if (!Exists) throw;
    }
    else
    {
      // Commit failed--probably due to a constraint violation or something
      // similar.  But we're still connected, so no worries from a consistency
      // point of view.

      // Try to delete transaction record ID, if it still exists (although it
      // really shouldn't)
      DeleteTransactionRecord(ID);
      throw;
    }
  }

  m_ID = oid_none;
  DeleteTransactionRecord(ID);
}

void pqxx::basic_robusttransaction::do_abort()
{
  m_ID = oid_none;

  // Rollback transaction.  Our transaction record will be dropped as a side
  // effect, which is what we want since "it never happened."
  DirectExec(SQL_ROLLBACK_WORK);
}

// Create transaction log table if it didn't already exist
void pqxx::basic_robusttransaction::CreateLogTable()
{
  // Create log table in case it doesn't already exist.  This code must only be
  // executed before the backend transaction has properly started.
  string CrTab = "CREATE TABLE \"" + m_LogTable + "\" "
		 "("
		 "name VARCHAR(256), "
		 "date TIMESTAMP, "
		 "CONSTRAINT identity UNIQUE(oid))";
  if (conn().supports(connection_base::cap_create_table_with_oids))
    CrTab += " WITH OIDS";

  try { DirectExec(CrTab.c_str(), 1); } catch (const exception &) { }
}

void pqxx::basic_robusttransaction::CreateTransactionRecord()
{
  static const string Fail = "Could not create transaction log record: ";

  // TODO: Might as well include real transaction ID and backend PID
  const string Insert = "INSERT INTO \"" + m_LogTable + "\" "
	                "(name, date) "
			"VALUES "
	                "(" +
			(name().empty() ? "null" : "'"+sqlesc(name())+"'") +
			", "
	                "CURRENT_TIMESTAMP"
	                ")";

  try
  {
    const result R(DirectExec(Insert.c_str()));
    m_ID = R.inserted_oid();
  }
  catch (const sql_error &e) { throw sql_error(Fail+e.what(), Insert); }
  catch (const broken_connection &) { throw; }
  catch (const bad_alloc &) { throw; }
  catch (const out_of_range &e) { throw out_of_range(Fail+e.what()); }
  catch (const range_error &e) { throw range_error(Fail+e.what()); }
  catch (const invalid_argument &e) { throw invalid_argument(Fail+e.what()); }
  catch (const runtime_error &e) { throw runtime_error(Fail+e.what()); }
  catch (const domain_error &e) { throw domain_error(Fail+e.what()); }
  catch (const logic_error &e) { throw logic_error(Fail+e.what()); }
  catch (const exception &e) { throw sql_error(Fail+e.what(), Insert); }

  if (m_ID == oid_none)
  {
    if (conn().supports(connection_base::cap_create_table_with_oids))
      throw runtime_error(Fail +
	  "Transaction log table " + m_LogTable + " exists but does not seem\n"
	  "to have been created with an implicit oid column.\n"
	  "This column was automatically present in all tables prior to "
	  "PostgreSQL 8.1.\n"
	  "It may be missing here because the table was created by a libpqxx "
	  "version prior to 2.6.0,\n"
	  "or the table may have been imported from a PostgreSQL version prior "
	  "to 8.1 without preserving the oid column.\n"
	  "It should be safe to drop the table; a new one will then be created "
	  "with the oid column present.");
    throw runtime_error(Fail + "For some reason the transaction log record "
	"was not assigned a valid oid by the backend.");
  }
}

void pqxx::basic_robusttransaction::DeleteTransactionRecord(IDType ID) throw ()
{
  if (ID == oid_none) return;

  try
  {
    // Try very, very hard to delete record.  Specify an absurd retry count to
    // ensure that the server gets a chance to restart before we give up.
    const string Del = "DELETE FROM \"" + m_LogTable + "\" "
	               "WHERE oid=" + to_string(ID);

    DirectExec(Del.c_str(), 20);

    // Now that we've arrived here, we're almost sure that record is quite dead.
    ID = oid_none;
  }
  catch (const exception &)
  {
  }

  if (ID != oid_none) try
  {
    process_notice("WARNING: "
	           "Failed to delete obsolete transaction record with oid " +
		   to_string(ID) + " ('" + name() + "'). "
		   "Please delete it manually.  Thank you.\n");
  }
  catch (const exception &)
  {
  }
}

// Attempt to establish whether transaction record with given ID still exists
bool pqxx::basic_robusttransaction::CheckTransactionRecord(IDType ID)
{
  /* First, wait for the old backend (with the lost connection) to die.
   *
   * On 2004-09-18, Tom Lane wrote:
   *
   * I don't see any reason for guesswork.  Remember the PID of the backend
   * you were connected to.  On reconnect, look in pg_stat_activity to see
   * if that backend is still alive; if so, sleep till it's not.  Then check
   * to see if your transaction committed or not.  No need for anything so
   * dangerous as a timeout.
   */
  /* Actually, looking if the query has finished is only possible if the
   * stats_command_string has been set in postgresql.conf and we're running
   * as the postgres superuser.  If we get a string saying this option has not
   * been enabled, we must wait as if the query were still executing--and hope
   * that the backend dies.
   */
  // TODO: Tom says we need stats_start_collector, not stats_command_string!?
  /* Starting with PostgreSQL 7.4, we can use pg_locks.  The entry for the
   * zombied transaction will have a "relation" field of null, a "transaction"
   * field with the transaction ID (which we don't have--m_ID is the ID of our
   * own transaction record!), and "pid" set to our backendpid.  If the relation
   * exists but no such record is found, then the transaction is no longer
   * running.
   */
  // TODO: Support multiple means of detection for zombied transaction?
  bool hold = true;
  for (int c=20; hold && c; internal::sleep_seconds(5), --c)
  {
    const result R(DirectExec(("SELECT current_query "
	  "FROM pq_stat_activity "
	  "WHERE procpid=" + to_string(m_backendpid)).c_str()));
    hold = (!R.empty() &&
      !R[0][0].as(string()).empty() &&
      (R[0][0].as(string()) != "<IDLE>"));
  }

  if (hold)
    throw runtime_error("Old backend process stays alive too long to wait for");

  // Now look for our transaction record
  const string Find = "SELECT oid FROM \"" + m_LogTable + "\" "
	              "WHERE oid=" + to_string(ID);

  return !DirectExec(Find.c_str(), 20).empty();
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 - 2016, Roland Bock
 * 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.
 *
 * 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 HOLDER 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 "TabSample.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>

#include <cassert>
#include <iostream>
#include <vector>

SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right)

namespace mysql = sqlpp::mysql;
int main()
{
  mysql::global_library_init();

  auto config = std::make_shared<mysql::connection_config>();
  config->user = "root";
  config->database = "sqlpp_mysql";
  config->debug = true;
  try
  {
    mysql::connection db(config);
  }
  catch (const sqlpp::exception& e)
  {
    std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
    std::cerr << e.what() << std::endl;
    return 1;
  }
  try
  {
    mysql::connection db(config);
    db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
    db.execute(R"(CREATE TABLE tab_sample (
			alpha bigint(20) AUTO_INCREMENT,
			beta varchar(255) DEFAULT NULL,
			gamma bool DEFAULT NULL,
			PRIMARY KEY (alpha)
			))");
    db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
    db.execute(R"(CREATE TABLE tab_foo (
		omega bigint(20) DEFAULT NULL
			))");

    assert(not db(select(sqlpp::value(false).as(sqlpp::alias::a))).front().a);

    const auto tab = TabSample{};
    // clear the table
    db(remove_from(tab).unconditionally());

    // Several ways of ensuring that tab is empty
    assert(not db(select(exists(select(tab.alpha).from(tab).unconditionally())))
                   .front()
                   .exists);  // this is probably the fastest
    assert(not db(select(count(tab.alpha)).from(tab).unconditionally()).front().count);
    assert(db(select(tab.alpha).from(tab).unconditionally()).empty());

    // explicit all_of(tab)
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    select(all_of(tab)).from(tab);
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    db(select(all_of(tab)).from(tab).unconditionally());
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
    {
      std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
      std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
                << std::endl;
    };
    // insert
    db(insert_into(tab).default_values());
    const auto x = select(all_of(tab)).from(tab).unconditionally();
    const auto y = db.prepare(x);
    for (const auto& row : db(db.prepare(select(all_of(tab)).from(tab).unconditionally())))
    {
      std::cerr << "alpha: " << row.alpha.is_null() << std::endl;
      std::cerr << "beta: " << row.beta.is_null() << std::endl;
      std::cerr << "gamma: " << row.gamma.is_null() << std::endl;
    }
    db(insert_into(tab).set(tab.beta = "kaesekuchen", tab.gamma = true));
    db(insert_into(tab).default_values());
    db(insert_into(tab).set(tab.beta = "", tab.gamma = true));

    // update
    db(update(tab).set(tab.gamma = false).where(tab.alpha.in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
    db(update(tab).set(tab.gamma = true).where(tab.alpha.in(1)));

    // remove
    db(remove_from(tab).where(tab.alpha == tab.alpha + 3));

    std::cerr << "+++++++++++++++++++++++++++" << std::endl;
    for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
    {
      std::cerr << __LINE__ << " row.beta: " << row.beta << std::endl;
    }
    std::cerr << "+++++++++++++++++++++++++++" << std::endl;
    decltype(db(select(all_of(tab)).from(tab).unconditionally())) result;
    result = db(select(all_of(tab)).from(tab).unconditionally());
    std::cerr << "Accessing a field directly from the result (using the current row): " << result.begin()->alpha
              << std::endl;
    std::cerr << "Can do that again, no problem: " << result.begin()->alpha << std::endl;

    auto tx = start_transaction(db);
    if (const auto& row =
            *db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally()).begin())
    {
      int a = row.alpha;
      int m = row.max;
      std::cerr << __LINE__ << " row.alpha: " << a << ", row.max: " << m << std::endl;
    }
    tx.commit();

    TabFoo foo;
    for (const auto& row : db(select(tab.alpha).from(tab.join(foo).on(tab.alpha == foo.omega)).unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }

    for (const auto& row :
         db(select(tab.alpha).from(tab.left_outer_join(foo).on(tab.alpha == foo.omega)).unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }

    auto ps = db.prepare(select(all_of(tab))
                             .from(tab)
                             .where(tab.alpha != parameter(tab.alpha) and tab.beta != parameter(tab.beta) and
                                    tab.gamma != parameter(tab.gamma)));
    ps.params.alpha = 7;
    ps.params.beta = "wurzelbrunft";
    ps.params.gamma = true;
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    std::cerr << "--------" << std::endl;
    ps.params.gamma = "false";
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    std::cerr << "--------" << std::endl;
    ps.params.beta = "kaesekuchen";
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    auto pi = db.prepare(insert_into(tab).set(tab.beta = parameter(tab.beta), tab.gamma = true));
    pi.params.beta = "prepared cake";
    std::cerr << "Inserted: " << db(pi) << std::endl;

    auto pu = db.prepare(update(tab).set(tab.gamma = parameter(tab.gamma)).where(tab.beta == "prepared cake"));
    pu.params.gamma = false;
    std::cerr << "Updated: " << db(pu) << std::endl;

    auto pr = db.prepare(remove_from(tab).where(tab.beta != parameter(tab.beta)));
    pr.params.beta = "prepared cake";
    std::cerr << "Deleted lines: " << db(pr) << std::endl;

    for (const auto& row : db(select(case_when(tab.gamma).then(tab.alpha).else_(foo.omega).as(tab.alpha))
                                  .from(tab.cross_join(foo))
                                  .unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }
  }
  catch (const std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << std::endl;
    return 1;
  }
}
<commit_msg>Add dynamic_insert_into test.<commit_after>/*
 * Copyright (c) 2013 - 2016, Roland Bock
 * 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.
 *
 * 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 HOLDER 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 "TabSample.h"
#include <sqlpp11/mysql/mysql.h>
#include <sqlpp11/sqlpp11.h>

#include <cassert>
#include <iostream>
#include <vector>

SQLPP_ALIAS_PROVIDER(left)
SQLPP_ALIAS_PROVIDER(right)

namespace mysql = sqlpp::mysql;
int main()
{
  mysql::global_library_init();

  auto config = std::make_shared<mysql::connection_config>();
  config->user = "root";
  config->database = "sqlpp_mysql";
  config->debug = true;
  try
  {
    mysql::connection db(config);
  }
  catch (const sqlpp::exception& e)
  {
    std::cerr << "For testing, you'll need to create a database sqlpp_mysql for user root (no password)" << std::endl;
    std::cerr << e.what() << std::endl;
    return 1;
  }
  try
  {
    mysql::connection db(config);
    db.execute(R"(DROP TABLE IF EXISTS tab_sample)");
    db.execute(R"(CREATE TABLE tab_sample (
			alpha bigint(20) AUTO_INCREMENT,
			beta varchar(255) DEFAULT NULL,
			gamma bool DEFAULT NULL,
			PRIMARY KEY (alpha)
			))");
    db.execute(R"(DROP TABLE IF EXISTS tab_foo)");
    db.execute(R"(CREATE TABLE tab_foo (
		omega bigint(20) DEFAULT NULL
			))");

    assert(not db(select(sqlpp::value(false).as(sqlpp::alias::a))).front().a);

    const auto tab = TabSample{};
    // clear the table
    db(remove_from(tab).unconditionally());

    // Several ways of ensuring that tab is empty
    assert(not db(select(exists(select(tab.alpha).from(tab).unconditionally())))
                   .front()
                   .exists);  // this is probably the fastest
    assert(not db(select(count(tab.alpha)).from(tab).unconditionally()).front().count);
    assert(db(select(tab.alpha).from(tab).unconditionally()).empty());

    // explicit all_of(tab)
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    select(all_of(tab)).from(tab);
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    db(select(all_of(tab)).from(tab).unconditionally());
    std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
    for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
    {
      std::cerr << __FILE__ << ": " << __LINE__ << std::endl;
      std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma
                << std::endl;
    };
    // insert
    db(insert_into(tab).default_values());
    const auto x = select(all_of(tab)).from(tab).unconditionally();
    const auto y = db.prepare(x);
    for (const auto& row : db(db.prepare(select(all_of(tab)).from(tab).unconditionally())))
    {
      std::cerr << "alpha: " << row.alpha.is_null() << std::endl;
      std::cerr << "beta: " << row.beta.is_null() << std::endl;
      std::cerr << "gamma: " << row.gamma.is_null() << std::endl;
    }
    db(insert_into(tab).set(tab.beta = "kaesekuchen", tab.gamma = true));
    db(insert_into(tab).default_values());
    db(insert_into(tab).set(tab.beta = "", tab.gamma = true));

    // update
    db(update(tab).set(tab.gamma = false).where(tab.alpha.in(sqlpp::value_list(std::vector<int>{1, 2, 3, 4}))));
    db(update(tab).set(tab.gamma = true).where(tab.alpha.in(1)));

    // dynamic insert
    auto dynin = dynamic_insert_into(db, tab).dynamic_set(tab.gamma = true);
    dynin.insert_list.add(tab.beta = "cheesecake");
    db(dynin);

    // remove
    db(remove_from(tab).where(tab.alpha == tab.alpha + 3));

    std::cerr << "+++++++++++++++++++++++++++" << std::endl;
    for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally()))
    {
      std::cerr << __LINE__ << " row.beta: " << row.beta << std::endl;
    }
    std::cerr << "+++++++++++++++++++++++++++" << std::endl;
    decltype(db(select(all_of(tab)).from(tab).unconditionally())) result;
    result = db(select(all_of(tab)).from(tab).unconditionally());
    std::cerr << "Accessing a field directly from the result (using the current row): " << result.begin()->alpha
              << std::endl;
    std::cerr << "Can do that again, no problem: " << result.begin()->alpha << std::endl;

    auto tx = start_transaction(db);
    if (const auto& row =
            *db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally()).begin())
    {
      int a = row.alpha;
      int m = row.max;
      std::cerr << __LINE__ << " row.alpha: " << a << ", row.max: " << m << std::endl;
    }
    tx.commit();

    TabFoo foo;
    for (const auto& row : db(select(tab.alpha).from(tab.join(foo).on(tab.alpha == foo.omega)).unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }

    for (const auto& row :
         db(select(tab.alpha).from(tab.left_outer_join(foo).on(tab.alpha == foo.omega)).unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }

    auto ps = db.prepare(select(all_of(tab))
                             .from(tab)
                             .where(tab.alpha != parameter(tab.alpha) and tab.beta != parameter(tab.beta) and
                                    tab.gamma != parameter(tab.gamma)));
    ps.params.alpha = 7;
    ps.params.beta = "wurzelbrunft";
    ps.params.gamma = true;
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    std::cerr << "--------" << std::endl;
    ps.params.gamma = "false";
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    std::cerr << "--------" << std::endl;
    ps.params.beta = "kaesekuchen";
    for (const auto& row : db(ps))
    {
      std::cerr << "bound result: alpha: " << row.alpha << std::endl;
      std::cerr << "bound result: beta: " << row.beta << std::endl;
      std::cerr << "bound result: gamma: " << row.gamma << std::endl;
    }

    auto pi = db.prepare(insert_into(tab).set(tab.beta = parameter(tab.beta), tab.gamma = true));
    pi.params.beta = "prepared cake";
    std::cerr << "Inserted: " << db(pi) << std::endl;

    auto pu = db.prepare(update(tab).set(tab.gamma = parameter(tab.gamma)).where(tab.beta == "prepared cake"));
    pu.params.gamma = false;
    std::cerr << "Updated: " << db(pu) << std::endl;

    auto pr = db.prepare(remove_from(tab).where(tab.beta != parameter(tab.beta)));
    pr.params.beta = "prepared cake";
    std::cerr << "Deleted lines: " << db(pr) << std::endl;

    for (const auto& row : db(select(case_when(tab.gamma).then(tab.alpha).else_(foo.omega).as(tab.alpha))
                                  .from(tab.cross_join(foo))
                                  .unconditionally()))
    {
      std::cerr << row.alpha << std::endl;
    }
  }
  catch (const std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << std::endl;
    return 1;
  }
}
<|endoftext|>