<commit_before>// kmfilterrulesedit.cpp
// Author: Marc Mutz <Marc@Mutz.com>
// This code is under GPL

#include "kmsearchpatternedit.h"
//#include "kmfilter.h"
//#include "kmfilterdlg.h"

#include <klocale.h>
#include <kdebug.h>
#include <kbuttonbox.h>

#include <qstring.h>
#include <qlayout.h>
#include <qradiobutton.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <qbuttongroup.h>

#include <assert.h>

static QStringList sFilterFieldList, sFilterFuncList;

//=============================================================================
//
// class KMSearchRuleWidget
//
//=============================================================================

KMSearchRuleWidget::KMSearchRuleWidget(QWidget *parent, KMSearchRule *aRule, const char *name)
  : QHBox(parent,name)
{
  kdDebug() << "KMSearchRuleWidget::KMSearchRuleWidget" << endl;
  initLists(); // sFilter{Func,Field}List are local to KMSearchRuleWidget
  initWidget();

  if ( aRule )
    setRule(aRule);
  else
    reset();
}

void KMSearchRuleWidget::initWidget()
{
  kdDebug() << "KMSearchRuleWidget::initWidget" << endl;
  //  QHBoxLayout *l = new QHBoxLayout(this,0,4); // with margin 0 and spacing 4

  setSpacing(4);

  mRuleField = new QComboBox( true, this, "mRuleField" );
  mRuleFunc = new QComboBox( false, this, "mRuleFunc" );
  mRuleValue = new QLineEdit( this, "mRuleValue" );

  mRuleFunc->insertStringList(sFilterFuncList);
  mRuleFunc->adjustSize();

  mRuleField->insertStringList(sFilterFieldList);
  mRuleField->adjustSize();

  connect( mRuleField, SIGNAL(textChanged(const QString &)),
	   this, SIGNAL(fieldChanged(const QString &)) );
  connect( mRuleValue, SIGNAL(textChanged(const QString &)),
	   this, SIGNAL(contentsChanged(const QString &)) );
}

void KMSearchRuleWidget::setRule(KMSearchRule *aRule)
{
  assert ( aRule );

  //--------------set the field
  int i = indexOfRuleField( aRule->field() );

  kdDebug() << aRule->function() << endl;

  if ( i<0 ) { // not found -> user defined field
    mRuleField->changeItem( aRule->field(), 0 );
    i=0;
  } else // found in the list of predefined fields
    mRuleField->changeItem( " ", 0 );

  mRuleField->setCurrentItem( i );

  kdDebug() << aRule->function() << endl;

  //--------------set function and contents
  mRuleFunc->setCurrentItem( (int)aRule->function() );
  mRuleValue->setText( aRule->contents() );
}

KMSearchRule* KMSearchRuleWidget::rule() const
{
  KMSearchRule *r = new KMSearchRule;

  r->init( ruleFieldToEnglish( mRuleField->currentText() ),
	   (KMSearchRule::Function)mRuleFunc->currentItem(),
	   mRuleValue->text() );

  return r;
}

void KMSearchRuleWidget::reset()
{
  mRuleField->changeItem( " ", 0 );
  mRuleField->setCurrentItem( 0 );

  mRuleFunc->setCurrentItem( 0 );

  mRuleValue->clear();
}

QString KMSearchRuleWidget::ruleFieldToEnglish(const QString & i18nVal) const
{
  if (i18nVal == i18n("<To or Cc>")) return QString("<To or Cc>");
  if (i18nVal == i18n("<body>")) return QString("<body>");
  if (i18nVal == i18n("<message>")) return QString("<message>");
  if (i18nVal == i18n("<any header>")) return QString("<any header>");
  return i18nVal;
}

int KMSearchRuleWidget::indexOfRuleField(const QString aName) const
{
  int i;

  if ( aName.isEmpty() ) return -1;

  for (i=sFilterFieldList.count()-1; i>=0; i--) {
    if (*(sFilterFieldList.at(i))==i18n(aName)) break;
  }
  return i;
}

void KMSearchRuleWidget::initLists() const
{
  //---------- initialize list of filter operators
  if ( sFilterFuncList.isEmpty() )
  {
    // also see KMSearchRule::matches() and KMSearchRule::Function
    // you change the following strings!
    sFilterFuncList.append(i18n("equals"));
    sFilterFuncList.append(i18n("doesn't equal"));
    sFilterFuncList.append(i18n("contains"));
    sFilterFuncList.append(i18n("doesn't contain"));
    sFilterFuncList.append(i18n("matches regular expr."));
    sFilterFuncList.append(i18n("doesn't match reg. expr."));
  }

  //---------- initialize list of filter operators
  if ( sFilterFieldList.isEmpty() )
  {
    sFilterFieldList.append(" ");
    // also see KMSearchRule::matches() and ruleFieldToEnglish() if
    // you change the following i18n-ized strings!
    sFilterFieldList.append(i18n("<message>"));
    sFilterFieldList.append(i18n("<body>"));
    sFilterFieldList.append(i18n("<any header>"));
    sFilterFieldList.append(i18n("<To or Cc>"));
    // these others only represent meassage headers and you can add to
    // them as you like
    sFilterFieldList.append("Subject");
    sFilterFieldList.append("From");
    sFilterFieldList.append("To");
    sFilterFieldList.append("Cc");
    sFilterFieldList.append("Reply-To");
    sFilterFieldList.append("Organization");
    sFilterFieldList.append("Resent-From");
    sFilterFieldList.append("X-Loop");
  }
}

//=============================================================================
//
// class KMFilterActionWidgetLister (the filter action editor)
//
//=============================================================================

KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( QWidget *parent, const char* name )
  : KWidgetLister( 1, FILTER_MAX_RULES, parent, name )
{
  mRuleList = 0;
}

KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister()
{
}

void KMSearchRuleWidgetLister::setRuleList( QList<KMSearchRule> *aList )
{
  assert ( aList );

  if ( mRuleList )
    regenerateRuleListFromWidgets();

  mRuleList = aList;

  if ( mWidgetList.first() ) // move this below next 'if'?
    mWidgetList.first()->blockSignals(TRUE);

  if ( aList->count() == 0 ) {
    slotClear();
    mWidgetList.first()->blockSignals(FALSE);
    return;
  }

  int superfluousItems = (int)mRuleList->count() - mMaxWidgets ;
  if ( superfluousItems > 0 ) {
    kdDebug() << "KMSearchRuleWidgetLister: Clipping rule list to "
	      << mMaxWidgets << " items!" << endl;

    for ( ; superfluousItems ; superfluousItems-- )
      mRuleList->removeLast();
  }

  // set the right number of widgets
  setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets) );

  // load the actions into the widgets
  QListIterator<KMSearchRule> rIt( *mRuleList );
  QListIterator<QWidget> wIt( mWidgetList );
  for ( rIt.toFirst(), wIt.toFirst() ;
	rIt.current() && wIt.current() ; ++rIt, ++wIt ) {
    ((KMSearchRuleWidget*)(*wIt))->setRule( (*rIt) );
  }

  assert( mWidgetList.first() );
  mWidgetList.first()->blockSignals(FALSE);
}

void KMSearchRuleWidgetLister::reset()
{
  if ( mRuleList )
    regenerateRuleListFromWidgets();

  mRuleList = 0;
  slotClear();
}

QWidget* KMSearchRuleWidgetLister::createWidget( QWidget *parent )
{
  return new KMSearchRuleWidget(parent);
}

void KMSearchRuleWidgetLister::clearWidget( QWidget *aWidget )
{
  if ( aWidget )
    ((KMSearchRuleWidget*)aWidget)->reset();
}

void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets()
{
  if ( !mRuleList ) return;

  mRuleList->clear();

  QListIterator<QWidget> it( mWidgetList );
  for ( it.toFirst() ; it.current() ; ++it ) {
    KMSearchRule *r = ((KMSearchRuleWidget*)(*it))->rule();
    if ( r )
      mRuleList->append( r );
  }
}

//=============================================================================
//
// class KMSearchPatternEdit
//
//=============================================================================

KMSearchPatternEdit::KMSearchPatternEdit(QWidget *parent, const char *name )
  : QGroupBox( 1/*columns*/, Horizontal, parent, name )
{
  setTitle( i18n("Search Criteria") );
  initLayout();
}

KMSearchPatternEdit::KMSearchPatternEdit(const QString & title, QWidget *parent, const char *name )
  : QGroupBox( 1/*column*/, Horizontal, title, parent, name )
{
  initLayout();
}

KMSearchPatternEdit::~KMSearchPatternEdit()
{
}

void KMSearchPatternEdit::initLayout()
{
  //------------the radio buttons
  mAllRBtn = new QRadioButton( i18n("Match all of the following"), this, "mAllRBtn" );
  mAnyRBtn = new QRadioButton( i18n("Match any of the following"), this, "mAnyRBtn" );

  mAllRBtn->setChecked(TRUE);
  mAnyRBtn->setChecked(FALSE);

  QButtonGroup *bg = new QButtonGroup( this );
  bg->hide();
  bg->insert( mAllRBtn, (int)KMSearchPattern::OpAnd );
  bg->insert( mAnyRBtn, (int)KMSearchPattern::OpOr );

  //------------the list of KMSearchRuleWidget's
  mRuleLister = new KMSearchRuleWidgetLister( this );
  mRuleLister->slotClear();

  //------------connect a few signals
  connect( bg, SIGNAL(clicked(int)),
	   this, SLOT(slotRadioClicked(int)) );

  KMSearchRuleWidget *srw = (KMSearchRuleWidget*)mRuleLister->mWidgetList.first();
  if ( srw ) {
    connect( srw, SIGNAL(fieldChanged(const QString &)),
	     this, SLOT(slotAutoNameHack()) );
    connect( srw, SIGNAL(contentsChanged(const QString &)),
	     this, SLOT(slotAutoNameHack()) );
  } else
    kdDebug() << "KMSearchPatternEdit: no first KMSearchRuleWidget, though slotClear() has been called!" << endl;
}

void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern )
{
  assert( aPattern );

  blockSignals(TRUE);

  mRuleLister->setRuleList( aPattern );

  mPattern = aPattern;

  if ( mPattern->op() == KMSearchPattern::OpOr )
    mAnyRBtn->setChecked(TRUE);
  else
    mAllRBtn->setChecked(TRUE);

  setEnabled( TRUE );

  blockSignals(FALSE);
}

void KMSearchPatternEdit::reset()
{
  mRuleLister->reset();
  mAllRBtn->setChecked( TRUE );
  setEnabled( FALSE );
}

void KMSearchPatternEdit::slotRadioClicked(int aIdx)
{
  if ( mPattern )
    mPattern->setOp( (KMSearchPattern::Operator)aIdx );
}

void KMSearchPatternEdit::slotAutoNameHack()
{
  mRuleLister->regenerateRuleListFromWidgets();
  emit maybeNameChanged();
}
#include "kmsearchpatternedit.moc"
<commit_msg>Increase the minimum number of search rules again to 2 and fix a missing variable initialization.<commit_after>// kmfilterrulesedit.cpp
// Author: Marc Mutz <Marc@Mutz.com>
// This code is under GPL

#include "kmsearchpatternedit.h"
//#include "kmfilter.h"
//#include "kmfilterdlg.h"

#include <klocale.h>
#include <kdebug.h>
#include <kbuttonbox.h>

#include <qstring.h>
#include <qlayout.h>
#include <qradiobutton.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <qbuttongroup.h>

#include <assert.h>

