<commit_before>#include "cell.h"

#include <cmath>
#include <limits>
#include <sstream>
#include <string>

#include "error.h"
#include "hdf5_interface.h"
#include "surface.h"
#include "xml_interface.h"

//TODO: remove this include
#include <iostream>

namespace openmc {

//==============================================================================
// Constants
//==============================================================================

constexpr int32_t OP_LEFT_PAREN   {std::numeric_limits<int32_t>::max()};
constexpr int32_t OP_RIGHT_PAREN  {std::numeric_limits<int32_t>::max() - 1};
constexpr int32_t OP_COMPLEMENT   {std::numeric_limits<int32_t>::max() - 2};
constexpr int32_t OP_INTERSECTION {std::numeric_limits<int32_t>::max() - 3};
constexpr int32_t OP_UNION        {std::numeric_limits<int32_t>::max() - 4};

extern "C" double FP_PRECISION;

//==============================================================================
//! Convert region specification string to integer tokens.
//!
//! The characters (, ), |, and ~ count as separate tokens since they represent
//! operators.
//==============================================================================

std::vector<int32_t>
tokenize(const std::string region_spec) {
  // Check for an empty region_spec first.
  std::vector<int32_t> tokens;
  if (region_spec.empty()) {
    return tokens;
  }

  // Split the region_spec into words delimited by whitespace.  This removes
  // intersection operators but we'll add them back later.
  std::vector<std::string> words{split(region_spec)};

  // Iterate over words in the region_spec.
  for (std::string word : words) {
    // First check to see if this word represents an operator token.
    if (word == "(") {
      tokens.push_back(OP_LEFT_PAREN);
    } else if (word == ")") {
      tokens.push_back(OP_RIGHT_PAREN);
    } else if (word == "|") {
      tokens.push_back(OP_UNION);
    } else if (word == "~") {
      tokens.push_back(OP_COMPLEMENT);

    } else {
      // This word might represent a halfspace.  Check to make sure we recognize
      // all the characters in it.
      for (char c : word) {
        if (!std::isdigit(c) && c != '-') {
          std::stringstream err_msg;
          err_msg << "Region specification contains invalid character, \""
                  << c << "\"";
          fatal_error(err_msg);
        }
      }

      // It's a halfspace.  Convert to integer token.
      tokens.push_back(stoi(word));
    }
  }

  // Add in intersection operators where a missing operator is needed.
  int i = 0;
  while (i < tokens.size()-1) {
    bool left_compat {(tokens[i] < OP_UNION) || (tokens[i] == OP_RIGHT_PAREN)};
    bool right_compat {(tokens[i+1] < OP_UNION)
                       || (tokens[i+1] == OP_LEFT_PAREN)
                       || (tokens[i+1] == OP_COMPLEMENT)};
    if (left_compat && right_compat) {
      tokens.insert(tokens.begin()+i+1, OP_INTERSECTION);
    }
    i++;
  }

  return tokens;
}

//==============================================================================
//! Convert infix region specification to Reverse Polish Notation (RPN)
//!
//! This function uses the shunting-yard algorithm.
//==============================================================================

std::vector<int32_t>
generate_rpn(int32_t cell_id, std::vector<int32_t> infix)
{
  std::vector<int32_t> rpn;
  std::vector<int32_t> stack;

  for (int32_t token : infix) {
    if (token < OP_UNION) {
      // If token is not an operator, add it to output
      rpn.push_back(token);

    } else if (token < OP_RIGHT_PAREN) {
      // Regular operators union, intersection, complement
      while (stack.size() > 0) {
        int32_t op = stack.back();

        if (op < OP_RIGHT_PAREN &&
             ((token == OP_COMPLEMENT && token < op) ||
             (token != OP_COMPLEMENT && token <= op))) {
          // While there is an operator, op, on top of the stack, if the token
          // is left-associative and its precedence is less than or equal to
          // that of op or if the token is right-associative and its precedence
          // is less than that of op, move op to the output queue and push the
          // token on to the stack. Note that only complement is
          // right-associative.
          rpn.push_back(op);
          stack.pop_back();
        } else {
          break;
        }
      }

      stack.push_back(token);

    } else if (token == OP_LEFT_PAREN) {
      // If the token is a left parenthesis, push it onto the stack
      stack.push_back(token);

    } else {
      // If the token is a right parenthesis, move operators from the stack to
      // the output queue until reaching the left parenthesis.
      for (auto it = stack.rbegin(); *it != OP_LEFT_PAREN; it++) {
        // If we run out of operators without finding a left parenthesis, it
        // means there are mismatched parentheses.
        if (it == stack.rend()) {
          std::stringstream err_msg;
          err_msg << "Mismatched parentheses in region specification for cell "
                  << cell_id;
          fatal_error(err_msg);
        }

        rpn.push_back(stack.back());
        stack.pop_back();
      }

      // Pop the left parenthesis.
      stack.pop_back();
    }
  }

  while (stack.size() > 0) {
    int32_t op = stack.back();

    // If the operator is a parenthesis it is mismatched.
    if (op >= OP_RIGHT_PAREN) {
      std::stringstream err_msg;
      err_msg << "Mismatched parentheses in region specification for cell "
              << cell_id;
      fatal_error(err_msg);
    }

    rpn.push_back(stack.back());
    stack.pop_back();
  }

  return rpn;
}

//==============================================================================
// Cell implementation
//==============================================================================

Cell::Cell(pugi::xml_node cell_node)
{
  if (check_for_node(cell_node, "id")) {
    id = stoi(get_node_value(cell_node, "id"));
  } else {
    fatal_error("Must specify id of cell in geometry XML file.");
  }

  //TODO: don't automatically lowercase cell and surface names
  if (check_for_node(cell_node, "name")) {
    name = get_node_value(cell_node, "name");
  }

  if (check_for_node(cell_node, "universe")) {
    universe = stoi(get_node_value(cell_node, "universe"));
  } else {
    universe = 0;
  }

  std::string region_spec {""};
  if (check_for_node(cell_node, "region")) {
    region_spec = get_node_value(cell_node, "region");
  }

  // Get a tokenized representation of the region specification.
  region = tokenize(region_spec);
  region.shrink_to_fit();

  // Convert user IDs to surface indices.
  // Note that the index has 1 added to it in order to preserve the sign.
  for (auto it = region.begin(); it != region.end(); it++) {
    if (*it < OP_UNION) {
      *it = copysign(surface_dict[abs(*it)]+1, *it);
    }
  }

  // Convert the infix region spec to RPN.
  rpn = generate_rpn(id, region);
  rpn.shrink_to_fit();

  // Check if this is a simple cell.
  simple = true;
  for (int32_t token : rpn) {
    if ((token == OP_COMPLEMENT) || (token == OP_UNION)) {
      simple = false;
      break;
    }
  }
}

bool
Cell::contains(const double xyz[3], const double uvw[3],
               int32_t on_surface) const
{
  if (simple) {
    return contains_simple(xyz, uvw, on_surface);
  } else {
    return contains_complex(xyz, uvw, on_surface);
  }
}

std::pair<double, int32_t>
Cell::distance(const double xyz[3], const double uvw[3],
               int32_t on_surface) const
{
  double min_dist {INFTY};
  int32_t i_surf {std::numeric_limits<int32_t>::max()};

  for (int32_t token : rpn) {
    // Ignore this token if it corresponds to an operator rather than a region.
    if (token >= OP_UNION) {continue;}

    // Calculate the distance to this surface.
    // Note the off-by-one indexing
    bool coincident {token == on_surface};
    double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)};
    //std::cout << token << " " << on_surface << " " << coincident << std::endl;

    // Check if this distance is the new minimum.
    if (d < min_dist) {
      if (std::abs(d - min_dist) / min_dist >= FP_PRECISION) {
        min_dist = d;
        i_surf = -token;
      }
    }
  }

  return {min_dist, i_surf};
}

void
Cell::to_hdf5(hid_t cell_group) const
{
//  std::string group_name {"surface "};
//  group_name += std::to_string(id);
//
//  hid_t surf_group = create_group(group_id, group_name);

  if (!name.empty()) {
    write_string(cell_group, "name", name);
  }

  //TODO: Lookup universe id in universe_dict
  //write_int(cell_group, "universe", universe);

  // Write the region specification.
  if (!region.empty()) {
    std::stringstream region_spec {};
    for (int32_t token : region) {
      if (token == OP_LEFT_PAREN) {
        region_spec << " (";
      } else if (token == OP_RIGHT_PAREN) {
        region_spec << " )";
      } else if (token == OP_COMPLEMENT) {
        region_spec << " ~";
      } else if (token == OP_INTERSECTION) {
      } else if (token == OP_UNION) {
        region_spec << " |";
      } else {
        // Note the off-by-one indexing
        region_spec << " " << copysign(surfaces_c[abs(token)-1]->id, token);
      }
    }
    write_string(cell_group, "region", region_spec.str());
  }

//  close_group(cell_group);
}

bool
Cell::contains_simple(const double xyz[3], const double uvw[3],
                      int32_t on_surface) const
{
  for (int32_t token : rpn) {
    if (token < OP_UNION) {
      // If the token is not an operator, evaluate the sense of particle with
      // respect to the surface and see if the token matches the sense. If the
      // particle's surface attribute is set and matches the token, that
      // overrides the determination based on sense().
      if (token == on_surface) {
      } else if (-token == on_surface) {
        return false;
      } else {
        // Note the off-by-one indexing
        bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);
        if (sense != (token > 0)) {return false;}
      }
    }
  }
  return true;
}

