<commit_before>// vim:filetype=cpp:textwidth=120:shiftwidth=2:softtabstop=2:expandtab
// Copyright 2014--2016 Christoph Schwering

#include <string>
#include <iostream>

#include <boost/bind.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>

#include <lela/solver.h>
#include <lela/internal/maybe.h>
#include <lela/format/output.h>
#include <lela/format/syntax.h>

using namespace lela;
using namespace lela::format;

namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

struct syntax_error : public std::exception {
  syntax_error(const std::string& id) : id_(id) {}
  virtual const char* what() const noexcept override { return id_.c_str(); }
 private:
  std::string id_;
};
struct redeclared_error : public syntax_error { using syntax_error::syntax_error; };
struct undeclared_error : public syntax_error { using syntax_error::syntax_error; };

struct Entailment {
  Entailment() : context_(solver_.sf(), solver_.tf()) {}
  ~Entailment() {
    for (auto p : funs_) {
      if (p.second) {
        delete p.second;
      }
    }
  }

  void RegisterSort(const std::string& id) {
    const Symbol::Sort sort = context_.NewSort();
    lela::format::RegisterSort(sort, id);
    sorts_[id] = sort;
    std::cout << "RegisterSort " << id << std::endl;
  }

  Symbol::Sort LookupSort(const std::string& id) const {
    const auto it = sorts_.find(id);
    if (it == sorts_.end())
      throw undeclared_error(id);
    return it->second;
  }

  void RegisterVar(const boost::fusion::vector<std::string, std::string>& d) {
    const std::string id = boost::fusion::at_c<0>(d);
    const std::string sort_id = boost::fusion::at_c<1>(d);
    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
      throw redeclared_error(id);
    const Symbol::Sort sort = LookupSort(sort_id);
    const Term var = context_.NewVar(sort);
    vars_[id] = var;
    lela::format::RegisterSymbol(var.symbol(), id);
    std::cout << "RegisterVar " << id << " / " << sort_id << std::endl;
  }

  Term LookupVar(const std::string& id) const {
    const auto it = vars_.find(id);
    if (it == vars_.end())
      throw undeclared_error(id);
    return it->second;
  }

  void RegisterName(const boost::fusion::vector<std::string, std::string>& d) {
    const std::string id = boost::fusion::at_c<0>(d);
    const std::string sort_id = boost::fusion::at_c<1>(d);
    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
      throw redeclared_error(id);
    const Symbol::Sort sort = LookupSort(sort_id);
    const Term name = context_.NewName(sort);
    names_[id] = name;
    lela::format::RegisterSymbol(name.symbol(), id);
    std::cout << "RegisterName " << id << " / " << sort_id << std::endl;
  }

  Term LookupName(const std::string& id) const {
    const auto it = names_.find(id);
    if (it == names_.end())
      throw undeclared_error(id);
    return it->second;
  }

  const Symbol& LookupFun(const std::string& id) const {
    const auto it = funs_.find(id);
    if (it == funs_.end())
      throw undeclared_error(id);
    return *it->second;
  }

  void RegisterFun(const boost::fusion::vector<std::string, int, std::string>& d) {
    const std::string id = boost::fusion::at_c<0>(d);
    const std::string sort_id = boost::fusion::at_c<2>(d);
    const int arity = boost::fusion::at_c<1>(d);
    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
      throw redeclared_error(id);
    const Symbol::Sort sort = sorts_[sort_id];
    const Symbol* symbol = new Symbol(context_.NewFun(sort, arity));
    funs_[id] = symbol;
    lela::format::RegisterSymbol(*symbol, id);
    std::cout << "RegisterFun " << id << " / " << arity << " / " << sort_id << std::endl;
  }

 private:
  std::map<std::string, Symbol::Sort>  sorts_;
  std::map<std::string, Term>          vars_;
  std::map<std::string, Term>          names_;
  std::map<std::string, const Symbol*> funs_;
  Solver  solver_;
  Context context_;
};

template<typename Iter>
class Syntax : public qi::grammar<Iter, void(), ascii::space_type> {
 public:
  Syntax() : Syntax::base_type(decls_) {
    identifier_      %= qi::alpha >> *qi::alnum;
    sort_keyword_     = "sort";
    var_keyword_      = "variable";
    name_keyword_     = "name";
    fun_keyword_      = "function";
    sort_decl_        = (identifier_ >> ':' >> sort_keyword_ >> ';') [boost::bind(&Entailment::RegisterSort, &e, ::_1)];
    var_decl_         = (identifier_ >> ':' >> var_keyword_  >> identifier_ >> ';') [boost::bind(&Entailment::RegisterVar, &e, ::_1)];
    name_decl_        = (identifier_ >> ':' >> name_keyword_ >> identifier_ >> ';') [boost::bind(&Entailment::RegisterName, &e, ::_1)];
    fun_decl_         = (identifier_ >> ':' >> fun_keyword_  >> '/' >> qi::uint_ >> identifier_ >> ';') [boost::bind(&Entailment::RegisterFun, &e, ::_1)];
    decls_            = *(sort_decl_ | var_decl_ | name_decl_ | fun_decl_);
    term_             = identifier_ >> -('(' >> (term_ % ',') >> ')');
    literal_          = term_ >> ("==" || "!=") >> term_;
    clause_           = literal_ >> *("||" >> literal_);
  }

 private:
  Entailment e;
  qi::rule<Iter, void(),                                        ascii::space_type> sort_keyword_;
  qi::rule<Iter, void(),                                        ascii::space_type> var_keyword_;
  qi::rule<Iter, void(),                                        ascii::space_type> name_keyword_;
  qi::rule<Iter, void(),                                        ascii::space_type> fun_keyword_;
  qi::rule<Iter, void(),                                        ascii::space_type> eol_;
  qi::rule<Iter, std::string(),                                 ascii::space_type> identifier_;
  qi::rule<Iter, std::string(),                                 ascii::space_type> sort_decl_;
  qi::rule<Iter, boost::tuple<std::string, std::string>(),      ascii::space_type> var_decl_;
  qi::rule<Iter, boost::tuple<std::string, std::string>(),      ascii::space_type> name_decl_;
  qi::rule<Iter, boost::tuple<std::string, int, std::string>(), ascii::space_type> fun_decl_;
  qi::rule<Iter, void(),                                        ascii::space_type> decls_;
  qi::rule<Iter, Term(),                                        ascii::space_type> term_;
  qi::rule<Iter, Literal(),                                     ascii::space_type> literal_;
  qi::rule<Iter, Clause(),                                      ascii::space_type> clause_;
};

#if 0
class Parser {
 public:
  Parser() = default;
  virtual ~Parser() = default;

  virtual internal::Maybe<std::string> ReadLine() = 0;

 private:
};

class StreamParser : public Parser {
  explicit StreamParser(std::istream& stream) : stream_(stream) {}

  virtual internal::Maybe<std::string> ReadLine() override {
    internal::Maybe<std::string> str;
    std::getline(stream_, str.val);
    return internal::Just(str);
  }

 private:
  std::istream& stream_;
};
#endif

int main() {
  const std::string s = "BOOL    :    sort;"\
                        "x : variable BOOL;"\
                        "y : variable BOOL;"\
                        "HUMAN:sort;"\
                        "T : name BOOL;"\
                        "F : name BOOL;"\
                        "fatherOf : function / 3 HUMAN;"\
                        "fatherOf2 : function/3 HUMAN;";
  Syntax<std::string::const_iterator> syntax;
  std::vector<std::string> d;
  qi::phrase_parse(s.begin(), s.end(), syntax, qi::ascii::space, d);
}

<commit_msg>Writing a new parser.<commit_after>// vim:filetype=cpp:textwidth=120:shiftwidth=2:softtabstop=2:expandtab
// Copyright 2014--2016 Christoph Schwering

#include <cassert>

#include <algorithm>
#include <iostream>
#include <list>
#include <functional>
#include <string>
#include <utility>

//#include <lela/solver.h>
//#include <lela/internal/maybe.h>
//#include <lela/format/output.h>
//#include <lela/format/syntax.h>
//
//using namespace lela;
//using namespace lela::format;
//
//struct Entailment {
//  Entailment() : context_(solver_.sf(), solver_.tf()) {}
//  ~Entailment() {
//    for (auto p : funs_) {
//      if (p.second) {
//        delete p.second;
//      }
//    }
//  }
//
//  void RegisterSort(const std::string& id) {
//    const Symbol::Sort sort = context_.NewSort();
//    lela::format::RegisterSort(sort, id);
//    sorts_[id] = sort;
//    std::cout << "RegisterSort " << id << std::endl;
//  }
//
//  Symbol::Sort LookupSort(const std::string& id) const {
//    const auto it = sorts_.find(id);
//    if (it == sorts_.end())
//      throw undeclared_error(id);
//    return it->second;
//  }
//
//  void RegisterVar(const boost::fusion::vector<std::string, std::string>& d) {
//    const std::string id = boost::fusion::at_c<0>(d);
//    const std::string sort_id = boost::fusion::at_c<1>(d);
//    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
//      throw redeclared_error(id);
//    const Symbol::Sort sort = LookupSort(sort_id);
//    const Term var = context_.NewVar(sort);
//    vars_[id] = var;
//    lela::format::RegisterSymbol(var.symbol(), id);
//    std::cout << "RegisterVar " << id << " / " << sort_id << std::endl;
//  }
//
//  Term LookupVar(const std::string& id) const {
//    const auto it = vars_.find(id);
//    if (it == vars_.end())
//      throw undeclared_error(id);
//    return it->second;
//  }
//
//  void RegisterName(const boost::fusion::vector<std::string, std::string>& d) {
//    const std::string id = boost::fusion::at_c<0>(d);
//    const std::string sort_id = boost::fusion::at_c<1>(d);
//    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
//      throw redeclared_error(id);
//    const Symbol::Sort sort = LookupSort(sort_id);
//    const Term name = context_.NewName(sort);
//    names_[id] = name;
//    lela::format::RegisterSymbol(name.symbol(), id);
//    std::cout << "RegisterName " << id << " / " << sort_id << std::endl;
//  }
//
//  Term LookupName(const std::string& id) const {
//    const auto it = names_.find(id);
//    if (it == names_.end())
//      throw undeclared_error(id);
//    return it->second;
//  }
//
//  const Symbol& LookupFun(const std::string& id) const {
//    const auto it = funs_.find(id);
//    if (it == funs_.end())
//      throw undeclared_error(id);
//    return *it->second;
//  }
//
//  void RegisterFun(const boost::fusion::vector<std::string, int, std::string>& d) {
//    const std::string id = boost::fusion::at_c<0>(d);
//    const std::string sort_id = boost::fusion::at_c<2>(d);
//    const int arity = boost::fusion::at_c<1>(d);
//    if (vars_.find(id) != vars_.end() || names_.find(id) != names_.end() || funs_.find(id) != funs_.end())
//      throw redeclared_error(id);
//    const Symbol::Sort sort = sorts_[sort_id];
//    const Symbol* symbol = new Symbol(context_.NewFun(sort, arity));
//    funs_[id] = symbol;
//    lela::format::RegisterSymbol(*symbol, id);
//    std::cout << "RegisterFun " << id << " / " << arity << " / " << sort_id << std::endl;
//  }
//
// private:
//  std::map<std::string, Symbol::Sort>  sorts_;
//  std::map<std::string, Term>          vars_;
//  std::map<std::string, Term>          names_;
//  std::map<std::string, const Symbol*> funs_;
//  Solver  solver_;
//  Context context_;
//};