static QStringList sFilterFieldList, sFilterFuncList;

//=============================================================================
//
// class KMSearchRuleWidget
//
//=============================================================================

KMSearchRuleWidget::KMSearchRuleWidget(QWidget *parent, KMSearchRule *aRule, const char *name)
  : QHBox(parent,name)
{
  kdDebug() << "KMSearchRuleWidget::KMSearchRuleWidget" << endl;
  initLists(); // sFilter{Func,Field}List are local to KMSearchRuleWidget
  initWidget();

  if ( aRule )
    setRule(aRule);
  else
    reset();
}

void KMSearchRuleWidget::initWidget()
{
  kdDebug() << "KMSearchRuleWidget::initWidget" << endl;
  //  QHBoxLayout *l = new QHBoxLayout(this,0,4); // with margin 0 and spacing 4

  setSpacing(4);

  mRuleField = new QComboBox( true, this, "mRuleField" );
  mRuleFunc = new QComboBox( false, this, "mRuleFunc" );
  mRuleValue = new QLineEdit( this, "mRuleValue" );

  mRuleFunc->insertStringList(sFilterFuncList);
  mRuleFunc->adjustSize();

  mRuleField->insertStringList(sFilterFieldList);
  mRuleField->adjustSize();

  connect( mRuleField, SIGNAL(textChanged(const QString &)),
	   this, SIGNAL(fieldChanged(const QString &)) );
  connect( mRuleValue, SIGNAL(textChanged(const QString &)),
	   this, SIGNAL(contentsChanged(const QString &)) );
}

void KMSearchRuleWidget::setRule(KMSearchRule *aRule)
{
  assert ( aRule );

  //--------------set the field
  int i = indexOfRuleField( aRule->field() );

  kdDebug() << aRule->function() << endl;

  if ( i<0 ) { // not found -> user defined field
    mRuleField->changeItem( aRule->field(), 0 );
    i=0;
  } else // found in the list of predefined fields
    mRuleField->changeItem( " ", 0 );

  mRuleField->setCurrentItem( i );

  kdDebug() << aRule->function() << endl;

  //--------------set function and contents
  mRuleFunc->setCurrentItem( (int)aRule->function() );
  mRuleValue->setText( aRule->contents() );
}

KMSearchRule* KMSearchRuleWidget::rule() const
{
  KMSearchRule *r = new KMSearchRule;

  r->init( ruleFieldToEnglish( mRuleField->currentText() ),
	   (KMSearchRule::Function)mRuleFunc->currentItem(),
	   mRuleValue->text() );

  return r;
}

void KMSearchRuleWidget::reset()
{
  mRuleField->changeItem( " ", 0 );
  mRuleField->setCurrentItem( 0 );

  mRuleFunc->setCurrentItem( 0 );

  mRuleValue->clear();
}

QString KMSearchRuleWidget::ruleFieldToEnglish(const QString & i18nVal) const
{
  if (i18nVal == i18n("<To or Cc>")) return QString("<To or Cc>");
  if (i18nVal == i18n("<body>")) return QString("<body>");
  if (i18nVal == i18n("<message>")) return QString("<message>");
  if (i18nVal == i18n("<any header>")) return QString("<any header>");
  return i18nVal;
}

int KMSearchRuleWidget::indexOfRuleField(const QString aName) const
{
  int i;

  if ( aName.isEmpty() ) return -1;

  for (i=sFilterFieldList.count()-1; i>=0; i--) {
    if (*(sFilterFieldList.at(i))==i18n(aName)) break;
  }
  return i;
}

void KMSearchRuleWidget::initLists() const
{
  //---------- initialize list of filter operators
  if ( sFilterFuncList.isEmpty() )
  {
    // also see KMSearchRule::matches() and KMSearchRule::Function
    // you change the following strings!
    sFilterFuncList.append(i18n("equals"));
    sFilterFuncList.append(i18n("doesn't equal"));
    sFilterFuncList.append(i18n("contains"));
    sFilterFuncList.append(i18n("doesn't contain"));
    sFilterFuncList.append(i18n("matches regular expr."));
    sFilterFuncList.append(i18n("doesn't match reg. expr."));
  }

  //---------- initialize list of filter operators
  if ( sFilterFieldList.isEmpty() )
  {
    sFilterFieldList.append(" ");
    // also see KMSearchRule::matches() and ruleFieldToEnglish() if
    // you change the following i18n-ized strings!
    sFilterFieldList.append(i18n("<message>"));
    sFilterFieldList.append(i18n("<body>"));
    sFilterFieldList.append(i18n("<any header>"));
    sFilterFieldList.append(i18n("<To or Cc>"));
    // these others only represent meassage headers and you can add to
    // them as you like
    sFilterFieldList.append("Subject");
    sFilterFieldList.append("From");
    sFilterFieldList.append("To");
    sFilterFieldList.append("Cc");
    sFilterFieldList.append("Reply-To");
    sFilterFieldList.append("Organization");
    sFilterFieldList.append("Resent-From");
    sFilterFieldList.append("X-Loop");
  }
}

//=============================================================================
//
// class KMFilterActionWidgetLister (the filter action editor)
//
//=============================================================================

KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( QWidget *parent, const char* name )
  : KWidgetLister( 2, FILTER_MAX_RULES, parent, name )
{
  mRuleList = 0;
}

KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister()
{
}

void KMSearchRuleWidgetLister::setRuleList( QList<KMSearchRule> *aList )
{
  assert ( aList );

  if ( mRuleList )
    regenerateRuleListFromWidgets();

  mRuleList = aList;

  if ( mWidgetList.first() ) // move this below next 'if'?
    mWidgetList.first()->blockSignals(TRUE);

  if ( aList->count() == 0 ) {
    slotClear();
    mWidgetList.first()->blockSignals(FALSE);
    return;
  }

  int superfluousItems = (int)mRuleList->count() - mMaxWidgets ;
  if ( superfluousItems > 0 ) {
    kdDebug() << "KMSearchRuleWidgetLister: Clipping rule list to "
	      << mMaxWidgets << " items!" << endl;

    for ( ; superfluousItems ; superfluousItems-- )
      mRuleList->removeLast();
  }

  // set the right number of widgets
  setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets) );

  // load the actions into the widgets
  QListIterator<KMSearchRule> rIt( *mRuleList );
  QListIterator<QWidget> wIt( mWidgetList );
  for ( rIt.toFirst(), wIt.toFirst() ;
	rIt.current() && wIt.current() ; ++rIt, ++wIt ) {
    ((KMSearchRuleWidget*)(*wIt))->setRule( (*rIt) );
  }
  for ( ; wIt.current() ; ++wIt )
    ((KMSearchRuleWidget*)(*wIt))->reset();

  assert( mWidgetList.first() );
  mWidgetList.first()->blockSignals(FALSE);
}

void KMSearchRuleWidgetLister::reset()
{
  if ( mRuleList )
    regenerateRuleListFromWidgets();

  mRuleList = 0;
  slotClear();
}

QWidget* KMSearchRuleWidgetLister::createWidget( QWidget *parent )
{
  return new KMSearchRuleWidget(parent);
}

void KMSearchRuleWidgetLister::clearWidget( QWidget *aWidget )
{
  if ( aWidget )
    ((KMSearchRuleWidget*)aWidget)->reset();
}

void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets()
{
  if ( !mRuleList ) return;

  mRuleList->clear();

  QListIterator<QWidget> it( mWidgetList );
  for ( it.toFirst() ; it.current() ; ++it ) {
    KMSearchRule *r = ((KMSearchRuleWidget*)(*it))->rule();
    if ( r )
      mRuleList->append( r );
  }
}

//=============================================================================
//
// class KMSearchPatternEdit
//
//=============================================================================

KMSearchPatternEdit::KMSearchPatternEdit(QWidget *parent, const char *name )
  : QGroupBox( 1/*columns*/, Horizontal, parent, name )
{
  setTitle( i18n("Search Criteria") );
  initLayout();
}

KMSearchPatternEdit::KMSearchPatternEdit(const QString & title, QWidget *parent, const char *name )
  : QGroupBox( 1/*column*/, Horizontal, title, parent, name )
{
  initLayout();
}

KMSearchPatternEdit::~KMSearchPatternEdit()
{
}

void KMSearchPatternEdit::initLayout()
{
  //------------the radio buttons
  mAllRBtn = new QRadioButton( i18n("Match all of the following"), this, "mAllRBtn" );
  mAnyRBtn = new QRadioButton( i18n("Match any of the following"), this, "mAnyRBtn" );

  mAllRBtn->setChecked(TRUE);
  mAnyRBtn->setChecked(FALSE);

  QButtonGroup *bg = new QButtonGroup( this );
  bg->hide();
  bg->insert( mAllRBtn, (int)KMSearchPattern::OpAnd );
  bg->insert( mAnyRBtn, (int)KMSearchPattern::OpOr );

  //------------the list of KMSearchRuleWidget's
  mRuleLister = new KMSearchRuleWidgetLister( this );
  mRuleLister->slotClear();

  //------------connect a few signals
  connect( bg, SIGNAL(clicked(int)),
	   this, SLOT(slotRadioClicked(int)) );

  KMSearchRuleWidget *srw = (KMSearchRuleWidget*)mRuleLister->mWidgetList.first();
  if ( srw ) {
    connect( srw, SIGNAL(fieldChanged(const QString &)),
	     this, SLOT(slotAutoNameHack()) );
    connect( srw, SIGNAL(contentsChanged(const QString &)),
	     this, SLOT(slotAutoNameHack()) );
  } else
    kdDebug() << "KMSearchPatternEdit: no first KMSearchRuleWidget, though slotClear() has been called!" << endl;
}

void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern )
{
  assert( aPattern );

  blockSignals(TRUE);

  mRuleLister->setRuleList( aPattern );

  mPattern = aPattern;

  if ( mPattern->op() == KMSearchPattern::OpOr )
    mAnyRBtn->setChecked(TRUE);
  else
    mAllRBtn->setChecked(TRUE);

  setEnabled( TRUE );

  blockSignals(FALSE);
}

void KMSearchPatternEdit::reset()
{
  mRuleLister->reset();
  mAllRBtn->setChecked( TRUE );
  setEnabled( FALSE );
}

void KMSearchPatternEdit::slotRadioClicked(int aIdx)
{
  if ( mPattern )
    mPattern->setOp( (KMSearchPattern::Operator)aIdx );
}

void KMSearchPatternEdit::slotAutoNameHack()
{
  mRuleLister->regenerateRuleListFromWidgets();
  emit maybeNameChanged();
}
#include "kmsearchpatternedit.moc"
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include <caf/all.hpp>

#include "vast/event.hpp"
#include "vast/logger.hpp"
#include "vast/concept/printable/std/chrono.hpp"
#include "vast/concept/printable/vast/event.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/concept/printable/vast/uuid.hpp"
#include "vast/detail/assert.hpp"
#include "vast/expression_visitors.hpp"

#include "vast/system/archive.hpp"
#include "vast/system/atoms.hpp"
#include "vast/system/exporter.hpp"

using namespace std::chrono;
using namespace std::string_literals;
using namespace caf;