bool
Cell::contains_complex(const double xyz[3], const double uvw[3],
                       int32_t on_surface) const
{
  // Make a stack of booleans.  We don't know how big it needs to be, but we do
  // know that rpn.size() is an upper-bound.
  bool stack[rpn.size()];
  int i_stack = -1;

  for (int32_t token : rpn) {
    // If the token is a binary operator (intersection/union), apply it to
    // the last two items on the stack. If the token is a unary operator
    // (complement), apply it to the last item on the stack.
    if (token == OP_UNION) {
      stack[i_stack-1] = stack[i_stack-1] || stack[i_stack];
      i_stack --;
    } else if (token == OP_INTERSECTION) {
      stack[i_stack-1] = stack[i_stack-1] && stack[i_stack];
      i_stack --;
    } else if (token == OP_COMPLEMENT) {
      stack[i_stack] = !stack[i_stack];
    } else {
      // If the token is not an operator, evaluate the sense of particle with
      // respect to the surface and see if the token matches the sense. If the
      // particle's surface attribute is set and matches the token, that
      // overrides the determination based on sense().
      i_stack ++;
      if (token == on_surface) {
        stack[i_stack] = true;
      } else if (-token == on_surface) {
        stack[i_stack] = false;
      } else {
        // Note the off-by-one indexing
        bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);;
        stack[i_stack] = (sense == (token > 0));
      }
    }
  }

  if (i_stack == 0) {
    // The one remaining bool on the stack indicates whether the particle is
    // in the cell.
    return stack[i_stack];
  } else {
    // This case occurs if there is no region specification since i_stack will
    // still be -1.
    return true;
  }
}

//==============================================================================

extern "C" void
read_cells(pugi::xml_node *node)
{
  // Count the number of cells.
  for (pugi::xml_node cell_node: node->children("cell")) {n_cells++;}
  if (n_cells == 0) {
    fatal_error("No cells found in geometry.xml!");
  }

  // Allocate the vector of Cells.
  cells_c.reserve(n_cells);

  // Loop over XML cell elements and populate the array.
  for (pugi::xml_node cell_node: node->children("cell")) {
    cells_c.push_back(Cell(cell_node));
  }
}

//==============================================================================
// Fortran compatibility functions
//==============================================================================

extern "C" {
  Cell* cell_pointer(int32_t cell_ind) {return &cells_c[cell_ind];}

  int32_t cell_id(Cell *c) {return c->id;}

  void cell_set_id(Cell *c, int32_t id) {c->id = id;}

  int32_t cell_universe(Cell *c) {return c->universe;}

  void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;}

  bool cell_simple(Cell *c) {return c->simple;}

  bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface)
  {return c->contains(xyz, uvw, on_surface);}

  void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface,
                     double &min_dist, int32_t &i_surf)
  {
    std::pair<double, int32_t> out = c->distance(xyz, uvw, on_surface);
    min_dist = out.first;
    i_surf = out.second;
  }

  void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);}
}

//extern "C" void free_memory_cells_c()
//{
//  delete cells_c;
//  cells_c = nullptr;
//  n_cells = 0;
//  cell_dict.clear();
//}

} // namespace openmc
<commit_msg>Fix complex cell tokenization<commit_after>#include "cell.h"

#include <cmath>
#include <limits>
#include <sstream>
#include <string>

#include "error.h"
#include "hdf5_interface.h"
#include "surface.h"
#include "xml_interface.h"

//TODO: remove this include
#include <iostream>

namespace openmc {

//==============================================================================
// Constants
//==============================================================================

constexpr int32_t OP_LEFT_PAREN   {std::numeric_limits<int32_t>::max()};
constexpr int32_t OP_RIGHT_PAREN  {std::numeric_limits<int32_t>::max() - 1};
constexpr int32_t OP_COMPLEMENT   {std::numeric_limits<int32_t>::max() - 2};
constexpr int32_t OP_INTERSECTION {std::numeric_limits<int32_t>::max() - 3};
constexpr int32_t OP_UNION        {std::numeric_limits<int32_t>::max() - 4};

extern "C" double FP_PRECISION;

//==============================================================================
//! Convert region specification string to integer tokens.
//!
//! The characters (, ), |, and ~ count as separate tokens since they represent
//! operators.
//==============================================================================

std::vector<int32_t>
tokenize(const std::string region_spec) {
  // Check for an empty region_spec first.
  std::vector<int32_t> tokens;
  if (region_spec.empty()) {
    return tokens;
  }

  // Parse all halfspaces and operators except for intersection (whitespace).
  for (int i = 0; i < region_spec.size(); ) {
    if (region_spec[i] == '(') {
      tokens.push_back(OP_LEFT_PAREN);
      i++;

    } else if (region_spec[i] == ')') {
      tokens.push_back(OP_RIGHT_PAREN);
      i++;

    } else if (region_spec[i] == '|') {
      tokens.push_back(OP_UNION);
      i++;

    } else if (region_spec[i] == '~') {
      tokens.push_back(OP_COMPLEMENT);
      i++;

    } else if (region_spec[i] == '-' || region_spec[i] == '+'
               || std::isdigit(region_spec[i])) {
      // This is the start of a halfspace specification.  Iterate j until we
      // find the end, then push-back everything between i and j.
      int j = i + 1;
      while (j < region_spec.size() && std::isdigit(region_spec[j])) {j++;}
      tokens.push_back(std::stoi(region_spec.substr(i, j-i)));
      i = j;

    } else if (std::isspace(region_spec[i])) {
      i++;

    } else {
      std::stringstream err_msg;
      err_msg << "Region specification contains invalid character, \""
              << region_spec[i] << "\"";
      fatal_error(err_msg);
    }
  }

  // Add in intersection operators where a missing operator is needed.
  int i = 0;
  while (i < tokens.size()-1) {
    bool left_compat {(tokens[i] < OP_UNION) || (tokens[i] == OP_RIGHT_PAREN)};
    bool right_compat {(tokens[i+1] < OP_UNION)
                       || (tokens[i+1] == OP_LEFT_PAREN)
                       || (tokens[i+1] == OP_COMPLEMENT)};
    if (left_compat && right_compat) {
      tokens.insert(tokens.begin()+i+1, OP_INTERSECTION);
    }
    i++;
  }

  return tokens;
}

//==============================================================================
//! Convert infix region specification to Reverse Polish Notation (RPN)
//!
//! This function uses the shunting-yard algorithm.
//==============================================================================

std::vector<int32_t>
generate_rpn(int32_t cell_id, std::vector<int32_t> infix)
{
  std::vector<int32_t> rpn;
  std::vector<int32_t> stack;

  for (int32_t token : infix) {
    if (token < OP_UNION) {
      // If token is not an operator, add it to output
      rpn.push_back(token);

    } else if (token < OP_RIGHT_PAREN) {
      // Regular operators union, intersection, complement
      while (stack.size() > 0) {
        int32_t op = stack.back();

        if (op < OP_RIGHT_PAREN &&
             ((token == OP_COMPLEMENT && token < op) ||
             (token != OP_COMPLEMENT && token <= op))) {
          // While there is an operator, op, on top of the stack, if the token
          // is left-associative and its precedence is less than or equal to
          // that of op or if the token is right-associative and its precedence
          // is less than that of op, move op to the output queue and push the
          // token on to the stack. Note that only complement is
          // right-associative.
          rpn.push_back(op);
          stack.pop_back();
        } else {
          break;
        }
      }

      stack.push_back(token);

    } else if (token == OP_LEFT_PAREN) {
      // If the token is a left parenthesis, push it onto the stack
      stack.push_back(token);

    } else {
      // If the token is a right parenthesis, move operators from the stack to
      // the output queue until reaching the left parenthesis.
      for (auto it = stack.rbegin(); *it != OP_LEFT_PAREN; it++) {
        // If we run out of operators without finding a left parenthesis, it
        // means there are mismatched parentheses.
        if (it == stack.rend()) {
          std::stringstream err_msg;
          err_msg << "Mismatched parentheses in region specification for cell "
                  << cell_id;
          fatal_error(err_msg);
        }

        rpn.push_back(stack.back());
        stack.pop_back();
      }

      // Pop the left parenthesis.
      stack.pop_back();
    }
  }

  while (stack.size() > 0) {
    int32_t op = stack.back();

    // If the operator is a parenthesis it is mismatched.
    if (op >= OP_RIGHT_PAREN) {
      std::stringstream err_msg;
      err_msg << "Mismatched parentheses in region specification for cell "
              << cell_id;
      fatal_error(err_msg);
    }

    rpn.push_back(stack.back());
    stack.pop_back();
  }

  return rpn;
}

//==============================================================================
// Cell implementation
//==============================================================================

Cell::Cell(pugi::xml_node cell_node)
{
  if (check_for_node(cell_node, "id")) {
    id = stoi(get_node_value(cell_node, "id"));
  } else {
    fatal_error("Must specify id of cell in geometry XML file.");
  }

  //TODO: don't automatically lowercase cell and surface names
  if (check_for_node(cell_node, "name")) {
    name = get_node_value(cell_node, "name");
  }

  if (check_for_node(cell_node, "universe")) {
    universe = stoi(get_node_value(cell_node, "universe"));
  } else {
    universe = 0;
  }

  std::string region_spec {""};
  if (check_for_node(cell_node, "region")) {
    region_spec = get_node_value(cell_node, "region");
  }

  // Get a tokenized representation of the region specification.
  region = tokenize(region_spec);
  region.shrink_to_fit();

  // Convert user IDs to surface indices.
  // Note that the index has 1 added to it in order to preserve the sign.
  for (auto it = region.begin(); it != region.end(); it++) {
    if (*it < OP_UNION) {
      *it = copysign(surface_dict[abs(*it)]+1, *it);
    }
  }

  // Convert the infix region spec to RPN.
  rpn = generate_rpn(id, region);
  rpn.shrink_to_fit();

  // Check if this is a simple cell.
  simple = true;
  for (int32_t token : rpn) {
    if ((token == OP_COMPLEMENT) || (token == OP_UNION)) {
      simple = false;
      break;
    }
  }
}

bool
Cell::contains(const double xyz[3], const double uvw[3],
               int32_t on_surface) const
{
  if (simple) {
    return contains_simple(xyz, uvw, on_surface);
  } else {
    return contains_complex(xyz, uvw, on_surface);
  }
}

std::pair<double, int32_t>
Cell::distance(const double xyz[3], const double uvw[3],
               int32_t on_surface) const
{
  double min_dist {INFTY};
  int32_t i_surf {std::numeric_limits<int32_t>::max()};

  for (int32_t token : rpn) {
    // Ignore this token if it corresponds to an operator rather than a region.
    if (token >= OP_UNION) {continue;}

    // Calculate the distance to this surface.
    // Note the off-by-one indexing
    bool coincident {token == on_surface};
    double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)};
    //std::cout << token << " " << on_surface << " " << coincident << std::endl;

