<commit_before>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */
#include <cassert>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <algorithm>

#include "halBedLine.h"

using namespace std;
using namespace hal;

BedLine::BedLine() : _start(NULL_INDEX), _end(NULL_INDEX), _strand('+'),
                     _version(NULL_INDEX), _srcStart(NULL_INDEX)
{

}

BedLine::~BedLine()
{

}

istream& BedLine::read(istream& is, int version, string& lineBuffer)
{
  _version = version;
  std::getline(is, lineBuffer);
  stringstream ss(lineBuffer);
  ss >> _chrName;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chrom");
  }
  ss >> _start;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chromStart");
  }
  ss >> _end;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chromEnd");
  }
  if (_version > 3)
  {
    ss >> _name;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED name");
    }
  }
  if (_version > 4)
  {
    ss >> _score;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED score");
    }
  }
  if (_version > 5)
  {
    ss >> _strand;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED strand");
    }
    if (_strand != '.' && _strand != '+' && _strand != '-')
    {
      throw hal_exception("Strand character must be + or - or .");
    }
  }
  if (_version > 6)
  {
    ss >> _thickStart;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED thickStart");
    }
  }
  if (_version > 7)
  {
    ss >> _thickEnd;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED thickEnd");
    }
  }
  if (_version > 8)
  {
    string rgb;
    ss >> rgb;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED itemRGB");
    }
    vector<string> rgbTokens = chopString(rgb, ",");
    if (rgbTokens.size() != 3)
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssr(rgbTokens[0]);
    rgbssr >> _itemR;
    if (rgbssr.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssg(rgbTokens[1]);
    rgbssg >> _itemG;
    if (rgbssg.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssb(rgbTokens[2]);
    rgbssb >> _itemB;
    if (rgbssb.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
  }
  if (_version > 9)
  {
    size_t numBlocks;
    ss >> numBlocks;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED blockCount");
    }
    if (numBlocks > 0)
    {
      string blockSizes;
      ss >> blockSizes;
      if (ss.bad() || ss.fail())
      {
        throw hal_exception("Error scanning BED blockSizes");
      }
      string blockStarts;
      ss >> blockStarts;
      if (ss.bad() || ss.fail())
      {
        throw hal_exception("Error scanning BED blockStarts");
      }
      _blocks.resize(numBlocks);
      vector<string> sizeBuf = chopString(blockSizes, ",");
      if (sizeBuf.size() != numBlocks)
      {
        throw hal_exception("Error scanning BED blockSizes");
      }
      vector<string> startBuf = chopString(blockStarts, ",");
      if (startBuf.size() != numBlocks)
      {
        throw hal_exception("Error scanning BED blockStarts");
      }
      for (size_t i = 0; i < numBlocks; ++i)
      {
        BedBlock& block = _blocks[i];
        stringstream ss1(sizeBuf[i]);
        ss1 >> block._length;
        if (ss1.bad())
        {
          throw hal_exception("Error scanning BED blockSizes");
        }
        stringstream ss2(startBuf[i]);
        ss2 >> block._start;
        if (ss2.bad())
        {
          throw hal_exception("Error scanning BED blockStarts");
        }
        if (_start + block._start + block._length > _end)
        {
          throw hal_exception("Error BED block out of range");
        }
      }
    }
  }
  _extra.clear();
  while (ss.good())
  {
    string extraBuf;
    ss >> extraBuf;
    if (extraBuf.length() > 0)
    {
      _extra.push_back(extraBuf);
    }
  }
  return is;
}

ostream& BedLine::write(ostream& os, int version)
{
  if (version <= 0)
  {
    version = _version;
  }
  os << _chrName << '\t' << _start << '\t' << _end;

  if (version > 3)
  {
    os << '\t' << _name;
  }
  if (version > 4)
  {
    os << '\t' << _score;
  }
  if (version > 5)
  {
    os << '\t' << _strand;
  }
  if (version > 6)
  {
    os << '\t' << _thickStart;
  }
  if (version > 7)
  {
    os << '\t' << _thickEnd;
  }
  if (version > 8)
  {
    os << '\t' << _itemR << ',' << _itemG << ',' << _itemB;
  }
  if (version > 9)
  {
    os << '\t' << _blocks.size();
    for (size_t i = 0; i < _blocks.size(); ++i)
    {
      if (i == 0)
      {
        os << '\t';
      }
      else
      {
        os << ',';
      }
      os << _blocks[i]._length;
    }
    for (size_t i = 0; i < _blocks.size(); ++i)
    {
      if (i == 0)
      {
        os << '\t';
      }
      else
      {
        os << ',';
      }
      os << _blocks[i]._start;
    }
  }

  for (size_t i = 0; i < _extra.size(); ++i)
  {
    os << '\t' << _extra[i];
  }

  os << '\n';
  return os;
}

bool BedBlock::operator<(const BedBlock& other) const
{
  bool isLess = _start < other._start;
  return isLess;
}

bool BedLineLess::operator()(const BedLine& b1, const BedLine& b2) const
{
  if (b1._chrName < b2._chrName)
  {
    return true;
  }
  else if (b1._chrName == b2._chrName)
  {
    if (b1._strand == '+' && b2._strand != '+')
    {
      return true;
    }
    else if (b1._strand == b2._strand)
    {
      if (b1._start < b2._start)
      {
        return true;
      }
      else if (b1._start == b2._start)
      {
        return b1._end < b2._end;
      }
    }
  }
  return false;
}

bool BedLineSrcLess::operator()(const BedLine& b1, const BedLine& b2) const
{
  return b1._srcStart < b2._srcStart;
}

<commit_msg>fix target bed line sort to prioritize strand last<commit_after>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */
#include <cassert>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <algorithm>

#include "halBedLine.h"

using namespace std;
using namespace hal;

BedLine::BedLine() : _start(NULL_INDEX), _end(NULL_INDEX), _strand('+'),
                     _version(NULL_INDEX), _srcStart(NULL_INDEX)
{

}

BedLine::~BedLine()
{

}

istream& BedLine::read(istream& is, int version, string& lineBuffer)
{
  _version = version;
  std::getline(is, lineBuffer);
  stringstream ss(lineBuffer);
  ss >> _chrName;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chrom");
  }
  ss >> _start;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chromStart");
  }
  ss >> _end;
  if (ss.bad() || ss.fail())
  {
    throw hal_exception("Error scanning BED chromEnd");
  }
  if (_version > 3)
  {
    ss >> _name;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED name");
    }
  }
  if (_version > 4)
  {
    ss >> _score;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED score");
    }
  }
  if (_version > 5)
  {
    ss >> _strand;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED strand");
    }
    if (_strand != '.' && _strand != '+' && _strand != '-')
    {
      throw hal_exception("Strand character must be + or - or .");
    }
  }
  if (_version > 6)
  {
    ss >> _thickStart;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED thickStart");
    }
  }
  if (_version > 7)
  {
    ss >> _thickEnd;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED thickEnd");
    }
  }
  if (_version > 8)
  {
    string rgb;
    ss >> rgb;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED itemRGB");
    }
    vector<string> rgbTokens = chopString(rgb, ",");
    if (rgbTokens.size() != 3)
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssr(rgbTokens[0]);
    rgbssr >> _itemR;
    if (rgbssr.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssg(rgbTokens[1]);
    rgbssg >> _itemG;
    if (rgbssg.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
    stringstream rgbssb(rgbTokens[2]);
    rgbssb >> _itemB;
    if (rgbssb.bad())
    {
      throw hal_exception("Error parsing BED itemRGB");
    }
  }
  if (_version > 9)
  {
    size_t numBlocks;
    ss >> numBlocks;
    if (ss.bad() || ss.fail())
    {
      throw hal_exception("Error scanning BED blockCount");
    }
    if (numBlocks > 0)
    {
      string blockSizes;
      ss >> blockSizes;
      if (ss.bad() || ss.fail())
      {
        throw hal_exception("Error scanning BED blockSizes");
      }
      string blockStarts;
      ss >> blockStarts;
      if (ss.bad() || ss.fail())
      {
        throw hal_exception("Error scanning BED blockStarts");
      }
      _blocks.resize(numBlocks);
      vector<string> sizeBuf = chopString(blockSizes, ",");
      if (sizeBuf.size() != numBlocks)
      {
        throw hal_exception("Error scanning BED blockSizes");
      }
      vector<string> startBuf = chopString(blockStarts, ",");
      if (startBuf.size() != numBlocks)
      {
        throw hal_exception("Error scanning BED blockStarts");
      }
      for (size_t i = 0; i < numBlocks; ++i)
      {
        BedBlock& block = _blocks[i];
        stringstream ss1(sizeBuf[i]);
        ss1 >> block._length;
        if (ss1.bad())
        {
          throw hal_exception("Error scanning BED blockSizes");
        }
        stringstream ss2(startBuf[i]);
        ss2 >> block._start;
        if (ss2.bad())
        {
          throw hal_exception("Error scanning BED blockStarts");
        }
        if (_start + block._start + block._length > _end)
        {
          throw hal_exception("Error BED block out of range");
        }
      }
    }
  }
  _extra.clear();
  while (ss.good())
  {
    string extraBuf;
    ss >> extraBuf;
    if (extraBuf.length() > 0)
    {
      _extra.push_back(extraBuf);
    }
  }
  return is;
}

ostream& BedLine::write(ostream& os, int version)
{
  if (version <= 0)
  {
    version = _version;
  }
  os << _chrName << '\t' << _start << '\t' << _end;

  if (version > 3)
  {
    os << '\t' << _name;
  }
  if (version > 4)
  {
    os << '\t' << _score;
  }
  if (version > 5)
  {
    os << '\t' << _strand;
  }
  if (version > 6)
  {
    os << '\t' << _thickStart;
  }
  if (version > 7)
  {
    os << '\t' << _thickEnd;
  }
  if (version > 8)
  {
    os << '\t' << _itemR << ',' << _itemG << ',' << _itemB;
  }
  if (version > 9)
  {
    os << '\t' << _blocks.size();
    for (size_t i = 0; i < _blocks.size(); ++i)
    {
      if (i == 0)
      {
        os << '\t';
      }
      else
      {
        os << ',';
      }
      os << _blocks[i]._length;
    }
    for (size_t i = 0; i < _blocks.size(); ++i)
    {
      if (i == 0)
      {
        os << '\t';
      }
      else
      {
        os << ',';
      }
      os << _blocks[i]._start;
    }
  }

  for (size_t i = 0; i < _extra.size(); ++i)
  {
    os << '\t' << _extra[i];
  }

  os << '\n';
  return os;
}

bool BedBlock::operator<(const BedBlock& other) const
{
  bool isLess = _start < other._start;
  return isLess;
}

bool BedLineLess::operator()(const BedLine& b1, const BedLine& b2) const
{
  if (b1._chrName < b2._chrName)
  {
    return true;
  }
  else if (b1._chrName == b2._chrName)
  {
    if (b1._start < b2._start)
    {
      return true;
    }
    else if (b1._start == b2._start)
    {
      if (b1._end < b2._end)
      {
        return true;
      }
      else if (b1._end == b2._end)
      {
        return b1._strand == '+' && b2._strand != '+';
      }
    }
  }
  return false;
}