struct syntax_error : public std::exception {
  syntax_error(const std::string& id) : id_(id) {}
  virtual const char* what() const noexcept override { return id_.c_str(); }
 private:
  std::string id_;
};
struct redeclared_error : public syntax_error { using syntax_error::syntax_error; };
struct undeclared_error : public syntax_error { using syntax_error::syntax_error; };

template<typename Iter>
class Lexer {
 public:
  enum Match { kMismatch, kPrefixMatch, kFullMatch };
  enum TokenId { kSort, kVar, kName, kFun, kColon, kSlash, kEOL, kUint, kIdentifier, kEOF, kError };
  typedef std::list<std::pair<TokenId, std::function<Match(Iter, Iter)>>> LexemeVector;

  class Token {
   public:
    explicit Token(TokenId id) : id_(id) {}
    Token(TokenId id, const std::string& str) : id_(id), str_(str) {}
    TokenId id() const { return id_; }
    const std::string& str() const { return str_; }
   private:
    TokenId id_;
    std::string str_;
  };

  struct iterator {
    typedef std::ptrdiff_t difference_type;
    typedef Token value_type;
    typedef value_type reference;
    typedef value_type* pointer;
    typedef std::input_iterator_tag iterator_category;
    //typedef lela::internal::iterator_proxy<iterator> proxy;

    iterator(const LexemeVector* lexemes, Iter it, Iter end) : lexemes_(lexemes), it_(it), end_(end) {}

    bool operator==(const iterator& it) const { return it_ == it.it_ && end_ == it.end_; }
    bool operator!=(const iterator& it) const { return !(*this == it); }

    reference operator*() const {
      std::pair<Iter, Iter> substr = NextWord();
      std::pair<Match, TokenId> match = LexemeMatch(substr.first, substr.second);
      return Token(match.second, std::string(substr.first, substr.second));
    }

    iterator& operator++() {
      it_ = NextWord().second;
      return *this;
    }

   private:
    std::pair<Iter, Iter> NextWord() const {
      assert(it_ != end_);
      Iter it;
      for (it = it_; it != end_ && IsWhitespace(*it); ++it) {
      }
      Iter jt;
      for (jt = it; jt != end_; ++jt) {
        if (LexemeMatch(it, std::next(jt)).first == kMismatch)
          break;
      }
      assert(it != jt);
      return std::make_pair(it, jt);
    }

    std::pair<Match, TokenId> LexemeMatch(Iter begin, Iter end) const {
      Match best_match = kMismatch;
      TokenId best_token = kError;
      for (auto& p : *lexemes_) {
        const Match m = p.second(begin, end);
        if ((best_match == kMismatch && m == kPrefixMatch) || (best_match == kMismatch && m == kFullMatch)) {
          best_match = m;
          best_token = p.first;
        }
      }
      return std::make_pair(best_match, best_token);
    }

    const LexemeVector* lexemes_;
    Iter it_;
    Iter end_;
  };

  Lexer(Iter begin, Iter end) : begin_(begin), end_(end) {
    lexemes_.push_back(std::make_pair(kSort,       [](Iter begin, Iter end) { return IsPrefix(begin, end, "sort"); }));
    lexemes_.push_back(std::make_pair(kVar,        [](Iter begin, Iter end) { return std::max( IsPrefix(begin, end, "var"), IsPrefix(begin, end, "variable") ); }));
    lexemes_.push_back(std::make_pair(kName,       [](Iter begin, Iter end) { return std::max( IsPrefix(begin, end, "name"), IsPrefix(begin, end, "stdname") ); }));
    lexemes_.push_back(std::make_pair(kFun,        [](Iter begin, Iter end) { return std::max( IsPrefix(begin, end, "fun"), IsPrefix(begin, end, "function") ); }));
    lexemes_.push_back(std::make_pair(kColon,      [](Iter begin, Iter end) { return IsPrefix(begin, end, ":"); }));
    lexemes_.push_back(std::make_pair(kSlash,      [](Iter begin, Iter end) { return IsPrefix(begin, end, "/"); }));
    lexemes_.push_back(std::make_pair(kEOL,        [](Iter begin, Iter end) { return IsPrefix(begin, end, ";"); }));
    lexemes_.push_back(std::make_pair(kUint,       [](Iter begin, Iter end) { return begin == end ? kPrefixMatch : *begin != '0' && std::all_of(begin, end, [](char c) { return IsDigit(c); }) ? kFullMatch : kMismatch; }));
    lexemes_.push_back(std::make_pair(kIdentifier, [](Iter begin, Iter end) { return begin == end ? kPrefixMatch : IsAlpha(*begin) && std::all_of(begin, end, [](char c) { return IsAlnum(c); }) ? kFullMatch : kMismatch; }));
  }

  iterator begin() const { return iterator(&lexemes_, begin_, end_); }
  iterator end()   const { return iterator(&lexemes_, end_, end_); }

 private:
  LexemeVector lexemes_;

  static Match IsPrefix(Iter begin, Iter end, const std::string& foobar) {
    size_t len = std::distance(begin, end);
    if (len > foobar.length() || std::mismatch(begin, end, foobar.begin()).first != end)
      return kMismatch;
    else
      return len < foobar.length() ? kPrefixMatch : kFullMatch;
  }
  static bool IsWhitespace(char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n'; }
  static bool IsDigit(char c) { return '0' <= c && c <= '9'; }
  static bool IsAlpha(char c) { return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '_'; }
  static bool IsAlnum(char c) { return IsAlpha(c) || IsDigit(c); }

  Iter begin_;
  Iter end_;
};

int main() {
  const std::string s = "BOOL    :    sort;"\
                        "x : variable BOOL;"\
                        "y : variable BOOL;"\
                        "HUMAN:sort;"\
                        "T : name BOOL;"\
                        "F : name BOOL;"\
                        "fatherOf : function / 3 HUMAN;"\
                        "fatherOf2 : function/3 HUMAN;";
  typedef Lexer<std::string::const_iterator> StrLexer;
  for (const StrLexer::Token& t : StrLexer(s.begin(), s.end())) {
    if (t.id() == StrLexer::kError) {
      std::cout << "ERROR ";
    }
    std::cout << t.str() << " ";
  }
  std::cout << std::endl;
}

<|endoftext|>


<commit_before>#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#ifndef BOOST_TEST_MODULE
#define BOOST_TEST_MODULE System
#endif

#include "system.hpp"
#include <boost/test/included/unit_test.hpp>

BOOST_AUTO_TEST_CASE(all) {
	using namespace System;
	BOOST_REQUIRE(Printer_Base::uni_special(0xc0));
	BOOST_REQUIRE(!Printer_Base::uni_special(0xb9));
}
<commit_msg>Added test cases for System<commit_after>#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#endif
#ifndef BOOST_TEST_MODULE
#define BOOST_TEST_MODULE System
#endif

#include "system.hpp"
#include <boost/test/included/unit_test.hpp>

using namespace System;

BOOST_AUTO_TEST_CASE(uni_special) {
	BOOST_REQUIRE(Printer_Base::uni_special(0x80));
	BOOST_REQUIRE(!Printer_Base::uni_special(0x79));
}

BOOST_AUTO_TEST_CASE(uni_strlen) {
	BOOST_REQUIRE_EQUAL(Printer_Base::uni_strlen("A"),1);
}

BOOST_AUTO_TEST_CASE(strlen_) {
	BOOST_REQUIRE_EQUAL(Printer_Base::strlen("\e[38;5;190mA\e[0m"),1);
}
<|endoftext|>


<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ReconstructionOperator.h"

#include "DataSource.h"
#include "ReconstructionWidget.h"
#include "TomographyReconstruction.h"
#include "TomographyTiltSeries.h"

#include "pqSMProxy.h"
#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkPointData.h"
#include "vtkSMProxyManager.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkTrivialProducer.h"

#include <QCoreApplication>
#include <QDebug>

namespace tomviz {
ReconstructionOperator::ReconstructionOperator(DataSource* source, QObject* p)
  : Operator(p), m_dataSource(source)
{
  qRegisterMetaType<std::vector<float>>();
  auto t = source->producer();
  auto imageData = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));
  int dataExtent[6];
  imageData->GetExtent(dataExtent);
  for (int i = 0; i < 6; ++i) {
    m_extent[i] = dataExtent[i];
  }
  setSupportsCancel(true);
  setTotalProgressSteps(m_extent[1] - m_extent[0] + 1);
  setHasChildDataSource(true);
  connect(
    this,
    static_cast<void (Operator::*)(const QString&,
                                   vtkSmartPointer<vtkDataObject>)>(
      &Operator::newChildDataSource),
    this,
    [this](const QString& label, vtkSmartPointer<vtkDataObject> childData) {
      this->createNewChildDataSource(label, childData, DataSource::Volume,
                                     DataSource::PersistenceState::Transient);
    });
}

QIcon ReconstructionOperator::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqExtractGrid24.png");
}

Operator* ReconstructionOperator::clone() const
{
  return new ReconstructionOperator(m_dataSource);
}

QWidget* ReconstructionOperator::getCustomProgressWidget(QWidget* p) const
{
  ReconstructionWidget* widget = new ReconstructionWidget(m_dataSource, p);
  QObject::connect(this, &Operator::progressStepChanged, widget,
                   &ReconstructionWidget::updateProgress);
  QObject::connect(this, &ReconstructionOperator::intermediateResults, widget,
                   &ReconstructionWidget::updateIntermediateResults);
  return widget;
}