    // Check if this distance is the new minimum.
    if (d < min_dist) {
      if (std::abs(d - min_dist) / min_dist >= FP_PRECISION) {
        min_dist = d;
        i_surf = -token;
      }
    }
  }

  return {min_dist, i_surf};
}

void
Cell::to_hdf5(hid_t cell_group) const
{
//  std::string group_name {"surface "};
//  group_name += std::to_string(id);
//
//  hid_t surf_group = create_group(group_id, group_name);

  if (!name.empty()) {
    write_string(cell_group, "name", name);
  }

  //TODO: Lookup universe id in universe_dict
  //write_int(cell_group, "universe", universe);

  // Write the region specification.
  if (!region.empty()) {
    std::stringstream region_spec {};
    for (int32_t token : region) {
      if (token == OP_LEFT_PAREN) {
        region_spec << " (";
      } else if (token == OP_RIGHT_PAREN) {
        region_spec << " )";
      } else if (token == OP_COMPLEMENT) {
        region_spec << " ~";
      } else if (token == OP_INTERSECTION) {
      } else if (token == OP_UNION) {
        region_spec << " |";
      } else {
        // Note the off-by-one indexing
        region_spec << " " << copysign(surfaces_c[abs(token)-1]->id, token);
      }
    }
    write_string(cell_group, "region", region_spec.str());
  }

//  close_group(cell_group);
}

bool
Cell::contains_simple(const double xyz[3], const double uvw[3],
                      int32_t on_surface) const
{
  for (int32_t token : rpn) {
    if (token < OP_UNION) {
      // If the token is not an operator, evaluate the sense of particle with
      // respect to the surface and see if the token matches the sense. If the
      // particle's surface attribute is set and matches the token, that
      // overrides the determination based on sense().
      if (token == on_surface) {
      } else if (-token == on_surface) {
        return false;
      } else {
        // Note the off-by-one indexing
        bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);
        if (sense != (token > 0)) {return false;}
      }
    }
  }
  return true;
}

bool
Cell::contains_complex(const double xyz[3], const double uvw[3],
                       int32_t on_surface) const
{
  // Make a stack of booleans.  We don't know how big it needs to be, but we do
  // know that rpn.size() is an upper-bound.
  bool stack[rpn.size()];
  int i_stack = -1;

  for (int32_t token : rpn) {
    // If the token is a binary operator (intersection/union), apply it to
    // the last two items on the stack. If the token is a unary operator
    // (complement), apply it to the last item on the stack.
    if (token == OP_UNION) {
      stack[i_stack-1] = stack[i_stack-1] || stack[i_stack];
      i_stack --;
    } else if (token == OP_INTERSECTION) {
      stack[i_stack-1] = stack[i_stack-1] && stack[i_stack];
      i_stack --;
    } else if (token == OP_COMPLEMENT) {
      stack[i_stack] = !stack[i_stack];
    } else {
      // If the token is not an operator, evaluate the sense of particle with
      // respect to the surface and see if the token matches the sense. If the
      // particle's surface attribute is set and matches the token, that
      // overrides the determination based on sense().
      i_stack ++;
      if (token == on_surface) {
        stack[i_stack] = true;
      } else if (-token == on_surface) {
        stack[i_stack] = false;
      } else {
        // Note the off-by-one indexing
        bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);;
        stack[i_stack] = (sense == (token > 0));
      }
    }
  }

  if (i_stack == 0) {
    // The one remaining bool on the stack indicates whether the particle is
    // in the cell.
    return stack[i_stack];
  } else {
    // This case occurs if there is no region specification since i_stack will
    // still be -1.
    return true;
  }
}

//==============================================================================

extern "C" void
read_cells(pugi::xml_node *node)
{
  // Count the number of cells.
  for (pugi::xml_node cell_node: node->children("cell")) {n_cells++;}
  if (n_cells == 0) {
    fatal_error("No cells found in geometry.xml!");
  }

  // Allocate the vector of Cells.
  cells_c.reserve(n_cells);

  // Loop over XML cell elements and populate the array.
  for (pugi::xml_node cell_node: node->children("cell")) {
    cells_c.push_back(Cell(cell_node));
  }
}

//==============================================================================
// Fortran compatibility functions
//==============================================================================

extern "C" {
  Cell* cell_pointer(int32_t cell_ind) {return &cells_c[cell_ind];}

  int32_t cell_id(Cell *c) {return c->id;}

  void cell_set_id(Cell *c, int32_t id) {c->id = id;}

  int32_t cell_universe(Cell *c) {return c->universe;}

  void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;}

  bool cell_simple(Cell *c) {return c->simple;}

  bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface)
  {return c->contains(xyz, uvw, on_surface);}

  void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface,
                     double &min_dist, int32_t &i_surf)
  {
    std::pair<double, int32_t> out = c->distance(xyz, uvw, on_surface);
    min_dist = out.first;
    i_surf = out.second;
  }

  void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);}
}

//extern "C" void free_memory_cells_c()
//{
//  delete cells_c;
//  cells_c = nullptr;
//  n_cells = 0;
//  cell_dict.clear();
//}

} // namespace openmc
<|endoftext|>


<commit_before>#include <stdexcept>
#include <iostream>
#include <chrono>
#include <thread>

#include "i2c.h"
#include "ledMatrix.h"

void dotSteps( LedMatrix *m, int x, int y, int col )
{
   m->clearBuffer();
   m->setDot( x, y, col );
   m->displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
}

void dotSquare( LedMatrix *m, int offset, int col )
{
   for( int x = offset; x < 8 - offset; ++x )
      dotSteps( m, x, offset, col );
   for( int y = offset + 1; y < 8 - offset; ++y )
      dotSteps( m, 7 - offset, y, col );
   for( int x = 6 - offset; x >= offset; --x )
      dotSteps( m, x, 7 - offset, col );
   for( int y = 6 - offset; y > offset; --y )
      dotSteps( m, offset, y, col );
}

void showHorse( LedMatrix *l )
{
   l->clearBuffer();
   // lawn
   l->setSquare( 0, 0, 7, 0, LedMatrix::GREEN );
   // shoes
   l->setDot( 2, 1, LedMatrix::RED );
   l->setDot( 5, 1, LedMatrix::RED );
   // legs
   l->setSquare( 2, 2, 2, 4, LedMatrix::YELLOW );
   l->setSquare( 5, 2, 5, 3, LedMatrix::YELLOW );
   // body
   l->setSquare( 3, 4, 5, 5, LedMatrix::YELLOW );
   // head
   l->setSquare( 0, 4, 0, 6, LedMatrix::YELLOW );
   l->setDot( 1, 5, LedMatrix::YELLOW );
   // tail
   l->setDot( 6, 5, LedMatrix::RED );
   l->setSquare( 7, 2, 7, 4, LedMatrix::RED );
   // mane
   l->setDot( 0, 7, LedMatrix::RED );
   l->setDot( 1, 6, LedMatrix::RED );
   l->setDot( 2, 5, LedMatrix::RED );
   l->displayBuffer();
}

void showCharacters( LedMatrix *l )
{
   for( char c = ' '; c <= '~'; ++c )
   {
      int color = LedMatrix::GREEN;
      switch( c % 3 )
      {
         case 0: color = LedMatrix::RED; break;
         case 1: color = LedMatrix::GREEN; break;
         case 2: color = LedMatrix::YELLOW; break;
      }
      l->clearBuffer();
      l->setChar( c, color );
      l->displayBuffer();
      std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
   }
}

void doIt( )
{
   LedMatrix ledMatrix( "/dev/i2c-1", 0x70 );

   showHorse( &ledMatrix );
   std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );

   // set pixel
   const uint8_t greenCross[LedMatrix::BUF_SIZE] = {
      0x81, 0, 0x42, 0, 0x24, 0, 0x18, 0, 0x18, 0, 0x24, 0, 0x42, 0, 0x81, 0 };

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::RED );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::GREEN );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::YELLOW );
   ledMatrix.displayBuffer();
   for( int k = 1; k <= 15; ++k )
   {
      ledMatrix.setBrightness( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
   }
   for( int k = 14; k >= 0; --k )
   {
      ledMatrix.setBrightness( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
   }

   // turn blink on
   for( int k = 1; k <= 3; ++k )
   {
      ledMatrix.setBlinkrate( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 2000 ) );
      ledMatrix.setBlinkrate( 0 );
      std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );
   }

   ledMatrix.clearBuffer( );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
   ledMatrix.setBuffer( greenCross );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   showCharacters( &ledMatrix );

   dotSquare( &ledMatrix, 0, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 1, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 2, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 3, LedMatrix::GREEN );

   dotSquare( &ledMatrix, 0, LedMatrix::RED );
   dotSquare( &ledMatrix, 1, LedMatrix::RED );
   dotSquare( &ledMatrix, 2, LedMatrix::RED );
   dotSquare( &ledMatrix, 3, LedMatrix::RED );

   dotSquare( &ledMatrix, 0, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 1, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 2, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 3, LedMatrix::YELLOW );
}