bool BedLineSrcLess::operator()(const BedLine& b1, const BedLine& b2) const
{
  return b1._srcStart < b2._srcStart;
}

<|endoftext|>


<commit_before>#include "IRMatch.h"

#include "IREquality.h"
#include "IROperator.h"
#include <iostream>

namespace Halide {
namespace Internal {

using std::vector;

void expr_match_test() {
    vector<Expr> matches;
    Expr w = Variable::make(Int(32), "*");
    Expr fw = Variable::make(Float(32), "*");
    Expr x = Variable::make(Int(32), "x");
    Expr y = Variable::make(Int(32), "y");
    Expr fx = Variable::make(Float(32), "fx");
    Expr fy = Variable::make(Float(32), "fy");

    assert(expr_match(w, 3, matches) &&
           equal(matches[0], 3));

    assert(expr_match(w + 3, (y*2) + 3, matches) &&
           equal(matches[0], y*2));

    assert(expr_match(fw * 17 + cast<float>(w + cast<int>(fw)),
                      (81.0f * fy) * 17 + cast<float>(x/2 + cast<int>(4.5f)), matches) &&
           equal(matches[0], 81.0f * fy) &&
           equal(matches[1], x/2) &&
           equal(matches[2], 4.5f));

    assert(!expr_match(fw + 17, fx + 18, matches) &&
           matches.empty());
    assert(!expr_match((w*2) + 17, fx + 17, matches) &&
           matches.empty());
    assert(!expr_match(w * 3, 3 * x, matches) &&
           matches.empty());

    std::cout << "expr_match test passed" << std::endl;
}

class IRMatch : public IRVisitor {
public:
    bool result;
    vector<Expr> &matches;
    Expr expr;

    IRMatch(Expr e, vector<Expr> &m) : result(true), matches(m), expr(e) {
    }

    using IRVisitor::visit;

    void visit(const IntImm *op) {
        const IntImm *e = expr.as<IntImm>();
        if (!e || e->value != op->value) {
            result = false;
        }
    }

    void visit(const FloatImm *op) {
        const FloatImm *e = expr.as<FloatImm>();
        if (!e || e->value != op->value) {
            result = false;
        }
    }