namespace vast {
namespace system {

namespace {

void ship_results(stateful_actor<exporter_state>* self) {
  if (self->state.results.empty() || self->state.stats.requested == 0)
    return;
  VAST_DEBUG(self, "relays", self->state.results.size(), "events");
  message msg;
  if (self->state.results.size() <= self->state.stats.requested) {
    self->state.stats.requested -= self->state.results.size();
    self->state.stats.shipped += self->state.results.size();
    msg = make_message(std::move(self->state.results));
  } else {
    std::vector<event> remainder;
    remainder.reserve(self->state.results.size() - self->state.stats.requested);
    auto begin = self->state.results.begin() + self->state.stats.requested;
    auto end = self->state.results.end();
    std::move(begin, end, std::back_inserter(remainder));
    self->state.results.resize(self->state.stats.requested);
    msg = make_message(std::move(self->state.results));
    self->state.results = std::move(remainder);
    self->state.stats.shipped += self->state.stats.requested;
    self->state.stats.requested = 0;
  }
  self->send(self->state.sink, msg);
}

void report_statistics(stateful_actor<exporter_state>* self) {
  timespan runtime = steady_clock::now() - self->state.start;
  self->state.stats.runtime = runtime;
  VAST_DEBUG(self, "completed in", runtime);
  self->send(self->state.sink, self->state.id, self->state.stats);
  if (self->state.accountant) {
    auto hits = rank(self->state.hits);
    auto processed = self->state.stats.processed;
    auto shipped = self->state.stats.shipped;
    auto results = shipped + self->state.results.size();
    auto selectivity = double(results) / hits;
    self->send(self->state.accountant, "exporter.hits", hits);
    self->send(self->state.accountant, "exporter.processed", processed);
    self->send(self->state.accountant, "exporter.results", results);
    self->send(self->state.accountant, "exporter.shipped", shipped);
    self->send(self->state.accountant, "exporter.selectivity", selectivity);
    self->send(self->state.accountant, "exporter.runtime", runtime);
  }
}

void shutdown(stateful_actor<exporter_state>* self) {
  if (rank(self->state.unprocessed) > 0 || !self->state.results.empty()
      || has_continuous_option(self->state.options))
    return;
  report_statistics(self);
  self->send_exit(self, exit_reason::normal);
}

void request_more_hits(stateful_actor<exporter_state>* self) {
  if (!has_historical_option(self->state.options))
    return;
  auto waiting_for_hits =
    self->state.stats.received == self->state.stats.scheduled;
  auto need_more_results = self->state.stats.requested > 0;
  auto have_no_inflight_requests = any<1>(self->state.unprocessed);
  // If we're (1) no longer waiting for index hits, (2) still need more
  // results, and (3) have no inflight requests to the archive, we ask
  // the index for more hits.
  if (waiting_for_hits && need_more_results && have_no_inflight_requests) {
    auto remaining = self->state.stats.expected - self->state.stats.received;
    // TODO: Figure out right amount of partitions to ask for.
    auto n = std::min(remaining, size_t{2});
    VAST_DEBUG(self, "asks index to process", n, "more partitions");
    self->send(self->state.index, self->state.id, n);
  }
}

} // namespace <anonymous>

behavior exporter(stateful_actor<exporter_state>* self, expression expr,
                  query_options options) {
  auto eu = self->system().dummy_execution_unit();
  self->state.sink = actor_pool::make(eu, actor_pool::broadcast());
  if (auto a = self->system().registry().get(accountant_atom::value))
    self->state.accountant = actor_cast<accountant_type>(a);
  self->state.options = options;
  if (has_continuous_option(options))
    VAST_DEBUG(self, "has continuous query option");
  self->set_exit_handler(
    [=](const exit_msg& msg) {
      self->send(self->state.sink, sys_atom::value, delete_atom::value);
      self->send_exit(self->state.sink, msg.reason);
      self->quit(msg.reason);
      if (msg.reason != exit_reason::kill)
        report_statistics(self);
    }
  );
  self->set_down_handler(
    [=](const down_msg& msg) {
      VAST_DEBUG(self, "received DOWN from", msg.source);
      if (has_continuous_option(self->state.options)
          && (msg.source == self->state.archive
              || msg.source == self->state.index))
        report_statistics(self);
    }
  );
  return {
    [=](ids& hits) {
      timespan runtime = steady_clock::now() - self->state.start;
      self->state.stats.runtime = runtime;
      auto count = rank(hits);
      if (self->state.accountant) {
        if (self->state.hits.empty())
          self->send(self->state.accountant, "exporter.hits.first", runtime);
        self->send(self->state.accountant, "exporter.hits.arrived", runtime);
        self->send(self->state.accountant, "exporter.hits.count", count);
      }
      VAST_DEBUG(self, "got", count, "index hits",
                 (count == 0 ? "" : ("in ["s + to_string(select(hits, 1)) + ','
                                     + to_string(select(hits, -1) + 1) + ')')));
      if (count > 0) {
        self->state.hits |= hits;
        self->state.unprocessed |= hits;
        VAST_DEBUG(self, "forwards hits to archive");
        // FIXME: restrict according to configured limit.
        self->send(self->state.archive, std::move(hits));
      }
      // Figure out if we're done.
      ++self->state.stats.received;
      self->send(self->state.sink, self->state.id, self->state.stats);
      if (self->state.stats.received < self->state.stats.expected) {
        VAST_DEBUG(self, "received", self->state.stats.received << '/'
                                     << self->state.stats.expected, "ID sets");
        request_more_hits(self);
      } else {
        VAST_DEBUG(self, "received all", self->state.stats.expected,
                   "ID set(s) in", runtime);
        if (self->state.accountant)
          self->send(self->state.accountant, "exporter.hits.runtime", runtime);
        shutdown(self);
      }
    },
    [=](std::vector<event>& candidates) {
      VAST_DEBUG(self, "got batch of", candidates.size(), "events");
      bitmap mask;
      auto sender = self->current_sender();
      for (auto& candidate : candidates) {
        auto& checker = self->state.checkers[candidate.type()];
        // Construct a candidate checker if we don't have one for this type.
        if (is<none>(checker)) {
          auto x = tailor(expr, candidate.type());
          if (!x) {
            VAST_ERROR(self, "failed to tailor expression:",
                       self->system().render(x.error()));
            ship_results(self);
            self->send_exit(self, exit_reason::normal);
            return;
          }
          checker = std::move(*x);
          VAST_DEBUG(self, "tailored AST to", candidate.type() << ':', checker);
        }
        // Perform candidate check and keep event as result on success.
        if (visit(event_evaluator{candidate}, checker))
          self->state.results.push_back(std::move(candidate));
        else
          VAST_DEBUG(self, "ignores false positive:", candidate);
        if (sender == self->state.archive) {
          mask.append_bits(false, candidate.id() - mask.size());
          mask.append_bit(true);
        }
      }
      self->state.stats.processed += candidates.size();
      if (sender == self->state.archive)
        self->state.unprocessed -= mask;
      ship_results(self);
      request_more_hits(self);
      if (self->state.stats.received == self->state.stats.expected)
        shutdown(self);
    },
    [=](extract_atom) {
      if (self->state.stats.requested == max_events) {
        VAST_WARNING(self, "ignores extract request, already getting all");
        return;
      }
      self->state.stats.requested = max_events;
      ship_results(self);
      request_more_hits(self);
    },
    [=](extract_atom, uint64_t requested) {
      if (self->state.stats.requested == max_events) {
        VAST_WARNING(self, "ignores extract request, already getting all");
        return;
      }
      auto n = std::min(max_events - requested, requested);
      self->state.stats.requested += n;
      VAST_DEBUG(self, "got request to extract", n, "new events in addition to",
                 self->state.stats.requested, "pending results");
      ship_results(self);
      request_more_hits(self);
    },
    [=](const archive_type& archive) {
      VAST_DEBUG(self, "registers archive", archive);
      self->state.archive = archive;
      if (has_continuous_option(self->state.options))
        self->monitor(archive);
    },
    [=](index_atom, const actor& index) {
      VAST_DEBUG(self, "registers index", index);
      self->state.index = index;
      if (has_continuous_option(self->state.options))
        self->monitor(index);
    },
    [=](sink_atom, const actor& sink) {
      VAST_DEBUG(self, "registers index", sink);
      self->send(self->state.sink, sys_atom::value, put_atom::value, sink);
      self->monitor(self->state.sink);
    },
    [=](importer_atom, const std::vector<actor>& importers) {
      // Register for events at running IMPORTERs.
      if (has_continuous_option(self->state.options))
        for (auto& x : importers)
          self->send(x, exporter_atom::value, self);
    },
    [=](run_atom) {
      VAST_INFO(self, "executes query", expr);
      self->state.start = steady_clock::now();
      if (!has_historical_option(self->state.options))
        return;
      self->request(self->state.index, infinite, expr).then(
        [=](const uuid& lookup, size_t partitions, size_t scheduled) {
          VAST_DEBUG(self, "got lookup handle", lookup << ", scheduled",
                     scheduled << '/' << partitions, "partitions");
          self->state.id = lookup;
          if (partitions > 0) {
            self->state.stats.expected = partitions;
            self->state.stats.scheduled = scheduled;
          } else {
            shutdown(self);
          }
        },
        [=](const error& e) {
          VAST_IGNORE_UNUSED(e);
          VAST_DEBUG(self, "failed to lookup query at index:",
                     self->system().render(e));
        }
      );
    },
  };
}

} // namespace system
} // namespace vast
<commit_msg>Avoid duplicate reporting of statistics<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include <caf/all.hpp>

#include "vast/event.hpp"
#include "vast/logger.hpp"
#include "vast/concept/printable/std/chrono.hpp"
#include "vast/concept/printable/vast/event.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/concept/printable/vast/uuid.hpp"
#include "vast/detail/assert.hpp"
#include "vast/expression_visitors.hpp"

#include "vast/system/archive.hpp"
#include "vast/system/atoms.hpp"
#include "vast/system/exporter.hpp"

using namespace std::chrono;
using namespace std::string_literals;
using namespace caf;