int main( int argc, char *argv[] )
{
   try
   {
      doIt( );
   }
   catch( const std::exception &e )
   {
      std::cerr << "Error: " << e.what() << '\n';
      return 1;
   }
   catch( ... )
   {
      std::cerr << "Unknown error\n";
      return 1;
   }
}
<commit_msg>LED Matrix: add showSmiley()<commit_after>#include <stdexcept>
#include <iostream>
#include <chrono>
#include <thread>

#include "i2c.h"
#include "ledMatrix.h"

void dotSteps( LedMatrix *m, int x, int y, int col )
{
   m->clearBuffer();
   m->setDot( x, y, col );
   m->displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
}

void dotSquare( LedMatrix *m, int offset, int col )
{
   for( int x = offset; x < 8 - offset; ++x )
      dotSteps( m, x, offset, col );
   for( int y = offset + 1; y < 8 - offset; ++y )
      dotSteps( m, 7 - offset, y, col );
   for( int x = 6 - offset; x >= offset; --x )
      dotSteps( m, x, 7 - offset, col );
   for( int y = 6 - offset; y > offset; --y )
      dotSteps( m, offset, y, col );
}

void showHorse( LedMatrix *l )
{
   l->clearBuffer();
   // lawn
   l->setSquare( 0, 0, 7, 0, LedMatrix::GREEN );
   // shoes
   l->setDot( 2, 1, LedMatrix::RED );
   l->setDot( 5, 1, LedMatrix::RED );
   // legs
   l->setSquare( 2, 2, 2, 4, LedMatrix::YELLOW );
   l->setSquare( 5, 2, 5, 3, LedMatrix::YELLOW );
   // body
   l->setSquare( 3, 4, 5, 5, LedMatrix::YELLOW );
   // head
   l->setSquare( 0, 4, 0, 6, LedMatrix::YELLOW );
   l->setDot( 1, 5, LedMatrix::YELLOW );
   // tail
   l->setDot( 6, 5, LedMatrix::RED );
   l->setSquare( 7, 2, 7, 4, LedMatrix::RED );
   // mane
   l->setDot( 0, 7, LedMatrix::RED );
   l->setDot( 1, 6, LedMatrix::RED );
   l->setDot( 2, 5, LedMatrix::RED );
   l->displayBuffer();
}

void showSmiley( LedMatrix *l )
{
   l->clearBuffer();
   // l->setDot( 0, 2, LedMatrix::RED );
   l->setDot( 0, 1, LedMatrix::RED );
   l->setSquare( 1, 0, 5, 0, LedMatrix::RED );
   l->setDot( 6, 1, LedMatrix::RED );
   // l->setDot( 6, 2, LedMatrix::RED );
   l->setDot( 3, 3, LedMatrix::YELLOW );
   l->setDot( 3, 4, LedMatrix::YELLOW );
   l->setDot( 1, 6, LedMatrix::GREEN );
   l->setDot( 5, 6, LedMatrix::GREEN );
   l->displayBuffer();
}

void showCharacters( LedMatrix *l )
{
   for( char c = ' '; c <= '~'; ++c )
   {
      int color = LedMatrix::GREEN;
      switch( c % 3 )
      {
         case 0: color = LedMatrix::RED; break;
         case 1: color = LedMatrix::GREEN; break;
         case 2: color = LedMatrix::YELLOW; break;
      }
      l->clearBuffer();
      l->setChar( c, color );
      l->displayBuffer();
      std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
   }
}

void doIt( )
{
   LedMatrix ledMatrix( "/dev/i2c-1", 0x70 );

   showHorse( &ledMatrix );
   std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );

   showSmiley( &ledMatrix );
   std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );

   // set pixel
   const uint8_t greenCross[LedMatrix::BUF_SIZE] = {
      0x81, 0, 0x42, 0, 0x24, 0, 0x18, 0, 0x18, 0, 0x24, 0, 0x42, 0, 0x81, 0 };

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::RED );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::GREEN );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   ledMatrix.clearBuffer( );
   ledMatrix.setSquare( 0, 0, 7, 7, LedMatrix::YELLOW );
   ledMatrix.displayBuffer();
   for( int k = 1; k <= 15; ++k )
   {
      ledMatrix.setBrightness( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
   }
   for( int k = 14; k >= 0; --k )
   {
      ledMatrix.setBrightness( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
   }

   // turn blink on
   for( int k = 1; k <= 3; ++k )
   {
      ledMatrix.setBlinkrate( k );
      std::this_thread::sleep_for( std::chrono::milliseconds( 2000 ) );
      ledMatrix.setBlinkrate( 0 );
      std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) );
   }

   ledMatrix.clearBuffer( );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
   ledMatrix.setBuffer( greenCross );
   ledMatrix.displayBuffer();
   std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );

   showCharacters( &ledMatrix );

   dotSquare( &ledMatrix, 0, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 1, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 2, LedMatrix::GREEN );
   dotSquare( &ledMatrix, 3, LedMatrix::GREEN );

   dotSquare( &ledMatrix, 0, LedMatrix::RED );
   dotSquare( &ledMatrix, 1, LedMatrix::RED );
   dotSquare( &ledMatrix, 2, LedMatrix::RED );
   dotSquare( &ledMatrix, 3, LedMatrix::RED );

   dotSquare( &ledMatrix, 0, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 1, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 2, LedMatrix::YELLOW );
   dotSquare( &ledMatrix, 3, LedMatrix::YELLOW );
}

int main( int argc, char *argv[] )
{
   try
   {
      doIt( );
   }
   catch( const std::exception &e )
   {
      std::cerr << "Error: " << e.what() << '\n';
      return 1;
   }
   catch( ... )
   {
      std::cerr << "Unknown error\n";
      return 1;
   }
}
<|endoftext|>


<commit_before>//===-- sanitizer_unwind_linux_libcdep.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the unwind.h-based (aka "slow") stack unwinding routines
// available to the tools on Linux, Android, NetBSD, FreeBSD, and Solaris.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
    SANITIZER_SOLARIS
#include "sanitizer_common.h"
#include "sanitizer_stacktrace.h"

#if SANITIZER_ANDROID
#include <dlfcn.h>  // for dlopen()
#endif

#if SANITIZER_FREEBSD
#define _GNU_SOURCE  // to declare _Unwind_Backtrace() from <unwind.h>
#endif
#include <unwind.h>

namespace __sanitizer {

namespace {

//---------------------------- UnwindSlow --------------------------------------

typedef struct {
  uptr absolute_pc;
  uptr stack_top;
  uptr stack_size;
} backtrace_frame_t;

extern "C" {
typedef void *(*acquire_my_map_info_list_func)();
typedef void (*release_my_map_info_list_func)(void *map);
typedef sptr (*unwind_backtrace_signal_arch_func)(
    void *siginfo, void *sigcontext, void *map_info_list,
    backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
acquire_my_map_info_list_func acquire_my_map_info_list;
release_my_map_info_list_func release_my_map_info_list;
unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
} // extern "C"

#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder() {
  if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return;

  // Pre-lollipop Android can not unwind through signal handler frames with
  // libgcc unwinder, but it has a libcorkscrew.so library with the necessary
  // workarounds.
  void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
  if (!p) {
    VReport(1,
            "Failed to open libcorkscrew.so. You may see broken stack traces "
            "in SEGV reports.");
    return;
  }
  acquire_my_map_info_list =
      (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
  release_my_map_info_list =
      (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
  unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
      p, "unwind_backtrace_signal_arch");
  if (!acquire_my_map_info_list || !release_my_map_info_list ||
      !unwind_backtrace_signal_arch) {
    VReport(1,
            "Failed to find one of the required symbols in libcorkscrew.so. "
            "You may see broken stack traces in SEGV reports.");
    acquire_my_map_info_list = 0;
    unwind_backtrace_signal_arch = 0;
    release_my_map_info_list = 0;
  }
}
#endif

#if defined(__arm__) && !SANITIZER_NETBSD
// NetBSD uses dwarf EH
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif

uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
#if defined(__arm__) && !SANITIZER_MAC
  uptr val;
  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
      15 /* r15 = PC */, _UVRSD_UINT32, &val);
  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
  // Clear the Thumb bit.
  return val & ~(uptr)1;
#else
  return (uptr)_Unwind_GetIP(ctx);
#endif
}

struct UnwindTraceArg {
  BufferedStackTrace *stack;
  u32 max_depth;
};

_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
  UnwindTraceArg *arg = (UnwindTraceArg*)param;
  CHECK_LT(arg->stack->size, arg->max_depth);
  uptr pc = Unwind_GetIP(ctx);
  const uptr kPageSize = GetPageSizeCached();
  // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
  // x86_64) is invalid and stop unwinding here.  If we're adding support for
  // a platform where this isn't true, we need to reconsider this check.
  if (pc < kPageSize) return UNWIND_STOP;
  arg->stack->trace_buffer[arg->stack->size++] = pc;
  if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
  return UNWIND_CONTINUE;
}

}  // namespace

void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
  CHECK_GE(max_depth, 2);
  size = 0;
  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
  _Unwind_Backtrace(Unwind_Trace, &arg);
  // We need to pop a few frames so that pc is on top.
  uptr to_pop = LocatePcInTrace(pc);
  // trace_buffer[0] belongs to the current function so we always pop it,
  // unless there is only 1 frame in the stack trace (1 frame is always better
  // than 0!).
  // 1-frame stacks don't normally happen, but this depends on the actual
  // unwinder implementation (libgcc, libunwind, etc) which is outside of our
  // control.
  if (to_pop == 0 && size > 1)
    to_pop = 1;
  PopStackFrames(to_pop);