    void visit(const Cast *op) {
        const Cast *e = expr.as<Cast>();
        if (result && e && e->type == op->type) {
            expr = e->value;
            op->value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Variable *op) {
        if (op->type != expr.type()) {
            result = false;
        } else if (op->name == "*") {
            matches.push_back(expr);
        } else if (result) {
            const Variable *e = expr.as<Variable>();
            result = e && (e->name == op->name);
        }
    }

    template<typename T>
    void visit_binary_operator(const T *op) {
        const T *e = expr.as<T>();
        if (result && e) {
            expr = e->a;
            op->a.accept(this);
            expr = e->b;
            op->b.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Add *op) {visit_binary_operator(op);}
    void visit(const Sub *op) {visit_binary_operator(op);}
    void visit(const Mul *op) {visit_binary_operator(op);}
    void visit(const Div *op) {visit_binary_operator(op);}
    void visit(const Mod *op) {visit_binary_operator(op);}
    void visit(const Min *op) {visit_binary_operator(op);}
    void visit(const Max *op) {visit_binary_operator(op);}
    void visit(const EQ *op) {visit_binary_operator(op);}
    void visit(const NE *op) {visit_binary_operator(op);}
    void visit(const LT *op) {visit_binary_operator(op);}
    void visit(const LE *op) {visit_binary_operator(op);}
    void visit(const GT *op) {visit_binary_operator(op);}
    void visit(const GE *op) {visit_binary_operator(op);}
    void visit(const And *op) {visit_binary_operator(op);}
    void visit(const Or *op) {visit_binary_operator(op);}

    void visit(const Not *op) {
        const Not *e = expr.as<Not>();
        if (result && e) {
            expr = e->a;
            op->a.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Select *op) {
        const Select *e = expr.as<Select>();
        if (result && e) {
            expr = e->condition;
            op->condition.accept(this);
            expr = e->true_value;
            op->true_value.accept(this);
            expr = e->false_value;
            op->false_value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Load *op) {
        const Load *e = expr.as<Load>();
        if (result && e && e->type == op->type && e->name == op->name) {
            expr = e->index;
            op->index.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Ramp *op) {
        const Ramp *e = expr.as<Ramp>();
        if (result && e && e->width == op->width) {
            expr = e->base;
            op->base.accept(this);
            expr = e->stride;
            op->stride.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Broadcast *op) {
        const Broadcast *e = expr.as<Broadcast>();
        if (result && e && e->width == op->width) {
            expr = e->value;
            op->value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Call *op) {
        const Call *e = expr.as<Call>();
        if (result && e &&
            e->type == op->type &&
            e->name == op->name &&
            e->call_type == op->call_type &&
            e->args.size() == op->args.size()) {
            for (size_t i = 0; result && (i < e->args.size()); i++) {
                expr = e->args[i];
                op->args[i].accept(this);
            }
        } else {
            result = false;
        }
    }

    void visit(const Let *op) {
        const Let *e = expr.as<Let>();
        if (result && e && e->name == op->name) {
            expr = e->value;
            op->value.accept(this);
            expr = e->body;
            op->body.accept(this);
        } else {
            result = false;
        }
    }
};

bool expr_match(Expr pattern, Expr expr, vector<Expr> &matches) {
    matches.clear();
    if (!pattern.defined() && !pattern.defined()) return true;
    if (!pattern.defined() || !pattern.defined()) return false;

    IRMatch eq(expr, matches);
    pattern.accept(&eq);
    if (eq.result) {
        return true;
    } else {
        matches.clear();
        return false;
    }
}

}}
<commit_msg>Added a vector test case to IRMatch<commit_after>#include "IRMatch.h"

#include "IREquality.h"
#include "IROperator.h"
#include <iostream>

namespace Halide {
namespace Internal {

using std::vector;

void expr_match_test() {
    vector<Expr> matches;
    Expr w = Variable::make(Int(32), "*");
    Expr fw = Variable::make(Float(32), "*");
    Expr x = Variable::make(Int(32), "x");
    Expr y = Variable::make(Int(32), "y");
    Expr fx = Variable::make(Float(32), "fx");
    Expr fy = Variable::make(Float(32), "fy");

    Expr vec_wild = Variable::make(Int(32, 4), "*");

    assert(expr_match(w, 3, matches) &&
           equal(matches[0], 3));

    assert(expr_match(w + 3, (y*2) + 3, matches) &&
           equal(matches[0], y*2));

    assert(expr_match(fw * 17 + cast<float>(w + cast<int>(fw)),
                      (81.0f * fy) * 17 + cast<float>(x/2 + cast<int>(4.5f)), matches) &&
           equal(matches[0], 81.0f * fy) &&
           equal(matches[1], x/2) &&
           equal(matches[2], 4.5f));

    assert(!expr_match(fw + 17, fx + 18, matches) &&
           matches.empty());
    assert(!expr_match((w*2) + 17, fx + 17, matches) &&
           matches.empty());
    assert(!expr_match(w * 3, 3 * x, matches) &&
           matches.empty());

    assert(expr_match(vec_wild * 3, Ramp::make(x, y, 4) * 3, matches));

    std::cout << "expr_match test passed" << std::endl;
}

class IRMatch : public IRVisitor {
public:
    bool result;
    vector<Expr> &matches;
    Expr expr;

    IRMatch(Expr e, vector<Expr> &m) : result(true), matches(m), expr(e) {
    }

    using IRVisitor::visit;

    void visit(const IntImm *op) {
        const IntImm *e = expr.as<IntImm>();
        if (!e || e->value != op->value) {
            result = false;
        }
    }

    void visit(const FloatImm *op) {
        const FloatImm *e = expr.as<FloatImm>();
        if (!e || e->value != op->value) {
            result = false;
        }
    }

    void visit(const Cast *op) {
        const Cast *e = expr.as<Cast>();
        if (result && e && e->type == op->type) {
            expr = e->value;
            op->value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Variable *op) {
        if (op->type != expr.type()) {
            result = false;
        } else if (op->name == "*") {
            matches.push_back(expr);
        } else if (result) {
            const Variable *e = expr.as<Variable>();
            result = e && (e->name == op->name);
        }
    }

    template<typename T>
    void visit_binary_operator(const T *op) {
        const T *e = expr.as<T>();
        if (result && e) {
            expr = e->a;
            op->a.accept(this);
            expr = e->b;
            op->b.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Add *op) {visit_binary_operator(op);}
    void visit(const Sub *op) {visit_binary_operator(op);}
    void visit(const Mul *op) {visit_binary_operator(op);}
    void visit(const Div *op) {visit_binary_operator(op);}
    void visit(const Mod *op) {visit_binary_operator(op);}
    void visit(const Min *op) {visit_binary_operator(op);}
    void visit(const Max *op) {visit_binary_operator(op);}
    void visit(const EQ *op) {visit_binary_operator(op);}
    void visit(const NE *op) {visit_binary_operator(op);}
    void visit(const LT *op) {visit_binary_operator(op);}
    void visit(const LE *op) {visit_binary_operator(op);}
    void visit(const GT *op) {visit_binary_operator(op);}
    void visit(const GE *op) {visit_binary_operator(op);}
    void visit(const And *op) {visit_binary_operator(op);}
    void visit(const Or *op) {visit_binary_operator(op);}

    void visit(const Not *op) {
        const Not *e = expr.as<Not>();
        if (result && e) {
            expr = e->a;
            op->a.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Select *op) {
        const Select *e = expr.as<Select>();
        if (result && e) {
            expr = e->condition;
            op->condition.accept(this);
            expr = e->true_value;
            op->true_value.accept(this);
            expr = e->false_value;
            op->false_value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Load *op) {
        const Load *e = expr.as<Load>();
        if (result && e && e->type == op->type && e->name == op->name) {
            expr = e->index;
            op->index.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Ramp *op) {
        const Ramp *e = expr.as<Ramp>();
        if (result && e && e->width == op->width) {
            expr = e->base;
            op->base.accept(this);
            expr = e->stride;
            op->stride.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Broadcast *op) {
        const Broadcast *e = expr.as<Broadcast>();
        if (result && e && e->width == op->width) {
            expr = e->value;
            op->value.accept(this);
        } else {
            result = false;
        }
    }

    void visit(const Call *op) {
        const Call *e = expr.as<Call>();
        if (result && e &&
            e->type == op->type &&
            e->name == op->name &&
            e->call_type == op->call_type &&
            e->args.size() == op->args.size()) {
            for (size_t i = 0; result && (i < e->args.size()); i++) {
                expr = e->args[i];
                op->args[i].accept(this);
            }
        } else {
            result = false;
        }
    }

    void visit(const Let *op) {
        const Let *e = expr.as<Let>();
        if (result && e && e->name == op->name) {
            expr = e->value;
            op->value.accept(this);
            expr = e->body;
            op->body.accept(this);
        } else {
            result = false;
        }
    }
};

bool expr_match(Expr pattern, Expr expr, vector<Expr> &matches) {
    matches.clear();
    if (!pattern.defined() && !pattern.defined()) return true;
    if (!pattern.defined() || !pattern.defined()) return false;

    IRMatch eq(expr, matches);
    pattern.accept(&eq);
    if (eq.result) {
        return true;
    } else {
        matches.clear();
        return false;
    }
}

}}
<|endoftext|>


<commit_before>#include <iostream>
#include <julia.h>
#include "NAlloc.h"
#include "JuAlloc.h"
#include "Kernel.h"

using namespace std;

map<int64_t,nj::JuAlloc*> nj::JuAlloc::pindex_index;

nj::JuAlloc::JuAlloc(jl_value_t *val) throw(JuliaException):Alloc()
{
   Kernel *kernel = Kernel::getSingleton();

   _pindex = kernel->preserve(val);
   _ptr = (char*)jl_array_data(val);
   _len = jl_array_len(val);
   pindex_index[_pindex] = this;
}

std::shared_ptr<nj::Alloc> nj::JuAlloc::create(jl_value_t *val) throw(JuliaException)
{
   Kernel *kernel = Kernel::getSingleton();
   int64_t pindex = kernel->get(val);
   std::shared_ptr<nj::Alloc> res;

   if(pindex == -1)
   {
      JuAlloc *L = new JuAlloc(val);
      int64_t index = L->store();

      res = alloc_list->get(index);
   }
   else
   {
      map<int64_t,JuAlloc*>::iterator s = pindex_index.find(pindex);

      if(s != pindex_index.end())
      {
         JuAlloc *L = s->second;

         if(L->index() != -1) res = alloc_list->get(s->second->index());
         else res = s->second->container()->loc(0);
      }
   }
   return res;
}

nj::JuAlloc::~JuAlloc()
{
   Kernel *kernel = Kernel::getSingleton();

   (void)kernel->free(_pindex);
   pindex_index[_pindex] = 0;
   pindex_index.erase(_pindex);
}
<commit_msg>Suppress windows warning<commit_after>#if defined(WIN32)
#pragma warning(disable:4200)
#endif

#include <iostream>
#include <julia.h>
#include "NAlloc.h"
#include "JuAlloc.h"
#include "Kernel.h"

using namespace std;

map<int64_t,nj::JuAlloc*> nj::JuAlloc::pindex_index;

nj::JuAlloc::JuAlloc(jl_value_t *val) throw(JuliaException):Alloc()
{
   Kernel *kernel = Kernel::getSingleton();

   _pindex = kernel->preserve(val);
   _ptr = (char*)jl_array_data(val);
   _len = jl_array_len(val);
   pindex_index[_pindex] = this;
}

std::shared_ptr<nj::Alloc> nj::JuAlloc::create(jl_value_t *val) throw(JuliaException)
{
   Kernel *kernel = Kernel::getSingleton();
   int64_t pindex = kernel->get(val);
   std::shared_ptr<nj::Alloc> res;

   if(pindex == -1)
   {
      JuAlloc *L = new JuAlloc(val);
      int64_t index = L->store();

      res = alloc_list->get(index);
   }
   else
   {
      map<int64_t,JuAlloc*>::iterator s = pindex_index.find(pindex);

      if(s != pindex_index.end())
      {
         JuAlloc *L = s->second;

         if(L->index() != -1) res = alloc_list->get(s->second->index());
         else res = s->second->container()->loc(0);
      }
   }
   return res;
}

nj::JuAlloc::~JuAlloc()
{
   Kernel *kernel = Kernel::getSingleton();

   (void)kernel->free(_pindex);
   pindex_index[_pindex] = 0;
   pindex_index.erase(_pindex);
}
<|endoftext|>


<commit_before>// SciTE - Scintilla based Text Editor
// PropSet.cxx - a java style properties file module
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

// Maintain a dictionary of properties

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

#include "Platform.h"

#include "PropSet.h"

bool EqualCaseInsensitive(const char *a, const char *b) {
#if PLAT_GTK
	return 0 == strcasecmp(a, b);
#elif PLAT_WIN
	return 0 == stricmp(a, b);
#elif PLAT_WX
	return 0 == wxStricmp(a, b);
#endif
}

// Get a line of input. If end of line escaped with '\\' then continue reading.
static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) {
	bool continuation = true;
	s[0] = '\0';
	while ((len > 1) && lenData > 0) {
		char ch = *fpc;
		fpc++;
		lenData--;
		if ((ch == '\r') || (ch == '\n')) {
			if (!continuation) {
				if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) {
					// munch the second half of a crlf
					fpc++;
					lenData--;
				}
				*s = '\0';
				return true;
			}
		} else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) {
			continuation = true;
		} else {
			continuation = false;
			*s++ = ch;
			*s = '\0';
			len--;
		}
	}
	return false;
}

PropSet::PropSet() {
	superPS = 0;
	size = 10;
	used = 0;
	vals = new char * [size];
}

PropSet::~PropSet() {
	superPS = 0;
	Clear();
	delete []vals;
}

void PropSet::EnsureCanAddEntry() {
	if (used >= size - 2) {
		int newsize = size + 10;
		char **newvals = new char * [newsize];

		for (int i = 0; i < used; i++) {
			newvals[i] = vals[i];
		}
		delete []vals;
		vals = newvals;
		size = newsize;
	}
}

void PropSet::Set(const char *key, const char *val) {
	EnsureCanAddEntry();
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			// Replace current value
			delete [](vals[i + 1]);
			vals[i + 1] = StringDup(val);
			return;
		}
	}
	// Not found
	vals[used++] = StringDup(key);
	vals[used++] = StringDup(val);
}

void PropSet::Set(char *keyval) {
    while (isspace(*keyval))
        keyval++;
	char *eqat = strchr(keyval, '=');
	if (eqat) {
		*eqat = '\0';
		Set(keyval, eqat + 1);
		*eqat = '=';
	}
}

SString PropSet::Get(const char *key) {
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			return vals[i + 1];
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->Get(key);
	} else {
		return "";
	}
}

int PropSet::GetInt(const char *key, int defaultValue) {
	SString val = Get(key);
	if (val.length())
		return val.value();
	else
		return defaultValue;
}

bool isprefix(const char *target, const char *prefix) {
	while (*target && *prefix) {
		if (*target != *prefix)
			return false;
		target++;
		prefix++;
	}
	if (*prefix)
		return false;
	else
		return true;
}

bool issuffix(const char *target, const char *suffix) {
	int lentarget = strlen(target);
	int lensuffix = strlen(suffix);
	if (lensuffix > lentarget)
		return false;
	for (int i = lensuffix - 1; i >= 0; i--) {
		if (target[i + lentarget - lensuffix] != suffix[i])
			return false;
	}
	return true;
}

SString PropSet::GetWild(const char *keybase, const char *filename) {
	for (int i = 0; i < used; i += 2) {
		if (isprefix(vals[i], keybase)) {
			char *orgkeyfile = vals[i] + strlen(keybase);
			char *keyfile = NULL;

			if (strstr(orgkeyfile, "$(") == orgkeyfile) {
				char *cpendvar = strchr(orgkeyfile, ')');
				if (cpendvar) {
					*cpendvar = '\0';
					SString s = Get(orgkeyfile + 2);
					*cpendvar= ')';
					keyfile = strdup(s.c_str());
				}
			}
			char *keyptr = keyfile;

			if (keyfile == NULL)
				keyfile = orgkeyfile;

			for (; ; ) {
				char *del = strchr(keyfile, ';');
				if (del == NULL)
					del = keyfile + strlen(keyfile);
				char delchr = *del;
				*del = '\0';
				if (*keyfile == '*') {
					if (issuffix(filename, keyfile + 1)) {
						*del = delchr;
						free(keyptr);
						return vals[i + 1];
					}
				} else if (0 == strcmp(keyfile, filename)) {
					*del = delchr;
					free(keyptr);
					return vals[i + 1];
				}
				if (delchr == '\0')
					break;
				*del = delchr;
				keyfile = del + 1;
			}
			free(keyptr);

			if (0 == strcmp(vals[i], keybase)) {
				return vals[i + 1];
			}
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->GetWild(keybase, filename);
	} else {
		return "";
	}
}

SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
	char *base = StringDup(GetWild(keybase, filename).c_str());
	char *cpvar = strstr(base, "$(");
	while (cpvar) {
		char *cpendvar = strchr(cpvar, ')');
		if (cpendvar) {
			int lenvar = cpendvar - cpvar - 2;  	// Subtract the $()
			char *var = new char[lenvar + 1];
			strncpy(var, cpvar + 2, lenvar);
			var[lenvar] = '\0';
			SString val = GetWild(var, filename);
			int newlenbase = strlen(base) + val.length() - lenvar;
			char *newbase = new char[newlenbase];
			strncpy(newbase, base, cpvar - base);
			strcpy(newbase + (cpvar - base), val.c_str());
			strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
			delete []var;
			delete []base;
			base = newbase;
		}
		cpvar = strstr(base, "$(");
	}
	SString sret = base;
	delete []base;
	return sret;
}

void PropSet::Clear() {
	for (int i = 0; i < used; i++) {
		delete [](vals[i]);
		vals[i] = 0;
	}
	used = 0;
}

void PropSet::ReadFromMemory(const char *data, int len, const char *directoryForImports) {
	const char *pd = data;
	char linebuf[60000];
	bool ifIsTrue = true;
	while (len > 0) {
		GetFullLine(pd, len, linebuf, sizeof(linebuf));
		if (isalpha(linebuf[0]))    // If clause ends with first non-indented line
			ifIsTrue = true;
		if (isprefix(linebuf, "if ")) {
			const char *expr = linebuf + strlen("if") + 1;
			ifIsTrue = GetInt(expr);
		} else if (isprefix(linebuf, "import ") && directoryForImports) {
			char importPath[MAX_PATH];
			strcpy(importPath, directoryForImports);
			strcat(importPath, linebuf + strlen("import") + 1);
			strcat(importPath, ".properties");
            Read(importPath,directoryForImports);
		} else if (isalpha(linebuf[0])) {
			Set(linebuf);
		} else if (isspace(linebuf[0]) && ifIsTrue) {
			Set(linebuf);
		}
	}
}

void PropSet::Read(const char *filename, const char *directoryForImports) {
	char propsData[60000];
	FILE *rcfile = fopen(filename, "rb");
	if (rcfile) {
		int lenFile = fread(propsData, 1, sizeof(propsData), rcfile);
		fclose(rcfile);
		ReadFromMemory(propsData, lenFile, directoryForImports);
	} else {
		//printf("Could not open <%s>\n", filename);
	}
}

static bool iswordsep(char ch, bool onlyLineEnds) {
	if (!isspace(ch))
		return false;
	if (!onlyLineEnds)
		return true;
	return ch == '\r' || ch == '\n';
}

// Creates an array that points into each word in the string and puts \0 terminators
// after each word.
static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) {
	char prev = '\n';
	int words = 0;
	for (int j = 0; wordlist[j]; j++) {
		if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds))
			words++;
		prev = wordlist[j];
	}
	char **keywords = new char * [words + 1];
	if (keywords) {
		words = 0;
		prev = '\0';
		int len = strlen(wordlist);
		for (int k = 0; k < len; k++) {
			if (!iswordsep(wordlist[k], onlyLineEnds)) {
				if (!prev) {
					keywords[words] = &wordlist[k];
					words++;
				}
			} else {
				wordlist[k] = '\0';
			}
			prev = wordlist[k];
		}
		keywords[words] = &wordlist[len];
	}
	return keywords;
}

void WordList::Clear() {
	if (words) {
		delete []words;
		delete []list;
	}
	words = 0;
	list = 0;
	len = 0;
}

void WordList::Set(const char *s) {
	len = 0;
	list = StringDup(s);
	words = ArrayFromWordList(list, onlyLineEnds);
}

char *WordList::Allocate(int size) {
	list = new char[size + 1];
	list[size] = '\0';
	return list;
}

void WordList::SetFromAllocated() {
	len = 0;
	words = ArrayFromWordList(list, onlyLineEnds);
}

// Shell sort based upon public domain C implementation by Raymond Gardner 1991
// Used here because of problems with mingw qsort.
static void SortWordList(char **words, unsigned int len) {
	unsigned int gap = len / 2;

	while (gap > 0) {
		unsigned int i = gap;
		while (i < len) {
			unsigned int j = i;
			char **a = words + j;
			do {
				j -= gap;
				char **b = a;
				a -= gap;
				if (strcmp(*a, *b) > 0) {
					char *tmp = *a;
					*a = *b;
					*b = tmp;
				} else {
					break;
				}
			} while (j >= gap);
			i++;
		}
		gap = gap / 2;
	}
}

bool WordList::InList(const char *s) {
	if (0 == words)
		return false;
	if (len == 0) {
		for (int i = 0; words[i][0]; i++)
			len++;
		SortWordList(words, len);
		for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
			starts[k] = -1;
		for (int l = len - 1; l >= 0; l--) {
			unsigned char indexChar = words[l][0];
			starts[indexChar] = l;
		}
	}
	unsigned char firstChar = s[0];
	int j = starts[firstChar];
	if (j >= 0) {
		while (words[j][0] == firstChar) {
			if (s[1] == words[j][1]) {
				const char *a = words[j] + 1;
				const char *b = s + 1;
				while (*a && *a == *b) {
					a++;
					b++;
				}
				if (!*a && !*b)
					return true;
			}
			j++;
		}
	}
	return false;
}
<commit_msg>Changed MAX_PATH to 1024 to make GTK+ version compile.<commit_after>// SciTE - Scintilla based Text Editor
// PropSet.cxx - a java style properties file module
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

// Maintain a dictionary of properties

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

#include "Platform.h"

#include "PropSet.h"

bool EqualCaseInsensitive(const char *a, const char *b) {
#if PLAT_GTK
	return 0 == strcasecmp(a, b);
#elif PLAT_WIN
	return 0 == stricmp(a, b);
#elif PLAT_WX
	return 0 == wxStricmp(a, b);
#endif
}

// Get a line of input. If end of line escaped with '\\' then continue reading.
static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) {
	bool continuation = true;
	s[0] = '\0';
	while ((len > 1) && lenData > 0) {
		char ch = *fpc;
		fpc++;
		lenData--;
		if ((ch == '\r') || (ch == '\n')) {
			if (!continuation) {
				if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) {
					// munch the second half of a crlf
					fpc++;
					lenData--;
				}
				*s = '\0';
				return true;
			}
		} else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) {
			continuation = true;
		} else {
			continuation = false;
			*s++ = ch;
			*s = '\0';
			len--;
		}
	}
	return false;
}

PropSet::PropSet() {
	superPS = 0;
	size = 10;
	used = 0;
	vals = new char * [size];
}

PropSet::~PropSet() {
	superPS = 0;
	Clear();
	delete []vals;
}

void PropSet::EnsureCanAddEntry() {
	if (used >= size - 2) {
		int newsize = size + 10;
		char **newvals = new char * [newsize];

		for (int i = 0; i < used; i++) {
			newvals[i] = vals[i];
		}
		delete []vals;
		vals = newvals;
		size = newsize;
	}
}

void PropSet::Set(const char *key, const char *val) {
	EnsureCanAddEntry();
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			// Replace current value
			delete [](vals[i + 1]);
			vals[i + 1] = StringDup(val);
			return;
		}
	}
	// Not found
	vals[used++] = StringDup(key);
	vals[used++] = StringDup(val);
}