namespace vast {
namespace system {

namespace {

void ship_results(stateful_actor<exporter_state>* self) {
  if (self->state.results.empty() || self->state.stats.requested == 0)
    return;
  VAST_DEBUG(self, "relays", self->state.results.size(), "events");
  message msg;
  if (self->state.results.size() <= self->state.stats.requested) {
    self->state.stats.requested -= self->state.results.size();
    self->state.stats.shipped += self->state.results.size();
    msg = make_message(std::move(self->state.results));
  } else {
    std::vector<event> remainder;
    remainder.reserve(self->state.results.size() - self->state.stats.requested);
    auto begin = self->state.results.begin() + self->state.stats.requested;
    auto end = self->state.results.end();
    std::move(begin, end, std::back_inserter(remainder));
    self->state.results.resize(self->state.stats.requested);
    msg = make_message(std::move(self->state.results));
    self->state.results = std::move(remainder);
    self->state.stats.shipped += self->state.stats.requested;
    self->state.stats.requested = 0;
  }
  self->send(self->state.sink, msg);
}

void report_statistics(stateful_actor<exporter_state>* self) {
  timespan runtime = steady_clock::now() - self->state.start;
  self->state.stats.runtime = runtime;
  VAST_DEBUG(self, "completed in", runtime);
  self->send(self->state.sink, self->state.id, self->state.stats);
  if (self->state.accountant) {
    auto hits = rank(self->state.hits);
    auto processed = self->state.stats.processed;
    auto shipped = self->state.stats.shipped;
    auto results = shipped + self->state.results.size();
    auto selectivity = double(results) / hits;
    self->send(self->state.accountant, "exporter.hits", hits);
    self->send(self->state.accountant, "exporter.processed", processed);
    self->send(self->state.accountant, "exporter.results", results);
    self->send(self->state.accountant, "exporter.shipped", shipped);
    self->send(self->state.accountant, "exporter.selectivity", selectivity);
    self->send(self->state.accountant, "exporter.runtime", runtime);
  }
}

void shutdown(stateful_actor<exporter_state>* self) {
  if (rank(self->state.unprocessed) > 0 || !self->state.results.empty()
      || has_continuous_option(self->state.options))
    return;
  self->send_exit(self, exit_reason::normal);
}

void request_more_hits(stateful_actor<exporter_state>* self) {
  if (!has_historical_option(self->state.options))
    return;
  auto waiting_for_hits =
    self->state.stats.received == self->state.stats.scheduled;
  auto need_more_results = self->state.stats.requested > 0;
  auto have_no_inflight_requests = any<1>(self->state.unprocessed);
  // If we're (1) no longer waiting for index hits, (2) still need more
  // results, and (3) have no inflight requests to the archive, we ask
  // the index for more hits.
  if (waiting_for_hits && need_more_results && have_no_inflight_requests) {
    auto remaining = self->state.stats.expected - self->state.stats.received;
    // TODO: Figure out right amount of partitions to ask for.
    auto n = std::min(remaining, size_t{2});
    VAST_DEBUG(self, "asks index to process", n, "more partitions");
    self->send(self->state.index, self->state.id, n);
  }
}

} // namespace <anonymous>

behavior exporter(stateful_actor<exporter_state>* self, expression expr,
                  query_options options) {
  auto eu = self->system().dummy_execution_unit();
  self->state.sink = actor_pool::make(eu, actor_pool::broadcast());
  if (auto a = self->system().registry().get(accountant_atom::value))
    self->state.accountant = actor_cast<accountant_type>(a);
  self->state.options = options;
  if (has_continuous_option(options))
    VAST_DEBUG(self, "has continuous query option");
  self->set_exit_handler(
    [=](const exit_msg& msg) {
      self->send(self->state.sink, sys_atom::value, delete_atom::value);
      self->send_exit(self->state.sink, msg.reason);
      self->quit(msg.reason);
      if (msg.reason != exit_reason::kill)
        report_statistics(self);
    }
  );
  self->set_down_handler(
    [=](const down_msg& msg) {
      VAST_DEBUG(self, "received DOWN from", msg.source);
      if (has_continuous_option(self->state.options)
          && (msg.source == self->state.archive
              || msg.source == self->state.index))
        report_statistics(self);
    }
  );
  return {
    [=](ids& hits) {
      timespan runtime = steady_clock::now() - self->state.start;
      self->state.stats.runtime = runtime;
      auto count = rank(hits);
      if (self->state.accountant) {
        if (self->state.hits.empty())
          self->send(self->state.accountant, "exporter.hits.first", runtime);
        self->send(self->state.accountant, "exporter.hits.arrived", runtime);
        self->send(self->state.accountant, "exporter.hits.count", count);
      }
      VAST_DEBUG(self, "got", count, "index hits",
                 (count == 0 ? "" : ("in ["s + to_string(select(hits, 1)) + ','
                                     + to_string(select(hits, -1) + 1) + ')')));
      if (count > 0) {
        self->state.hits |= hits;
        self->state.unprocessed |= hits;
        VAST_DEBUG(self, "forwards hits to archive");
        // FIXME: restrict according to configured limit.
        self->send(self->state.archive, std::move(hits));
      }
      // Figure out if we're done.
      ++self->state.stats.received;
      self->send(self->state.sink, self->state.id, self->state.stats);
      if (self->state.stats.received < self->state.stats.expected) {
        VAST_DEBUG(self, "received", self->state.stats.received << '/'
                                     << self->state.stats.expected, "ID sets");
        request_more_hits(self);
      } else {
        VAST_DEBUG(self, "received all", self->state.stats.expected,
                   "ID set(s) in", runtime);
        if (self->state.accountant)
          self->send(self->state.accountant, "exporter.hits.runtime", runtime);
        shutdown(self);
      }
    },
    [=](std::vector<event>& candidates) {
      VAST_DEBUG(self, "got batch of", candidates.size(), "events");
      bitmap mask;
      auto sender = self->current_sender();
      for (auto& candidate : candidates) {
        auto& checker = self->state.checkers[candidate.type()];
        // Construct a candidate checker if we don't have one for this type.
        if (is<none>(checker)) {
          auto x = tailor(expr, candidate.type());
          if (!x) {
            VAST_ERROR(self, "failed to tailor expression:",
                       self->system().render(x.error()));
            ship_results(self);
            self->send_exit(self, exit_reason::normal);
            return;
          }
          checker = std::move(*x);
          VAST_DEBUG(self, "tailored AST to", candidate.type() << ':', checker);
        }
        // Perform candidate check and keep event as result on success.
        if (visit(event_evaluator{candidate}, checker))
          self->state.results.push_back(std::move(candidate));
        else
          VAST_DEBUG(self, "ignores false positive:", candidate);
        if (sender == self->state.archive) {
          mask.append_bits(false, candidate.id() - mask.size());
          mask.append_bit(true);
        }
      }
      self->state.stats.processed += candidates.size();
      if (sender == self->state.archive)
        self->state.unprocessed -= mask;
      ship_results(self);
      request_more_hits(self);
      if (self->state.stats.received == self->state.stats.expected)
        shutdown(self);
    },
    [=](extract_atom) {
      if (self->state.stats.requested == max_events) {
        VAST_WARNING(self, "ignores extract request, already getting all");
        return;
      }
      self->state.stats.requested = max_events;
      ship_results(self);
      request_more_hits(self);
    },
    [=](extract_atom, uint64_t requested) {
      if (self->state.stats.requested == max_events) {
        VAST_WARNING(self, "ignores extract request, already getting all");
        return;
      }
      auto n = std::min(max_events - requested, requested);
      self->state.stats.requested += n;
      VAST_DEBUG(self, "got request to extract", n, "new events in addition to",
                 self->state.stats.requested, "pending results");
      ship_results(self);
      request_more_hits(self);
    },
    [=](const archive_type& archive) {
      VAST_DEBUG(self, "registers archive", archive);
      self->state.archive = archive;
      if (has_continuous_option(self->state.options))
        self->monitor(archive);
    },
    [=](index_atom, const actor& index) {
      VAST_DEBUG(self, "registers index", index);
      self->state.index = index;
      if (has_continuous_option(self->state.options))
        self->monitor(index);
    },
    [=](sink_atom, const actor& sink) {
      VAST_DEBUG(self, "registers index", sink);
      self->send(self->state.sink, sys_atom::value, put_atom::value, sink);
      self->monitor(self->state.sink);
    },
    [=](importer_atom, const std::vector<actor>& importers) {
      // Register for events at running IMPORTERs.
      if (has_continuous_option(self->state.options))
        for (auto& x : importers)
          self->send(x, exporter_atom::value, self);
    },
    [=](run_atom) {
      VAST_INFO(self, "executes query", expr);
      self->state.start = steady_clock::now();
      if (!has_historical_option(self->state.options))
        return;
      self->request(self->state.index, infinite, expr).then(
        [=](const uuid& lookup, size_t partitions, size_t scheduled) {
          VAST_DEBUG(self, "got lookup handle", lookup << ", scheduled",
                     scheduled << '/' << partitions, "partitions");
          self->state.id = lookup;
          if (partitions > 0) {
            self->state.stats.expected = partitions;
            self->state.stats.scheduled = scheduled;
          } else {
            shutdown(self);
          }
        },
        [=](const error& e) {
          VAST_IGNORE_UNUSED(e);
          VAST_DEBUG(self, "failed to lookup query at index:",
                     self->system().render(e));
        }
      );
    },
  };
}

} // namespace system
} // namespace vast
<|endoftext|>


<commit_before>#include "lua_class.h"
#include "../table/table.h"
#include "../util/string_enum.h"

namespace saki
{

bool isValidSuitStr(const std::string &s)
{
    return s.size() == 1 && T34::isValidSuit(s[0]);
}

std::string toLower(const char *s)
{
    std::string res(s);
    std::for_each(res.begin(), res.end(), [](char &c) {
        c = static_cast<char>(std::tolower(c));
    });
    return res;
}

std::pair<Mount::Exit, bool> parseMountExit(const std::string &s)
{
    std::pair<Mount::Exit, bool> res;

    res.second = true;
    if (s == "pii")
        res.first = Mount::Exit::PII;
    else if (s == "rinshan")
        res.first = Mount::Exit::RINSHAN;
    else if (s == "dorahyou")
        res.first = Mount::Exit::DORAHYOU;
    else if (s == "urahyou")
        res.first = Mount::Exit::URAHYOU;
    else
        res.second = false;

    return res;
}

template<typename Class, typename Ret, typename... Args>
class AsTable
{
public:
    using Method = Ret (Class::*)(Args...) const;
    using Table = sol::as_table_t<sol::meta::unqualified_t<Ret>>;

    explicit AsTable(Method method)
        : mMethod(method)
    {
    }