bool ReconstructionOperator::applyTransform(vtkDataObject* dataObject)
{
  vtkSmartPointer<vtkImageData> imageData =
    vtkImageData::SafeDownCast(dataObject);
  if (!imageData) {
    return false;
  }
  int dataExtent[6];
  imageData->GetExtent(dataExtent);
  for (int i = 0; i < 6; ++i) {
    if (dataExtent[i] != m_extent[i]) {
      // Extent changing shouldn't matter, but update so that correct
      // number of steps can be reported.
      m_extent[i] = dataExtent[i];
    }
  }
  setTotalProgressSteps(m_extent[1] - m_extent[0] + 1);

  int numXSlices = dataExtent[1] - dataExtent[0] + 1;
  int numYSlices = dataExtent[3] - dataExtent[2] + 1;
  int numZSlices = dataExtent[5] - dataExtent[4] + 1;
  std::vector<float> sinogramPtr(numYSlices * numZSlices);
  std::vector<float> reconstructionPtr(numYSlices * numYSlices);
  QVector<double> tiltAngles;

  vtkFieldData* fd = dataObject->GetFieldData();
  vtkDataArray* tiltAnglesVTKArray = fd->GetArray("tilt_angles");
  if (tiltAnglesVTKArray) {
    tiltAngles.resize(tiltAnglesVTKArray->GetNumberOfTuples());
    for (int i = 0; i < tiltAngles.size(); ++i) {
      tiltAngles[i] = tiltAnglesVTKArray->GetTuple1(i);
    }
  }

  if (tiltAngles.size() < numZSlices) {
    qDebug() << "Incorrect number of tilt angles. There are"
             << tiltAngles.size() << "and there should be" << numZSlices
             << ".\n";
    return false;
  }

  vtkNew<vtkImageData> reconstructionImage;
  int extent2[6] = { dataExtent[0], m_extent[1],   dataExtent[2],
                     dataExtent[3], dataExtent[2], dataExtent[3] };
  reconstructionImage->SetExtent(extent2);
  reconstructionImage->AllocateScalars(VTK_FLOAT, 1);
  vtkDataArray* darray = reconstructionImage->GetPointData()->GetScalars();
  darray->SetName("scalars");

  // TODO: talk to Dave Lonie about how to do this in new data array API
  float* reconstruction = (float*)darray->GetVoidPointer(0);
  for (int i = 0; i < numXSlices && !isCanceled(); ++i) {
    QCoreApplication::processEvents();
    TomographyTiltSeries::getSinogram(imageData, i, &sinogramPtr[0]);
    TomographyReconstruction::unweightedBackProjection2(
      &sinogramPtr[0], tiltAngles.data(), &reconstructionPtr[0], numZSlices,
      numYSlices);
    for (int j = 0; j < numYSlices; ++j) {
      for (int k = 0; k < numYSlices; ++k) {
        reconstruction[j * (numYSlices * numXSlices) + k * numXSlices + i] =
          reconstructionPtr[k * numYSlices + j];
      }
    }
    emit intermediateResults(reconstructionPtr);
    setProgressStep(i);
  }
  if (isCanceled()) {
    return false;
  }
  emit newChildDataSource("Reconstruction", reconstructionImage);
  return true;
}
} // namespace tomviz
<commit_msg>Use transformed data for the reconstruction widget<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ReconstructionOperator.h"

#include "DataSource.h"
#include "Pipeline.h"
#include "ReconstructionWidget.h"
#include "TomographyReconstruction.h"
#include "TomographyTiltSeries.h"

#include "pqSMProxy.h"
#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkPointData.h"
#include "vtkSMProxyManager.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkTrivialProducer.h"

#include <QCoreApplication>
#include <QDebug>

namespace tomviz {
ReconstructionOperator::ReconstructionOperator(DataSource* source, QObject* p)
  : Operator(p), m_dataSource(source)
{
  qRegisterMetaType<std::vector<float>>();
  auto t = source->producer();
  auto imageData = vtkImageData::SafeDownCast(t->GetOutputDataObject(0));
  int dataExtent[6];
  imageData->GetExtent(dataExtent);
  for (int i = 0; i < 6; ++i) {
    m_extent[i] = dataExtent[i];
  }
  setSupportsCancel(true);
  setTotalProgressSteps(m_extent[1] - m_extent[0] + 1);
  setHasChildDataSource(true);
  connect(
    this,
    static_cast<void (Operator::*)(const QString&,
                                   vtkSmartPointer<vtkDataObject>)>(
      &Operator::newChildDataSource),
    this,
    [this](const QString& label, vtkSmartPointer<vtkDataObject> childData) {
      this->createNewChildDataSource(label, childData, DataSource::Volume,
                                     DataSource::PersistenceState::Transient);
    });
}

QIcon ReconstructionOperator::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqExtractGrid24.png");
}

Operator* ReconstructionOperator::clone() const
{
  return new ReconstructionOperator(m_dataSource);
}

QWidget* ReconstructionOperator::getCustomProgressWidget(QWidget* p) const
{
  DataSource* source = m_dataSource;
  if (source && source->pipeline()) {
    // Use the transformed data source for the reconstruction widget
    source = source->pipeline()->transformedDataSource();
  }

  ReconstructionWidget* widget = new ReconstructionWidget(source, p);
  QObject::connect(this, &Operator::progressStepChanged, widget,
                   &ReconstructionWidget::updateProgress);
  QObject::connect(this, &ReconstructionOperator::intermediateResults, widget,
                   &ReconstructionWidget::updateIntermediateResults);
  return widget;
}

bool ReconstructionOperator::applyTransform(vtkDataObject* dataObject)
{
  vtkSmartPointer<vtkImageData> imageData =
    vtkImageData::SafeDownCast(dataObject);
  if (!imageData) {
    return false;
  }
  int dataExtent[6];
  imageData->GetExtent(dataExtent);
  for (int i = 0; i < 6; ++i) {
    if (dataExtent[i] != m_extent[i]) {
      // Extent changing shouldn't matter, but update so that correct
      // number of steps can be reported.
      m_extent[i] = dataExtent[i];
    }
  }
  setTotalProgressSteps(m_extent[1] - m_extent[0] + 1);

  int numXSlices = dataExtent[1] - dataExtent[0] + 1;
  int numYSlices = dataExtent[3] - dataExtent[2] + 1;
  int numZSlices = dataExtent[5] - dataExtent[4] + 1;
  std::vector<float> sinogramPtr(numYSlices * numZSlices);
  std::vector<float> reconstructionPtr(numYSlices * numYSlices);
  QVector<double> tiltAngles;

  vtkFieldData* fd = dataObject->GetFieldData();
  vtkDataArray* tiltAnglesVTKArray = fd->GetArray("tilt_angles");
  if (tiltAnglesVTKArray) {
    tiltAngles.resize(tiltAnglesVTKArray->GetNumberOfTuples());
    for (int i = 0; i < tiltAngles.size(); ++i) {
      tiltAngles[i] = tiltAnglesVTKArray->GetTuple1(i);
    }
  }

  if (tiltAngles.size() < numZSlices) {
    qDebug() << "Incorrect number of tilt angles. There are"
             << tiltAngles.size() << "and there should be" << numZSlices
             << ".\n";
    return false;
  }

  vtkNew<vtkImageData> reconstructionImage;
  int extent2[6] = { dataExtent[0], m_extent[1],   dataExtent[2],
                     dataExtent[3], dataExtent[2], dataExtent[3] };
  reconstructionImage->SetExtent(extent2);
  reconstructionImage->AllocateScalars(VTK_FLOAT, 1);
  vtkDataArray* darray = reconstructionImage->GetPointData()->GetScalars();
  darray->SetName("scalars");

  // TODO: talk to Dave Lonie about how to do this in new data array API
  float* reconstruction = (float*)darray->GetVoidPointer(0);
  for (int i = 0; i < numXSlices && !isCanceled(); ++i) {
    QCoreApplication::processEvents();
    TomographyTiltSeries::getSinogram(imageData, i, &sinogramPtr[0]);
    TomographyReconstruction::unweightedBackProjection2(
      &sinogramPtr[0], tiltAngles.data(), &reconstructionPtr[0], numZSlices,
      numYSlices);
    for (int j = 0; j < numYSlices; ++j) {
      for (int k = 0; k < numYSlices; ++k) {
        reconstruction[j * (numYSlices * numXSlices) + k * numXSlices + i] =
          reconstructionPtr[k * numYSlices + j];
      }
    }
    emit intermediateResults(reconstructionPtr);
    setProgressStep(i);
  }
  if (isCanceled()) {
    return false;
  }
  emit newChildDataSource("Reconstruction", reconstructionImage);
  return true;
}
} // namespace tomviz
<|endoftext|>