void PropSet::Set(char *keyval) {
    while (isspace(*keyval))
        keyval++;
	char *eqat = strchr(keyval, '=');
	if (eqat) {
		*eqat = '\0';
		Set(keyval, eqat + 1);
		*eqat = '=';
	}
}

SString PropSet::Get(const char *key) {
	for (int i = 0; i < used; i += 2) {
		if (0 == strcmp(vals[i], key)) {
			return vals[i + 1];
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->Get(key);
	} else {
		return "";
	}
}

int PropSet::GetInt(const char *key, int defaultValue) {
	SString val = Get(key);
	if (val.length())
		return val.value();
	else
		return defaultValue;
}

bool isprefix(const char *target, const char *prefix) {
	while (*target && *prefix) {
		if (*target != *prefix)
			return false;
		target++;
		prefix++;
	}
	if (*prefix)
		return false;
	else
		return true;
}

bool issuffix(const char *target, const char *suffix) {
	int lentarget = strlen(target);
	int lensuffix = strlen(suffix);
	if (lensuffix > lentarget)
		return false;
	for (int i = lensuffix - 1; i >= 0; i--) {
		if (target[i + lentarget - lensuffix] != suffix[i])
			return false;
	}
	return true;
}

SString PropSet::GetWild(const char *keybase, const char *filename) {
	for (int i = 0; i < used; i += 2) {
		if (isprefix(vals[i], keybase)) {
			char *orgkeyfile = vals[i] + strlen(keybase);
			char *keyfile = NULL;

			if (strstr(orgkeyfile, "$(") == orgkeyfile) {
				char *cpendvar = strchr(orgkeyfile, ')');
				if (cpendvar) {
					*cpendvar = '\0';
					SString s = Get(orgkeyfile + 2);
					*cpendvar= ')';
					keyfile = strdup(s.c_str());
				}
			}
			char *keyptr = keyfile;

			if (keyfile == NULL)
				keyfile = orgkeyfile;

			for (; ; ) {
				char *del = strchr(keyfile, ';');
				if (del == NULL)
					del = keyfile + strlen(keyfile);
				char delchr = *del;
				*del = '\0';
				if (*keyfile == '*') {
					if (issuffix(filename, keyfile + 1)) {
						*del = delchr;
						free(keyptr);
						return vals[i + 1];
					}
				} else if (0 == strcmp(keyfile, filename)) {
					*del = delchr;
					free(keyptr);
					return vals[i + 1];
				}
				if (delchr == '\0')
					break;
				*del = delchr;
				keyfile = del + 1;
			}
			free(keyptr);

			if (0 == strcmp(vals[i], keybase)) {
				return vals[i + 1];
			}
		}
	}
	if (superPS) {
		// Failed here, so try in base property set
		return superPS->GetWild(keybase, filename);
	} else {
		return "";
	}
}

SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
	char *base = StringDup(GetWild(keybase, filename).c_str());
	char *cpvar = strstr(base, "$(");
	while (cpvar) {
		char *cpendvar = strchr(cpvar, ')');
		if (cpendvar) {
			int lenvar = cpendvar - cpvar - 2;  	// Subtract the $()
			char *var = new char[lenvar + 1];
			strncpy(var, cpvar + 2, lenvar);
			var[lenvar] = '\0';
			SString val = GetWild(var, filename);
			int newlenbase = strlen(base) + val.length() - lenvar;
			char *newbase = new char[newlenbase];
			strncpy(newbase, base, cpvar - base);
			strcpy(newbase + (cpvar - base), val.c_str());
			strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
			delete []var;
			delete []base;
			base = newbase;
		}
		cpvar = strstr(base, "$(");
	}
	SString sret = base;
	delete []base;
	return sret;
}

void PropSet::Clear() {
	for (int i = 0; i < used; i++) {
		delete [](vals[i]);
		vals[i] = 0;
	}
	used = 0;
}

void PropSet::ReadFromMemory(const char *data, int len, const char *directoryForImports) {
	const char *pd = data;
	char linebuf[60000];
	bool ifIsTrue = true;
	while (len > 0) {
		GetFullLine(pd, len, linebuf, sizeof(linebuf));
		if (isalpha(linebuf[0]))    // If clause ends with first non-indented line
			ifIsTrue = true;
		if (isprefix(linebuf, "if ")) {
			const char *expr = linebuf + strlen("if") + 1;
			ifIsTrue = GetInt(expr);
		} else if (isprefix(linebuf, "import ") && directoryForImports) {
			char importPath[1024];
			strcpy(importPath, directoryForImports);
			strcat(importPath, linebuf + strlen("import") + 1);
			strcat(importPath, ".properties");
            		Read(importPath,directoryForImports);
		} else if (isalpha(linebuf[0])) {
			Set(linebuf);
		} else if (isspace(linebuf[0]) && ifIsTrue) {
			Set(linebuf);
		}
	}
}

void PropSet::Read(const char *filename, const char *directoryForImports) {
	char propsData[60000];
	FILE *rcfile = fopen(filename, "rb");
	if (rcfile) {
		int lenFile = fread(propsData, 1, sizeof(propsData), rcfile);
		fclose(rcfile);
		ReadFromMemory(propsData, lenFile, directoryForImports);
	} else {
		//printf("Could not open <%s>\n", filename);
	}
}

static bool iswordsep(char ch, bool onlyLineEnds) {
	if (!isspace(ch))
		return false;
	if (!onlyLineEnds)
		return true;
	return ch == '\r' || ch == '\n';
}

// Creates an array that points into each word in the string and puts \0 terminators
// after each word.
static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) {
	char prev = '\n';
	int words = 0;
	for (int j = 0; wordlist[j]; j++) {
		if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds))
			words++;
		prev = wordlist[j];
	}
	char **keywords = new char * [words + 1];
	if (keywords) {
		words = 0;
		prev = '\0';
		int len = strlen(wordlist);
		for (int k = 0; k < len; k++) {
			if (!iswordsep(wordlist[k], onlyLineEnds)) {
				if (!prev) {
					keywords[words] = &wordlist[k];
					words++;
				}
			} else {
				wordlist[k] = '\0';
			}
			prev = wordlist[k];
		}
		keywords[words] = &wordlist[len];
	}
	return keywords;
}

void WordList::Clear() {
	if (words) {
		delete []words;
		delete []list;
	}
	words = 0;
	list = 0;
	len = 0;
}

void WordList::Set(const char *s) {
	len = 0;
	list = StringDup(s);
	words = ArrayFromWordList(list, onlyLineEnds);
}

char *WordList::Allocate(int size) {
	list = new char[size + 1];
	list[size] = '\0';
	return list;
}

void WordList::SetFromAllocated() {
	len = 0;
	words = ArrayFromWordList(list, onlyLineEnds);
}

// Shell sort based upon public domain C implementation by Raymond Gardner 1991
// Used here because of problems with mingw qsort.
static void SortWordList(char **words, unsigned int len) {
	unsigned int gap = len / 2;

	while (gap > 0) {
		unsigned int i = gap;
		while (i < len) {
			unsigned int j = i;
			char **a = words + j;
			do {
				j -= gap;
				char **b = a;
				a -= gap;
				if (strcmp(*a, *b) > 0) {
					char *tmp = *a;
					*a = *b;
					*b = tmp;
				} else {
					break;
				}
			} while (j >= gap);
			i++;
		}
		gap = gap / 2;
	}
}