#if defined(__GNUC__) && defined(__sparc__)
  // __builtin_return_address returns the address of the call instruction
  // on the SPARC and not the return address, so we need to compensate.
  trace_buffer[0] = GetNextInstructionPc(pc);
#else
  trace_buffer[0] = pc;
#endif
}

void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
  CHECK(context);
  CHECK_GE(max_depth, 2);
  if (!unwind_backtrace_signal_arch) {
    UnwindSlow(pc, max_depth);
    return;
  }

  void *map = acquire_my_map_info_list();
  CHECK(map);
  InternalMmapVector<backtrace_frame_t> frames(kStackTraceMax);
  // siginfo argument appears to be unused.
  sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
                                          frames.data(),
                                          /* ignore_depth */ 0, max_depth);
  release_my_map_info_list(map);
  if (res < 0) return;
  CHECK_LE((uptr)res, kStackTraceMax);

  size = 0;
  // +2 compensate for libcorkscrew unwinder returning addresses of call
  // instructions instead of raw return addresses.
  for (sptr i = 0; i < res; ++i)
    trace_buffer[size++] = frames[i].absolute_pc + 2;
}

}  // namespace __sanitizer

#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
        // SANITIZER_SOLARIS
<commit_msg>Move SanitizerInitializeUnwinder outside anonymous namespace.<commit_after>//===-- sanitizer_unwind_linux_libcdep.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the unwind.h-based (aka "slow") stack unwinding routines
// available to the tools on Linux, Android, NetBSD, FreeBSD, and Solaris.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
    SANITIZER_SOLARIS
#include "sanitizer_common.h"
#include "sanitizer_stacktrace.h"

#if SANITIZER_ANDROID
#include <dlfcn.h>  // for dlopen()
#endif

#if SANITIZER_FREEBSD
#define _GNU_SOURCE  // to declare _Unwind_Backtrace() from <unwind.h>
#endif
#include <unwind.h>

namespace __sanitizer {

namespace {

//---------------------------- UnwindSlow --------------------------------------

typedef struct {
  uptr absolute_pc;
  uptr stack_top;
  uptr stack_size;
} backtrace_frame_t;

extern "C" {
typedef void *(*acquire_my_map_info_list_func)();
typedef void (*release_my_map_info_list_func)(void *map);
typedef sptr (*unwind_backtrace_signal_arch_func)(
    void *siginfo, void *sigcontext, void *map_info_list,
    backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth);
acquire_my_map_info_list_func acquire_my_map_info_list;
release_my_map_info_list_func release_my_map_info_list;
unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
} // extern "C"

#if defined(__arm__) && !SANITIZER_NETBSD
// NetBSD uses dwarf EH
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif

uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
#if defined(__arm__) && !SANITIZER_MAC
  uptr val;
  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
      15 /* r15 = PC */, _UVRSD_UINT32, &val);
  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
  // Clear the Thumb bit.
  return val & ~(uptr)1;
#else
  return (uptr)_Unwind_GetIP(ctx);
#endif
}

struct UnwindTraceArg {
  BufferedStackTrace *stack;
  u32 max_depth;
};

_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
  UnwindTraceArg *arg = (UnwindTraceArg*)param;
  CHECK_LT(arg->stack->size, arg->max_depth);
  uptr pc = Unwind_GetIP(ctx);
  const uptr kPageSize = GetPageSizeCached();
  // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
  // x86_64) is invalid and stop unwinding here.  If we're adding support for
  // a platform where this isn't true, we need to reconsider this check.
  if (pc < kPageSize) return UNWIND_STOP;
  arg->stack->trace_buffer[arg->stack->size++] = pc;
  if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
  return UNWIND_CONTINUE;
}

}  // namespace

#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder() {
  if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return;

  // Pre-lollipop Android can not unwind through signal handler frames with
  // libgcc unwinder, but it has a libcorkscrew.so library with the necessary
  // workarounds.
  void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
  if (!p) {
    VReport(1,
            "Failed to open libcorkscrew.so. You may see broken stack traces "
            "in SEGV reports.");
    return;
  }
  acquire_my_map_info_list =
      (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list");
  release_my_map_info_list =
      (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list");
  unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym(
      p, "unwind_backtrace_signal_arch");
  if (!acquire_my_map_info_list || !release_my_map_info_list ||
      !unwind_backtrace_signal_arch) {
    VReport(1,
            "Failed to find one of the required symbols in libcorkscrew.so. "
            "You may see broken stack traces in SEGV reports.");
    acquire_my_map_info_list = 0;
    unwind_backtrace_signal_arch = 0;
    release_my_map_info_list = 0;
  }
}
#endif

void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
  CHECK_GE(max_depth, 2);
  size = 0;
  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
  _Unwind_Backtrace(Unwind_Trace, &arg);
  // We need to pop a few frames so that pc is on top.
  uptr to_pop = LocatePcInTrace(pc);
  // trace_buffer[0] belongs to the current function so we always pop it,
  // unless there is only 1 frame in the stack trace (1 frame is always better
  // than 0!).
  // 1-frame stacks don't normally happen, but this depends on the actual
  // unwinder implementation (libgcc, libunwind, etc) which is outside of our
  // control.
  if (to_pop == 0 && size > 1)
    to_pop = 1;
  PopStackFrames(to_pop);
#if defined(__GNUC__) && defined(__sparc__)
  // __builtin_return_address returns the address of the call instruction
  // on the SPARC and not the return address, so we need to compensate.
  trace_buffer[0] = GetNextInstructionPc(pc);
#else
  trace_buffer[0] = pc;
#endif
}

void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
  CHECK(context);
  CHECK_GE(max_depth, 2);
  if (!unwind_backtrace_signal_arch) {
    UnwindSlow(pc, max_depth);
    return;
  }

  void *map = acquire_my_map_info_list();
  CHECK(map);
  InternalMmapVector<backtrace_frame_t> frames(kStackTraceMax);
  // siginfo argument appears to be unused.
  sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map,
                                          frames.data(),
                                          /* ignore_depth */ 0, max_depth);
  release_my_map_info_list(map);
  if (res < 0) return;
  CHECK_LE((uptr)res, kStackTraceMax);

  size = 0;
  // +2 compensate for libcorkscrew unwinder returning addresses of call
  // instructions instead of raw return addresses.
  for (sptr i = 0; i < res; ++i)
    trace_buffer[size++] = frames[i].absolute_pc + 2;
}

}  // namespace __sanitizer

#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
        // SANITIZER_SOLARIS
<|endoftext|>


<commit_before>#pragma once

#include "util/typedefs.hpp"

#include <fmt/format.h>
#include <plog/Log.h>

#include "core/ui/canvas.hpp"

namespace top1::ui::drawing {

  const uint WIDTH = 320;
  const uint HEIGHT = 240;

  namespace Colours {

    const Colour Black     = Colour(0x000000);

    const MainColour White = {0xFFFFFF, 0x646464};
    const MainColour Red   = {0xFF2A2A, 0x6E0C0C};
    const MainColour Green = {0x5ECF3E, 0x0C6E0C};
    const MainColour Blue  = {0x0A7CFF, 0x0C0C6E};

    const Colour Gray60    = 0x999999;
    const Colour Gray70    = 0xB2B2B2;

  } // Colours

  namespace Fonts {
    inline Font Light;
    inline Font Norm;
    inline Font Bold;
  }

  inline void initUtils(Canvas &canvas) {
    Fonts::Light = Font(canvas, "TOP-1 Light", "./fonts/TOP-1/TOP-1.ttf.ttf");
    if (!Fonts::Light.valid()) {
      LOGE << "Invalid font: " << Fonts::Light.name;
    }
    Fonts::Norm = Font(canvas, "TOP-1 Regular", "./fonts/TOP-1/TOP-1.ttf");
    if (!Fonts::Norm.valid()) {
      LOGE << "Invalid font: " << Fonts::Norm.name;
    }
    Fonts::Bold = Font(canvas, "TOP-1 Bold", "./fonts/TOP-1/TOP-1.ttf");
    if (!Fonts::Bold.valid()) {
      LOGE << "Invalid font: " << Fonts::Bold.name;
    }
  }

} // ui::drawing
<commit_msg>Who needs three fonts when you can have one?<commit_after>#pragma once

#include "util/typedefs.hpp"

#include <fmt/format.h>
#include <plog/Log.h>

#include "core/ui/canvas.hpp"

namespace top1::ui::drawing {

  const uint WIDTH = 320;
  const uint HEIGHT = 240;

  namespace Colours {

    const Colour Black     = Colour(0x000000);

    const MainColour White = {0xFFFFFF, 0x646464};
    const MainColour Red   = {0xFF2A2A, 0x6E0C0C};
    const MainColour Green = {0x5ECF3E, 0x0C6E0C};
    const MainColour Blue  = {0x0A7CFF, 0x0C0C6E};

    const Colour Gray60    = 0x999999;
    const Colour Gray70    = 0xB2B2B2;

  } // Colours

  namespace Fonts {
    inline Font Light;
    inline Font Norm;
    inline Font Bold;
  }

  inline void initUtils(Canvas &canvas) {
    Fonts::Light = Font(canvas, "TOP-1 Light", "./fonts/TOP-1/TOP-1.ttf");
    if (!Fonts::Light.valid()) {
      LOGE << "Invalid font: " << Fonts::Light.name;
    }
    Fonts::Norm = Font(canvas, "TOP-1 Regular", "./fonts/TOP-1/TOP-1.ttf");
    if (!Fonts::Norm.valid()) {
      LOGE << "Invalid font: " << Fonts::Norm.name;
    }
    Fonts::Bold = Font(canvas, "TOP-1 Bold", "./fonts/TOP-1/TOP-1.ttf");
    if (!Fonts::Bold.valid()) {
      LOGE << "Invalid font: " << Fonts::Bold.name;
    }
  }

} // ui::drawing
<|endoftext|>