<commit_before>/*
Copyright (C) 2018 Rodrigo Jose Hernandez Cordoba

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <QIcon>
#include <QFile>
#include <QMimeData>
#include <QDataStream>
#include <QByteArray>
#include <QXmlStreamWriter>
#include <QTextStream>
#include <QAction>

#include "aeongames/Model.h"
#include "ComponentModel.h"

namespace AeonGames
{
    ComponentModel::ComponentModel ( QObject *parent ) :
        QAbstractItemModel ( parent ) {}

    ComponentModel::~ComponentModel() = default;

    QVariant ComponentModel::headerData ( int section, Qt::Orientation orientation, int role ) const
    {
        if ( ( orientation == Qt::Horizontal ) && ( role == Qt::DisplayRole ) )
        {
            switch ( section )
            {
            case 0:
                return QString ( "Property" );
            case 1:
                return QString ( "Value" );
            default:
                return QVariant();
            }
        }
        return QVariant();
    }

    QModelIndex ComponentModel::index ( int row, int column, const QModelIndex & parent ) const
    {
        if ( row < static_cast<int> ( mProperties.size() ) )
        {
            return createIndex ( row, column, nullptr );
        }
        return QModelIndex();
    }

    QModelIndex ComponentModel::parent ( const QModelIndex & index ) const
    {
        return QModelIndex();
    }

    int ComponentModel::rowCount ( const QModelIndex & index ) const
    {
        if ( !index.isValid() )
        {
            return static_cast<int> ( mProperties.size() );
        }
        // Only root may have children/rows
        return 0;
    }

    int ComponentModel::columnCount ( const QModelIndex & index ) const
    {
        return 2;
    }

    bool ComponentModel::hasChildren ( const QModelIndex & index ) const
    {
        return rowCount() > 0;
    }

    static std::unordered_map<size_t, std::function<QVariant ( const PropertyRef& aRef ) >> PropertyRefToVariant =
    {
        {
            typeid ( size_t ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                return aRef.Get<size_t>();
            }
        },
        {
            typeid ( double ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                return aRef.Get<double>();
            }
        },
        {
            typeid ( std::shared_ptr<Model> ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                try
                {
                    return ( Model::GetPath ( aRef.Get<std::shared_ptr<Model>>() ).c_str() );
                }
                catch ( std::runtime_error& e )
                {
                    return QVariant();
                }
            }
        }
    };

    QVariant ComponentModel::data ( const QModelIndex & index, int role ) const
    {
        if ( index.isValid() )
        {
            if ( role == Qt::EditRole || role == Qt::DisplayRole )
                switch ( index.column() )
                {
                case 0:
                    if ( role == Qt::DisplayRole )
                    {
                        return QString ( mProperties[index.row()].GetName() );
                    }
                    break;
                case 1:
                    return PropertyRefToVariant[mProperties[index.row()].GetTypeInfo().hash_code()] ( mProperties[index.row()] );
                }
        }
        return QVariant();
    }

    Qt::ItemFlags ComponentModel::flags ( const QModelIndex & index ) const
    {
        if ( index.isValid() && ( index.column() == 1 )  )
        {
            return QAbstractItemModel::flags ( index ) | Qt::ItemIsEditable;
        }
        return QAbstractItemModel::flags ( index );
    }

    static std::unordered_map<size_t, std::function<void ( const PropertyRef&, const QVariant& ) >> SetPropertyRef =
    {
        {
            typeid ( size_t ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                aRef.Get<size_t>() = static_cast<size_t> ( aVariant.toULongLong() );
            }
        },
        {
            typeid ( double ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                aRef.Get<double>() = aVariant.toDouble();
            }
        },
        {
            typeid ( std::shared_ptr<Model> ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                try
                {
                    aRef.Get<std::shared_ptr<Model>>() = Model::GetModel ( aVariant.toString().toStdString() );
                }
                catch ( std::runtime_error& e )
                {
                    aRef.Get<std::shared_ptr<Model>>().reset();
                }
            }
        },
    };

    bool ComponentModel::setData ( const QModelIndex & index, const QVariant & value, int role )
    {
        if ( ( role == Qt::EditRole ) && ( index.isValid() ) && ( value.isValid() ) && ( index.column() == 1 ) )
        {
            SetPropertyRef[mProperties[index.row()].GetTypeInfo().hash_code()] ( mProperties[index.row()], value );
            emit dataChanged ( index, index );
            return true;
        }
        return false;
    }

    void ComponentModel::SetComponent ( Component* aComponent )
    {
        beginResetModel();
        mComponent = aComponent;
        mProperties.clear();
        if ( mComponent )
        {
            mProperties = mComponent->GetProperties();
        }
        endResetModel();
    }
}
<commit_msg>Linux build fix.<commit_after>/*
Copyright (C) 2018 Rodrigo Jose Hernandez Cordoba

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <QIcon>
#include <QFile>
#include <QMimeData>
#include <QDataStream>
#include <QByteArray>
#include <QXmlStreamWriter>
#include <QTextStream>
#include <QAction>

#include "aeongames/Model.h"
#include "ComponentModel.h"

namespace AeonGames
{
    ComponentModel::ComponentModel ( QObject *parent ) :
        QAbstractItemModel ( parent ) {}

    ComponentModel::~ComponentModel() = default;

    QVariant ComponentModel::headerData ( int section, Qt::Orientation orientation, int role ) const
    {
        if ( ( orientation == Qt::Horizontal ) && ( role == Qt::DisplayRole ) )
        {
            switch ( section )
            {
            case 0:
                return QString ( "Property" );
            case 1:
                return QString ( "Value" );
            default:
                return QVariant();
            }
        }
        return QVariant();
    }

    QModelIndex ComponentModel::index ( int row, int column, const QModelIndex & parent ) const
    {
        if ( row < static_cast<int> ( mProperties.size() ) )
        {
            return createIndex ( row, column, nullptr );
        }
        return QModelIndex();
    }

    QModelIndex ComponentModel::parent ( const QModelIndex & index ) const
    {
        return QModelIndex();
    }

    int ComponentModel::rowCount ( const QModelIndex & index ) const
    {
        if ( !index.isValid() )
        {
            return static_cast<int> ( mProperties.size() );
        }
        // Only root may have children/rows
        return 0;
    }

    int ComponentModel::columnCount ( const QModelIndex & index ) const
    {
        return 2;
    }

    bool ComponentModel::hasChildren ( const QModelIndex & index ) const
    {
        return rowCount() > 0;
    }

    static std::unordered_map<size_t, std::function<QVariant ( const PropertyRef& aRef ) >> PropertyRefToVariant =
    {
        {
            typeid ( size_t ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                return QVariant ( static_cast<qulonglong> ( aRef.Get<size_t>() ) );
            }
        },
        {
            typeid ( double ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                return aRef.Get<double>();
            }
        },
        {
            typeid ( std::shared_ptr<Model> ).hash_code(),
            [] ( const PropertyRef & aRef ) -> QVariant
            {
                try
                {
                    return ( Model::GetPath ( aRef.Get<std::shared_ptr<Model>>() ).c_str() );
                }
                catch ( std::runtime_error& e )
                {
                    return QVariant();
                }
            }
        }
    };

    QVariant ComponentModel::data ( const QModelIndex & index, int role ) const
    {
        if ( index.isValid() )
        {
            if ( role == Qt::EditRole || role == Qt::DisplayRole )
                switch ( index.column() )
                {
                case 0:
                    if ( role == Qt::DisplayRole )
                    {
                        return QString ( mProperties[index.row()].GetName() );
                    }
                    break;
                case 1:
                    return PropertyRefToVariant[mProperties[index.row()].GetTypeInfo().hash_code()] ( mProperties[index.row()] );
                }
        }
        return QVariant();
    }

    Qt::ItemFlags ComponentModel::flags ( const QModelIndex & index ) const
    {
        if ( index.isValid() && ( index.column() == 1 )  )
        {
            return QAbstractItemModel::flags ( index ) | Qt::ItemIsEditable;
        }
        return QAbstractItemModel::flags ( index );
    }

    static std::unordered_map<size_t, std::function<void ( const PropertyRef&, const QVariant& ) >> SetPropertyRef =
    {
        {
            typeid ( size_t ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                aRef.Get<size_t>() = static_cast<size_t> ( aVariant.toULongLong() );
            }
        },
        {
            typeid ( double ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                aRef.Get<double>() = aVariant.toDouble();
            }
        },
        {
            typeid ( std::shared_ptr<Model> ).hash_code(),
            [] ( const PropertyRef & aRef, const QVariant & aVariant )
            {
                try
                {
                    aRef.Get<std::shared_ptr<Model>>() = Model::GetModel ( aVariant.toString().toStdString() );
                }
                catch ( std::runtime_error& e )
                {
                    aRef.Get<std::shared_ptr<Model>>().reset();
                }
            }
        },
    };

    bool ComponentModel::setData ( const QModelIndex & index, const QVariant & value, int role )
    {
        if ( ( role == Qt::EditRole ) && ( index.isValid() ) && ( value.isValid() ) && ( index.column() == 1 ) )
        {
            SetPropertyRef[mProperties[index.row()].GetTypeInfo().hash_code()] ( mProperties[index.row()], value );
            emit dataChanged ( index, index );
            return true;
        }
        return false;
    }

    void ComponentModel::SetComponent ( Component* aComponent )
    {
        beginResetModel();
        mComponent = aComponent;
        mProperties.clear();
        if ( mComponent )
        {
            mProperties = mComponent->GetProperties();
        }
        endResetModel();
    }
}
<|endoftext|>


<commit_before>#include "ROOT/RDataFrame.hxx"
#include "TChain.h"
#include "TEntryList.h"
#include "TFile.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "gtest/gtest.h"

#include <vector>

// Write to disk file filename with TTree "t" with nEntries of branch "e" assuming integer values [0..nEntries).
void MakeInputFile(const std::string &filename, int nEntries)
{
   const auto treename = "t";
   auto d = ROOT::RDataFrame(nEntries)
               .Define("e", [](ULong64_t e) { return int(e); }, {"rdfentry_"})
               .Snapshot<int>(treename, filename, {"e"});
}

class RMTRAII {
   bool fIsMT;

public:
   RMTRAII(bool isMT) : fIsMT(isMT)
   {
      if (fIsMT)
         ROOT::EnableImplicitMT();
   }
   ~RMTRAII()
   {
      if (fIsMT)
         ROOT::DisableImplicitMT();
   }
};

void TestTreeWithEntryList(bool isMT = false)
{
   const auto nEntries = 10;
   const auto treename = "t";
   const auto filename = "rdfentrylist.root";
   MakeInputFile(filename, nEntries);

   TEntryList elist("e", "e", treename, filename);
   elist.Enter(0);
   elist.Enter(nEntries - 1);

   TFile f(filename);
   auto t = f.Get<TTree>(treename);
   t->SetEntryList(&elist);

   RMTRAII gomt(isMT);
   auto entries = ROOT::RDataFrame(*t).Take<int>("e");
   EXPECT_EQ(*entries, std::vector<int>({0, nEntries - 1}));

   gSystem->Unlink(filename);
}

void TestChainWithEntryList(bool isMT = false)
{
   const auto nEntries = 10;
   const auto treename = "t";
   const auto file1 = "rdfentrylist1.root";
   MakeInputFile(file1, nEntries);
   const auto file2 = "rdfentrylist2.root";
   MakeInputFile(file2, nEntries);

   TEntryList elist1("e", "e", treename, file1);
   elist1.Enter(0);
   elist1.Enter(2 * nEntries - 1);
   TEntryList elist2("e", "e", treename, file2);
   elist2.Enter(0);
   elist2.Enter(2 * nEntries - 1);

   // make a TEntryList that contains two TEntryLists in its list of TEntryLists,
   // as required by TChain (see TEntryList's doc)
   TEntryList elists;
   elists.Add(&elist1);
   elists.Add(&elist2);

   TChain c(treename);
   c.Add(file1, nEntries);
   c.Add(file2, nEntries);
   c.SetEntryList(&elists);

   RMTRAII gomt(isMT);
   auto entries = ROOT::RDataFrame(c).Take<int>("e");
   EXPECT_EQ(*entries, std::vector<int>({0, nEntries - 1, 0, nEntries - 1}));

   gSystem->Unlink(file1);
   gSystem->Unlink(file2);
}

TEST(RDFEntryList, Chain)
{
   TestChainWithEntryList();
}

TEST(RDFEntryList, Tree)
{
   TestTreeWithEntryList();
}

#ifdef R__USE_IMT
TEST(RDFEntryList, DISABLED_ChainMT)
{
   TestChainWithEntryList(true);
}

TEST(RDFEntryList, TreeMT)
{
   TestTreeWithEntryList(true);
}
#endif
<commit_msg>[RDF] Let the tree and RDF have the same MT status<commit_after>#include "ROOT/RDataFrame.hxx"
#include "TChain.h"
#include "TEntryList.h"
#include "TFile.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "gtest/gtest.h"

#include <vector>

// Write to disk file filename with TTree "t" with nEntries of branch "e" assuming integer values [0..nEntries).
void MakeInputFile(const std::string &filename, int nEntries)
{
   const auto treename = "t";
   auto d = ROOT::RDataFrame(nEntries)
               .Define("e", [](ULong64_t e) { return int(e); }, {"rdfentry_"})
               .Snapshot<int>(treename, filename, {"e"});
}

class RMTRAII {
   bool fIsMT;

public:
   RMTRAII(bool isMT) : fIsMT(isMT)
   {
      if (fIsMT)
         ROOT::EnableImplicitMT();
   }
   ~RMTRAII()
   {
      if (fIsMT)
         ROOT::DisableImplicitMT();
   }
};

void TestTreeWithEntryList(bool isMT = false)
{
   const auto nEntries = 10;
   const auto treename = "t";
   const auto filename = "rdfentrylist.root";
   MakeInputFile(filename, nEntries);

   RMTRAII gomt(isMT);

   TEntryList elist("e", "e", treename, filename);
   elist.Enter(0);
   elist.Enter(nEntries - 1);

   TFile f(filename);
   auto t = f.Get<TTree>(treename);
   t->SetEntryList(&elist);

   auto entries = ROOT::RDataFrame(*t).Take<int>("e");
   EXPECT_EQ(*entries, std::vector<int>({0, nEntries - 1}));

   gSystem->Unlink(filename);
}

void TestChainWithEntryList(bool isMT = false)
{
   const auto nEntries = 10;
   const auto treename = "t";
   const auto file1 = "rdfentrylist1.root";
   MakeInputFile(file1, nEntries);
   const auto file2 = "rdfentrylist2.root";
   MakeInputFile(file2, nEntries);

   RMTRAII gomt(isMT);

   TEntryList elist1("e", "e", treename, file1);
   elist1.Enter(0);
   elist1.Enter(2 * nEntries - 1);
   TEntryList elist2("e", "e", treename, file2);
   elist2.Enter(0);
   elist2.Enter(2 * nEntries - 1);

   // make a TEntryList that contains two TEntryLists in its list of TEntryLists,
   // as required by TChain (see TEntryList's doc)
   TEntryList elists;
   elists.Add(&elist1);
   elists.Add(&elist2);

   TChain c(treename);
   c.Add(file1, nEntries);
   c.Add(file2, nEntries);
   c.SetEntryList(&elists);

   auto entries = ROOT::RDataFrame(c).Take<int>("e");
   EXPECT_EQ(*entries, std::vector<int>({0, nEntries - 1, 0, nEntries - 1}));

   gSystem->Unlink(file1);
   gSystem->Unlink(file2);
}

TEST(RDFEntryList, Chain)
{
   TestChainWithEntryList();
}

TEST(RDFEntryList, Tree)
{
   TestTreeWithEntryList();
}

#ifdef R__USE_IMT
TEST(RDFEntryList, DISABLED_ChainMT)
{
   TestChainWithEntryList(true);
}

TEST(RDFEntryList, TreeMT)
{
   TestTreeWithEntryList(true);
}
#endif
<|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  02/2018

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TCUTFLOWREPORT
#define ROOT_TCUTFLOWREPORT

#include "RtypesCore.h"
#include "TString.h"

#include <string>
#include <vector>

namespace ROOT {

namespace Detail {
namespace TDF {
class TFilterBase;
} // End NS TDF
} // End NS Detail

namespace Experimental {
namespace TDF {

class TCutInfo {
   friend class TCutFlowReport;
   friend class ROOT::Detail::TDF::TFilterBase;

private:
   const std::string fName;
   const ULong64_t fPass;
   const ULong64_t fAll;
   TCutInfo(const std::string &name, ULong64_t pass, ULong64_t all) : fName(name), fPass(pass), fAll(all) {}

public:
   const std::string &GetName() const { return fName; }
   ULong64_t GetAll() const { return fAll; }
   ULong64_t GetPass() const { return fPass; }
   float GetEff() const { return 100.f * (fPass / float(fAll)); }
};

class TCutFlowReport {
   friend class ROOT::Detail::TDF::TFilterBase;

private:
   std::vector<TCutInfo> fCutInfos;
   void AddCut(TCutInfo &&ci) { fCutInfos.emplace_back(std::move(ci)); };

public:
   void Print();
   const TCutInfo &operator[](std::string_view cutName);
   std::vector<TCutInfo>::const_iterator begin() const { return fCutInfos.begin(); }
   std::vector<TCutInfo>::const_iterator end() const { return fCutInfos.end(); }
};

} // End NS TDF
} // End NS Experimental
} // End NS ROOT

#endif
<commit_msg>[TDF] Improve TCutFlowReport with At accessor and const_iterator type<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  02/2018

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TCUTFLOWREPORT
#define ROOT_TCUTFLOWREPORT

#include "RtypesCore.h"
#include "TString.h"

#include <string>
#include <vector>

namespace ROOT {

namespace Detail {
namespace TDF {
class TFilterBase;
} // End NS TDF
} // End NS Detail

namespace Experimental {
namespace TDF {

class TCutInfo {
   friend class TCutFlowReport;
   friend class ROOT::Detail::TDF::TFilterBase;

private:
   const std::string fName;
   const ULong64_t fPass;
   const ULong64_t fAll;
   TCutInfo(const std::string &name, ULong64_t pass, ULong64_t all) : fName(name), fPass(pass), fAll(all) {}

public:
   const std::string &GetName() const { return fName; }
   ULong64_t GetAll() const { return fAll; }
   ULong64_t GetPass() const { return fPass; }
   float GetEff() const { return 100.f * (fPass / float(fAll)); }
};

class TCutFlowReport {
   friend class ROOT::Detail::TDF::TFilterBase;

private:
   std::vector<TCutInfo> fCutInfos;
   void AddCut(TCutInfo &&ci) { fCutInfos.emplace_back(std::move(ci)); };

public:
   using const_iterator = typename std::vector<TCutInfo>::const_iterator;
   void Print();
   const TCutInfo &operator[](std::string_view cutName);
   const TCutInfo &At(std::string_view cutName) { return operator[](cutName); }
   const_iterator begin() const { return fCutInfos.begin(); }
   const_iterator end() const { return fCutInfos.end(); }
};

} // End NS TDF
} // End NS Experimental
} // End NS ROOT

#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "eventql/util/stringutil.h"
#include "eventql/util/io/fileutil.h"
#include "test_runner.h"

namespace eventql {
namespace test {

TestContext::TestContext() :
    tmpdir("/tmp"),
    logdir("./"),
    bindir("./src"),
    srcdir("./"),
    log_fd(-1) {}

TestContext::~TestContext() {
  if (log_fd >= 0) {
    close(log_fd);
  }
}

void TestContext::openLogfile(const std::string& path) {
  log_file = path;
  log_fd = open(log_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
}

TestRunner::TestRunner(TestRepository* test_repo) : test_repo_(test_repo) {}

bool TestRunner::runTest(const std::string& test_id, TestOutputFormat format) {
  return runTests(std::set<std::string>{test_id}, format);
}

static void expandTestList(
    TestRepository* test_repo,
    std::set<std::string>* test_ids) {
}

struct TestFailure {
  std::string test_id;
  std::string description;
  std::string error;
  std::string logfile;
};

bool TestRunner::runTests(
    std::set<std::string> test_ids,
    TestOutputFormat format) {
  expandTestList(test_repo_, &test_ids);

  size_t tests_count = test_ids.size();

  switch (format) {
    case TestOutputFormat::ASCII:
      fprintf(
          stderr,
          "\033[1;97mRunning %i/%i tests\e[0m\n\n",
          (int) tests_count,
          (int) test_repo_->getTestCount());
      break;
    case TestOutputFormat::TAP:
      fprintf(stdout, "1..%i\n", (int) tests_count);
      break;
  }

  std::vector<TestFailure> test_failures;
  size_t tests_passed = 0;
  size_t test_num = 0;
  for (const auto& bundle : test_repo_->getTestBundles()) {
    TestContext test_ctx;
    if (!bundle.logfile_path.empty()) {
      test_ctx.openLogfile(
          FileUtil::joinPaths(test_ctx.logdir, bundle.logfile_path));
    }

    for (const auto& test : bundle.test_cases) {
      if (test_ids.count(test.test_id) == 0) {
        break;
      }

      ++test_num;

      bool test_result = false;
      std::string test_message;
      try {
        test_result = test.fun(&test_ctx);
      } catch (const std::exception& e) {
        test_message = e.what();
      }

      StringUtil::replaceAll(&test_message, "\n", "\\n");
      StringUtil::replaceAll(&test_message, "\r", "");

      if (test_result) {
        ++tests_passed;

        switch (format) {
          case TestOutputFormat::ASCII:
            fprintf(
                stderr,
                " * %s \033[1;32m[PASS]\e[0m -- %s\n",
                test.test_id.c_str(),
                test.description.c_str());
            break;
          case TestOutputFormat::TAP:
            fprintf(
                stdout,
                "ok %i - %s # %s\n",
                (int) test_num,
                test.test_id.c_str(),
                test.description.c_str());
            break;
        }
      } else {
        test_failures.emplace_back(TestFailure {
          .test_id = test.test_id,
          .description = test.description,
          .error = test_message,
          .logfile = test_ctx.log_file
        });

        switch (format) {
          case TestOutputFormat::ASCII:
            fprintf(
                stderr,
                " * %s \033[1;31m[FAIL]\e[0m -- %s\n",
                test.test_id.c_str(),
                test.description.c_str());
            break;
          case TestOutputFormat::TAP:
            fprintf(
                stdout,
                "not ok %i - %s # %s; ERROR: %s\n",
                (int) test_num,
                test.test_id.c_str(),
                test.description.c_str(),
                test_message.c_str());
            break;
        }
      }
    }
  }

  if (tests_count == 0 || tests_passed < tests_count) {
    switch (format) {
      case TestOutputFormat::ASCII:
        for (const auto& fail : test_failures) {
          fprintf(
              stderr,
              "\n\033[1;31m[FAIL] %s\e[0m -- %s\n  ERROR: %s\n",
              fail.test_id.c_str(),
              fail.description.c_str(),
              fail.error.c_str());

          if (!fail.logfile.empty()) {
            fprintf(stderr, "  LOGFILE: %s\n", fail.logfile.c_str());
          }
        }

        fprintf(
            stderr,
            "\n\033[1;31m[FAIL] %i/%i tests failed :(\e[0m\n",
            (int) (tests_count - tests_passed),
            (int) tests_count);

        break;
      case TestOutputFormat::TAP:
        break;
    }

    return false;
  } else {
    switch (format) {
      case TestOutputFormat::ASCII:
        fprintf(
            stderr,
            "\n\033[1;32m[PASS] %i tests passed :)\e[0m\n",
            (int) tests_count);
        break;
      case TestOutputFormat::TAP:
        break;
    }

    return true;
  }
}

bool TestRunner::runTestSuite(const std::string& suite, TestOutputFormat format) {
  if (suite == "world") {
    return runTestSuite(TestSuite::WORLD, format);
  }

  if (suite == "smoke") {
    return runTestSuite(TestSuite::WORLD, format);
  }

  std::cerr << "ERROR: invalid test suite" << std::endl;
  return false;
}

bool TestRunner::runTestSuite(TestSuite suite, TestOutputFormat format) {
  std::set<std::string> test_ids;

  for (const auto& bundle : test_repo_->getTestBundles()) {
    for (const auto& test : bundle.test_cases) {
      if (test.suites.count(suite) > 0) {
        test_ids.insert(test.test_id);
      }
    }
  }

  return runTests(test_ids, format);
}

void TestRunner::printTestList() {
}

} // namespace test
} // namespace eventql

<commit_msg>skip remaining tests in bundle after failure<commit_after>/**
 * Copyright (c) 2017 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Laura Schlimmer <laura@eventql.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "eventql/util/stringutil.h"
#include "eventql/util/io/fileutil.h"
#include "test_runner.h"

namespace eventql {
namespace test {

TestContext::TestContext() :
    tmpdir("/tmp"),
    logdir("./"),
    bindir("./src"),
    srcdir("./"),
    log_fd(-1) {}

TestContext::~TestContext() {
  if (log_fd >= 0) {
    close(log_fd);
  }
}

void TestContext::openLogfile(const std::string& path) {
  log_file = path;
  log_fd = open(log_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
}

TestRunner::TestRunner(TestRepository* test_repo) : test_repo_(test_repo) {}

bool TestRunner::runTest(const std::string& test_id, TestOutputFormat format) {
  return runTests(std::set<std::string>{test_id}, format);
}

static void expandTestList(
    TestRepository* test_repo,
    std::set<std::string>* test_ids) {
}

struct TestFailure {
  std::string test_id;
  std::string description;
  std::string error;
  std::string logfile;
};

bool TestRunner::runTests(
    std::set<std::string> test_ids,
    TestOutputFormat format) {
  expandTestList(test_repo_, &test_ids);

  size_t tests_count = test_ids.size();

  switch (format) {
    case TestOutputFormat::ASCII:
      fprintf(
          stderr,
          "\033[1;97mRunning %i/%i tests\e[0m\n\n",
          (int) tests_count,
          (int) test_repo_->getTestCount());
      break;
    case TestOutputFormat::TAP:
      fprintf(stdout, "1..%i\n", (int) tests_count);
      break;
  }

  std::vector<TestFailure> test_failures;
  size_t tests_passed = 0;
  size_t test_num = 0;
  for (const auto& bundle : test_repo_->getTestBundles()) {
    TestContext test_ctx;
    if (!bundle.logfile_path.empty()) {
      test_ctx.openLogfile(
          FileUtil::joinPaths(test_ctx.logdir, bundle.logfile_path));
    }

    bool test_bundle_failed = false;
    for (const auto& test : bundle.test_cases) {
      if (test_ids.count(test.test_id) == 0) {
        break;
      }

      ++test_num;

      if (test_bundle_failed) {
        switch (format) {
          case TestOutputFormat::ASCII:
            fprintf(
                stderr,
                " * %s \033[1;93m[SKIP]\e[0m -- %s\n",
                test.test_id.c_str(),
                test.description.c_str());
            break;
          case TestOutputFormat::TAP:
            fprintf(
                stdout,
                "not ok %i - %s # %s; skipped because of previous failure\n",
                (int) test_num,
                test.test_id.c_str(),
                test.description.c_str());
            break;
        }
        continue;
      }

      bool test_result = false;
      std::string test_message;
      try {
        test_result = test.fun(&test_ctx);
      } catch (const std::exception& e) {
        test_message = e.what();
      }

      StringUtil::replaceAll(&test_message, "\n", "\\n");
      StringUtil::replaceAll(&test_message, "\r", "");

      if (test_result) {
        ++tests_passed;

        switch (format) {
          case TestOutputFormat::ASCII:
            fprintf(
                stderr,
                " * %s \033[1;32m[PASS]\e[0m -- %s\n",
                test.test_id.c_str(),
                test.description.c_str());
            break;
          case TestOutputFormat::TAP:
            fprintf(
                stdout,
                "ok %i - %s # %s\n",
                (int) test_num,
                test.test_id.c_str(),
                test.description.c_str());
            break;
        }
      } else {
        test_failures.emplace_back(TestFailure {
          .test_id = test.test_id,
          .description = test.description,
          .error = test_message,
          .logfile = test_ctx.log_file
        });

        switch (format) {
          case TestOutputFormat::ASCII:
            fprintf(
                stderr,
                " * %s \033[1;31m[FAIL]\e[0m -- %s\n",
                test.test_id.c_str(),
                test.description.c_str());
            break;
          case TestOutputFormat::TAP:
            fprintf(
                stdout,
                "not ok %i - %s # %s; ERROR: %s\n",
                (int) test_num,
                test.test_id.c_str(),
                test.description.c_str(),
                test_message.c_str());
            break;
        }

        test_bundle_failed = true;
      }
    }
  }

  if (tests_count == 0 || tests_passed < tests_count) {
    switch (format) {
      case TestOutputFormat::ASCII:
        for (const auto& fail : test_failures) {
          fprintf(
              stderr,
              "\n\033[1;31m[FAIL] %s\e[0m -- %s\n  ERROR: %s\n",
              fail.test_id.c_str(),
              fail.description.c_str(),
              fail.error.c_str());

          if (!fail.logfile.empty()) {
            fprintf(stderr, "  LOGFILE: %s\n", fail.logfile.c_str());
          }
        }

        fprintf(
            stderr,
            "\n\033[1;31m[FAIL] %i/%i tests failed :(\e[0m\n",
            (int) (tests_count - tests_passed),
            (int) tests_count);

        break;
      case TestOutputFormat::TAP:
        break;
    }

    return false;
  } else {
    switch (format) {
      case TestOutputFormat::ASCII:
        fprintf(
            stderr,
            "\n\033[1;32m[PASS] %i tests passed :)\e[0m\n",
            (int) tests_count);
        break;
      case TestOutputFormat::TAP:
        break;
    }

    return true;
  }
}

bool TestRunner::runTestSuite(const std::string& suite, TestOutputFormat format) {
  if (suite == "world") {
    return runTestSuite(TestSuite::WORLD, format);
  }

  if (suite == "smoke") {
    return runTestSuite(TestSuite::WORLD, format);
  }

  std::cerr << "ERROR: invalid test suite" << std::endl;
  return false;
}

bool TestRunner::runTestSuite(TestSuite suite, TestOutputFormat format) {
  std::set<std::string> test_ids;

  for (const auto& bundle : test_repo_->getTestBundles()) {
    for (const auto& test : bundle.test_cases) {
      if (test.suites.count(suite) > 0) {
        test_ids.insert(test.test_id);
      }
    }
  }

  return runTests(test_ids, format);
}

void TestRunner::printTestList() {
}

} // namespace test
} // namespace eventql

<|endoftext|>


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

#include "scriptEngineWorker.h"

#include <QtCore/QFile>
#include <QtCore/QVector>
#include <QtCore/QTextStream>
#include <QtCore/QSignalMapper>

#include <trikKernel/fileUtils.h>
#include <trikKernel/paths.h>
#include <trikKernel/timeVal.h>
#include <trikControl/batteryInterface.h>
#include <trikControl/colorSensorInterface.h>
#include <trikControl/displayInterface.h>
#include <trikControl/encoderInterface.h>
#include <trikControl/eventCodeInterface.h>
#include <trikControl/eventDeviceInterface.h>
#include <trikControl/eventInterface.h>
#include <trikControl/gamepadInterface.h>
#include <trikControl/gyroSensorInterface.h>
#include <trikControl/lineSensorInterface.h>
#include <trikControl/motorInterface.h>
#include <trikControl/objectSensorInterface.h>
#include <trikControl/soundSensorInterface.h>
#include <trikControl/sensorInterface.h>
#include <trikControl/vectorSensorInterface.h>
#include <trikNetwork/mailboxInterface.h>

#include "scriptable.h"
#include "utils.h"

#include <QsLog.h>

using namespace trikScriptRunner;
using namespace trikControl;
using namespace trikNetwork;

Q_DECLARE_METATYPE(BatteryInterface*)
Q_DECLARE_METATYPE(ColorSensorInterface*)
Q_DECLARE_METATYPE(FifoInterface*)
Q_DECLARE_METATYPE(DisplayInterface*)
Q_DECLARE_METATYPE(EncoderInterface*)
Q_DECLARE_METATYPE(EventCodeInterface*)
Q_DECLARE_METATYPE(EventDeviceInterface*)
Q_DECLARE_METATYPE(EventInterface*)
Q_DECLARE_METATYPE(GamepadInterface*)
Q_DECLARE_METATYPE(GyroSensorInterface*)
Q_DECLARE_METATYPE(KeysInterface*)
Q_DECLARE_METATYPE(LedInterface*)
Q_DECLARE_METATYPE(LineSensorInterface*)
Q_DECLARE_METATYPE(MailboxInterface*)
Q_DECLARE_METATYPE(MotorInterface*)
Q_DECLARE_METATYPE(ObjectSensorInterface*)
Q_DECLARE_METATYPE(SoundSensorInterface*)
Q_DECLARE_METATYPE(SensorInterface*)
Q_DECLARE_METATYPE(Threading*)
Q_DECLARE_METATYPE(VectorSensorInterface*)
Q_DECLARE_METATYPE(QVector<int>)
Q_DECLARE_METATYPE(trikKernel::TimeVal)
Q_DECLARE_METATYPE(QTimer*)

QScriptValue print(QScriptContext *context, QScriptEngine *engine)
{
	QString result;
	for (int i = 0; i < context->argumentCount(); ++i) {
		if (i > 0) {
			result.append(" ");
		}

		result.append(context->argument(i).toString());
	}

	QTextStream(stdout) << result << "\n";
	auto scriptValue = engine->globalObject().property("script");
	auto script = dynamic_cast<ScriptExecutionControl*> (scriptValue.toQObject());
	if (script) {
		QMetaObject::invokeMethod(script, "sendMessage", Q_ARG(QString, QString("print: %1").arg(result)));
//		If this does not work then it can be workarrounded:
//		QSignalMapper *mapper = new QSignalMapper();
//		QObject::connect(mapper, SIGNAL(mapped(QString)), script, SIGNAL(sendMessage(QString)), Qt::DirectConnection);
//		mapper->setMapping(nullptr, QString("print: %1").arg(result));
//		mapper->map(nullptr);
//		delete mapper;
	}

	return engine->toScriptValue(result);
}

QScriptValue timeInterval(QScriptContext *context, QScriptEngine *engine)
{
	int result = trikKernel::TimeVal::timeInterval(context->argument(0).toInteger(), context->argument(1).toInteger());
	return engine->toScriptValue(result);
}

ScriptEngineWorker::ScriptEngineWorker(trikControl::BrickInterface &brick
		, trikNetwork::MailboxInterface * const mailbox
		, ScriptExecutionControl &scriptControl
		)
	: mBrick(brick)
	, mMailbox(mailbox)
	, mScriptControl(scriptControl)
	, mThreading(this, scriptControl)
	, mDirectScriptsEngine(nullptr)
	, mScriptId(0)
	, mState(ready)
{
	connect(&mScriptControl, SIGNAL(quitSignal()), this, SLOT(onScriptRequestingToQuit()));

	registerUserFunction("print", print);
	registerUserFunction("timeInterval", timeInterval);
}

void ScriptEngineWorker::brickBeep()
{
	mBrick.playSound(trikKernel::Paths::mediaPath() + "media/beep_soft.wav");
}

void ScriptEngineWorker::stopScript()
{
	QMutexLocker locker(&mScriptStateMutex);

	if (mState == stopping) {
		// Already stopping, so we can do nothing.
		return;
	}

	if (mState == ready) {
		// Engine is ready for execution.
		return;
	}

	while (mState == starting) {
		// Some script is starting right now, so we are in inconsistent state. Let it start, then stop it.
		QThread::yieldCurrentThread();
	}

	QLOG_INFO() << "ScriptEngineWorker: stopping script";

	mState = stopping;

	mScriptControl.reset();

	if (mMailbox) {
		mMailbox->stopWaiting();
		/// @todo: here script will continue to execute and may execute some statements before it will eventually
		/// be stopped by mThreading.reset(). But if we do mThreading.reset() before mMailbox->stopWaiting(),
		/// we will get deadlock, since mMailbox->stopWaiting() shall be executed in already stopped thread.
		/// Actually we shall stop script engines here, do mMailbox->stopWaiting(), then stop threads.
	}

	mThreading.reset();

	if (mDirectScriptsEngine) {
		mDirectScriptsEngine->abortEvaluation();
		QLOG_INFO() << "ScriptEngineWorker : ending interpretation";
		emit completed(mDirectScriptsEngine->hasUncaughtException()
						? mDirectScriptsEngine->uncaughtException().toString()
						: ""
				, mScriptId);

		mDirectScriptsEngine->deleteLater();
		mDirectScriptsEngine = nullptr;
	}

	mState = ready;

	/// @todo: is it actually stopped?

	QLOG_INFO() << "ScriptEngineWorker: stopping complete";
}

void ScriptEngineWorker::resetBrick()
{
	QLOG_INFO() << "Stopping robot";

	if (mMailbox) {
		mMailbox->stopWaiting();
		mMailbox->clearQueue();
	}

	mBrick.reset();
}

void ScriptEngineWorker::run(const QString &script, int scriptId)
{
	QMutexLocker locker(&mScriptStateMutex);
	startScriptEvaluation(scriptId);
	QMetaObject::invokeMethod(this, "doRun", Q_ARG(const QString &, script));
}

void ScriptEngineWorker::doRun(const QString &script)
{
	/// When starting script execution (by any means), clear button states.
	mBrick.keys()->reset();

	mThreading.startMainThread(script);
	mState = running;
	mThreading.waitForAll();
	const QString error = mThreading.errorMessage();
	QLOG_INFO() << "ScriptEngineWorker: evaluation ended with message" << error;
	emit completed(error, mScriptId);
}

void ScriptEngineWorker::runDirect(const QString &command, int scriptId)
{
	qDebug() << "ScriptEngineWorker::runDirect";

	QMutexLocker locker(&mScriptStateMutex);
	if (!mScriptControl.isInEventDrivenMode()) {
		QLOG_INFO() << "ScriptEngineWorker: starting interpretation";
		locker.unlock();
		stopScript();
	}

	QMetaObject::invokeMethod(this, "doRunDirect", Q_ARG(const QString &, command), Q_ARG(int, scriptId));
}

void ScriptEngineWorker::doRunDirect(const QString &command, int scriptId)
{
	if (!mScriptControl.isInEventDrivenMode() && !mDirectScriptsEngine) {
		startScriptEvaluation(scriptId);
		mDirectScriptsEngine = createScriptEngine(false);
		mScriptControl.run();
		mState = running;
	}

	if (mDirectScriptsEngine) {
		mDirectScriptsEngine->evaluate(command);

		/// If script was stopped by quit(), engine will already be reset to nullptr in ScriptEngineWorker::stopScript.
		if (mDirectScriptsEngine && mDirectScriptsEngine->hasUncaughtException()) {
			QLOG_INFO() << "ScriptEngineWorker : ending interpretation of direct script";
			emit completed(mDirectScriptsEngine->hasUncaughtException()
					? mDirectScriptsEngine->uncaughtException().toString()
					: "", mScriptId);
			mDirectScriptsEngine->deleteLater();
			mDirectScriptsEngine = nullptr;
		}
	}
}

void ScriptEngineWorker::startScriptEvaluation(int scriptId)
{
	QLOG_INFO() << "ScriptEngineWorker: starting script" << scriptId << ", thread:" << QThread::currentThread();
	mState = starting;
	mScriptId = scriptId;
	emit startedScript(mScriptId);
}

void ScriptEngineWorker::onScriptRequestingToQuit()
{
	if (!mScriptControl.isInEventDrivenMode()) {
		// Somebody erroneously called script.quit() before entering event loop, so we must force event loop for script
		// and only then quit, to send completed() signal properly.
		mScriptControl.run();
	}

	stopScript();
}

static QScriptValue timeValToScriptValue(QScriptEngine *engine, const trikKernel::TimeVal &in)
{
	QScriptValue obj = engine->newObject();
	obj.setProperty("mcsec", in.packedUInt32());
	return obj;
}

static void timeValFromScriptValue(const QScriptValue &object, trikKernel::TimeVal &out)
{
	out = trikKernel::TimeVal(0, object.property("mcsec").toInt32());
}

QScriptEngine * ScriptEngineWorker::createScriptEngine(bool supportThreads)
{
	QScriptEngine *engine = new QScriptEngine();
	QLOG_INFO() << "New script engine" << engine << ", thread:" << QThread::currentThread();

	Scriptable<BatteryInterface>::registerMetatype(engine);
	Scriptable<ColorSensorInterface>::registerMetatype(engine);
	Scriptable<DisplayInterface>::registerMetatype(engine);
	Scriptable<EncoderInterface>::registerMetatype(engine);
	Scriptable<EventCodeInterface>::registerMetatype(engine);
	Scriptable<EventDeviceInterface>::registerMetatype(engine);
	Scriptable<EventInterface>::registerMetatype(engine);
	Scriptable<GamepadInterface>::registerMetatype(engine);
	Scriptable<GyroSensorInterface>::registerMetatype(engine);
	Scriptable<FifoInterface>::registerMetatype(engine);
	Scriptable<KeysInterface>::registerMetatype(engine);
	Scriptable<LedInterface>::registerMetatype(engine);
	Scriptable<LineSensorInterface>::registerMetatype(engine);
	Scriptable<MailboxInterface>::registerMetatype(engine);
	Scriptable<MotorInterface>::registerMetatype(engine);
	Scriptable<ObjectSensorInterface>::registerMetatype(engine);
	Scriptable<SensorInterface>::registerMetatype(engine);
	Scriptable<SoundSensorInterface>::registerMetatype(engine);
	Scriptable<QTimer>::registerMetatype(engine);
	qScriptRegisterMetaType(engine, timeValToScriptValue, timeValFromScriptValue);
	Scriptable<VectorSensorInterface>::registerMetatype(engine);

	qScriptRegisterSequenceMetaType<QVector<int>>(engine);
	qScriptRegisterSequenceMetaType<QStringList>(engine);

	engine->globalObject().setProperty("brick", engine->newQObject(&mBrick));
	engine->globalObject().setProperty("script", engine->newQObject(&mScriptControl));

	if (mMailbox) {
		engine->globalObject().setProperty("mailbox", engine->newQObject(mMailbox));
	}

	// Gamepad can still be accessed from script as brick.gamepad(), 'gamepad' variable is here for backwards
	// compatibility.
	if (mBrick.gamepad()) {
		engine->globalObject().setProperty("gamepad", engine->newQObject(mBrick.gamepad()));
	}

	if (supportThreads) {
		engine->globalObject().setProperty("Threading", engine->newQObject(&mThreading));
	}

	for (const auto &step : mCustomInitSteps) {
		step(engine);
	}

	evalSystemJs(engine);

	engine->setProcessEventsInterval(1);
	return engine;
}

QScriptEngine *ScriptEngineWorker::copyScriptEngine(const QScriptEngine * const original)
{
	QScriptEngine *const result = createScriptEngine();

	QScriptValue globalObject = result->globalObject();
	Utils::copyRecursivelyTo(original->globalObject(), globalObject, result);
	result->setGlobalObject(globalObject);

	// We need to re-eval system.js after global object copying because functions did not get copied by
	// copyRecursivelyTo, and existing ones were overwritten by copying.
	evalSystemJs(result);

	return result;
}

void ScriptEngineWorker::registerUserFunction(const QString &name, QScriptEngine::FunctionSignature function)
{
	mRegisteredUserFunctions[name] = function;
}

void ScriptEngineWorker::addCustomEngineInitStep(const std::function<void (QScriptEngine *)> &step)
{
	mCustomInitSteps.append(step);
}

void ScriptEngineWorker::evalSystemJs(QScriptEngine * const engine) const
{
	const QString systemJsPath = trikKernel::Paths::systemScriptsPath() + "system.js";
	if (QFile::exists(systemJsPath)) {
		engine->evaluate(trikKernel::FileUtils::readFromFile(systemJsPath));
		if (engine->hasUncaughtException()) {
			const int line = engine->uncaughtExceptionLineNumber();
			const QString message = engine->uncaughtException().toString();
			QLOG_ERROR() << "system.js: Uncaught exception at line" << line << ":" << message;
		}
	} else {
		QLOG_ERROR() << "system.js not found, path:" << systemJsPath;
	}

	for (const auto &functionName : mRegisteredUserFunctions.keys()) {
		QScriptValue functionValue = engine->newFunction(mRegisteredUserFunctions[functionName]);
		engine->globalObject().setProperty(functionName, functionValue);
	}
}
<commit_msg>moved custom init steps after system.js evaluation<commit_after>/* Copyright 2013 - 2016 Yurii Litvinov, CyberTech Labs Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "scriptEngineWorker.h"

#include <QtCore/QFile>
#include <QtCore/QVector>
#include <QtCore/QTextStream>
#include <QtCore/QSignalMapper>

#include <trikKernel/fileUtils.h>
#include <trikKernel/paths.h>
#include <trikKernel/timeVal.h>
#include <trikControl/batteryInterface.h>
#include <trikControl/colorSensorInterface.h>
#include <trikControl/displayInterface.h>
#include <trikControl/encoderInterface.h>
#include <trikControl/eventCodeInterface.h>
#include <trikControl/eventDeviceInterface.h>
#include <trikControl/eventInterface.h>
#include <trikControl/gamepadInterface.h>
#include <trikControl/gyroSensorInterface.h>
#include <trikControl/lineSensorInterface.h>
#include <trikControl/motorInterface.h>
#include <trikControl/objectSensorInterface.h>
#include <trikControl/soundSensorInterface.h>
#include <trikControl/sensorInterface.h>
#include <trikControl/vectorSensorInterface.h>
#include <trikNetwork/mailboxInterface.h>

#include "scriptable.h"
#include "utils.h"

#include <QsLog.h>

using namespace trikScriptRunner;
using namespace trikControl;
using namespace trikNetwork;

Q_DECLARE_METATYPE(BatteryInterface*)
Q_DECLARE_METATYPE(ColorSensorInterface*)
Q_DECLARE_METATYPE(FifoInterface*)
Q_DECLARE_METATYPE(DisplayInterface*)
Q_DECLARE_METATYPE(EncoderInterface*)
Q_DECLARE_METATYPE(EventCodeInterface*)
Q_DECLARE_METATYPE(EventDeviceInterface*)
Q_DECLARE_METATYPE(EventInterface*)
Q_DECLARE_METATYPE(GamepadInterface*)
Q_DECLARE_METATYPE(GyroSensorInterface*)
Q_DECLARE_METATYPE(KeysInterface*)
Q_DECLARE_METATYPE(LedInterface*)
Q_DECLARE_METATYPE(LineSensorInterface*)
Q_DECLARE_METATYPE(MailboxInterface*)
Q_DECLARE_METATYPE(MotorInterface*)
Q_DECLARE_METATYPE(ObjectSensorInterface*)
Q_DECLARE_METATYPE(SoundSensorInterface*)
Q_DECLARE_METATYPE(SensorInterface*)
Q_DECLARE_METATYPE(Threading*)
Q_DECLARE_METATYPE(VectorSensorInterface*)
Q_DECLARE_METATYPE(QVector<int>)
Q_DECLARE_METATYPE(trikKernel::TimeVal)
Q_DECLARE_METATYPE(QTimer*)

QScriptValue print(QScriptContext *context, QScriptEngine *engine)
{
	QString result;
	for (int i = 0; i < context->argumentCount(); ++i) {
		if (i > 0) {
			result.append(" ");
		}

		result.append(context->argument(i).toString());
	}

	QTextStream(stdout) << result << "\n";
	auto scriptValue = engine->globalObject().property("script");
	auto script = dynamic_cast<ScriptExecutionControl*> (scriptValue.toQObject());
	if (script) {
		QMetaObject::invokeMethod(script, "sendMessage", Q_ARG(QString, QString("print: %1").arg(result)));
//		If this does not work then it can be workarrounded:
//		QSignalMapper *mapper = new QSignalMapper();
//		QObject::connect(mapper, SIGNAL(mapped(QString)), script, SIGNAL(sendMessage(QString)), Qt::DirectConnection);
//		mapper->setMapping(nullptr, QString("print: %1").arg(result));
//		mapper->map(nullptr);
//		delete mapper;
	}

	return engine->toScriptValue(result);
}

QScriptValue timeInterval(QScriptContext *context, QScriptEngine *engine)
{
	int result = trikKernel::TimeVal::timeInterval(context->argument(0).toInteger(), context->argument(1).toInteger());
	return engine->toScriptValue(result);
}

ScriptEngineWorker::ScriptEngineWorker(trikControl::BrickInterface &brick
		, trikNetwork::MailboxInterface * const mailbox
		, ScriptExecutionControl &scriptControl
		)
	: mBrick(brick)
	, mMailbox(mailbox)
	, mScriptControl(scriptControl)
	, mThreading(this, scriptControl)
	, mDirectScriptsEngine(nullptr)
	, mScriptId(0)
	, mState(ready)
{
	connect(&mScriptControl, SIGNAL(quitSignal()), this, SLOT(onScriptRequestingToQuit()));

	registerUserFunction("print", print);
	registerUserFunction("timeInterval", timeInterval);
}

void ScriptEngineWorker::brickBeep()
{
	mBrick.playSound(trikKernel::Paths::mediaPath() + "media/beep_soft.wav");
}

void ScriptEngineWorker::stopScript()
{
	QMutexLocker locker(&mScriptStateMutex);

	if (mState == stopping) {
		// Already stopping, so we can do nothing.
		return;
	}

	if (mState == ready) {
		// Engine is ready for execution.
		return;
	}

	while (mState == starting) {
		// Some script is starting right now, so we are in inconsistent state. Let it start, then stop it.
		QThread::yieldCurrentThread();
	}

	QLOG_INFO() << "ScriptEngineWorker: stopping script";

	mState = stopping;

	mScriptControl.reset();

	if (mMailbox) {
		mMailbox->stopWaiting();
		/// @todo: here script will continue to execute and may execute some statements before it will eventually
		/// be stopped by mThreading.reset(). But if we do mThreading.reset() before mMailbox->stopWaiting(),
		/// we will get deadlock, since mMailbox->stopWaiting() shall be executed in already stopped thread.
		/// Actually we shall stop script engines here, do mMailbox->stopWaiting(), then stop threads.
	}

	mThreading.reset();

	if (mDirectScriptsEngine) {
		mDirectScriptsEngine->abortEvaluation();
		QLOG_INFO() << "ScriptEngineWorker : ending interpretation";
		emit completed(mDirectScriptsEngine->hasUncaughtException()
						? mDirectScriptsEngine->uncaughtException().toString()
						: ""
				, mScriptId);

		mDirectScriptsEngine->deleteLater();
		mDirectScriptsEngine = nullptr;
	}

	mState = ready;

	/// @todo: is it actually stopped?

	QLOG_INFO() << "ScriptEngineWorker: stopping complete";
}

void ScriptEngineWorker::resetBrick()
{
	QLOG_INFO() << "Stopping robot";

	if (mMailbox) {
		mMailbox->stopWaiting();
		mMailbox->clearQueue();
	}

	mBrick.reset();
}

void ScriptEngineWorker::run(const QString &script, int scriptId)
{
	QMutexLocker locker(&mScriptStateMutex);
	startScriptEvaluation(scriptId);
	QMetaObject::invokeMethod(this, "doRun", Q_ARG(const QString &, script));
}

void ScriptEngineWorker::doRun(const QString &script)
{
	/// When starting script execution (by any means), clear button states.
	mBrick.keys()->reset();

	mThreading.startMainThread(script);
	mState = running;
	mThreading.waitForAll();
	const QString error = mThreading.errorMessage();
	QLOG_INFO() << "ScriptEngineWorker: evaluation ended with message" << error;
	emit completed(error, mScriptId);
}

void ScriptEngineWorker::runDirect(const QString &command, int scriptId)
{
	qDebug() << "ScriptEngineWorker::runDirect";

	QMutexLocker locker(&mScriptStateMutex);
	if (!mScriptControl.isInEventDrivenMode()) {
		QLOG_INFO() << "ScriptEngineWorker: starting interpretation";
		locker.unlock();
		stopScript();
	}

	QMetaObject::invokeMethod(this, "doRunDirect", Q_ARG(const QString &, command), Q_ARG(int, scriptId));
}

void ScriptEngineWorker::doRunDirect(const QString &command, int scriptId)
{
	if (!mScriptControl.isInEventDrivenMode() && !mDirectScriptsEngine) {
		startScriptEvaluation(scriptId);
		mDirectScriptsEngine = createScriptEngine(false);
		mScriptControl.run();
		mState = running;
	}

	if (mDirectScriptsEngine) {
		mDirectScriptsEngine->evaluate(command);

		/// If script was stopped by quit(), engine will already be reset to nullptr in ScriptEngineWorker::stopScript.
		if (mDirectScriptsEngine && mDirectScriptsEngine->hasUncaughtException()) {
			QLOG_INFO() << "ScriptEngineWorker : ending interpretation of direct script";
			emit completed(mDirectScriptsEngine->hasUncaughtException()
					? mDirectScriptsEngine->uncaughtException().toString()
					: "", mScriptId);
			mDirectScriptsEngine->deleteLater();
			mDirectScriptsEngine = nullptr;
		}
	}
}

void ScriptEngineWorker::startScriptEvaluation(int scriptId)
{
	QLOG_INFO() << "ScriptEngineWorker: starting script" << scriptId << ", thread:" << QThread::currentThread();
	mState = starting;
	mScriptId = scriptId;
	emit startedScript(mScriptId);
}

void ScriptEngineWorker::onScriptRequestingToQuit()
{
	if (!mScriptControl.isInEventDrivenMode()) {
		// Somebody erroneously called script.quit() before entering event loop, so we must force event loop for script
		// and only then quit, to send completed() signal properly.
		mScriptControl.run();
	}

	stopScript();
}

static QScriptValue timeValToScriptValue(QScriptEngine *engine, const trikKernel::TimeVal &in)
{
	QScriptValue obj = engine->newObject();
	obj.setProperty("mcsec", in.packedUInt32());
	return obj;
}

static void timeValFromScriptValue(const QScriptValue &object, trikKernel::TimeVal &out)
{
	out = trikKernel::TimeVal(0, object.property("mcsec").toInt32());
}

QScriptEngine * ScriptEngineWorker::createScriptEngine(bool supportThreads)
{
	QScriptEngine *engine = new QScriptEngine();
	QLOG_INFO() << "New script engine" << engine << ", thread:" << QThread::currentThread();

	Scriptable<BatteryInterface>::registerMetatype(engine);
	Scriptable<ColorSensorInterface>::registerMetatype(engine);
	Scriptable<DisplayInterface>::registerMetatype(engine);
	Scriptable<EncoderInterface>::registerMetatype(engine);
	Scriptable<EventCodeInterface>::registerMetatype(engine);
	Scriptable<EventDeviceInterface>::registerMetatype(engine);
	Scriptable<EventInterface>::registerMetatype(engine);
	Scriptable<GamepadInterface>::registerMetatype(engine);
	Scriptable<GyroSensorInterface>::registerMetatype(engine);
	Scriptable<FifoInterface>::registerMetatype(engine);
	Scriptable<KeysInterface>::registerMetatype(engine);
	Scriptable<LedInterface>::registerMetatype(engine);
	Scriptable<LineSensorInterface>::registerMetatype(engine);
	Scriptable<MailboxInterface>::registerMetatype(engine);
	Scriptable<MotorInterface>::registerMetatype(engine);
	Scriptable<ObjectSensorInterface>::registerMetatype(engine);
	Scriptable<SensorInterface>::registerMetatype(engine);
	Scriptable<SoundSensorInterface>::registerMetatype(engine);
	Scriptable<QTimer>::registerMetatype(engine);
	qScriptRegisterMetaType(engine, timeValToScriptValue, timeValFromScriptValue);
	Scriptable<VectorSensorInterface>::registerMetatype(engine);

	qScriptRegisterSequenceMetaType<QVector<int>>(engine);
	qScriptRegisterSequenceMetaType<QStringList>(engine);

	engine->globalObject().setProperty("brick", engine->newQObject(&mBrick));
	engine->globalObject().setProperty("script", engine->newQObject(&mScriptControl));

	if (mMailbox) {
		engine->globalObject().setProperty("mailbox", engine->newQObject(mMailbox));
	}

	// Gamepad can still be accessed from script as brick.gamepad(), 'gamepad' variable is here for backwards
	// compatibility.
	if (mBrick.gamepad()) {
		engine->globalObject().setProperty("gamepad", engine->newQObject(mBrick.gamepad()));
	}

	if (supportThreads) {
		engine->globalObject().setProperty("Threading", engine->newQObject(&mThreading));
	}

	evalSystemJs(engine);

	for (const auto &step : mCustomInitSteps) {
		step(engine);
	}

	engine->setProcessEventsInterval(1);
	return engine;
}

QScriptEngine *ScriptEngineWorker::copyScriptEngine(const QScriptEngine * const original)
{
	QScriptEngine *const result = createScriptEngine();

	QScriptValue globalObject = result->globalObject();
	Utils::copyRecursivelyTo(original->globalObject(), globalObject, result);
	result->setGlobalObject(globalObject);

	// We need to re-eval system.js after global object copying because functions did not get copied by
	// copyRecursivelyTo, and existing ones were overwritten by copying.
	evalSystemJs(result);

	return result;
}

void ScriptEngineWorker::registerUserFunction(const QString &name, QScriptEngine::FunctionSignature function)
{
	mRegisteredUserFunctions[name] = function;
}

void ScriptEngineWorker::addCustomEngineInitStep(const std::function<void (QScriptEngine *)> &step)
{
	mCustomInitSteps.append(step);
}

void ScriptEngineWorker::evalSystemJs(QScriptEngine * const engine) const
{
	const QString systemJsPath = trikKernel::Paths::systemScriptsPath() + "system.js";
	if (QFile::exists(systemJsPath)) {
		engine->evaluate(trikKernel::FileUtils::readFromFile(systemJsPath));
		if (engine->hasUncaughtException()) {
			const int line = engine->uncaughtExceptionLineNumber();
			const QString message = engine->uncaughtException().toString();
			QLOG_ERROR() << "system.js: Uncaught exception at line" << line << ":" << message;
		}
	} else {
		QLOG_ERROR() << "system.js not found, path:" << systemJsPath;
	}

	for (const auto &functionName : mRegisteredUserFunctions.keys()) {
		QScriptValue functionValue = engine->newFunction(mRegisteredUserFunctions[functionName]);
		engine->globalObject().setProperty(functionName, functionValue);
	}
}
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include "derivatives.hh"

BOOST_AUTO_TEST_CASE(derivative_test)
{
  using namespace manifolds;
  BOOST_CHECK_EQUAL(Derivative(Sin()), Cos());
  auto f = Cos()(x*x);
  auto d = Derivative(f);
  auto check = -2_c * x * Sin()(x * x);
  BOOST_CHECK_EQUAL(d(2), check(2));
}
<commit_msg>Added more tests<commit_after>#include <boost/test/unit_test.hpp>
#include "derivatives.hh"

BOOST_AUTO_TEST_CASE(derivative_test)
{
  using namespace manifolds;
  BOOST_CHECK_EQUAL(Derivative(Sin()), Cos());
  auto f = Cos()(x*x);
  auto d = Derivative(f);
  auto check = -2_c * x * Sin()(x * x);
  BOOST_CHECK_EQUAL(d(2), check(2));

  D<2> d2;
  auto ddf = d2(f);
  auto ddf2 = Derivative(d);
  BOOST_CHECK_EQUAL(ddf(1), ddf2(1));
  std::cout << f << "\n\n"
	    << Derivative(f) << "\n\n"
	    << Derivative(d) << "\n\n";
}
<|endoftext|>