bool WordList::InList(const char *s) {
	if (0 == words)
		return false;
	if (len == 0) {
		for (int i = 0; words[i][0]; i++)
			len++;
		SortWordList(words, len);
		for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
			starts[k] = -1;
		for (int l = len - 1; l >= 0; l--) {
			unsigned char indexChar = words[l][0];
			starts[indexChar] = l;
		}
	}
	unsigned char firstChar = s[0];
	int j = starts[firstChar];
	if (j >= 0) {
		while (words[j][0] == firstChar) {
			if (s[1] == words[j][1]) {
				const char *a = words[j] + 1;
				const char *b = s + 1;
				while (*a && *a == *b) {
					a++;
					b++;
				}
				if (!*a && !*b)
					return true;
			}
			j++;
		}
	}
	return false;
}
<|endoftext|>


<commit_before>#include <mi/Routine.hpp>
#include <mi/Timer.hpp>
#include <sstream>
#include <iostream>
namespace mi
{
	class Routine::Impl {
	private:
		const std::string _name;
		std::stringstream _ss;
		bool _status;
	private:
		Impl ( const Impl& that );
		void operator = ( const Impl& that );
	public:
		Impl ( const std::string &name ) : _name(name), _status(true) {
			return;
		}

		std::string getName ( void ) const {
			return this->_name;
		}

		std::stringstream& getStream( void ) {
			return this->_ss;
		}

		bool getStatus ( void ) const {
			return this->_status;
		}

		void setFailed ( void ) {
			this->_status = false;
		}

		static Timer& getTimer( void ) {
			static Timer timer;
			return timer;
		}

		static bool& debug_mode ( void ) {
			static bool isDebugMode = false;
			return isDebugMode;
		}

	};

	Routine::Routine ( const std::string& name ) : _impl ( new Impl ( name ) ) {
		Routine::Impl::getTimer().start( this->_impl->getName() );
		if ( this->is_debug_mode() ) {
			std::cerr<< "applying "<< this->_impl->getName() <<" routine ... ";
		}
		return;
	}

	Routine::~Routine ( void ) {
		Routine::Impl::getTimer().end( this->_impl->getName() );
		if ( this->is_debug_mode() ) {
			if ( ! this->check() ) {
				std::cerr << " failed." << std::endl;
				std::cerr << this->_impl->getStream().str()<<std::endl;
			} else {
				std::cerr << " done." << std::endl;
			}
		}
		// delete
		if ( this->_impl != NULL ) delete this->_impl;
		this->_impl = NULL;
		return ;
	}

	bool
	Routine::run ( Routine& routine ) {
		if ( ! routine.check() ) return false;
		return routine.run_main_routine();
	}

	bool
	Routine::check ( void ) const {
		return this->_impl->getStatus();
	}

	void
	Routine::setDebugModeOn( void ) {
		Routine::Impl::debug_mode() = true;
		return;
	}

	std::stringstream&
	Routine::stream ( void ) {
		return this->_impl->getStream();
	}

	bool
	Routine::run_main_routine( void ) {
		this->set_failed();
		return this->_impl->getStatus();
	}

	void
	Routine::set_failed( void ) {
		this->_impl->setFailed();
		return;
	}

	bool
	Routine::is_debug_mode ( void ) {
		return Routine::Impl::debug_mode();
	}

}

<commit_msg>mi:Routine added<commit_after>#include <mi/Routine.hpp>
#include <mi/Timer.hpp>
#include <sstream>
#include <iostream>
namespace mi
{
	class Routine::Impl {
	private:
		const std::string _name;
		std::stringstream _ss;
		bool _status;
	private:
		Impl ( const Impl& that );
		void operator = ( const Impl& that );
	public:
		Impl ( const std::string &name ) : _name(name), _status(true) {
			return;
		}

		std::string getName ( void ) const {
			return this->_name;
		}

		std::stringstream& getStream( void ) {
			return this->_ss;
		}

		bool getStatus ( void ) const {
			return this->_status;
		}

		void setFailed ( void ) {
			this->_status = false;
		}

		static Timer& getTimer( void ) {
			static Timer timer;
			return timer;
		}

		static bool& debug_mode ( void ) {
			static bool isDebugMode = false;
			return isDebugMode;
		}

	};

	Routine::Routine ( const std::string& name ) : _impl ( new Impl ( name ) ) {
		Routine::Impl::getTimer().start( this->_impl->getName() );
		if ( this->is_debug_mode() ) {
			std::cerr<< this->_impl->getName() <<" routine ... ";
		}
		return;
	}

	Routine::~Routine ( void ) {
		Routine::Impl::getTimer().end( this->_impl->getName() );
		if ( this->check() ) std::cerr <<" done."<<std::endl;
		else  {
			std::cerr <<" failed."<<std::endl;;
			std::cerr << this->_impl->getStream().str()<<std::endl;
		}
		// delete
		if ( this->_impl != NULL ) delete this->_impl;
		this->_impl = NULL;
		return ;
	}

	bool
	Routine::run ( Routine& routine ) {
		if ( ! routine.check() ) return false;
		return routine.run_main_routine();
	}

	bool
	Routine::check ( void ) const {
		return this->_impl->getStatus();
	}

	void
	Routine::setDebugModeOn( void ) {
		Routine::Impl::debug_mode() = true;
		return;
	}

	std::stringstream&
	Routine::stream ( void ) {
		return this->_impl->getStream();
	}

	bool
	Routine::run_main_routine( void ) {
		this->set_failed();
		return this->_impl->getStatus();
	}

	void
	Routine::set_failed( void ) {
		this->_impl->setFailed();
		return;
	}

	bool
	Routine::is_debug_mode ( void ) {
		return Routine::Impl::debug_mode();
	}

}

<|endoftext|>


<commit_before>#include "../inc/Sniffer.hpp"

std::ofstream Sniffer::output;
std::vector<Bridge> Sniffer::bridges;
Client * Sniffer::client;
bool Sniffer::hadTC;
bool Sniffer::noConnect;

Sniffer::Sniffer(bool nC, std::string outputFileName, std::string hostname, int port){
    bridges = std::vector<Bridge>();
    Sniffer::output.open(outputFileName, std::ios::app);
    if(!Sniffer::output.is_open()){
        std::cerr << "could not open file" << std::endl;
        exit(-1);
    }

    noConnect = nC;
    if(noConnect){
        client = NULL;
    }else{
        client = new Client(hostname, port);
    }
    hadTC = false;
}

Sniffer::~Sniffer(){
    output.flush();
    output.close();
    delete client;
}

void Sniffer::start(const std::string inputFileName, const std::string deviceName){
    output << "sniffer starting\n";
    if(!noConnect){
        output << "registering client\n";
        client->regServer();
    }
    char err[PCAP_ERRBUF_SIZE];
    if(inputFileName.size() == 0){
        output << "getting interfaces\n";
        pcap_if_t *alldevs;
        if(pcap_findalldevs(&alldevs, err)){
            output << "error while getting interfaces, error code: " << err << std::endl;
            exit(-1);
        }

        pcap_if_t *device;
        output << "found devices:\n";
        for(device = alldevs; device != NULL; device = device->next){
            if(device->name){
                output << device->name;
                if(device->description)
                    output << " - " << device->description;
                output << std::endl;
            }
        }

        if(deviceName == ""){
            output << "selecting first named device\n";
            for(device = alldevs; device != NULL && device->name == NULL; device = device->next)
                ;
            if(device == NULL){
                output << "no named device found\n";
                exit(-1);
            }
        }else{
            for(device = alldevs; device != NULL && device->name != deviceName; device = device->next)
                ;
            if(device == NULL){
                output << "desired device not found\n";
                exit(-1);
            }
        }

        //save device name for restart
        std::string devname = std::string(device->name);

        output << "opening device " << device->name << " for sniffing" << std::endl;
        pcap_t *capture_handle = pcap_open_live(device->name, 65536, 1, 0, err);
        if(!capture_handle){
            output << "could not start capture" << std::endl;
            exit(-1);
        }

        while(1){
            pcap_loop(capture_handle, -1, process_packet, NULL);
            output << "interface disconnected, closing capture\n";
            pcap_close(capture_handle);
            capture_handle = NULL;

            output << "trying to find device " << devname << " again\n";
            while(capture_handle == NULL){
                sleep(2);
                pcap_if_t *alldevs;
                if(pcap_findalldevs(&alldevs, err)){
                    output << "error while getting interfaces, error code: " << err << std::endl;
                    exit(-1);
                }

                for(device = alldevs; device != NULL && device->name != devname; device = device->next)
                    ;
                if(device != NULL){
                    capture_handle = pcap_open_live(device->name, 65536, 1, 0, err);
                    if(!capture_handle){
                        output << "could not start capture" << std::endl;
                        exit(-1);
                    }
                }
            }
            output << "device found, restarting capture\n";
        }
    }else{
        output << "reading from file\n";
        pcap_t *pcap = pcap_open_offline(inputFileName.c_str(), err);
        struct pcap_pkthdr *header;
        const u_char *data;
        while(pcap_next_ex(pcap, &header, &data) >= 0)
            process_packet(NULL, header, data);
    }
}