<commit_before>//=======================================================================
// Copyright 2014-2015 David Simmons-Duffin.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

// Currently, SDPB uses tinyxml2 to parse an input file into an XML
// tree, which is stored entirely in memory.  This tree is then
// transformed into the appropriate data structures using the parse
// functions below.  In the future, this could be made more memory
// efficient by avoiding building the XML tree in memory.

// See the manual for a description of the correct XML input format.

#include <vector>
#include "types.h"
#include "parse.h"
#include "Polynomial.h"
#include "SDP.h"
#ifdef ___SHARED_TINYXML2___
#include <tinyxml2.h>
#else
#include "tinyxml2/tinyxml2.h"
#endif

using std::vector;
using tinyxml2::XMLDocument;
using tinyxml2::XMLElement;
using boost::filesystem::path;

// parse a bunch of adjacent elements with tag `name'
// using the function `parse' for each element, and
// append the result to returnvec.
template <class T>
void parseAppendMany(const char *name,
                     T(*parse)(XMLElement *),
                     XMLElement *elt,
                     vector<T> &returnvec) {
  XMLElement *e;
  for (e = elt->FirstChildElement(name);
       e != NULL;
       e = e->NextSiblingElement(name)) {
    returnvec.push_back(parse(e));
  }
}

template <class T>
vector<T> parseMany(const char *name,
                    T(*parse)(XMLElement *),
                    XMLElement *elt) {
  vector<T> v;
  parseAppendMany(name, parse, elt, v);
  return v;
}

Real parseReal(XMLElement *xml) {
  return Real(xml->GetText());
}

int parseInt(XMLElement *xml) {
  return atoi(xml->GetText());
}

Vector parseVector(XMLElement *xml) {
  return parseMany("elt", parseReal, xml);
}

Matrix parseMatrix(XMLElement *xml) {
  Matrix m;
  m.rows     = parseInt(xml->FirstChildElement("rows"));
  m.cols     = parseInt(xml->FirstChildElement("cols"));
  m.elements = parseVector(xml->FirstChildElement("elements"));
  return m;
}

Polynomial parsePolynomial(XMLElement *xml) {
  Polynomial p;
  p.coefficients = parseMany("coeff", parseReal, xml);
  return p;
}

vector<Polynomial> parsePolynomialVector(XMLElement *xml) {
  return parseMany("polynomial", parsePolynomial, xml);
}

PolynomialVectorMatrix parsePolynomialVectorMatrix(XMLElement *xml) {
  PolynomialVectorMatrix m;
  m.rows           = parseInt(xml->FirstChildElement("rows"));
  m.cols           = parseInt(xml->FirstChildElement("cols"));
  m.elements       = parseMany("polynomialVector", parsePolynomialVector,
                               xml->FirstChildElement("elements"));
  m.samplePoints   = parseVector(xml->FirstChildElement("samplePoints"));
  m.sampleScalings = parseVector(xml->FirstChildElement("sampleScalings"));
  m.bilinearBasis  = parsePolynomialVector(xml->FirstChildElement("bilinearBasis"));
  return m;
}

SDP readBootstrapSDP(const vector<path> sdpFiles) {
  Vector objective;
  vector<PolynomialVectorMatrix> polynomialVectorMatrices;
  for (auto const& sdpFile: sdpFiles) {
    XMLDocument doc;
    doc.LoadFile(sdpFile.c_str());
    XMLElement* xml = doc.FirstChildElement("sdp");
    if(xml->FirstChildElement("objective") != NULL) {
      objective = parseVector(xml->FirstChildElement("objective"));
    }
    if(xml->FirstChildElement("polynomialVectorMatrices") != NULL) {
      parseAppendMany("polynomialVectorMatrix",
                      parsePolynomialVectorMatrix,
                      xml->FirstChildElement("polynomialVectorMatrices"),
                      polynomialVectorMatrices);
    }
  }
  return bootstrapSDP(objective,polynomialVectorMatrices);
}
<commit_msg>Presumably fixed a compilation error on Windows.<commit_after>//=======================================================================
// Copyright 2014-2015 David Simmons-Duffin.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

// Currently, SDPB uses tinyxml2 to parse an input file into an XML
// tree, which is stored entirely in memory.  This tree is then
// transformed into the appropriate data structures using the parse
// functions below.  In the future, this could be made more memory
// efficient by avoiding building the XML tree in memory.

// See the manual for a description of the correct XML input format.

#include <vector>
#include "types.h"
#include "parse.h"
#include "Polynomial.h"
#include "SDP.h"
#ifdef ___SHARED_TINYXML2___
#include <tinyxml2.h>
#else
#include "tinyxml2/tinyxml2.h"
#endif

using std::vector;
using tinyxml2::XMLDocument;
using tinyxml2::XMLElement;
using boost::filesystem::path;

// parse a bunch of adjacent elements with tag `name'
// using the function `parse' for each element, and
// append the result to returnvec.
template <class T>
void parseAppendMany(const char *name,
                     T(*parse)(XMLElement *),
                     XMLElement *elt,
                     vector<T> &returnvec) {
  XMLElement *e;
  for (e = elt->FirstChildElement(name);
       e != NULL;
       e = e->NextSiblingElement(name)) {
    returnvec.push_back(parse(e));
  }
}

template <class T>
vector<T> parseMany(const char *name,
                    T(*parse)(XMLElement *),
                    XMLElement *elt) {
  vector<T> v;
  parseAppendMany(name, parse, elt, v);
  return v;
}

Real parseReal(XMLElement *xml) {
  return Real(xml->GetText());
}

int parseInt(XMLElement *xml) {
  return atoi(xml->GetText());
}

Vector parseVector(XMLElement *xml) {
  return parseMany("elt", parseReal, xml);
}

Matrix parseMatrix(XMLElement *xml) {
  Matrix m;
  m.rows     = parseInt(xml->FirstChildElement("rows"));
  m.cols     = parseInt(xml->FirstChildElement("cols"));
  m.elements = parseVector(xml->FirstChildElement("elements"));
  return m;
}

Polynomial parsePolynomial(XMLElement *xml) {
  Polynomial p;
  p.coefficients = parseMany("coeff", parseReal, xml);
  return p;
}

vector<Polynomial> parsePolynomialVector(XMLElement *xml) {
  return parseMany("polynomial", parsePolynomial, xml);
}

PolynomialVectorMatrix parsePolynomialVectorMatrix(XMLElement *xml) {
  PolynomialVectorMatrix m;
  m.rows           = parseInt(xml->FirstChildElement("rows"));
  m.cols           = parseInt(xml->FirstChildElement("cols"));
  m.elements       = parseMany("polynomialVector", parsePolynomialVector,
                               xml->FirstChildElement("elements"));
  m.samplePoints   = parseVector(xml->FirstChildElement("samplePoints"));
  m.sampleScalings = parseVector(xml->FirstChildElement("sampleScalings"));
  m.bilinearBasis  = parsePolynomialVector(xml->FirstChildElement("bilinearBasis"));
  return m;
}

SDP readBootstrapSDP(const vector<path> sdpFiles) {
  Vector objective;
  vector<PolynomialVectorMatrix> polynomialVectorMatrices;
  for (auto const& sdpFile: sdpFiles) {
    XMLDocument doc;
    doc.LoadFile(sdpFile.string().c_str());
    XMLElement* xml = doc.FirstChildElement("sdp");
    if(xml->FirstChildElement("objective") != NULL) {
      objective = parseVector(xml->FirstChildElement("objective"));
    }
    if(xml->FirstChildElement("polynomialVectorMatrices") != NULL) {
      parseAppendMany("polynomialVectorMatrix",
                      parsePolynomialVectorMatrix,
                      xml->FirstChildElement("polynomialVectorMatrices"),
                      polynomialVectorMatrices);
    }
  }
  return bootstrapSDP(objective,polynomialVectorMatrices);
}
<|endoftext|>


<commit_before>#include "gdrawer.hpp"

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/home/phoenix/object/new.hpp>
#include <stdexcept>
#include <QDebug>

using namespace boost;
using namespace spirit;
using namespace ascii;
using namespace phoenix;

template<class Iterator>
struct ExprGrammar : qi::grammar<Iterator, expr_t*(), ascii::space_type>
{
	ExprGrammar(): ExprGrammar::base_type(expr, "Expression")
	{
		primitive.name("Primitive");
		factor.name("Factor");
		term.name("Term");
		expr.name("Expression");

		primitive
			= ('(' >> expr >> ')')[_val = _1]
			| ('|' >> expr >> '|')[_val = new_<unop_t>('|', _1)]
			| (char_('a', 'z') | char_('A', 'Z'))[_val = new_<var_t>(_1)]
			| real[_val = new_<const_t>(_1)];

		factor
			= (primitive >> '^' >> factor)[_val = new_<binop_t>('^', _1, _2)]
			| primitive[_val = _1];

		term
			= factor[_val = _1] >>
				*( (char_("/*") >> factor)[_val = new_<binop_t>(_1, _val, _2)]
				| !char_("-+") >> factor[_val = new_<binop_t>('*', _val, _1)] );

		expr
			= term[_val = _1] >> *(char_("+-") >> term)[_val = new_<binop_t>(_1, _val, _2)]
			| ('-' >> term)[_val = new_<unop_t>('-', _1)];

		qi::on_error<qi::fail>
		(
			expr,
			std::cout
                << val("Error! Expecting ")
                << _4                               // what failed?
                << val(" here: \"")
                << construct<std::string>(_3, _2)   // iterators to error-pos, end
                << val("\"")
                << std::endl
		);
		qi::debug(expr); qi::debug(term); qi::debug(factor); qi::debug(primitive);
	}