    Table operator()(Class &thiz, Args... args)
    {
        return sol::as_table((thiz.*mMethod)(args...));
    }

private:
    Method mMethod;
};

void setupLuaClasses(const sol::environment &env, LuaUserErrorHandler &error)
{
    setupLuaTile(env, error);
    setupLuaWho(env);
    setupLuaMeld(env, error);
    setupLuaExist(env, error);
    setupLuaMount(env, error);
    setupLuaTileCount(env, error);
    setupLuaHand(env);
    setupLuaGame(env);
}

void setupLuaTile(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<T34>(
        "T34",
        sol::meta_function::construct, sol::factories(
            [&error](int ti) {
                if (ti < 0 || ti >= 34) {
                    error.handleUserError("invalid T34 id");
                    return T34();
                }

                return T34(ti);
            },
            [&error](const std::string s) {
                static const std::array<std::string, 34> dict {
                    "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m",
                    "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p",
                    "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
                    "1f", "2f", "3f", "4f", "1y", "2y", "3y"
                };

                auto it = std::find(dict.begin(), dict.end(), s);
                if (it == dict.end()) {
                    error.handleUserError("invalid T34 string");
                    return T34();
                }

                return T34(static_cast<int>(it - dict.begin()));
            }
        ),
        "id34", &T34::id34,
        "suit", [](T34 t) { return T34::charOf(t.suit()); },
        "val", &T34::val,
        "str34", &T34::str34,
        "isz", &T34::isZ,
        "isnum", &T34::isNum,
        "isnum19", &T34::isNum19,
        "isyao", &T34::isYao,
        "isyakuhai", &T34::isYakuhai,
        "dora", &T34::dora,
        "indicator", &T34::indicator,
        sol::meta_function::to_string, &T34::str34,
        sol::meta_function::equal_to, &T34::operator==,
        sol::meta_function::less_than, &T34::operator<,
        sol::meta_function::modulus, &T34::operator%,
        "all", sol::var(std::vector<T34>(tiles34::ALL34.begin(), tiles34::ALL34.end()))
    );

    env.new_usertype<T37>(
        "T37",
        sol::meta_function::construct, sol::factories(
            [&error](int ti) {
                if (ti < 0 || ti >= 34) {
                    error.handleUserError("invalid T34 id");
                    return T37();
                }

                return T37(ti);
            },
            [&error](const std::string s) {
                if (!T37::isValidStr(s.c_str())) {
                    error.handleUserError("invalid T37 suit");
                    return T37();
                }
                return T37(s.c_str());
            }
        ),
        "isaka5", &T37::isAka5,
        "lookssame", &T37::looksSame,
        "str37", &T37::str37,
        sol::meta_function::to_string, &T37::str37,
        sol::base_classes, sol::bases<T34>()
    );
}

void setupLuaWho(sol::environment env)
{
    env.new_usertype<Who>(
        "Who",
        "right", &Who::right,
        "cross", &Who::cross,
        "left", &Who::left,
        "bydice", &Who::byDice,
        "byturn", &Who::byTurn,
        "looksat", &Who::looksAt,
        "turnfrom", &Who::turnFrom,
        "index", [](Who w) { return w.index() + 1; },
        sol::meta_function::to_string, [](Who w) { return w.index() + 1; },
        sol::meta_function::equal_to, &Who::operator==
    );
}

void setupLuaMeld(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<M37>(
        "M37",
        "type", [](const M37 &m) {
            return toLower(util::stringOf(m.type()));
        },
        "has", &M37::has,
        sol::meta_function::index, [&error](const M37 &m, int index) {
            int zeroIndex = index - 1;
            int size = static_cast<int>(m.tiles().size());
            if (zeroIndex < 0 || zeroIndex > size) {
                error.handleUserError("invalid meld index");
                return T37();
            }

            return m[index];
        }
    );
}

void setupLuaExist(sol::environment env, LuaUserErrorHandler &error)
{
    (void) error;
    env.new_usertype<Exist>(
        "Exist",
        "incmk", sol::overload(
            [](Exist &exist, T34 t, int delta) {
                exist.incMk(t, delta);
            },
            [](Exist &exist, const T37 &t, int delta) {
                exist.incMk(t, delta);
            }
        )
    );
}

void setupLuaMount(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<Mount>(
        "Mount",
        "remainpii", &Mount::remainPii,
        "remainrinshan", &Mount::remainRinshan,
        "remaina", sol::overload(
            [](Mount &mount, T34 t) {
                mount.remainA(t);
            },
            [](Mount &mount, const T37 &t) {
                mount.remainA(t);
            }
        ),
        "getdrids", AsTable(&Mount::getDrids),
        "geturids", AsTable(&Mount::getUrids),
        "lighta", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, const T37 &t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightA(t, mk);
            },
            [](Mount &mount, const T37 &t, int mk) {
                mount.lightA(t, mk);
            }
        ),
        "lightb", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightB(t, mk, rin);
            },
            [](Mount &mount, const T37 &t, int mk, bool rin) {
                mount.lightB(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightB(t, mk);
            },
            [](Mount &mount, const T37 &t, int mk) {
                mount.lightB(t, mk);
            }
        ),
        "incmk", sol::overload(
            [&error](Mount &mount, std::string exit, size_t pos, T34 t, int delta, bool bSpace) {
                auto [e, ok] = parseMountExit(exit);
                if (!ok) {
                    error.handleUserError("invalid mount exit");
                    return;
                }
                mount.incMk(e, pos, t, delta, bSpace);
            },
            [&error](Mount &mount, std::string exit, size_t pos, const T37 &t, int delta, bool bSpace) {
                auto [e, ok] = parseMountExit(exit);
                if (!ok) {
                    error.handleUserError("invalid mount exit");
                    return;
                }
                mount.incMk(e, pos, t, delta, bSpace);
            }
        ),
        "loadb", &Mount::loadB
    );
}

void setupLuaTileCount(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<TileCount>(
        "Tilecount",
        "ct", sol::overload(
            [](const TileCount &tc, T34 t) {
                return tc.ct(t);
            },
            [](const TileCount &tc, const T37 &t) {
                return tc.ct(t);
            },
            [&error](const TileCount &tc, std::string suit) {
                if (!isValidSuitStr(suit)) {
                    error.handleUserError("invalid suit");
                    return 0;
                }

                return tc.ct(T34::suitOf(suit[0]));
            }
        )
    );
}

void setupLuaHand(sol::environment env)
{
    env.new_usertype<Hand>(
        "Hand",
        "closed", &Hand::closed,
        "ct", &Hand::ct,
        "ctaka5", &Hand::ctAka5,
        "ready", &Hand::ready,
        "step", &Hand::step,
        "step4", &Hand::step4,
        "step7", &Hand::step7,
        "step7gb", &Hand::step7Gb,
        "step13", &Hand::step13,
        "effa", AsTable(&Hand::effA),
        "effa4", AsTable(&Hand::effA4),
        "ismenzen", &Hand::isMenzen,
        "barks", AsTable(&Hand::barks),
        "canchii", &Hand::canChii,
        "canchiiasleft", &Hand::canChiiAsLeft,
        "canchiiasmiddle", &Hand::canChiiAsMiddle,
        "canchiiasright", &Hand::canChiiAsRight,
        "canpon", &Hand::canPon,
        "candaiminkan", &Hand::canDaiminkan,
        sol::meta_function::modulus, sol::overload(
            [](const util::Stactor<T37, 5> &ids, const Hand &hand) {
                return ids % hand;
            },
            [](T34 indic, const Hand &hand) {
                return indic % hand;
            }
        )
    );
}

void setupLuaGame(sol::environment env)
{
    env.new_usertype<Table>(
        "Game",
        "gethand", &Table::getHand,
        "getround", &Table::getRound,
        "getextraround", &Table::getExtraRound,
        "getdealer", &Table::getDealer,
        "getselfwind", &Table::getSelfWind,
        "getroundwind", &Table::getRoundWind,
        "getriver", AsTable(&Table::getRiver),
        "riichiestablished", &Table::riichiEstablished
    );
}

sol::table toLuaTable(sol::environment env, const TableEvent &event)
{
    using TE = TableEvent;

    sol::table args = env.create();

    switch (event.type()) {
    case TE::Type::TABLE_STARTED:
        args["seed"] = event.as<TE::TableStarted>().seed;
        break;
    case TE::Type::FIRST_DEALER_CHOSEN:
        args["who"] = event.as<TE::FirstDealerChosen>().who;
        break;
    case TE::Type::ROUND_STARTED: {
        const auto &a = event.as<TE::RoundStarted>();
        args["round"] = a.round;
        args["extraround"] = a.extraRound;
        args["dealer"] = a.dealer;
        args["alllast"] = a.allLast;
        args["deposit"] = a.deposit;
        args["seed"] = a.seed;
        break;
    }
    case TE::Type::DICED: {
        const auto &a = event.as<TE::Diced>();
        args["die1"] = a.die1;
        args["die2"] = a.die2;
        break;
    }
    case TE::Type::DRAWN:
        args["who"] = event.as<TE::Drawn>().who;
        break;
    case TE::Type::DISCARDED:
        args["spin"] = event.as<TE::Discarded>().spin;
        break;
    case TE::Type::RIICHI_CALLED:
        args["who"] = event.as<TE::RiichiCalled>().who;
        break;
    case TE::Type::RIICHI_ESTABLISHED:
        args["who"] = event.as<TE::RiichiEstablished>().who;
        break;
    case TE::Type::BARKED: {
        const auto &a = event.as<TE::Barked>();
        args["who"] = a.who;
        args["bark"] = a.bark;
        args["spin"] = a.spin;
        break;
    }
    case TE::Type::ROUND_ENDED: {
        const auto &a = event.as<TE::RoundEnded>();
        args["result"] = util::stringOf(a.result);
        args["openers"] = a.openers;
        args["gunner"] = a.gunner;
        args["forms"] = a.forms;
        break;
    }
    case TE::Type::TABLE_ENDED: {
        const auto &a = event.as<TE::TableEnded>();
        args["ranks"] = a.ranks;
        args["scores"] = a.scores;
        break;
    }
    case TE::Type::POPPED_UP:
        args["who"] = event.as<TE::PoppedUp>().who;
        break;
    default:
        break;
    }

    return env.create_with(
        "type", util::stringOf(event.type()),
        "args", args
                );
}

} // namespace saki
<commit_msg>add table-based "drids % hand" to lua api<commit_after>#include "lua_class.h"
#include "../table/table.h"
#include "../util/string_enum.h"

namespace saki
{

bool isValidSuitStr(const std::string &s)
{
    return s.size() == 1 && T34::isValidSuit(s[0]);
}

std::string toLower(const char *s)
{
    std::string res(s);
    std::for_each(res.begin(), res.end(), [](char &c) {
        c = static_cast<char>(std::tolower(c));
    });
    return res;
}

std::pair<Mount::Exit, bool> parseMountExit(const std::string &s)
{
    std::pair<Mount::Exit, bool> res;

    res.second = true;
    if (s == "pii")
        res.first = Mount::Exit::PII;
    else if (s == "rinshan")
        res.first = Mount::Exit::RINSHAN;
    else if (s == "dorahyou")
        res.first = Mount::Exit::DORAHYOU;
    else if (s == "urahyou")
        res.first = Mount::Exit::URAHYOU;
    else
        res.second = false;

    return res;
}

template<typename Class, typename Ret, typename... Args>
class AsTable
{
public:
    using Method = Ret (Class::*)(Args...) const;
    using Table = sol::as_table_t<sol::meta::unqualified_t<Ret>>;

    explicit AsTable(Method method)
        : mMethod(method)
    {
    }