void Sniffer::process_packet(u_char *user, const struct pcap_pkthdr *header, const u_char *bytes){
    struct ethhdr *ethh = (struct ethhdr*) bytes;

    char buffer[17];
    sprintf(buffer,"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ethh->h_dest[0], ethh->h_dest[1], ethh->h_dest[2], ethh->h_dest[3], ethh->h_dest[4], ethh->h_dest[5]);
    if(std::string(buffer, 17) != "01:80:C2:00:00:00")
        return;

    //handle payload
    const u_char *payload = bytes+sizeof(struct ethhdr);
    int psize = header->len - sizeof(struct ethhdr);
    //payload starts at logical link control level
    //llc has 3 bytes
    payload+=3;
    psize-=3;
    //payload is now at the start of the stp payload
    //protocol identifier stp (2 bytes)
    payload+=2;
    psize-=2;

    //one byte for version and bpdu type
    payload+=2;
    psize-=2;

    //tc flag
    int tc = *(payload++);
    psize--;

    //root identifier
    //bridge priority is the next 2 bytes
    unsigned short rPriority;
    //actual priority is 4 bits
    rPriority = *((short*)payload);
    payload+=2;
    psize-=2;
    //next 6 bytes is the root bridge id
    Mac rootMac(payload);
    payload+=6;
    psize-=6;

    //root path cost (4 bytes)
    payload+=4;
    psize-=4;

    //bridge identifier
    ////bridge priority is the next 2 bytes
    unsigned short bPriority;
    bPriority = *((short*)payload);
    payload+=2;
    psize-=2;
    //next 6 bytes is the bridge mac address
    Mac bridgeMac(payload);
    payload+=6;
    psize-=6;

    //next 2 bytes are port identifier
    payload+=2;
    psize-=2;

    //next 2 bytes is message age
    short messageAge;
    messageAge = *((short*)payload);
    payload+=2;
    psize-=2;

    //generate Bridge objects
    Bridge root(rootMac, rPriority, 0);
    Bridge firstHop(bridgeMac, bPriority, messageAge);

    //check if the two nodes are contained
    int rootContained = 0, oldHopMa = -1;
    for(Bridge b : bridges){
        if(b == root)
            rootContained = 1;
        if(b == firstHop)
            oldHopMa = b.getMessageAge();
    }

    //handle network changes
    if(rootContained){
        if(oldHopMa >= 0){
            //both contained
            if(oldHopMa != firstHop.getMessageAge()){
                //i don't know when this would happen
                clearAndAdd(firstHop, root);
            }else{
                //everything is as it was
                //if something changed upstream a tc flag will be sent
                //->reset
                if(tc)
                    clearAndAdd(firstHop, root);
            }
        }else{
            //first hop not contained
            //this means that the node was plugged in on a different bridge
            //(most likely)
            //we don't know how long we were disconnected, so reregister the client
            if(!noConnect)
                client->regServer();
            clearAndAdd(firstHop, root);
        }
    }else{
        //root not contained
        if(oldHopMa >= 0){
            //if the first hop was contained this means there were some changes upstream
            if(oldHopMa == firstHop.getMessageAge() - 1){
                std::cout << "root moved away\n";
                //this means we have to increase every message age and add the new root
                for(Bridge &b : bridges)
                    b.setMessageAge(b.getMessageAge() + 1);
                bridges.push_back(root);
            }else{
                clearAndAdd(firstHop, root);
            }
        }else{
            //entirely new setup
            clearAndAdd(firstHop, root);
        }
    }

    SpanningTree currentTree = getTree();
    Json::FastWriter writer;
    Json::Value toSend;
    toSend["messagetype"] = "push";
    toSend["tree"] = currentTree.toJson();
    output << "sniffer is sending: " << std::endl << writer.write(toSend) << std::endl;
    try{
        if(client)
            client->send(toSend);
    }catch(const char * msg){
        output << msg << std::endl;
    }
}

SpanningTree Sniffer::getTree(){
    std::sort(bridges.begin(), bridges.end(), [](Bridge a, Bridge b) {return a.getMessageAge() < b.getMessageAge();});
    return treeHelper(bridges.begin(), bridges.end());
}

void Sniffer::clearAndAdd(Bridge firstHop, Bridge root){
    bridges.clear();
    if(firstHop != root)
        bridges.push_back(root);
    bridges.push_back(firstHop);
}

SpanningTree Sniffer::treeHelper(std::vector<Bridge>::iterator current, std::vector<Bridge>::iterator end){
    if(current == end-1)
        return SpanningTree(*current);

    SpanningTree newTree(*current);
    newTree.addChild(treeHelper(++current, end));
    return newTree;
}
<commit_msg>fixed tc check (was only tc, now is tc \&\& !hadTC)<commit_after>#include "../inc/Sniffer.hpp"

std::ofstream Sniffer::output;
std::vector<Bridge> Sniffer::bridges;
Client * Sniffer::client;
bool Sniffer::hadTC;
bool Sniffer::noConnect;

Sniffer::Sniffer(bool nC, std::string outputFileName, std::string hostname, int port){
    bridges = std::vector<Bridge>();
    Sniffer::output.open(outputFileName, std::ios::app);
    if(!Sniffer::output.is_open()){
        std::cerr << "could not open file" << std::endl;
        exit(-1);
    }

    noConnect = nC;
    if(noConnect){
        client = NULL;
    }else{
        client = new Client(hostname, port);
    }
    hadTC = false;
}

Sniffer::~Sniffer(){
    output.flush();
    output.close();
    delete client;
}

void Sniffer::start(const std::string inputFileName, const std::string deviceName){
    output << "sniffer starting\n";
    if(!noConnect){
        output << "registering client\n";
        client->regServer();
    }
    char err[PCAP_ERRBUF_SIZE];
    if(inputFileName.size() == 0){
        output << "getting interfaces\n";
        pcap_if_t *alldevs;
        if(pcap_findalldevs(&alldevs, err)){
            output << "error while getting interfaces, error code: " << err << std::endl;
            exit(-1);
        }

        pcap_if_t *device;
        output << "found devices:\n";
        for(device = alldevs; device != NULL; device = device->next){
            if(device->name){
                output << device->name;
                if(device->description)
                    output << " - " << device->description;
                output << std::endl;
            }
        }

        if(deviceName == ""){
            output << "selecting first named device\n";
            for(device = alldevs; device != NULL && device->name == NULL; device = device->next)
                ;
            if(device == NULL){
                output << "no named device found\n";
                exit(-1);
            }
        }else{
            for(device = alldevs; device != NULL && device->name != deviceName; device = device->next)
                ;
            if(device == NULL){
                output << "desired device not found\n";
                exit(-1);
            }
        }

        //save device name for restart
        std::string devname = std::string(device->name);

        output << "opening device " << device->name << " for sniffing" << std::endl;
        pcap_t *capture_handle = pcap_open_live(device->name, 65536, 1, 0, err);
        if(!capture_handle){
            output << "could not start capture" << std::endl;
            exit(-1);
        }

        while(1){
            pcap_loop(capture_handle, -1, process_packet, NULL);
            output << "interface disconnected, closing capture\n";
            pcap_close(capture_handle);
            capture_handle = NULL;

            output << "trying to find device " << devname << " again\n";
            while(capture_handle == NULL){
                sleep(2);
                pcap_if_t *alldevs;
                if(pcap_findalldevs(&alldevs, err)){
                    output << "error while getting interfaces, error code: " << err << std::endl;
                    exit(-1);
                }

                for(device = alldevs; device != NULL && device->name != devname; device = device->next)
                    ;
                if(device != NULL){
                    capture_handle = pcap_open_live(device->name, 65536, 1, 0, err);
                    if(!capture_handle){
                        output << "could not start capture" << std::endl;
                        exit(-1);
                    }
                }
            }
            output << "device found, restarting capture\n";
        }
    }else{
        output << "reading from file\n";
        pcap_t *pcap = pcap_open_offline(inputFileName.c_str(), err);
        struct pcap_pkthdr *header;
        const u_char *data;
        while(pcap_next_ex(pcap, &header, &data) >= 0)
            process_packet(NULL, header, data);
    }
}

void Sniffer::process_packet(u_char *user, const struct pcap_pkthdr *header, const u_char *bytes){
    struct ethhdr *ethh = (struct ethhdr*) bytes;

    char buffer[17];
    sprintf(buffer,"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ethh->h_dest[0], ethh->h_dest[1], ethh->h_dest[2], ethh->h_dest[3], ethh->h_dest[4], ethh->h_dest[5]);
    if(std::string(buffer, 17) != "01:80:C2:00:00:00")
        return;

    //handle payload
    const u_char *payload = bytes+sizeof(struct ethhdr);
    int psize = header->len - sizeof(struct ethhdr);
    //payload starts at logical link control level
    //llc has 3 bytes
    payload+=3;
    psize-=3;
    //payload is now at the start of the stp payload
    //protocol identifier stp (2 bytes)
    payload+=2;
    psize-=2;

    //one byte for version and bpdu type
    payload+=2;
    psize-=2;

    //tc flag
    bool tc = *(payload++);
    psize--;

    //root identifier
    //bridge priority is the next 2 bytes
    unsigned short rPriority;
    //actual priority is 4 bits
    rPriority = *((short*)payload);
    payload+=2;
    psize-=2;
    //next 6 bytes is the root bridge id
    Mac rootMac(payload);
    payload+=6;
    psize-=6;

    //root path cost (4 bytes)
    payload+=4;
    psize-=4;

    //bridge identifier
    ////bridge priority is the next 2 bytes
    unsigned short bPriority;
    bPriority = *((short*)payload);
    payload+=2;
    psize-=2;
    //next 6 bytes is the bridge mac address
    Mac bridgeMac(payload);
    payload+=6;
    psize-=6;

    //next 2 bytes are port identifier
    payload+=2;
    psize-=2;

    //next 2 bytes is message age
    short messageAge;
    messageAge = *((short*)payload);
    payload+=2;
    psize-=2;

    //generate Bridge objects
    Bridge root(rootMac, rPriority, 0);
    Bridge firstHop(bridgeMac, bPriority, messageAge);

    //check if the two nodes are contained
    int rootContained = 0, oldHopMa = -1;
    for(Bridge b : bridges){
        if(b == root)
            rootContained = 1;
        if(b == firstHop)
            oldHopMa = b.getMessageAge();
    }

    //handle network changes
    if(rootContained){
        if(oldHopMa >= 0){
            //both contained
            if(oldHopMa != firstHop.getMessageAge()){
                //i don't know when this would happen
                clearAndAdd(firstHop, root);
            }else{
                //everything is as it was
                //if something changed upstream a tc flag will be sent
                //->reset
                if(tc && !hadTC)
                    clearAndAdd(firstHop, root);
            }
        }else{
            //first hop not contained
            //this means that the node was plugged in on a different bridge
            //(most likely)
            //we don't know how long we were disconnected, so reregister the client
            if(!noConnect)
                client->regServer();
            clearAndAdd(firstHop, root);
        }
    }else{
        //root not contained
        if(oldHopMa >= 0){
            //if the first hop was contained this means there were some changes upstream
            if(oldHopMa == firstHop.getMessageAge() - 1){
                std::cout << "root moved away\n";
                //this means we have to increase every message age and add the new root
                for(Bridge &b : bridges)
                    b.setMessageAge(b.getMessageAge() + 1);
                bridges.push_back(root);
            }else{
                clearAndAdd(firstHop, root);
            }
        }else{
            //entirely new setup
            clearAndAdd(firstHop, root);
        }
    }
    hadTC = tc;

    SpanningTree currentTree = getTree();
    Json::FastWriter writer;
    Json::Value toSend;
    toSend["messagetype"] = "push";
    toSend["tree"] = currentTree.toJson();
    output << "sniffer is sending: " << std::endl << writer.write(toSend) << std::endl;
    try{
        if(client)
            client->send(toSend);
    }catch(const char * msg){
        output << msg << std::endl;
    }
}

SpanningTree Sniffer::getTree(){
    std::sort(bridges.begin(), bridges.end(), [](Bridge a, Bridge b) {return a.getMessageAge() < b.getMessageAge();});
    return treeHelper(bridges.begin(), bridges.end());
}

void Sniffer::clearAndAdd(Bridge firstHop, Bridge root){
    bridges.clear();
    if(firstHop != root)
        bridges.push_back(root);
    bridges.push_back(firstHop);
}

SpanningTree Sniffer::treeHelper(std::vector<Bridge>::iterator current, std::vector<Bridge>::iterator end){
    if(current == end-1)
        return SpanningTree(*current);

    SpanningTree newTree(*current);
    newTree.addChild(treeHelper(++current, end));
    return newTree;
}
<|endoftext|>


<commit_before>/*******************************************************************************
 Copyright 2008 Enseed inc.

 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.

 Author: Gaspard Petit
*******************************************************************************/
//==============================================================================
//	EXTERNAL DECLARATIONS
//==============================================================================
#include "../Version.h"

#ifdef GENERIC_LAYER_NAMESPACE
namespace GENERIC_LAYER_NAMESPACE {
#endif

#ifdef GENERIC_LAYER_NAMESPACE
}
#endif

<commit_msg>Standardized namespace guard<commit_after>/*******************************************************************************
 Copyright 2008 Enseed inc.

 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.

 Author: Gaspard Petit
*******************************************************************************/
//==============================================================================
//	EXTERNAL DECLARATIONS
//==============================================================================
#include "../Version.h"

#ifdef GENERIC_NAMESPACE
namespace GENERIC_NAMESPACE {
#endif

#ifdef GENERIC_NAMESPACE
}
#endif

<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2015 Wojciech Migda
 * All rights reserved
 * Distributed under the terms of the GNU LGPL v3
 *******************************************************************************
 *
 * Filename: array2d.hpp
 *
 * Description:
 *      Let's try to have a numpy-like environment
 *
 * Authors:
 *          Wojciech Migda (wm)
 *
 *******************************************************************************
 * History:
 * --------
 * Date         Who  Ticket     Description
 * ----------   ---  ---------  ------------------------------------------------
 * 2015-01-30   wm              Initial version. TripSafetyFactors
 * 2015-02-22   wm              ChildStuntedness5
 *
 ******************************************************************************/

#ifndef ARRAY2D_HPP_
#define ARRAY2D_HPP_

#include "num.hpp"
#include <cstdlib>
#include <utility>
#include <valarray>
#include <map>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <string>
#include <sstream>
#include <type_traits>
#include <unordered_set>

#pragma GCC optimize ( "-ftree-vectorize" )

namespace num
{

typedef std::pair<size_type, size_type> shape_type;

/**
 *******************************************************************************
 *   @brief 2d array
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-01-30              wm      Class created.
 *   2015-02-22              wm      @c column interface: size_type -> int
 *   2015-02-22              wm      @c at method
 *   @endcode
 *******************************************************************************
 *   2d clone of numpy's ndarray:
 *   http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
 *******************************************************************************
 */
template<typename _Type>
class array2d
{
public:
    enum class Axis
    {
        Row,
        Column
    };

    typedef _Type value_type;
    typedef std::size_t size_type;
    typedef std::pair<size_type, size_type> shape_type;
    typedef std::valarray<value_type> varray_type;

    array2d(shape_type shape, value_type initializer);

    shape_type shape(void) const;

    value_type at(int p, int q) const;
    value_type & at(int p, int q);

    std::slice row(size_type n) const;
    std::slice column(int n) const;
    std::slice stripe(size_type n, enum Axis axis) const;

    std::gslice columns(int p, int q) const;

    std::valarray<value_type> operator[](std::slice slicearr) const;
    std::slice_array<value_type> operator[](std::slice slicearr);
    std::valarray<value_type> operator[](const std::gslice & gslicearr) const;
    std::gslice_array<value_type> operator[](const std::gslice & gslicearr);

private:
    shape_type m_shape;
    varray_type m_varray;
};

template<typename _Type>
inline
array2d<_Type>::array2d(shape_type shape, array2d<_Type>::value_type initializer)
:
    m_shape(shape),
    m_varray(initializer, shape.first * shape.second)
{

}

template<typename _Type>
inline
shape_type
array2d<_Type>::shape(void) const
{
    return m_shape;
}

template<typename _Type>
inline
_Type
array2d<_Type>::at(int p, int q) const
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return m_varray[p * m_shape.second + q];
}

template<typename _Type>
inline
_Type &
array2d<_Type>::at(int p, int q)
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return m_varray[p * m_shape.second + q];
}

template<typename _Type>
inline
std::slice
array2d<_Type>::row(size_type n) const
{
    return std::slice(n * m_shape.second, m_shape.second, 1);
}

template<typename _Type>
inline
std::slice
array2d<_Type>::column(int n) const
{
    if (n < 0)
    {
        assert(-n < m_shape.second);
        n = m_shape.second + n;
    }

    return std::slice(n, m_shape.first, m_shape.second);
}

template<typename _Type>
inline
std::gslice
array2d<_Type>::columns(int p, int q) const
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return std::gslice(
        p,
        {m_shape.first, {q - p + 1u}},
        {m_shape.second, 1u}
    );
}