	qi::rule<Iterator, expr_t*(), ascii::space_type> primitive, factor, term, expr;
	qi::real_parser<real_t> real;
};

Instrs Instrs::get(const QString& expr)
{
	expr_t* tree = NULL;
	std::string s = expr.toStdString();
	ExprGrammar<std::string::const_iterator> g;
	std::string::const_iterator begin = s.begin(), end = s.end();
	bool r = phrase_parse(begin, end, g, space, tree);
	if (!r || begin != end || !tree)
	{
//		qDebug() << "end - begin = " << int(end - begin) << " tree " << (long long)tree << std::endl;
		if (tree) delete tree;
		throw Exception("Syntax error");
	}

	Instrs ret;
	tree->addInstr(&ret);
	ret.requiredStackSize = tree->getDepth();
	delete tree;
	return ret;
}
<commit_msg>Speedup parsing by removing debug output<commit_after>#include "gdrawer.hpp"

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/home/phoenix/object/new.hpp>
#include <stdexcept>
#include <QDebug>

using namespace boost;
using namespace spirit;
using namespace ascii;
using namespace phoenix;

template<class Iterator>
struct ExprGrammar : qi::grammar<Iterator, expr_t*(), ascii::space_type>
{
	ExprGrammar(): ExprGrammar::base_type(expr, "Expression")
	{
		primitive.name("Primitive");
		factor.name("Factor");
		term.name("Term");
		expr.name("Expression");

		primitive
			= ('(' >> expr >> ')')[_val = _1]
			| ('|' >> expr >> '|')[_val = new_<unop_t>('|', _1)]
			| (char_('a', 'z') | char_('A', 'Z'))[_val = new_<var_t>(_1)]
			| real[_val = new_<const_t>(_1)];

		factor
			= (primitive >> '^' >> factor)[_val = new_<binop_t>('^', _1, _2)]
			| primitive[_val = _1];

		term
			= factor[_val = _1] >>
				*( (char_("/*") >> factor)[_val = new_<binop_t>(_1, _val, _2)]
				| !char_("-+") >> factor[_val = new_<binop_t>('*', _val, _1)] );

		expr
			= term[_val = _1] >> *(char_("+-") >> term)[_val = new_<binop_t>(_1, _val, _2)]
			| ('-' >> term)[_val = new_<unop_t>('-', _1)];

		qi::on_error<qi::fail>
		(
			expr,
			std::cout
                << val("Error! Expecting ")
                << _4                               // what failed?
                << val(" here: \"")
                << construct<std::string>(_3, _2)   // iterators to error-pos, end
                << val("\"")
                << std::endl
		);
		/* qi::debug(expr); qi::debug(term); qi::debug(factor); qi::debug(primitive); */
	}

	qi::rule<Iterator, expr_t*(), ascii::space_type> primitive, factor, term, expr;
	qi::real_parser<real_t> real;
};

Instrs Instrs::get(const QString& expr)
{
	expr_t* tree = NULL;
	std::string s = expr.toStdString();
	ExprGrammar<std::string::const_iterator> g;
	std::string::const_iterator begin = s.begin(), end = s.end();
	bool r = phrase_parse(begin, end, g, space, tree);
	if (!r || begin != end || !tree)
	{
//		qDebug() << "end - begin = " << int(end - begin) << " tree " << (long long)tree << std::endl;
		if (tree) delete tree;
		throw Exception("Syntax error");
	}

	Instrs ret;
	tree->addInstr(&ret);
	ret.requiredStackSize = tree->getDepth();
	delete tree;
	return ret;
}
<|endoftext|>


<commit_before>#include <cstring>

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <node_buffer.h>
#include <mcnet.h>

#include "parser.h"

using namespace v8;
using namespace node;

mcnet::Parser::Parser() {
  settings.on_packet = mcnet::Parser::on_packet;
  settings.on_error = mcnet::Parser::on_error;
}

mcnet::Parser::~Parser() {
}