    Table operator()(Class &thiz, Args... args)
    {
        return sol::as_table((thiz.*mMethod)(args...));
    }

private:
    Method mMethod;
};

void setupLuaClasses(const sol::environment &env, LuaUserErrorHandler &error)
{
    setupLuaTile(env, error);
    setupLuaWho(env);
    setupLuaMeld(env, error);
    setupLuaExist(env, error);
    setupLuaMount(env, error);
    setupLuaTileCount(env, error);
    setupLuaHand(env);
    setupLuaGame(env);
}

void setupLuaTile(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<T34>(
        "T34",
        sol::meta_function::construct, sol::factories(
            [&error](int ti) {
                if (ti < 0 || ti >= 34) {
                    error.handleUserError("invalid T34 id");
                    return T34();
                }

                return T34(ti);
            },
            [&error](const std::string s) {
                static const std::array<std::string, 34> dict {
                    "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m",
                    "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p",
                    "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
                    "1f", "2f", "3f", "4f", "1y", "2y", "3y"
                };

                auto it = std::find(dict.begin(), dict.end(), s);
                if (it == dict.end()) {
                    error.handleUserError("invalid T34 string");
                    return T34();
                }

                return T34(static_cast<int>(it - dict.begin()));
            }
        ),
        "id34", &T34::id34,
        "suit", [](T34 t) { return T34::charOf(t.suit()); },
        "val", &T34::val,
        "str34", &T34::str34,
        "isz", &T34::isZ,
        "isnum", &T34::isNum,
        "isnum19", &T34::isNum19,
        "isyao", &T34::isYao,
        "isyakuhai", &T34::isYakuhai,
        "dora", &T34::dora,
        "indicator", &T34::indicator,
        sol::meta_function::to_string, &T34::str34,
        sol::meta_function::equal_to, &T34::operator==,
        sol::meta_function::less_than, &T34::operator<,
        sol::meta_function::modulus, &T34::operator%,
        "all", sol::var(std::vector<T34>(tiles34::ALL34.begin(), tiles34::ALL34.end()))
    );

    env.new_usertype<T37>(
        "T37",
        sol::meta_function::construct, sol::factories(
            [&error](int ti) {
                if (ti < 0 || ti >= 34) {
                    error.handleUserError("invalid T34 id");
                    return T37();
                }

                return T37(ti);
            },
            [&error](const std::string s) {
                if (!T37::isValidStr(s.c_str())) {
                    error.handleUserError("invalid T37 suit");
                    return T37();
                }
                return T37(s.c_str());
            }
        ),
        "isaka5", &T37::isAka5,
        "lookssame", &T37::looksSame,
        "str37", &T37::str37,
        sol::meta_function::to_string, &T37::str37,
        sol::base_classes, sol::bases<T34>()
    );
}

void setupLuaWho(sol::environment env)
{
    env.new_usertype<Who>(
        "Who",
        "right", &Who::right,
        "cross", &Who::cross,
        "left", &Who::left,
        "bydice", &Who::byDice,
        "byturn", &Who::byTurn,
        "looksat", &Who::looksAt,
        "turnfrom", &Who::turnFrom,
        "index", [](Who w) { return w.index() + 1; },
        sol::meta_function::to_string, [](Who w) { return w.index() + 1; },
        sol::meta_function::equal_to, &Who::operator==
    );
}

void setupLuaMeld(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<M37>(
        "M37",
        "type", [](const M37 &m) {
            return toLower(util::stringOf(m.type()));
        },
        "has", &M37::has,
        sol::meta_function::index, [&error](const M37 &m, int index) {
            int zeroIndex = index - 1;
            int size = static_cast<int>(m.tiles().size());
            if (zeroIndex < 0 || zeroIndex > size) {
                error.handleUserError("invalid meld index");
                return T37();
            }

            return m[index];
        }
    );
}

void setupLuaExist(sol::environment env, LuaUserErrorHandler &error)
{
    (void) error;
    env.new_usertype<Exist>(
        "Exist",
        "incmk", sol::overload(
            [](Exist &exist, T34 t, int delta) {
                exist.incMk(t, delta);
            },
            [](Exist &exist, const T37 &t, int delta) {
                exist.incMk(t, delta);
            }
        )
    );
}

void setupLuaMount(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<Mount>(
        "Mount",
        "remainpii", &Mount::remainPii,
        "remainrinshan", &Mount::remainRinshan,
        "remaina", sol::overload(
            [](Mount &mount, T34 t) {
                mount.remainA(t);
            },
            [](Mount &mount, const T37 &t) {
                mount.remainA(t);
            }
        ),
        "getdrids", AsTable(&Mount::getDrids),
        "geturids", AsTable(&Mount::getUrids),
        "lighta", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, const T37 &t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightA(t, mk);
            },
            [](Mount &mount, const T37 &t, int mk) {
                mount.lightA(t, mk);
            }
        ),
        "lightb", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightB(t, mk, rin);
            },
            [](Mount &mount, const T37 &t, int mk, bool rin) {
                mount.lightB(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightB(t, mk);
            },
            [](Mount &mount, const T37 &t, int mk) {
                mount.lightB(t, mk);
            }
        ),
        "incmk", sol::overload(
            [&error](Mount &mount, std::string exit, size_t pos, T34 t, int delta, bool bSpace) {
                auto [e, ok] = parseMountExit(exit);
                if (!ok) {
                    error.handleUserError("invalid mount exit");
                    return;
                }
                mount.incMk(e, pos, t, delta, bSpace);
            },
            [&error](Mount &mount, std::string exit, size_t pos, const T37 &t, int delta, bool bSpace) {
                auto [e, ok] = parseMountExit(exit);
                if (!ok) {
                    error.handleUserError("invalid mount exit");
                    return;
                }
                mount.incMk(e, pos, t, delta, bSpace);
            }
        ),
        "loadb", &Mount::loadB
    );
}

void setupLuaTileCount(sol::environment env, LuaUserErrorHandler &error)
{
    env.new_usertype<TileCount>(
        "Tilecount",
        "ct", sol::overload(
            [](const TileCount &tc, T34 t) {
                return tc.ct(t);
            },
            [](const TileCount &tc, const T37 &t) {
                return tc.ct(t);
            },
            [&error](const TileCount &tc, std::string suit) {
                if (!isValidSuitStr(suit)) {
                    error.handleUserError("invalid suit");
                    return 0;
                }

                return tc.ct(T34::suitOf(suit[0]));
            }
        )
    );
}

void setupLuaHand(sol::environment env)
{
    env.new_usertype<Hand>(
        "Hand",
        "closed", &Hand::closed,
        "ct", &Hand::ct,
        "ctaka5", &Hand::ctAka5,
        "ready", &Hand::ready,
        "step", &Hand::step,
        "step4", &Hand::step4,
        "step7", &Hand::step7,
        "step7gb", &Hand::step7Gb,
        "step13", &Hand::step13,
        "effa", AsTable(&Hand::effA),
        "effa4", AsTable(&Hand::effA4),
        "ismenzen", &Hand::isMenzen,
        "barks", AsTable(&Hand::barks),
        "canchii", &Hand::canChii,
        "canchiiasleft", &Hand::canChiiAsLeft,
        "canchiiasmiddle", &Hand::canChiiAsMiddle,
        "canchiiasright", &Hand::canChiiAsRight,
        "canpon", &Hand::canPon,
        "candaiminkan", &Hand::canDaiminkan,
        sol::meta_function::modulus, sol::overload(
            [](sol::table ids, const Hand &hand) {
                int ct = 0;
                for (auto [key, ref] : ids) {
                    (void) ref; // conv-to-opt doesn't work somehow

                    std::optional<T34> id;
                    id = ids[key];
                    if (id == std::nullopt) {
                        std::optional<T37> id37 = ids[key];
                        id = id37;
                    }

                    if (id != std::nullopt)
                        ct += *id % hand;
                }

                return ct;
            },
            [](T34 indic, const Hand &hand) {
                return indic % hand;
            }
        )
    );
}

void setupLuaGame(sol::environment env)
{
    env.new_usertype<Table>(
        "Game",
        "gethand", &Table::getHand,
        "getround", &Table::getRound,
        "getextraround", &Table::getExtraRound,
        "getdealer", &Table::getDealer,
        "getselfwind", &Table::getSelfWind,
        "getroundwind", &Table::getRoundWind,
        "getriver", AsTable(&Table::getRiver),
        "riichiestablished", &Table::riichiEstablished
    );
}

sol::table toLuaTable(sol::environment env, const TableEvent &event)
{
    using TE = TableEvent;

    sol::table args = env.create();

    switch (event.type()) {
    case TE::Type::TABLE_STARTED:
        args["seed"] = event.as<TE::TableStarted>().seed;
        break;
    case TE::Type::FIRST_DEALER_CHOSEN:
        args["who"] = event.as<TE::FirstDealerChosen>().who;
        break;
    case TE::Type::ROUND_STARTED: {
        const auto &a = event.as<TE::RoundStarted>();
        args["round"] = a.round;
        args["extraround"] = a.extraRound;
        args["dealer"] = a.dealer;
        args["alllast"] = a.allLast;
        args["deposit"] = a.deposit;
        args["seed"] = a.seed;
        break;
    }
    case TE::Type::DICED: {
        const auto &a = event.as<TE::Diced>();
        args["die1"] = a.die1;
        args["die2"] = a.die2;
        break;
    }
    case TE::Type::DRAWN:
        args["who"] = event.as<TE::Drawn>().who;
        break;
    case TE::Type::DISCARDED:
        args["spin"] = event.as<TE::Discarded>().spin;
        break;
    case TE::Type::RIICHI_CALLED:
        args["who"] = event.as<TE::RiichiCalled>().who;
        break;
    case TE::Type::RIICHI_ESTABLISHED:
        args["who"] = event.as<TE::RiichiEstablished>().who;
        break;
    case TE::Type::BARKED: {
        const auto &a = event.as<TE::Barked>();
        args["who"] = a.who;
        args["bark"] = a.bark;
        args["spin"] = a.spin;
        break;
    }
    case TE::Type::ROUND_ENDED: {
        const auto &a = event.as<TE::RoundEnded>();
        args["result"] = util::stringOf(a.result);
        args["openers"] = a.openers;
        args["gunner"] = a.gunner;
        args["forms"] = a.forms;
        break;
    }
    case TE::Type::TABLE_ENDED: {
        const auto &a = event.as<TE::TableEnded>();
        args["ranks"] = a.ranks;
        args["scores"] = a.scores;
        break;
    }
    case TE::Type::POPPED_UP:
        args["who"] = event.as<TE::PoppedUp>().who;
        break;
    default:
        break;
    }

    return env.create_with(
        "type", util::stringOf(event.type()),
        "args", args
                );
}

} // namespace saki
<|endoftext|>


<commit_before>//===- X86MacroFusion.cpp - X86 Macro Fusion ------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file This file contains the X86 implementation of the DAG scheduling
/// mutation to pair instructions back to back.
//
//===----------------------------------------------------------------------===//

#include "X86MacroFusion.h"
#include "X86Subtarget.h"
#include "llvm/CodeGen/MacroFusion.h"
#include "llvm/CodeGen/TargetInstrInfo.h"

using namespace llvm;