template<typename _Type>
inline
std::slice
array2d<_Type>::stripe(size_type n, enum Axis axis) const
{
    return axis == Axis::Row ? row(n) : column(n);
}

template<typename _Type>
inline
std::valarray<_Type>
array2d<_Type>::operator[](std::slice slicearr) const
{
    return m_varray[slicearr];
}

template<typename _Type>
inline
std::slice_array<_Type>
array2d<_Type>::operator[](std::slice slicearr)
{
    return m_varray[slicearr];
}

template<typename _Type>
inline
std::valarray<_Type>
array2d<_Type>::operator[](const std::gslice & gslicearr) const
{
    return m_varray[gslicearr];
}

template<typename _Type>
inline
std::gslice_array<_Type>
array2d<_Type>::operator[](const std::gslice & gslicearr)
{
    return m_varray[gslicearr];
}

template<typename _Type>
inline
array2d<_Type>
zeros(shape_type shape)
{
    return array2d<_Type>(shape, 0.0);
}

template<typename _Type>
inline
array2d<_Type>
ones(shape_type shape)
{
    return array2d<_Type>(shape, 1.0);
}

/**
 *******************************************************************************
 *   @brief Configuration for @c loadtxt
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-02-07              wm      Class created. TripSafetyFactors
 *   2015-02-22              wm      Index of -1 for converters means all cols
 *   2015-02-22              wm      use_cols accessor
 *   @endcode
 *******************************************************************************
 */
template<typename _Type = double>
struct loadtxtCfg
{
    typedef std::map<int, _Type(*)(const char *)> converters_type;
    typedef std::unordered_set<size_type> use_cols_type;

    loadtxtCfg()
    :
        m_comments{'#'},
        m_delimiter{' '},
        m_converters{},
        m_skip_header{0},
        m_skip_footer{0},
        m_use_cols{}
    {}

    loadtxtCfg & comments(char _comments)
    {
        m_comments = _comments;
        return *this;
    }

    char delimiter(void) const
    {
        return m_delimiter;
    }

    loadtxtCfg & delimiter(char _delimiter)
    {
        m_delimiter = _delimiter;
        return *this;
    }

    const converters_type & converters(void) const
    {
        return m_converters;
    }

    loadtxtCfg & converters(converters_type && _converters)
    {
        m_converters = std::move(_converters);
        return *this;
    }

    size_type skip_header(void) const
    {
        return m_skip_header;
    }

    loadtxtCfg & skip_header(size_type _skip_header)
    {
        m_skip_header = _skip_header;
        return *this;
    }

    size_type skip_footer(void) const
    {
        return m_skip_footer;
    }

    loadtxtCfg & skip_footer(size_type _skip_footer)
    {
        m_skip_footer = _skip_footer;
        return *this;
    }

    const use_cols_type & use_cols(void) const
    {
        return m_use_cols;
    }

    loadtxtCfg & use_cols(const use_cols_type & _use_cols)
    {
        m_use_cols = _use_cols;
        return *this;
    }

    loadtxtCfg & use_cols(use_cols_type && _use_cols)
    {
        m_use_cols = std::move(_use_cols);
        return *this;
    }

    char m_comments;
    char m_delimiter;
    converters_type m_converters;
    size_type m_skip_header;
    size_type m_skip_footer;
    use_cols_type m_use_cols;
};

/**
 *******************************************************************************
 *   @brief Load data from a vector of strings.
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-02-07              wm      Class created. TripSafetyFactors
 *   2015-02-22              wm      Index of -1 for converters means all cols
 *   2015-02-22              wm      use_cols selector applied
 *   @endcode
 *******************************************************************************
 *   @param txt vector of strings to read from
 *   @param cfg confguration of the processor
 *******************************************************************************
 *   @return 2d array created from passed vector of strings
 *******************************************************************************
 *   Implementation based on
 *   http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
 *   interface.
 *******************************************************************************
 */
template<typename _Type>
array2d<_Type>
loadtxt(
    std::vector<std::string> && txt,
    loadtxtCfg<_Type> && cfg
)
{
    typedef _Type value_type;
    const bool skip_empty = false;

    auto count_delimiters = [&skip_empty](std::string where, char delim) -> size_type
    {
        auto predicate = [&delim](char _this, char _that)
        {
            return _this == _that && _this == delim;
        };
        if (skip_empty)
        {
            std::unique(where.begin(), where.end(), predicate);
        }

        return std::count(where.cbegin(), where.cend(), delim);
    };

    assert(txt.size() >= (cfg.skip_header() + cfg.skip_footer()));
    const size_type NROWS = txt.size() - cfg.skip_header() - cfg.skip_footer();
    if (NROWS == 0)
    {
        return zeros<value_type>(shape_type(0, 0));
    }

    const bool WIDESPAN_CONVERTER = cfg.converters().find(-1) != cfg.converters().cend();
    const bool USE_COLS = cfg.use_cols().size() != 0;
    const size_type NICOLS = 1 + count_delimiters(txt.front(), cfg.delimiter()); // TODO
    const size_type NCOLS = USE_COLS ? cfg.use_cols().size() : NICOLS;

    array2d<_Type> result = zeros<value_type>(shape_type(NROWS, NCOLS));

    for (size_type ridx{0}; ridx < NROWS; ++ridx)
    {
        std::valarray<value_type> row(NROWS);
        std::stringstream ss(txt[ridx + cfg.skip_header()]);
        std::string item;
        size_type ocidx{0};

        for (size_type icidx{0}; icidx < NICOLS && std::getline(ss, item, cfg.delimiter()); ++icidx) // TODO
        {
            if (USE_COLS && (cfg.use_cols().find(icidx) == cfg.use_cols().cend()))
            {
                continue;
            }

            if (WIDESPAN_CONVERTER)
            {
                row[ocidx] = cfg.converters().at(-1)(item.c_str());
            }
            else if (cfg.converters().find(icidx) != cfg.converters().cend())
            {
                row[ocidx] = cfg.converters().at(icidx)(item.c_str());
            }
            else if (std::is_convertible<value_type, long double>::value)
            {
                row[ocidx] = std::strtold(item.c_str(), nullptr);
            }
            else if (std::is_convertible<value_type, long long>::value)
            {
                row[ocidx] = std::atoll(item.c_str());
            }
            else
            {
                std::stringstream item_ss(item);
                item_ss >> row[ocidx];
            }

            ++ocidx;
        }

        result[result.row(ridx)] = row;
    }

    return result;
}

} // namespace num

namespace std
{

std::ostream & operator<<(std::ostream & os, const num::shape_type & shape)
{
    os << '(' << shape.first << ',' << shape.second << ')';
    return os;
}

} // namespace std

#endif /* ARRAY2D_HPP_ */
<commit_msg>multiplication by vector<commit_after>/*******************************************************************************
 * Copyright (c) 2015 Wojciech Migda
 * All rights reserved
 * Distributed under the terms of the GNU LGPL v3
 *******************************************************************************
 *
 * Filename: array2d.hpp
 *
 * Description:
 *      Let's try to have a numpy-like environment
 *
 * Authors:
 *          Wojciech Migda (wm)
 *
 *******************************************************************************
 * History:
 * --------
 * Date         Who  Ticket     Description
 * ----------   ---  ---------  ------------------------------------------------
 * 2015-01-30   wm              Initial version. TripSafetyFactors
 * 2015-02-22   wm              ChildStuntedness5
 *
 ******************************************************************************/

#ifndef ARRAY2D_HPP_
#define ARRAY2D_HPP_