void mcnet::Parser::Init(Handle< Object > target) {
  Local< FunctionTemplate > tpl = FunctionTemplate::New(New);

  tpl->SetClassName(String::NewSymbol("Parser"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  tpl->PrototypeTemplate()->Set(String::NewSymbol("execute"), FunctionTemplate::New(Execute)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EAGAIN"), Number::New(MCNET_EAGAIN));
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EINVALID"), Number::New(MCNET_EINVALID));

  Persistent< Function > constructor = Persistent< Function >::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Parser"), constructor);
}

Handle< Value > mcnet::Parser::New(const Arguments& args) {
  HandleScope scope;

  Parser* obj = new Parser();
  obj->Wrap(args.This());

  return args.This();
}

Handle< Value > mcnet::Parser::Execute(const Arguments& args) {
  HandleScope scope;

  mcnet::Parser* parser = ObjectWrap::Unwrap< mcnet::Parser >(args.This());

  Local< Object > buffer = Local< Object >::Cast(args[0]);

  Handle< Object > obj = args.This();
  parser->parser.data = (void*)&obj;
  size_t nparsed = mcnet_parser_execute(&(parser->parser), &(parser->settings), reinterpret_cast< uint8_t* >(Buffer::Data(buffer)), Buffer::Length(buffer));
  parser->parser.data = NULL;

  return scope.Close(Number::New(nparsed));
}

void mcnet::Parser::on_packet(mcnet_parser_t* parser, mcnet_packet_t* packet) {
  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Local< Object > object = Object::New();

  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));

#define PACKET(id, code) case 0x##id: { \
  mcnet_packet_##id##_t* pkt = reinterpret_cast< mcnet_packet_##id##_t* >(packet); \
  BYTE(pid) \
  code \
  break; \
}

#define CODE(data)
#define BOOL(name) object->Set(String::New(#name), Boolean::New(pkt->name ? true : false));
#define NUMBER(name) object->Set(String::New(#name), Number::New(pkt->name));
#define BYTE(name) NUMBER(name)
#define UBYTE(name) NUMBER(name)
#define SHORT(name) NUMBER(name)
#define USHORT(name) NUMBER(name)
#define INT(name) NUMBER(name)
#define LONG(name) NUMBER(name)
#define FLOAT(name) NUMBER(name)
#define DOUBLE(name) NUMBER(name)
#define STRING8(name) BLOB(name, name##_len)
#define STRING16(name) BLOB(name, name##_len * 2)
#define BLOB(name, length) \
  Buffer* name##_buffer = Buffer::New(pkt->length); \
  memcpy(Buffer::Data(name##_buffer), pkt->name, pkt->length); \
  Handle< Value > name##_args[3] = { name##_buffer->handle_, Integer::New(pkt->length), Integer::New(0) }; \
  object->Set(String::New(#name), buffer_constructor->NewInstance(3, name##_args));
#define METADATA(name) \
  Local< Object > name##_metadata = Object::New(); \
  mcnet_metadata_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = NULL; \
  name##_parser.on_entry = mcnet::Parser::on_metadata_entry; \
  name##_parser.data = &name##_metadata; \
  mcnet_metadata_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  object->Set(String::New(#name), name##_metadata);
#define SLOT(name) \
  Local< Object > name##_slot = Object::New(); \
  mcnet_slot_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = mcnet::Parser::on_slot; \
  name##_parser.data = &name##_slot; \
  mcnet_slot_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  name##_parser.data = NULL; \
  object->Set(String::New(#name), name##_slot);
#define SLOTS(name, count) \
  Local< Array > name##_slots = Array::New(pkt->count); \
  mcnet_slot_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = mcnet::Parser::on_slot; \
  int name##_nparsed = 0, name##_i = 0; \
  while (name##_nparsed < pkt->name##_len) { \
    Local< Object > name##_slot = Object::New(); \
    name##_parser.data = &name##_slot; \
    name##_nparsed += mcnet_slot_parser_parse(&name##_parser, pkt->name + name##_nparsed, pkt->name##_len - name##_nparsed); \
    name##_parser.data = NULL; \
    name##_slots->Set(name##_i++, name##_slot); \
  } \
  object->Set(String::New(#name), name##_slots);

  switch (packet->pid) {
PACKETS
  }

#undef CODE
#undef BOOL
#undef NUMBER
#undef BYTE
#undef UBYTE
#undef SHORT
#undef USHORT
#undef INT
#undef LONG
#undef FLOAT
#undef DOUBLE
#undef STRING8
#undef STRING16
#undef BLOB
#undef METADATA
#undef SLOT
#undef SLOTS

#undef PACKET

  Handle< Value > argv[2] = {
    String::New("packet"),
    object
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_error(mcnet_parser_t* parser, int err) {
  if (err == MCNET_EAGAIN) {
    return;
  }

  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Handle< Value > argv[2] = {
    String::New("error"),
    Number::New(err)
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_metadata_entry(mcnet_metadata_parser_t* parser, mcnet_metadata_entry_t* entry) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  switch (entry->type) {
    case MCNET_METADATA_TYPE_BYTE: {
      mcnet_metadata_entry_byte_t* ent = reinterpret_cast< mcnet_metadata_entry_byte_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_SHORT: {
      mcnet_metadata_entry_short_t* ent = reinterpret_cast< mcnet_metadata_entry_short_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_INT: {
      mcnet_metadata_entry_int_t* ent = reinterpret_cast< mcnet_metadata_entry_int_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_FLOAT: {
      mcnet_metadata_entry_float_t* ent = reinterpret_cast< mcnet_metadata_entry_float_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_STRING16: {
      mcnet_metadata_entry_string16_t* ent = reinterpret_cast< mcnet_metadata_entry_string16_t* >(entry);
      Buffer* buffer = Buffer::New(ent->data_length * 2);
      memcpy(Buffer::Data(buffer), ent->data, ent->data_length * 2);
      Handle< Value > args[3] = { buffer->handle_, Integer::New(ent->data_length * 2), Integer::New(0) };
      Local< Object > global = Context::GetCurrent()->Global();
      Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));
      (*obj)->Set(ent->index, buffer_constructor->NewInstance(3, args));
      break;
    }
    case MCNET_METADATA_TYPE_SLOT: {
      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
      Local< Object > object = Object::New();
      object->Set(String::New("id"), Number::New(ent->id));
      object->Set(String::New("count"), Number::New(ent->count));
      object->Set(String::New("damage"), Number::New(ent->damage));
      (*obj)->Set(ent->index, object);
      break;
    }
    case MCNET_METADATA_TYPE_INTS: {
      mcnet_metadata_entry_iii_t* ent = reinterpret_cast< mcnet_metadata_entry_iii_t* >(entry);
      Local< Array > array = Array::New(3);
      array->Set(0, Number::New(ent->data[0]));
      array->Set(1, Number::New(ent->data[1]));
      array->Set(2, Number::New(ent->data[2]));
      (*obj)->Set(ent->index, array);
      break;
    }
  }
}

void mcnet::Parser::on_slot(mcnet_slot_parser_t* parser, mcnet_slot_t* slot) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  (*obj)->Set(String::New("item"), Number::New(slot->item));
  (*obj)->Set(String::New("count"), Number::New(slot->count));
  (*obj)->Set(String::New("meta"), Number::New(slot->meta));

  Buffer* buffer = Buffer::New(slot->data_len);
  memcpy(Buffer::Data(buffer), slot->data, slot->data_len);
  Handle< Value > args[3] = { buffer->handle_, Integer::New(slot->data_len), Integer::New(0) };
  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));
  (*obj)->Set(String::New("data"), buffer_constructor->NewInstance(3, args));
}
<commit_msg>make sure we clear out any pointers to v8 objects<commit_after>#include <cstring>

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <node_buffer.h>
#include <mcnet.h>

#include "parser.h"

using namespace v8;
using namespace node;

mcnet::Parser::Parser() {
  settings.on_packet = mcnet::Parser::on_packet;
  settings.on_error = mcnet::Parser::on_error;
}

mcnet::Parser::~Parser() {
}

void mcnet::Parser::Init(Handle< Object > target) {
  Local< FunctionTemplate > tpl = FunctionTemplate::New(New);

  tpl->SetClassName(String::NewSymbol("Parser"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  tpl->PrototypeTemplate()->Set(String::NewSymbol("execute"), FunctionTemplate::New(Execute)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EAGAIN"), Number::New(MCNET_EAGAIN));
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EINVALID"), Number::New(MCNET_EINVALID));

  Persistent< Function > constructor = Persistent< Function >::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Parser"), constructor);
}

Handle< Value > mcnet::Parser::New(const Arguments& args) {
  HandleScope scope;

  Parser* obj = new Parser();
  obj->Wrap(args.This());

  return args.This();
}

Handle< Value > mcnet::Parser::Execute(const Arguments& args) {
  HandleScope scope;

  mcnet::Parser* parser = ObjectWrap::Unwrap< mcnet::Parser >(args.This());

  Local< Object > buffer = Local< Object >::Cast(args[0]);

  Handle< Object > obj = args.This();
  parser->parser.data = (void*)&obj;
  size_t nparsed = mcnet_parser_execute(&(parser->parser), &(parser->settings), reinterpret_cast< uint8_t* >(Buffer::Data(buffer)), Buffer::Length(buffer));
  parser->parser.data = NULL;

  return scope.Close(Number::New(nparsed));
}

void mcnet::Parser::on_packet(mcnet_parser_t* parser, mcnet_packet_t* packet) {
  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Local< Object > object = Object::New();

  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));

#define PACKET(id, code) case 0x##id: { \
  mcnet_packet_##id##_t* pkt = reinterpret_cast< mcnet_packet_##id##_t* >(packet); \
  BYTE(pid) \
  code \
  break; \
}

#define CODE(data)
#define BOOL(name) object->Set(String::New(#name), Boolean::New(pkt->name ? true : false));
#define NUMBER(name) object->Set(String::New(#name), Number::New(pkt->name));
#define BYTE(name) NUMBER(name)
#define UBYTE(name) NUMBER(name)
#define SHORT(name) NUMBER(name)
#define USHORT(name) NUMBER(name)
#define INT(name) NUMBER(name)
#define LONG(name) NUMBER(name)
#define FLOAT(name) NUMBER(name)
#define DOUBLE(name) NUMBER(name)
#define STRING8(name) BLOB(name, name##_len)
#define STRING16(name) BLOB(name, name##_len * 2)
#define BLOB(name, length) \
  Buffer* name##_buffer = Buffer::New(pkt->length); \
  memcpy(Buffer::Data(name##_buffer), pkt->name, pkt->length); \
  Handle< Value > name##_args[3] = { name##_buffer->handle_, Integer::New(pkt->length), Integer::New(0) }; \
  object->Set(String::New(#name), buffer_constructor->NewInstance(3, name##_args));
#define METADATA(name) \
  Local< Object > name##_metadata = Object::New(); \
  mcnet_metadata_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = NULL; \
  name##_parser.on_entry = mcnet::Parser::on_metadata_entry; \
  name##_parser.data = &name##_metadata; \
  mcnet_metadata_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  name##_parser.data = NULL; \
  object->Set(String::New(#name), name##_metadata);
#define SLOT(name) \
  Local< Object > name##_slot = Object::New(); \
  mcnet_slot_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = mcnet::Parser::on_slot; \
  name##_parser.data = &name##_slot; \
  mcnet_slot_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  name##_parser.data = NULL; \
  object->Set(String::New(#name), name##_slot);
#define SLOTS(name, count) \
  Local< Array > name##_slots = Array::New(pkt->count); \
  mcnet_slot_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = mcnet::Parser::on_slot; \
  int name##_nparsed = 0, name##_i = 0; \
  while (name##_nparsed < pkt->name##_len) { \
    Local< Object > name##_slot = Object::New(); \
    name##_parser.data = &name##_slot; \
    name##_nparsed += mcnet_slot_parser_parse(&name##_parser, pkt->name + name##_nparsed, pkt->name##_len - name##_nparsed); \
    name##_parser.data = NULL; \
    name##_slots->Set(name##_i++, name##_slot); \
  } \
  object->Set(String::New(#name), name##_slots);

  switch (packet->pid) {
PACKETS
  }

#undef CODE
#undef BOOL
#undef NUMBER
#undef BYTE
#undef UBYTE
#undef SHORT
#undef USHORT
#undef INT
#undef LONG
#undef FLOAT
#undef DOUBLE
#undef STRING8
#undef STRING16
#undef BLOB
#undef METADATA
#undef SLOT
#undef SLOTS

#undef PACKET

  Handle< Value > argv[2] = {
    String::New("packet"),
    object
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_error(mcnet_parser_t* parser, int err) {
  if (err == MCNET_EAGAIN) {
    return;
  }

  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Handle< Value > argv[2] = {
    String::New("error"),
    Number::New(err)
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_metadata_entry(mcnet_metadata_parser_t* parser, mcnet_metadata_entry_t* entry) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  switch (entry->type) {
    case MCNET_METADATA_TYPE_BYTE: {
      mcnet_metadata_entry_byte_t* ent = reinterpret_cast< mcnet_metadata_entry_byte_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_SHORT: {
      mcnet_metadata_entry_short_t* ent = reinterpret_cast< mcnet_metadata_entry_short_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_INT: {
      mcnet_metadata_entry_int_t* ent = reinterpret_cast< mcnet_metadata_entry_int_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_FLOAT: {
      mcnet_metadata_entry_float_t* ent = reinterpret_cast< mcnet_metadata_entry_float_t* >(entry);
      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_STRING16: {
      mcnet_metadata_entry_string16_t* ent = reinterpret_cast< mcnet_metadata_entry_string16_t* >(entry);
      Buffer* buffer = Buffer::New(ent->data_length * 2);
      memcpy(Buffer::Data(buffer), ent->data, ent->data_length * 2);
      Handle< Value > args[3] = { buffer->handle_, Integer::New(ent->data_length * 2), Integer::New(0) };
      Local< Object > global = Context::GetCurrent()->Global();
      Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));
      (*obj)->Set(ent->index, buffer_constructor->NewInstance(3, args));
      break;
    }
    case MCNET_METADATA_TYPE_SLOT: {
      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
      Local< Object > object = Object::New();
      object->Set(String::New("id"), Number::New(ent->id));
      object->Set(String::New("count"), Number::New(ent->count));
      object->Set(String::New("damage"), Number::New(ent->damage));
      (*obj)->Set(ent->index, object);
      break;
    }
    case MCNET_METADATA_TYPE_INTS: {
      mcnet_metadata_entry_iii_t* ent = reinterpret_cast< mcnet_metadata_entry_iii_t* >(entry);
      Local< Array > array = Array::New(3);
      array->Set(0, Number::New(ent->data[0]));
      array->Set(1, Number::New(ent->data[1]));
      array->Set(2, Number::New(ent->data[2]));
      (*obj)->Set(ent->index, array);
      break;
    }
  }
}

void mcnet::Parser::on_slot(mcnet_slot_parser_t* parser, mcnet_slot_t* slot) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  (*obj)->Set(String::New("item"), Number::New(slot->item));
  (*obj)->Set(String::New("count"), Number::New(slot->count));
  (*obj)->Set(String::New("meta"), Number::New(slot->meta));

  Buffer* buffer = Buffer::New(slot->data_len);
  memcpy(Buffer::Data(buffer), slot->data, slot->data_len);
  Handle< Value > args[3] = { buffer->handle_, Integer::New(slot->data_len), Integer::New(0) };
  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));
  (*obj)->Set(String::New("data"), buffer_constructor->NewInstance(3, args));
}
<|endoftext|>