/// Check if the instr pair, FirstMI and SecondMI, should be fused
/// together. Given SecondMI, when FirstMI is unspecified, then check if
/// SecondMI may be part of a fused pair at all.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
                                   const TargetSubtargetInfo &TSI,
                                   const MachineInstr *FirstMI,
                                   const MachineInstr &SecondMI) {
  const X86Subtarget &ST = static_cast<const X86Subtarget&>(TSI);
  // Check if this processor supports macro-fusion.
  if (!ST.hasMacroFusion())
    return false;

  enum {
    FuseTest,
    FuseCmp,
    FuseInc
  } FuseKind;

  unsigned FirstOpcode = FirstMI
                         ? FirstMI->getOpcode()
                         : static_cast<unsigned>(X86::INSTRUCTION_LIST_END);
  unsigned SecondOpcode = SecondMI.getOpcode();

  switch (SecondOpcode) {
  default:
    return false;
  case X86::JE_1:
  case X86::JNE_1:
  case X86::JL_1:
  case X86::JLE_1:
  case X86::JG_1:
  case X86::JGE_1:
    FuseKind = FuseInc;
    break;
  case X86::JB_1:
  case X86::JBE_1:
  case X86::JA_1:
  case X86::JAE_1:
    FuseKind = FuseCmp;
    break;
  case X86::JS_1:
  case X86::JNS_1:
  case X86::JP_1:
  case X86::JNP_1:
  case X86::JO_1:
  case X86::JNO_1:
    FuseKind = FuseTest;
    break;
  }

  switch (FirstOpcode) {
  default:
    return false;
  case X86::TEST8rr:
  case X86::TEST16rr:
  case X86::TEST32rr:
  case X86::TEST64rr:
  case X86::TEST8ri:
  case X86::TEST16ri:
  case X86::TEST32ri:
  case X86::TEST32i32:
  case X86::TEST64i32:
  case X86::TEST64ri32:
  case X86::TEST8mr:
  case X86::TEST16mr:
  case X86::TEST32mr:
  case X86::TEST64mr:
  case X86::AND16i16:
  case X86::AND16ri:
  case X86::AND16ri8:
  case X86::AND16rm:
  case X86::AND16rr:
  case X86::AND32i32:
  case X86::AND32ri:
  case X86::AND32ri8:
  case X86::AND32rm:
  case X86::AND32rr:
  case X86::AND64i32:
  case X86::AND64ri32:
  case X86::AND64ri8:
  case X86::AND64rm:
  case X86::AND64rr:
  case X86::AND8i8:
  case X86::AND8ri:
  case X86::AND8rm:
  case X86::AND8rr:
    return true;
  case X86::CMP16i16:
  case X86::CMP16ri:
  case X86::CMP16ri8:
  case X86::CMP16rm:
  case X86::CMP16rr:
  case X86::CMP16mr:
  case X86::CMP32i32:
  case X86::CMP32ri:
  case X86::CMP32ri8:
  case X86::CMP32rm:
  case X86::CMP32rr:
  case X86::CMP32mr:
  case X86::CMP64i32:
  case X86::CMP64ri32:
  case X86::CMP64ri8:
  case X86::CMP64rm:
  case X86::CMP64rr:
  case X86::CMP64mr:
  case X86::CMP8i8:
  case X86::CMP8ri:
  case X86::CMP8rm:
  case X86::CMP8rr:
  case X86::CMP8mr:
  case X86::ADD16i16:
  case X86::ADD16ri:
  case X86::ADD16ri8:
  case X86::ADD16ri8_DB:
  case X86::ADD16ri_DB:
  case X86::ADD16rm:
  case X86::ADD16rr:
  case X86::ADD16rr_DB:
  case X86::ADD32i32:
  case X86::ADD32ri:
  case X86::ADD32ri8:
  case X86::ADD32ri8_DB:
  case X86::ADD32ri_DB:
  case X86::ADD32rm:
  case X86::ADD32rr:
  case X86::ADD32rr_DB:
  case X86::ADD64i32:
  case X86::ADD64ri32:
  case X86::ADD64ri32_DB:
  case X86::ADD64ri8:
  case X86::ADD64ri8_DB:
  case X86::ADD64rm:
  case X86::ADD64rr:
  case X86::ADD64rr_DB:
  case X86::ADD8i8:
  case X86::ADD8ri:
  case X86::ADD8rm:
  case X86::ADD8rr:
  case X86::SUB16i16:
  case X86::SUB16ri:
  case X86::SUB16ri8:
  case X86::SUB16rm:
  case X86::SUB16rr:
  case X86::SUB32i32:
  case X86::SUB32ri:
  case X86::SUB32ri8:
  case X86::SUB32rm:
  case X86::SUB32rr:
  case X86::SUB64i32:
  case X86::SUB64ri32:
  case X86::SUB64ri8:
  case X86::SUB64rm:
  case X86::SUB64rr:
  case X86::SUB8i8:
  case X86::SUB8ri:
  case X86::SUB8rm:
  case X86::SUB8rr:
    return FuseKind == FuseCmp || FuseKind == FuseInc;
  case X86::INC16r:
  case X86::INC32r:
  case X86::INC64r:
  case X86::INC8r:
  case X86::DEC16r:
  case X86::DEC32r:
  case X86::DEC64r:
  case X86::DEC8r:
    return FuseKind == FuseInc;
  case X86::INSTRUCTION_LIST_END:
    return true;
  }
}

namespace llvm {

std::unique_ptr<ScheduleDAGMutation>
createX86MacroFusionDAGMutation () {
  return createBranchMacroFusionDAGMutation(shouldScheduleAdjacent);
}

} // end namespace llvm
<commit_msg>[X86] Remove the AL/AX/EAX/RAX short immediate forms from the macro fusion shouldScheduleAdjacent. NFC<commit_after>//===- X86MacroFusion.cpp - X86 Macro Fusion ------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file This file contains the X86 implementation of the DAG scheduling
/// mutation to pair instructions back to back.
//
//===----------------------------------------------------------------------===//

#include "X86MacroFusion.h"
#include "X86Subtarget.h"
#include "llvm/CodeGen/MacroFusion.h"
#include "llvm/CodeGen/TargetInstrInfo.h"

using namespace llvm;

/// Check if the instr pair, FirstMI and SecondMI, should be fused
/// together. Given SecondMI, when FirstMI is unspecified, then check if
/// SecondMI may be part of a fused pair at all.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
                                   const TargetSubtargetInfo &TSI,
                                   const MachineInstr *FirstMI,
                                   const MachineInstr &SecondMI) {
  const X86Subtarget &ST = static_cast<const X86Subtarget&>(TSI);
  // Check if this processor supports macro-fusion.
  if (!ST.hasMacroFusion())
    return false;

  enum {
    FuseTest,
    FuseCmp,
    FuseInc
  } FuseKind;

  unsigned FirstOpcode = FirstMI
                         ? FirstMI->getOpcode()
                         : static_cast<unsigned>(X86::INSTRUCTION_LIST_END);
  unsigned SecondOpcode = SecondMI.getOpcode();

  switch (SecondOpcode) {
  default:
    return false;
  case X86::JE_1:
  case X86::JNE_1:
  case X86::JL_1:
  case X86::JLE_1:
  case X86::JG_1:
  case X86::JGE_1:
    FuseKind = FuseInc;
    break;
  case X86::JB_1:
  case X86::JBE_1:
  case X86::JA_1:
  case X86::JAE_1:
    FuseKind = FuseCmp;
    break;
  case X86::JS_1:
  case X86::JNS_1:
  case X86::JP_1:
  case X86::JNP_1:
  case X86::JO_1:
  case X86::JNO_1:
    FuseKind = FuseTest;
    break;
  }

  switch (FirstOpcode) {
  default:
    return false;
  case X86::TEST8rr:
  case X86::TEST16rr:
  case X86::TEST32rr:
  case X86::TEST64rr:
  case X86::TEST8ri:
  case X86::TEST16ri:
  case X86::TEST32ri:
  case X86::TEST64ri32:
  case X86::TEST8mr:
  case X86::TEST16mr:
  case X86::TEST32mr:
  case X86::TEST64mr:
  case X86::AND16ri:
  case X86::AND16ri8:
  case X86::AND16rm:
  case X86::AND16rr:
  case X86::AND32ri:
  case X86::AND32ri8:
  case X86::AND32rm:
  case X86::AND32rr:
  case X86::AND64ri32:
  case X86::AND64ri8:
  case X86::AND64rm:
  case X86::AND64rr:
  case X86::AND8ri:
  case X86::AND8rm:
  case X86::AND8rr:
    return true;
  case X86::CMP16ri:
  case X86::CMP16ri8:
  case X86::CMP16rm:
  case X86::CMP16rr:
  case X86::CMP16mr:
  case X86::CMP32ri:
  case X86::CMP32ri8:
  case X86::CMP32rm:
  case X86::CMP32rr:
  case X86::CMP32mr:
  case X86::CMP64ri32:
  case X86::CMP64ri8:
  case X86::CMP64rm:
  case X86::CMP64rr:
  case X86::CMP64mr:
  case X86::CMP8ri:
  case X86::CMP8rm:
  case X86::CMP8rr:
  case X86::CMP8mr:
  case X86::ADD16ri:
  case X86::ADD16ri8:
  case X86::ADD16ri8_DB:
  case X86::ADD16ri_DB:
  case X86::ADD16rm:
  case X86::ADD16rr:
  case X86::ADD16rr_DB:
  case X86::ADD32ri:
  case X86::ADD32ri8:
  case X86::ADD32ri8_DB:
  case X86::ADD32ri_DB:
  case X86::ADD32rm:
  case X86::ADD32rr:
  case X86::ADD32rr_DB:
  case X86::ADD64ri32:
  case X86::ADD64ri32_DB:
  case X86::ADD64ri8:
  case X86::ADD64ri8_DB:
  case X86::ADD64rm:
  case X86::ADD64rr:
  case X86::ADD64rr_DB:
  case X86::ADD8ri:
  case X86::ADD8rm:
  case X86::ADD8rr:
  case X86::SUB16ri:
  case X86::SUB16ri8:
  case X86::SUB16rm:
  case X86::SUB16rr:
  case X86::SUB32ri:
  case X86::SUB32ri8:
  case X86::SUB32rm:
  case X86::SUB32rr:
  case X86::SUB64ri32:
  case X86::SUB64ri8:
  case X86::SUB64rm:
  case X86::SUB64rr:
  case X86::SUB8ri:
  case X86::SUB8rm:
  case X86::SUB8rr:
    return FuseKind == FuseCmp || FuseKind == FuseInc;
  case X86::INC16r:
  case X86::INC32r:
  case X86::INC64r:
  case X86::INC8r:
  case X86::DEC16r:
  case X86::DEC32r:
  case X86::DEC64r:
  case X86::DEC8r:
    return FuseKind == FuseInc;
  case X86::INSTRUCTION_LIST_END:
    return true;
  }
}

namespace llvm {

std::unique_ptr<ScheduleDAGMutation>
createX86MacroFusionDAGMutation () {
  return createBranchMacroFusionDAGMutation(shouldScheduleAdjacent);
}

} // end namespace llvm
<|endoftext|>


<commit_before>//
//  R2000DataReader.cpp
//  R2000DataReader
//
//  Created by inx on 20/12/15.
//
//

#include "ofxR2000DataReader.h"

#include <zlib.h>

static int sps[] = {25200, 16800, 12600, 10080, 8400, 7200, 6300, 5600, 5040, 4200, 3600, 2400, 1800, 1440, 1200, 900, 800, 720, 600, 480, 450, 400, 360, 240, 180, 144, 120, 90, 72};
static int sps_size = sizeof(sps) / sizeof(int);

/*
 */
static void zipuncompress_uint32( const std::vector< unsigned char > & src, std::vector< std::uint32_t > & ret )
{
	if ( src.size() < 4 ) {
		ret.clear();
		return;
	}

	/// load header (size of compressed buffer)
	uLongf originalSize = 0;
	{
		originalSize += ( src[0] << 24 );
		originalSize += ( src[1] << 16 );
		originalSize += ( src[2] <<  8 );
		originalSize += ( src[3] <<  0 );
	}

	ret.resize( originalSize, 0 );
	unsigned long ret_size = originalSize * sizeof(std::uint32_t);
	{
		// try to uncompress with sizeof( uLongf )
		int error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeof( uLongf ), src.size() );

		if ( error == Z_OK )
		{
			ret.resize( ret_size / sizeof(std::uint32_t), 0 );
		}
		else
		{
			// failed... try with other uLongSize...
			int error = Z_OK;

			if (sizeof(uLongf) == 4) {
				// try with uLongF size 8
				uint8_t sizeOfULongf = 8;
				error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeOfULongf, src.size() );

			} else if (sizeof(uLongf) == 8) {
				// try with uLongF size 4
				uint8_t sizeOfULongf = 4;
				error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeOfULongf, src.size() );
			}

			if ( error == Z_OK )
			{
				ret.resize( ret_size / sizeof(std::uint32_t), 0 );
			} else {
				ofLogError( "zipuncompress_uint32()" ) << "zlib uncompress() error: " << error;
				ret.clear();
			}
		}
	}
}

/*
 */
R2000DataReader::R2000DataReader() :
	dataStart(0)
	,count(0)
	,samplesPerScan(0)
	,scanFrequency(0)
	,updateTime(0)
	,lastUpdate(0)
{}

R2000DataReader::R2000DataReader(string& filepath) : R2000DataReader() {

	bool ret = load(filepath);
}

R2000DataReader::R2000DataReader(ofFile& file) : R2000DataReader() {
	load(file);
}

R2000DataReader::~R2000DataReader() {
	infile.close();
}

bool R2000DataReader::load(const char* filepath) {
	string p(filepath);
	return load(p);
}

bool R2000DataReader::load(string& filepath) {

	bool ret = infile.open(filepath);

	if (ret){
		initRead();
	}

	return ret;
}

void R2000DataReader::load(ofFile& file) {
	infile = file;
	initRead();
}