#include "num.hpp"
#include <cstdlib>
#include <utility>
#include <valarray>
#include <map>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <string>
#include <sstream>
#include <type_traits>
#include <unordered_set>

#pragma GCC optimize ( "-ftree-vectorize" )

namespace num
{

typedef std::pair<size_type, size_type> shape_type;

/**
 *******************************************************************************
 *   @brief 2d array
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-01-30              wm      Class created.
 *   2015-02-22              wm      @c column interface: size_type -> int
 *   2015-02-22              wm      @c at method
 *   @endcode
 *******************************************************************************
 *   2d clone of numpy's ndarray:
 *   http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
 *******************************************************************************
 */
template<typename _Type>
class array2d
{
public:
    enum class Axis
    {
        Row,
        Column
    };

    typedef _Type value_type;
    typedef std::size_t size_type;
    typedef std::pair<size_type, size_type> shape_type;
    typedef std::valarray<value_type> vector_type;

    array2d(shape_type shape, value_type initializer);

    shape_type shape(void) const;

    value_type at(int p, int q) const;
    value_type & at(int p, int q);

    std::slice row(size_type n) const;
    std::slice column(int n) const;
    std::slice stripe(size_type n, enum Axis axis) const;

    std::gslice columns(int p, int q) const;

    void mul(
        const Axis,
        const std::valarray<value_type> & ivector,
        std::valarray<value_type> & ovector) const;

    template<typename _Op>
    void mul(
        const Axis,
        const std::valarray<value_type> & ivector,
        std::valarray<value_type> & ovector,
        _Op op) const;

    std::valarray<value_type> operator[](std::slice slicearr) const;
    std::slice_array<value_type> operator[](std::slice slicearr);
    std::valarray<value_type> operator[](const std::gslice & gslicearr) const;
    std::gslice_array<value_type> operator[](const std::gslice & gslicearr);

private:
    shape_type m_shape;
    vector_type m_varray;
};

template<typename _Type>
inline
array2d<_Type>::array2d(shape_type shape, array2d<_Type>::value_type initializer)
:
    m_shape(shape),
    m_varray(initializer, shape.first * shape.second)
{

}

template<typename _Type>
inline
shape_type
array2d<_Type>::shape(void) const
{
    return m_shape;
}

template<typename _Type>
inline
_Type
array2d<_Type>::at(int p, int q) const
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return m_varray[p * m_shape.second + q];
}

template<typename _Type>
inline
_Type &
array2d<_Type>::at(int p, int q)
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return m_varray[p * m_shape.second + q];
}

template<typename _Type>
inline
std::slice
array2d<_Type>::row(size_type n) const
{
    return std::slice(n * m_shape.second, m_shape.second, 1);
}

template<typename _Type>
inline
std::slice
array2d<_Type>::column(int n) const
{
    if (n < 0)
    {
        assert(-n < m_shape.second);
        n = m_shape.second + n;
    }

    return std::slice(n, m_shape.first, m_shape.second);
}

template<typename _Type>
inline
std::gslice
array2d<_Type>::columns(int p, int q) const
{
    if (p < 0)
    {
        assert(-p < m_shape.second);
        p = m_shape.second + p;
    }
    if (q < 0)
    {
        assert(-q < m_shape.second);
        q = m_shape.second + q;
    }

    return std::gslice(
        p,
        {m_shape.first, {q - p + 1u}},
        {m_shape.second, 1u}
    );
}

template<typename _Type>
inline
std::slice
array2d<_Type>::stripe(size_type n, enum Axis axis) const
{
    return axis == Axis::Row ? row(n) : column(n);
}

template<typename _Type>
inline
void
array2d<_Type>::mul(
    const enum Axis axis,
    const std::valarray<_Type> & ivector,
    std::valarray<_Type> & ovector) const
{
    mul(axis, ivector, ovector,
        [](const value_type & lhs, const value_type & rhs) -> value_type
        {
            return rhs;
        }
    );
}

template<typename _Type>
template<typename _Op>
inline
void
array2d<_Type>::mul(
    const enum Axis axis,
    const std::valarray<_Type> & ivector,
    std::valarray<_Type> & ovector,
    _Op op) const
{
    if (axis == Axis::Column)
    {
        assert(ivector.size() == m_shape.first);
        assert(ovector.size() == m_shape.second);

        for (size_type r{0}; r < m_shape.second; ++r)
        {
            ovector[r] = op(ovector[r], (m_varray[column(r)] * ivector).sum());
        }
    }
    else
    {
        assert(ivector.size() == m_shape.second);
        assert(ovector.size() == m_shape.first);

        for (size_type r{0}; r < m_shape.first; ++r)
        {
            ovector[r] = op(ovector[r], (m_varray[row(r)] * ivector).sum());
        }
    }
}

template<typename _Type>
inline
std::valarray<_Type>
array2d<_Type>::operator[](std::slice slicearr) const
{
    return m_varray[slicearr];
}

template<typename _Type>
inline
std::slice_array<_Type>
array2d<_Type>::operator[](std::slice slicearr)
{
    return m_varray[slicearr];
}

template<typename _Type>
inline
std::valarray<_Type>
array2d<_Type>::operator[](const std::gslice & gslicearr) const
{
    return m_varray[gslicearr];
}

template<typename _Type>
inline
std::gslice_array<_Type>
array2d<_Type>::operator[](const std::gslice & gslicearr)
{
    return m_varray[gslicearr];
}

template<typename _Type>
inline
array2d<_Type>
zeros(shape_type shape)
{
    return array2d<_Type>(shape, 0.0);
}

template<typename _Type>
inline
array2d<_Type>
ones(shape_type shape)
{
    return array2d<_Type>(shape, 1.0);
}

/**
 *******************************************************************************
 *   @brief Configuration for @c loadtxt
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-02-07              wm      Class created. TripSafetyFactors
 *   2015-02-22              wm      Index of -1 for converters means all cols
 *   2015-02-22              wm      use_cols accessor
 *   @endcode
 *******************************************************************************
 */
template<typename _Type = double>
struct loadtxtCfg
{
    typedef std::map<int, _Type(*)(const char *)> converters_type;
    typedef std::unordered_set<size_type> use_cols_type;

    loadtxtCfg()
    :
        m_comments{'#'},
        m_delimiter{' '},
        m_converters{},
        m_skip_header{0},
        m_skip_footer{0},
        m_use_cols{}
    {}

    loadtxtCfg & comments(char _comments)
    {
        m_comments = _comments;
        return *this;
    }

    char delimiter(void) const
    {
        return m_delimiter;
    }

    loadtxtCfg & delimiter(char _delimiter)
    {
        m_delimiter = _delimiter;
        return *this;
    }

    const converters_type & converters(void) const
    {
        return m_converters;
    }

    loadtxtCfg & converters(converters_type && _converters)
    {
        m_converters = std::move(_converters);
        return *this;
    }

    size_type skip_header(void) const
    {
        return m_skip_header;
    }

    loadtxtCfg & skip_header(size_type _skip_header)
    {
        m_skip_header = _skip_header;
        return *this;
    }

    size_type skip_footer(void) const
    {
        return m_skip_footer;
    }

    loadtxtCfg & skip_footer(size_type _skip_footer)
    {
        m_skip_footer = _skip_footer;
        return *this;
    }

    const use_cols_type & use_cols(void) const
    {
        return m_use_cols;
    }

    loadtxtCfg & use_cols(const use_cols_type & _use_cols)
    {
        m_use_cols = _use_cols;
        return *this;
    }

    loadtxtCfg & use_cols(use_cols_type && _use_cols)
    {
        m_use_cols = std::move(_use_cols);
        return *this;
    }

    char m_comments;
    char m_delimiter;
    converters_type m_converters;
    size_type m_skip_header;
    size_type m_skip_footer;
    use_cols_type m_use_cols;
};

/**
 *******************************************************************************
 *   @brief Load data from a vector of strings.
 *******************************************************************************
 *   @history @code
 *   DATE         VERSION    WHO     DESCRIPTION
 *   -----------  -------    ------  -----------
 *   2015-02-07              wm      Class created. TripSafetyFactors
 *   2015-02-22              wm      Index of -1 for converters means all cols
 *   2015-02-22              wm      use_cols selector applied
 *   @endcode
 *******************************************************************************
 *   @param txt vector of strings to read from
 *   @param cfg confguration of the processor
 *******************************************************************************
 *   @return 2d array created from passed vector of strings
 *******************************************************************************
 *   Implementation based on
 *   http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
 *   interface.
 *******************************************************************************
 */
template<typename _Type>
array2d<_Type>
loadtxt(
    std::vector<std::string> && txt,
    loadtxtCfg<_Type> && cfg
)
{
    typedef _Type value_type;
    const bool skip_empty = false;

    auto count_delimiters = [&skip_empty](std::string where, char delim) -> size_type
    {
        auto predicate = [&delim](char _this, char _that)
        {
            return _this == _that && _this == delim;
        };
        if (skip_empty)
        {
            std::unique(where.begin(), where.end(), predicate);
        }

        return std::count(where.cbegin(), where.cend(), delim);
    };

    assert(txt.size() >= (cfg.skip_header() + cfg.skip_footer()));
    const size_type NROWS = txt.size() - cfg.skip_header() - cfg.skip_footer();
    if (NROWS == 0)
    {
        return zeros<value_type>(shape_type(0, 0));
    }

    const bool WIDESPAN_CONVERTER = cfg.converters().find(-1) != cfg.converters().cend();
    const bool USE_COLS = cfg.use_cols().size() != 0;
    const size_type NICOLS = 1 + count_delimiters(txt.front(), cfg.delimiter()); // TODO
    const size_type NCOLS = USE_COLS ? cfg.use_cols().size() : NICOLS;

    array2d<_Type> result = zeros<value_type>(shape_type(NROWS, NCOLS));

    for (size_type ridx{0}; ridx < NROWS; ++ridx)
    {
        std::valarray<value_type> row(NROWS);
        std::stringstream ss(txt[ridx + cfg.skip_header()]);
        std::string item;
        size_type ocidx{0};

        for (size_type icidx{0}; icidx < NICOLS && std::getline(ss, item, cfg.delimiter()); ++icidx) // TODO
        {
            if (USE_COLS && (cfg.use_cols().find(icidx) == cfg.use_cols().cend()))
            {
                continue;
            }

            if (WIDESPAN_CONVERTER)
            {
                row[ocidx] = cfg.converters().at(-1)(item.c_str());
            }
            else if (cfg.converters().find(icidx) != cfg.converters().cend())
            {
                row[ocidx] = cfg.converters().at(icidx)(item.c_str());
            }
            else if (std::is_convertible<value_type, long double>::value)
            {
                row[ocidx] = std::strtold(item.c_str(), nullptr);
            }
            else if (std::is_convertible<value_type, long long>::value)
            {
                row[ocidx] = std::atoll(item.c_str());
            }
            else
            {
                std::stringstream item_ss(item);
                item_ss >> row[ocidx];
            }

            ++ocidx;
        }

        result[result.row(ridx)] = row;
    }

    return result;
}

} // namespace num

namespace std
{

std::ostream & operator<<(std::ostream & os, const num::shape_type & shape)
{
    os << '(' << shape.first << ',' << shape.second << ')';
    return os;
}

} // namespace std

#endif /* ARRAY2D_HPP_ */
<|endoftext|>