void R2000DataReader::initRead() {

	if (!infile.isFile()) {
		return;
	}

	uint8_t readSize;

	infile.read((char*)&readSize, sizeof(uint8_t));
	infile.read((char*)&samplesPerScan, readSize);

	infile.read((char*)&readSize, sizeof(uint8_t));
	infile.read((char*)&scanFrequency, readSize);

	//----------------------------------------
	// check values
	bool correctValue = false;
	for (int j=0; j<sps_size; j++) {
		if (samplesPerScan == sps[j]) {
			correctValue = true;
			break;
		}
	}

	if (scanFrequency < 10 || scanFrequency > 50) {
		correctValue = false;
	}

	if (!correctValue) {
		ofLogError() << "not a correct value";
		OF_EXIT_APP(-1);
	}

	lastScanData.distance_data.resize(samplesPerScan);
	lastScanData.amplitude_data.resize(samplesPerScan);

	//----------------------------------------
	updateTime = 1000.0 / (double)scanFrequency;
	dataStart = infile.tellg();
	lastUpdate = ofGetElapsedTimeMillis() - updateTime;
}

bool R2000DataReader::update() {

	bool newScan = false;

	if ((double)(ofGetElapsedTimeMillis() - lastUpdate) >= updateTime) {

		lastUpdate = ofGetElapsedTimeMillis();

		bool doCompress = false;

		uint8_t readSize;
		std::uint32_t vectorSize;

		//----------------------------------------------------
		// get count
		infile.read((char*)&readSize, sizeof(uint8_t));
		// check for eof, assume that data is alligned
		if (infile.eof()) {
			infile.clear();
			infile.seekg(dataStart);

			// read byte again
			infile.read((char*)&readSize, sizeof(uint8_t));
		}
		infile.read((char*)&count, readSize);

		//----------------------------------------------------
		// distance data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress) {
			std::vector<unsigned char> data;
			data.resize(vectorSize);
			infile.read((char*)data.data(), vectorSize);

			ofLogNotice() << "uncompress distance data: " << vectorSize;

			zipuncompress_uint32(data, lastScanData.distance_data);

			// correct
			vectorSize = lastScanData.distance_data.size();
		} else {
			if (lastScanData.distance_data.size() != vectorSize) {
				ofLogNotice() << "resize distance vector";
				lastScanData.distance_data.resize(vectorSize);
			}
			infile.read((char*)lastScanData.distance_data.data(), (vectorSize * sizeof(std::uint32_t)));
		}

		//----------------------------------------------------
		// amplitude data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress) {
			std::vector<unsigned char> data;
			data.resize(vectorSize);
			infile.read((char*)data.data(), vectorSize);

			ofLogNotice() << "uncompress amplitude data: " << vectorSize;

			zipuncompress_uint32(data, lastScanData.amplitude_data);
			// correct
			vectorSize = lastScanData.amplitude_data.size();
		} else {
			if (lastScanData.amplitude_data.size() != vectorSize) {
				ofLogNotice() << "resize amplitude vector";
				lastScanData.amplitude_data.resize(vectorSize);
			}
			infile.read((char*)lastScanData.amplitude_data.data(), (vectorSize * sizeof(std::uint32_t)));
		}

		//----------------------------------------------------
		// header data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress || !doCompress) {
			if (lastScanData.headers.size() != vectorSize) {
				lastScanData.headers.resize(vectorSize);
			}
			infile.read((char*)lastScanData.headers.data(), (vectorSize * sizeof(PacketHeader)));
		}
		//		ofLogNotice() << "HEADERS: " << vectorSize;

		newScan = true;
	}

	return newScan;
}<commit_msg>remove logs<commit_after>//
//  R2000DataReader.cpp
//  R2000DataReader
//
//  Created by inx on 20/12/15.
//
//

#include "ofxR2000DataReader.h"

#include <zlib.h>

static int sps[] = {25200, 16800, 12600, 10080, 8400, 7200, 6300, 5600, 5040, 4200, 3600, 2400, 1800, 1440, 1200, 900, 800, 720, 600, 480, 450, 400, 360, 240, 180, 144, 120, 90, 72};
static int sps_size = sizeof(sps) / sizeof(int);

/*
 */
static void zipuncompress_uint32( const std::vector< unsigned char > & src, std::vector< std::uint32_t > & ret )
{
	if ( src.size() < 4 ) {
		ret.clear();
		return;
	}

	/// load header (size of compressed buffer)
	uLongf originalSize = 0;
	{
		originalSize += ( src[0] << 24 );
		originalSize += ( src[1] << 16 );
		originalSize += ( src[2] <<  8 );
		originalSize += ( src[3] <<  0 );
	}

	ret.resize( originalSize, 0 );
	unsigned long ret_size = originalSize * sizeof(std::uint32_t);
	{
		// try to uncompress with sizeof( uLongf )
		int error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeof( uLongf ), src.size() );

		if ( error == Z_OK )
		{
			ret.resize( ret_size / sizeof(std::uint32_t), 0 );
		}
		else
		{
			// failed... try with other uLongSize...
			int error = Z_OK;

			if (sizeof(uLongf) == 4) {
				// try with uLongF size 8
				uint8_t sizeOfULongf = 8;
				error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeOfULongf, src.size() );

			} else if (sizeof(uLongf) == 8) {
				// try with uLongF size 4
				uint8_t sizeOfULongf = 4;
				error = uncompress( (unsigned char*)ret.data(), &ret_size, src.data() + sizeOfULongf, src.size() );
			}

			if ( error == Z_OK )
			{
				ret.resize( ret_size / sizeof(std::uint32_t), 0 );
			} else {
				ofLogError( "zipuncompress_uint32()" ) << "zlib uncompress() error: " << error;
				ret.clear();
			}
		}
	}
}

/*
 */
R2000DataReader::R2000DataReader() :
	dataStart(0)
	,count(0)
	,samplesPerScan(0)
	,scanFrequency(0)
	,updateTime(0)
	,lastUpdate(0)
{}

R2000DataReader::R2000DataReader(string& filepath) : R2000DataReader() {

	bool ret = load(filepath);
}

R2000DataReader::R2000DataReader(ofFile& file) : R2000DataReader() {
	load(file);
}

R2000DataReader::~R2000DataReader() {
	infile.close();
}

bool R2000DataReader::load(const char* filepath) {
	string p(filepath);
	return load(p);
}

bool R2000DataReader::load(string& filepath) {

	bool ret = infile.open(filepath);

	if (ret){
		initRead();
	}

	return ret;
}

void R2000DataReader::load(ofFile& file) {
	infile = file;
	initRead();
}

void R2000DataReader::initRead() {

	if (!infile.isFile()) {
		return;
	}

	uint8_t readSize;

	infile.read((char*)&readSize, sizeof(uint8_t));
	infile.read((char*)&samplesPerScan, readSize);

	infile.read((char*)&readSize, sizeof(uint8_t));
	infile.read((char*)&scanFrequency, readSize);

	//----------------------------------------
	// check values
	bool correctValue = false;
	for (int j=0; j<sps_size; j++) {
		if (samplesPerScan == sps[j]) {
			correctValue = true;
			break;
		}
	}

	if (scanFrequency < 10 || scanFrequency > 50) {
		correctValue = false;
	}

	if (!correctValue) {
		ofLogError() << "not a correct value";
		OF_EXIT_APP(-1);
	}

	lastScanData.distance_data.resize(samplesPerScan);
	lastScanData.amplitude_data.resize(samplesPerScan);

	//----------------------------------------
	updateTime = 1000.0 / (double)scanFrequency;
	dataStart = infile.tellg();
	lastUpdate = ofGetElapsedTimeMillis() - updateTime;
}

bool R2000DataReader::update() {

	bool newScan = false;

	if ((double)(ofGetElapsedTimeMillis() - lastUpdate) >= updateTime) {

		lastUpdate = ofGetElapsedTimeMillis();

		bool doCompress = false;

		uint8_t readSize;
		std::uint32_t vectorSize;

		//----------------------------------------------------
		// get count
		infile.read((char*)&readSize, sizeof(uint8_t));
		// check for eof, assume that data is alligned
		if (infile.eof()) {
			infile.clear();
			infile.seekg(dataStart);

			// read byte again
			infile.read((char*)&readSize, sizeof(uint8_t));
		}
		infile.read((char*)&count, readSize);

		//----------------------------------------------------
		// distance data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress) {
			std::vector<unsigned char> data;
			data.resize(vectorSize);
			infile.read((char*)data.data(), vectorSize);

			zipuncompress_uint32(data, lastScanData.distance_data);

			// correct
			vectorSize = lastScanData.distance_data.size();
		} else {
			if (lastScanData.distance_data.size() != vectorSize) {
				ofLogNotice() << "resize distance vector";
				lastScanData.distance_data.resize(vectorSize);
			}
			infile.read((char*)lastScanData.distance_data.data(), (vectorSize * sizeof(std::uint32_t)));
		}

		//----------------------------------------------------
		// amplitude data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress) {
			std::vector<unsigned char> data;
			data.resize(vectorSize);
			infile.read((char*)data.data(), vectorSize);

			zipuncompress_uint32(data, lastScanData.amplitude_data);
			// correct
			vectorSize = lastScanData.amplitude_data.size();
		} else {
			if (lastScanData.amplitude_data.size() != vectorSize) {
				ofLogNotice() << "resize amplitude vector";
				lastScanData.amplitude_data.resize(vectorSize);
			}
			infile.read((char*)lastScanData.amplitude_data.data(), (vectorSize * sizeof(std::uint32_t)));
		}

		//----------------------------------------------------
		// header data

		// compression-flag
		infile.read((char*)&doCompress, 1);

		infile.read((char*)&readSize, sizeof(uint8_t));
		infile.read((char*)&vectorSize, readSize);
		if (doCompress || !doCompress) {
			if (lastScanData.headers.size() != vectorSize) {
				lastScanData.headers.resize(vectorSize);
			}
			infile.read((char*)lastScanData.headers.data(), (vectorSize * sizeof(PacketHeader)));
		}
		//		ofLogNotice() << "HEADERS: " << vectorSize;

		newScan = true;
	}

	return newScan;
}<|endoftext|>


<commit_before>#include "memory.hpp"
#include <new>
#include <atomic>

namespace warpcoil
{
    namespace
    {
        std::atomic<std::uint64_t> allocation_counter;
    }

    std::uint64_t number_of_allocations()
    {
        return allocation_counter.load();
    }
}

void *operator new(std::size_t count)
{
    ++warpcoil::allocation_counter;
    return std::malloc(count);
}

void *operator new[](std::size_t count)
{
    ++warpcoil::allocation_counter;
    return std::malloc(count);
}

void operator delete(void *ptr)
{
    std::free(ptr);
}

void operator delete[](void *ptr)
{
    std::free(ptr);
}
<commit_msg>#include for GCC<commit_after>#include "memory.hpp"
#include <new>
#include <atomic>
#include <cstdlib>

namespace warpcoil
{
    namespace
    {
        std::atomic<std::uint64_t> allocation_counter;
    }

    std::uint64_t number_of_allocations()
    {
        return allocation_counter.load();
    }
}

void *operator new(std::size_t count)
{
    ++warpcoil::allocation_counter;
    return std::malloc(count);
}

void *operator new[](std::size_t count)
{
    ++warpcoil::allocation_counter;
    return std::malloc(count);
}

void operator delete(void *ptr)
{
    std::free(ptr);
}

void operator delete[](void *ptr)
{
    std::free(ptr);
}
<|endoftext|>