<commit_before>/*
 *  This file is part of the KDE libraries
 *  Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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 GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 */
#include "kautoconfig.h"

#include <kglobal.h>
#include <qsqlpropertymap.h>
#include <qobjectlist.h>
#include <kconfig.h>
#include <kapplication.h>

/**
 * Macro function to warn developers when they are making calls
 * that can never return anything of value
 */
#ifndef NDEBUG
#include "kdebug.h"
#define functionCallOrderCheck(functionName, returnValue) \
  if(!d->retrievedSettings){ \
      kdDebug(180) << "KAutoConfig::"functionName"() was called before " \
      "KAutoConfig::retrieveSettings().  This should NEVER happen.  " \
      "Please Fix." << endl; \
    return returnValue; \
  }
#else
#define functionCallOrderCheck(functionName, returnValue)
#endif

class KAutoConfig::KAutoConfigPrivate {

public:
  KAutoConfigPrivate() : changed(false)
#ifndef NDEBUG
    , retrievedSettings(false)
#endif
  { init(); }

  // Widgets to parse
  QPtrList<QWidget> widgets;
  // Name of the group that KConfig should be set to for each widget.
  QMap<QWidget*, QString> groups;

  // Child widgets of widgets to ignore
  QPtrList<QWidget> ignore;

  // Reset to false after saveSettings returns true.
  bool changed;

#ifndef NDEBUG
  // Many functions require this to be true to be of any value.
  bool retrievedSettings;
#endif

  // Known widgets that can be configured
  QMap<QWidget*, QPtrList<QWidget> > autoWidgets;
  // Default values for the widgets.
  QMap<QWidget*, QVariant> defaultValues;
  // Widgets to not get properties on (QLabel etc)
  QAsciiDict<int> ignoreTheseWidgets;

  void init(){
    ignoreTheseWidgets.insert("QLabel", new int(1));
    ignoreTheseWidgets.insert("QFrame", new int(2));
    ignoreTheseWidgets.insert("QGroupBox", new int(3));
    ignoreTheseWidgets.insert("QButtonGroup", new int(4));
    ignoreTheseWidgets.insert("QWidget", new int(5));
    ignoreTheseWidgets.setAutoDelete(true);

    static bool defaultKDEPropertyMapInstalled = false;
    if ( !defaultKDEPropertyMapInstalled && kapp ) {
      kapp->installKDEPropertyMap();
      defaultKDEPropertyMapInstalled = true;
    }
  }
};

KAutoConfig::KAutoConfig(KConfig *kconfig, QObject *parent,
    const char *name) : QObject(parent, name), config(kconfig) {
  d = new KAutoConfigPrivate();
}

KAutoConfig::KAutoConfig(QObject *parent, const char *name) :
    QObject(parent, name), config(KGlobal::config()) {
  d = new KAutoConfigPrivate();
}

KAutoConfig::~KAutoConfig(){
  delete d;
}

void KAutoConfig::addWidget(QWidget *widget, const QString &group){
  d->groups.insert(widget, group);
  d->widgets.append(widget);
  QPtrList<QWidget> newAutoConfigWidget;
  d->autoWidgets.insert(widget, newAutoConfigWidget );
}

void KAutoConfig::ignoreSubWidget(QWidget *widget){
  d->ignore.append(widget);
}

bool KAutoConfig::retrieveSettings(bool trackChanges){
#ifndef NDEBUG
  if(d->retrievedSettings){
      kdDebug(180) << "This should not happen.  Function "
       "KAutoConfig::retrieveSettings() was called more then once, returning "
       "false.  Please fix." << endl;
    return false;
  }
  d->retrievedSettings = true;
#endif

  if(trackChanges){
    // QT
    changedMap.insert("QButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QCheckBox", SIGNAL(stateChanged(int)));
    changedMap.insert("QPushButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QRadioButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QComboBox", SIGNAL(activated (int)));
    //qsqlproperty map doesn't store the text, but the value!
    //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &)));
    changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &)));
    changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &)));
    changedMap.insert("QDial", SIGNAL(valueChanged (int)));
    changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert("QSlider", SIGNAL(valueChanged(int)));
    changedMap.insert("QSpinBox", SIGNAL(valueChanged(int)));
    changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &)));
    changedMap.insert("QTextEdit", SIGNAL(textChanged()));
    changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &)));
    changedMap.insert("QMultiLineEdit", SIGNAL(textChanged()));
    changedMap.insert("QListBox", SIGNAL(selectionChanged()));
    changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *)));

    // KDE
    changedMap.insert( "KComboBox", SIGNAL(activated (int)));
    changedMap.insert( "KFontCombo", SIGNAL(activated (int)));
    changedMap.insert( "KFontRequester", SIGNAL(fontSelected(const QFont &)));
    changedMap.insert( "KFontChooser",  SIGNAL(fontSelected(const QFont &)));
    changedMap.insert( "KHistoryCombo", SIGNAL(activated (int)));

    changedMap.insert( "KColorButton", SIGNAL(changed(const QColor &)));
    changedMap.insert( "KDatePicker", SIGNAL(dateSelected (QDate)));
    changedMap.insert( "KEditListBox", SIGNAL(changed()));
    changedMap.insert( "KListBox", SIGNAL(selectionChanged()));
    changedMap.insert( "KLineEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KPasswordEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KRestrictedLine", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &)));
    changedMap.insert( "KTextEdit", SIGNAL(textChanged()));
    changedMap.insert( "KURLRequester",  SIGNAL(textChanged (const QString& )));
    changedMap.insert( "KIntNumInput", SIGNAL(valueChanged (int)));
    changedMap.insert( "KIntSpinBox", SIGNAL(valueChanged (int)));
    changedMap.insert( "KDoubleNumInput", SIGNAL(valueChanged (double)));
  }

  // Go through all of the children of the widgets and find all known widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  bool usingDefaultValues = false;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    usingDefaultValues |= parseChildren(widget, d->autoWidgets[widget], trackChanges);
  }
  return usingDefaultValues;
}

bool KAutoConfig::saveSettings() {
  functionCallOrderCheck("saveSettings", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);

    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    bool widgetChanged = false;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);

      if(!config->hasDefault(groupWidget->name()) && currentValue == defaultValue){
        config->revertToDefault(groupWidget->name());
        widgetChanged = true;
      }
      else{
        QVariant savedValue = config->readPropertyEntry(groupWidget->name(),
                                                             defaultValue);
        if(savedValue != currentValue){
          config->writeEntry(groupWidget->name(), currentValue);
          widgetChanged = true;
        }
      }
    }
    d->changed |= widgetChanged;
    if(widgetChanged)
      emit( settingsChanged(widget) );
  }

  if(d->changed){
    emit( settingsChanged() );
    d->changed = false;
    config->sync();
    return true;
  }
  return false;
}

bool KAutoConfig::hasChanged() const {
  functionCallOrderCheck("hasChanged", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);
      QVariant savedValue = config->readPropertyEntry(groupWidget->name(),
      defaultValue);

      // Return once just one item is found to have changed.
      if((currentValue == defaultValue && savedValue != currentValue) ||
         (savedValue != currentValue))
        return true;
    }
  }
  return false;
}

bool KAutoConfig::isDefault() const {
  functionCallOrderCheck("isDefault", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);
      if(currentValue != defaultValue){
        //qDebug("groupWidget %s, has changed: default: %s new: %s", groupWidget->name(), defaultValue.toString().latin1(), currentValue.toString().latin1());
        return false;
      }
    }
  }
  return true;
}

void KAutoConfig::resetSettings() const {
  functionCallOrderCheck("resetSettings",);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);

    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      if(defaultValue != propertyMap->property(groupWidget)){
        propertyMap->setProperty(groupWidget, defaultValue);
        d->changed = true;
      }
    }
  }
}

void KAutoConfig::reloadSettings() const {
  functionCallOrderCheck("reloadSettings", );

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *pageWidget;
  while ( (pageWidget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[pageWidget]);

    // Go through the known widgets of this page and reload
    QPtrListIterator<QWidget> it( d->autoWidgets[pageWidget] );
    QWidget *widget;
    while ( (widget = it.current()) != 0 ){
      ++it;
      QVariant defaultSetting = d->defaultValues[widget];
      QVariant setting =
        config->readPropertyEntry(widget->name(), defaultSetting);
      propertyMap->setProperty(widget, setting);
    }
  }
  d->changed = false;
}

bool KAutoConfig::parseChildren(const QWidget *widget,
    QPtrList<QWidget>& currentGroup, bool trackChanges){
  bool valueChanged = false;
  const QPtrList<QObject> *listOfChildren = widget->children();
  if(!listOfChildren)
    return valueChanged;

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  QPtrListIterator<QObject> it( *listOfChildren );
  QObject *object;
  while ( (object = it.current()) != 0 )
  {
    ++it;
    if(!object->isWidgetType()){
      continue;
    }
    QWidget *childWidget = (QWidget *)object;
    if(d->ignore.containsRef(childWidget)){
      continue;
    }

    bool parseTheChildren = true;
    if( d->ignoreTheseWidgets[childWidget->className()] == 0 &&
      childWidget->name(0) != NULL )
    {
      QVariant defaultSetting = propertyMap->property(childWidget);
      if(defaultSetting.isValid())
      {
        parseTheChildren = false;
        // Disable the widget if it is immutable?
        if(config->entryIsImmutable( childWidget->name()))
          childWidget->setEnabled(false);
        else
        {
          // FOR THOSE WHO ARE LOOKING
          // Here is the code were the widget is actually marked to watch.
          //qDebug("KAutoConfig: Adding widget(%s)",childWidget->name());
          currentGroup.append(childWidget);
          d->defaultValues.insert(childWidget, defaultSetting);
        }
        // Get/Set settings and connect up the changed signal
        QVariant setting =
         config->readPropertyEntry(childWidget->name(), defaultSetting);
        if(setting != defaultSetting)
        {
          propertyMap->setProperty(childWidget, setting);
          valueChanged = true;
        }
        if(trackChanges && changedMap.find(childWidget->className()) !=
            changedMap.end())
        {
          connect(childWidget, changedMap[childWidget->className()],
                  this, SIGNAL(widgetModified()));
        }
#ifndef NDEBUG
        else if(trackChanges &&
          changedMap.find(childWidget->className()) == changedMap.end())
        {
          kdDebug(180) << "KAutoConfig::retrieveSettings, Unknown changed "
           "signal for widget:" << childWidget->className() << endl;
        }
#endif

      }
#ifndef NDEBUG
      else
      {
          kdDebug(180) << "KAutoConfig::retrieveSettings, Unknown widget:"
           << childWidget->className() << endl;
      }
#endif
    }
    if(parseTheChildren)
    {
      // this widget is not known as something we can store.
      // Maybe we can store one of its children.
      valueChanged |= parseChildren(childWidget, currentGroup, trackChanges);
    }
  }
  return valueChanged;
}

#include "kautoconfig.moc"

<commit_msg>compilation in kde 3.1<commit_after>/*
 *  This file is part of the KDE libraries
 *  Copyright (C) 2003 Benjamin C Meyer (ben+kdelibs at meyerhome dot net)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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 GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 */
#include "kautoconfig.h"

#include <kglobal.h>
#include <qsqlpropertymap.h>
#include <qobjectlist.h>
#include <kconfig.h>
#include <kapplication.h>
#include <kdeversion.h>

/**
 * Macro function to warn developers when they are making calls
 * that can never return anything of value
 */
#ifndef NDEBUG
#include "kdebug.h"
#define functionCallOrderCheck(functionName, returnValue) \
  if(!d->retrievedSettings){ \
      kdDebug(180) << "KAutoConfig::"functionName"() was called before " \
      "KAutoConfig::retrieveSettings().  This should NEVER happen.  " \
      "Please Fix." << endl; \
    return returnValue; \
  }
#else
#define functionCallOrderCheck(functionName, returnValue)
#endif

class KAutoConfig::KAutoConfigPrivate {

public:
  KAutoConfigPrivate() : changed(false)
#ifndef NDEBUG
    , retrievedSettings(false)
#endif
  { init(); }

  // Widgets to parse
  QPtrList<QWidget> widgets;
  // Name of the group that KConfig should be set to for each widget.
  QMap<QWidget*, QString> groups;

  // Child widgets of widgets to ignore
  QPtrList<QWidget> ignore;

  // Reset to false after saveSettings returns true.
  bool changed;

#ifndef NDEBUG
  // Many functions require this to be true to be of any value.
  bool retrievedSettings;
#endif

  // Known widgets that can be configured
  QMap<QWidget*, QPtrList<QWidget> > autoWidgets;
  // Default values for the widgets.
  QMap<QWidget*, QVariant> defaultValues;
  // Widgets to not get properties on (QLabel etc)
  QAsciiDict<int> ignoreTheseWidgets;

  void init(){
    ignoreTheseWidgets.insert("QLabel", new int(1));
    ignoreTheseWidgets.insert("QFrame", new int(2));
    ignoreTheseWidgets.insert("QGroupBox", new int(3));
    ignoreTheseWidgets.insert("QButtonGroup", new int(4));
    ignoreTheseWidgets.insert("QWidget", new int(5));
    ignoreTheseWidgets.setAutoDelete(true);

    static bool defaultKDEPropertyMapInstalled = false;
    if ( !defaultKDEPropertyMapInstalled && kapp ) {
      kapp->installKDEPropertyMap();
      defaultKDEPropertyMapInstalled = true;
    }
  }
};

KAutoConfig::KAutoConfig(KConfig *kconfig, QObject *parent,
    const char *name) : QObject(parent, name), config(kconfig) {
  d = new KAutoConfigPrivate();
}

KAutoConfig::KAutoConfig(QObject *parent, const char *name) :
    QObject(parent, name), config(KGlobal::config()) {
  d = new KAutoConfigPrivate();
}

KAutoConfig::~KAutoConfig(){
  delete d;
}

void KAutoConfig::addWidget(QWidget *widget, const QString &group){
  d->groups.insert(widget, group);
  d->widgets.append(widget);
  QPtrList<QWidget> newAutoConfigWidget;
  d->autoWidgets.insert(widget, newAutoConfigWidget );
}

void KAutoConfig::ignoreSubWidget(QWidget *widget){
  d->ignore.append(widget);
}

bool KAutoConfig::retrieveSettings(bool trackChanges){
#ifndef NDEBUG
  if(d->retrievedSettings){
      kdDebug(180) << "This should not happen.  Function "
       "KAutoConfig::retrieveSettings() was called more then once, returning "
       "false.  Please fix." << endl;
    return false;
  }
  d->retrievedSettings = true;
#endif

  if(trackChanges){
    // QT
    changedMap.insert("QButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QCheckBox", SIGNAL(stateChanged(int)));
    changedMap.insert("QPushButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QRadioButton", SIGNAL(stateChanged(int)));
    changedMap.insert("QComboBox", SIGNAL(activated (int)));
    //qsqlproperty map doesn't store the text, but the value!
    //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &)));
    changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &)));
    changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &)));
    changedMap.insert("QDial", SIGNAL(valueChanged (int)));
    changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert("QSlider", SIGNAL(valueChanged(int)));
    changedMap.insert("QSpinBox", SIGNAL(valueChanged(int)));
    changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &)));
    changedMap.insert("QTextEdit", SIGNAL(textChanged()));
    changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &)));
    changedMap.insert("QMultiLineEdit", SIGNAL(textChanged()));
    changedMap.insert("QListBox", SIGNAL(selectionChanged()));
    changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *)));

    // KDE
    changedMap.insert( "KComboBox", SIGNAL(activated (int)));
    changedMap.insert( "KFontCombo", SIGNAL(activated (int)));
    changedMap.insert( "KFontRequester", SIGNAL(fontSelected(const QFont &)));
    changedMap.insert( "KFontChooser",  SIGNAL(fontSelected(const QFont &)));
    changedMap.insert( "KHistoryCombo", SIGNAL(activated (int)));

    changedMap.insert( "KColorButton", SIGNAL(changed(const QColor &)));
    changedMap.insert( "KDatePicker", SIGNAL(dateSelected (QDate)));
    changedMap.insert( "KEditListBox", SIGNAL(changed()));
    changedMap.insert( "KListBox", SIGNAL(selectionChanged()));
    changedMap.insert( "KLineEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KPasswordEdit", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KRestrictedLine", SIGNAL(textChanged(const QString &)));
    changedMap.insert( "KTextBrowser", SIGNAL(sourceChanged(const QString &)));
    changedMap.insert( "KTextEdit", SIGNAL(textChanged()));
    changedMap.insert( "KURLRequester",  SIGNAL(textChanged (const QString& )));
    changedMap.insert( "KIntNumInput", SIGNAL(valueChanged (int)));
    changedMap.insert( "KIntSpinBox", SIGNAL(valueChanged (int)));
    changedMap.insert( "KDoubleNumInput", SIGNAL(valueChanged (double)));
  }

  // Go through all of the children of the widgets and find all known widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  bool usingDefaultValues = false;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    usingDefaultValues |= parseChildren(widget, d->autoWidgets[widget], trackChanges);
  }
  return usingDefaultValues;
}

bool KAutoConfig::saveSettings() {
  functionCallOrderCheck("saveSettings", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);

    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    bool widgetChanged = false;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);
#if KDE_IS_VERSION( 3, 1, 90 )
      if(!config->hasDefault(groupWidget->name()) && currentValue == defaultValue){
        config->revertToDefault(groupWidget->name());
        widgetChanged = true;
      }
      else{
#endif
        QVariant savedValue = config->readPropertyEntry(groupWidget->name(),
                                                             defaultValue);
        if(savedValue != currentValue){
          config->writeEntry(groupWidget->name(), currentValue);
          widgetChanged = true;
        }
#if KDE_IS_VERSION( 3, 1, 90 )
      }
#endif
    }
    d->changed |= widgetChanged;
    if(widgetChanged)
      emit( settingsChanged(widget) );
  }

  if(d->changed){
    emit( settingsChanged() );
    d->changed = false;
    config->sync();
    return true;
  }
  return false;
}

bool KAutoConfig::hasChanged() const {
  functionCallOrderCheck("hasChanged", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);
      QVariant savedValue = config->readPropertyEntry(groupWidget->name(),
      defaultValue);

      // Return once just one item is found to have changed.
      if((currentValue == defaultValue && savedValue != currentValue) ||
         (savedValue != currentValue))
        return true;
    }
  }
  return false;
}

bool KAutoConfig::isDefault() const {
  functionCallOrderCheck("isDefault", false);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);
    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      QVariant currentValue = propertyMap->property(groupWidget);
      if(currentValue != defaultValue){
        //qDebug("groupWidget %s, has changed: default: %s new: %s", groupWidget->name(), defaultValue.toString().latin1(), currentValue.toString().latin1());
        return false;
      }
    }
  }
  return true;
}

void KAutoConfig::resetSettings() const {
  functionCallOrderCheck("resetSettings",);

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *widget;
  while ( (widget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[widget]);

    // Go through the known autowidgets of this widget and save
    QPtrListIterator<QWidget> it( d->autoWidgets[widget] );
    QWidget *groupWidget;
    while ( (groupWidget = it.current()) != 0 ){
      ++it;
      QVariant defaultValue = d->defaultValues[groupWidget];
      if(defaultValue != propertyMap->property(groupWidget)){
        propertyMap->setProperty(groupWidget, defaultValue);
        d->changed = true;
      }
    }
  }
}

void KAutoConfig::reloadSettings() const {
  functionCallOrderCheck("reloadSettings", );

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  // Go through all of the widgets
  QPtrListIterator<QWidget> it( d->widgets );
  QWidget *pageWidget;
  while ( (pageWidget = it.current()) != 0 ) {
    ++it;
    config->setGroup(d->groups[pageWidget]);

    // Go through the known widgets of this page and reload
    QPtrListIterator<QWidget> it( d->autoWidgets[pageWidget] );
    QWidget *widget;
    while ( (widget = it.current()) != 0 ){
      ++it;
      QVariant defaultSetting = d->defaultValues[widget];
      QVariant setting =
        config->readPropertyEntry(widget->name(), defaultSetting);
      propertyMap->setProperty(widget, setting);
    }
  }
  d->changed = false;
}

bool KAutoConfig::parseChildren(const QWidget *widget,
    QPtrList<QWidget>& currentGroup, bool trackChanges){
  bool valueChanged = false;
  const QPtrList<QObject> *listOfChildren = widget->children();
  if(!listOfChildren)
    return valueChanged;

  QSqlPropertyMap *propertyMap = QSqlPropertyMap::defaultMap();
  QPtrListIterator<QObject> it( *listOfChildren );
  QObject *object;
  while ( (object = it.current()) != 0 )
  {
    ++it;
    if(!object->isWidgetType()){
      continue;
    }
    QWidget *childWidget = (QWidget *)object;
    if(d->ignore.containsRef(childWidget)){
      continue;
    }

    bool parseTheChildren = true;
    if( d->ignoreTheseWidgets[childWidget->className()] == 0 &&
      childWidget->name(0) != NULL )
    {
      QVariant defaultSetting = propertyMap->property(childWidget);
      if(defaultSetting.isValid())
      {
        parseTheChildren = false;
        // Disable the widget if it is immutable?
        if(config->entryIsImmutable( childWidget->name()))
          childWidget->setEnabled(false);
        else
        {
          // FOR THOSE WHO ARE LOOKING
          // Here is the code were the widget is actually marked to watch.
          //qDebug("KAutoConfig: Adding widget(%s)",childWidget->name());
          currentGroup.append(childWidget);
          d->defaultValues.insert(childWidget, defaultSetting);
        }
        // Get/Set settings and connect up the changed signal
        QVariant setting =
         config->readPropertyEntry(childWidget->name(), defaultSetting);
        if(setting != defaultSetting)
        {
          propertyMap->setProperty(childWidget, setting);
          valueChanged = true;
        }
        if(trackChanges && changedMap.find(childWidget->className()) !=
            changedMap.end())
        {
          connect(childWidget, changedMap[childWidget->className()],
                  this, SIGNAL(widgetModified()));
        }
#ifndef NDEBUG
        else if(trackChanges &&
          changedMap.find(childWidget->className()) == changedMap.end())
        {
          kdDebug(180) << "KAutoConfig::retrieveSettings, Unknown changed "
           "signal for widget:" << childWidget->className() << endl;
        }
#endif

      }
#ifndef NDEBUG
      else
      {
          kdDebug(180) << "KAutoConfig::retrieveSettings, Unknown widget:"
           << childWidget->className() << endl;
      }
#endif
    }
    if(parseTheChildren)
    {
      // this widget is not known as something we can store.
      // Maybe we can store one of its children.
      valueChanged |= parseChildren(childWidget, currentGroup, trackChanges);
    }
  }
  return valueChanged;
}

#include "kautoconfig.moc"

<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 <sstream>
#include <stdexcept>
#include <sys/stat.h>

#include <ament_index_cpp/get_search_paths.hpp>

#ifdef _WIN32
#define stat _stat
#endif

namespace ament_index_cpp
{

std::list<std::string>
get_search_paths()
{
  char * ament_prefix_path = nullptr;
  const char * env_var = "AMENT_PREFIX_PATH";

  // get environment variable
#ifndef _WIN32
  ament_prefix_path = getenv(env_var);
#else
  size_t ament_prefix_path_size;
  _dupenv_s(&ament_prefix_path, &ament_prefix_path_size, env_var);
#endif
  if (!ament_prefix_path || std::string(ament_prefix_path).empty()) {
    throw std::runtime_error("Environment variable 'AMENT_PREFIX_PATH' is not set or empty");
  }

  // split at token into separate paths
  std::list<std::string> paths;
  std::stringstream ss(ament_prefix_path);
  std::string tok;
#ifndef _WIN32
  char delim = ':';
#else
  char delim = ';';
#endif
  while (getline(ss, tok, delim)) {
    // skip non existing directories
    struct stat s;
    auto retcode = stat(tok.c_str(), &s);
    if (retcode) {
      continue;
    }
#ifndef _WIN32
    if (!S_ISDIR(s.st_mode)) {
#else
    if (s.st_mode & _S_IFDIR) {
#endif
      continue;
    }

    paths.push_back(tok);
  }

#ifdef _WIN32
  if (ament_prefix_path) {
    free(ament_prefix_path);
  }
#endif

  return paths;
}

}  // namespace
<commit_msg>fix directory check on Windows<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 <sstream>
#include <stdexcept>
#include <sys/stat.h>

#include <ament_index_cpp/get_search_paths.hpp>

#ifdef _WIN32
#define stat _stat
#endif

namespace ament_index_cpp
{

std::list<std::string>
get_search_paths()
{
  char * ament_prefix_path = nullptr;
  const char * env_var = "AMENT_PREFIX_PATH";

  // get environment variable
#ifndef _WIN32
  ament_prefix_path = getenv(env_var);
#else
  size_t ament_prefix_path_size;
  _dupenv_s(&ament_prefix_path, &ament_prefix_path_size, env_var);
#endif
  if (!ament_prefix_path || std::string(ament_prefix_path).empty()) {
    throw std::runtime_error("Environment variable 'AMENT_PREFIX_PATH' is not set or empty");
  }

  // split at token into separate paths
  std::list<std::string> paths;
  std::stringstream ss(ament_prefix_path);
  std::string tok;
#ifndef _WIN32
  char delim = ':';
#else
  char delim = ';';
#endif
  while (getline(ss, tok, delim)) {
    if (tok.empty()) {
      continue;
    }
    // skip non existing directories
    struct stat s;
    if (stat(tok.c_str(), &s)) {
      continue;
    }
    if ((s.st_mode & S_IFMT) == S_IFDIR) {
      paths.push_back(tok);
    }
  }

#ifdef _WIN32
  if (ament_prefix_path) {
    free(ament_prefix_path);
  }
#endif

  return paths;
}

}  // namespace
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#ifdef INTEL_MKL

#define EIGEN_USE_THREADS

#include "mkldnn.hpp"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/type_traits.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/graph/mkl_graph_util.h"
#include "tensorflow/core/kernels/meta_support.h"
#include "tensorflow/core/kernels/quantization_utils.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/util/mkl_util.h"

using mkldnn::primitive_attr;
using mkldnn::stream;

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T>
class MklDequantizeOp : public OpKernel {
 public:
  explicit MklDequantizeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    string mode_string;
    OP_REQUIRES_OK(ctx, ctx->GetAttr("mode", &mode_string));
    OP_REQUIRES(ctx, mode_string == "SCALED",
                errors::InvalidArgument(
                    "MklDequantizeOp only supports 'SCALED' mode, but got '" +
                    mode_string + "'"));
  }

  void Compute(OpKernelContext* ctx) override {
    try {
      // Using CPU device
      auto cpu_engine = engine(engine::kind::cpu, 0);

      // Get the inputs
      const Tensor& src_tensor = MklGetInput(ctx, kSrcIndex);
      const float min_range =
          MklGetInput(ctx, kMinIndex).template flat<float>()(0);
      const float max_range =
          MklGetInput(ctx, kMaxIndex).template flat<float>()(0);

      // Get MklShape
      MklDnnShape src_mkl_shape;
      GetMklShape(ctx, kSrcIndex, &src_mkl_shape);

      // src_dims is the dimension of src_tensor
      // output_dims are same as src_dims
      auto src_dims = src_mkl_shape.IsMklTensor()
                          ? src_mkl_shape.GetSizesAsMklDnnDims()
                          : TFShapeToMklDnnDims(src_tensor.shape());
      auto output_dims = src_dims;

      // Create reorder memory for src and dst
      MklDnnData<T> src(&cpu_engine);
      MklDnnData<float> dst(&cpu_engine);

      std::shared_ptr<stream> reorder_stream;
      reorder_stream.reset(CreateStream(ctx, cpu_engine));

      // If input is in MKL layout, then simply grab input layout; otherwise,
      // construct input TF layout. For TF layout, although input shape
      // (src_dims) required is in MKL-DNN order, the layout is Tensorflow's
      // layout
      auto src_md = src_mkl_shape.IsMklTensor()
                        ? src_mkl_shape.GetMklLayout()
                        : memory::desc(src_dims, MklDnnType<T>(),
                                       src_dims.size() == 4 ? MEMORY_FORMAT::nhwc : MEMORY_FORMAT::nc);

      src.SetUsrMem(src_md, &src_tensor);
      src.SetUsrMemDataHandle(&src_tensor, reorder_stream);

      Tensor* output_tensor = nullptr;
      MklDnnShape output_mkl_shape;
      TensorShape output_tf_shape;
      memory::desc dst_md = memory::desc();
      if (src_mkl_shape.IsMklTensor()) {
        dst_md = memory::desc(src_mkl_shape.GetMklLayout().data);
        // There is no API in MKL-DNN v1.x to construct memory descriptor with
        // same .data field but different type.
        dst_md.data.data_type = memory::convert_to_c(MklDnnType<float>());
      } else {
        dst_md = memory::desc(src_dims, MklDnnType<float>(),
                              src_dims.size() == 4 ? MEMORY_FORMAT::nhwc : MEMORY_FORMAT::nc);
      }

      // If input is MKL shape, output is also MKL shape.
      // If input is TF shape, output is also TF shape.
      if (src_mkl_shape.IsMklTensor()) {
        output_mkl_shape.SetMklTensor(true);
        output_mkl_shape.SetMklLayout(&dst_md);
        output_mkl_shape.SetElemType(MklDnnType<float>());
        output_mkl_shape.SetTfLayout(src_mkl_shape.GetDimension(),
                                     src_mkl_shape.GetSizesAsMklDnnDims(),
                                     src_mkl_shape.GetTfDataFormat());
        output_tf_shape.AddDim(dst_md.get_size() / sizeof(float));
      } else {
        output_mkl_shape.SetMklTensor(false);
        output_tf_shape = MklDnnDimsToTFShape(output_dims);
      }

      // Allocate MKL or TF output shape based on the above
      AllocateOutputSetMklShape(ctx, 0, &output_tensor, output_tf_shape,
                                output_mkl_shape);
      dst.SetUsrMem(dst_md, output_tensor);
      dst.SetUsrMemDataHandle(output_tensor, reorder_stream);

      // The quantization logic here for mode SCALED is similar to the logic
      // in QuantizeAndDequantizeV2 and QuantizeAndDequantizeV3.
      static constexpr int num_bits = sizeof(T) * 8;
      const float max_abs = std::max(std::abs(min_range), std::abs(max_range));
      bool is_signed = std::is_signed<T>::value;
      // If it is signed, we try to keep 0.0 being 0 and drop one bucket. For
      // example, if it is 8 bits, we have the range [-127, 127]. So for input
      // range of [-x, x], the scale should be (2*x)/254.
      //
      // If it is unsigned and num_bits == 8, the range with 8 bits is [0, 255].
      // If the input range is [0, x], then the scale is x/255 instead of 254 as
      // in the case above.
      const int target_bits = is_signed ? (num_bits - 1) : num_bits;
      const float target_range =
          static_cast<float>((uint64_t{1} << target_bits) - 1);
      const float scale_factor = max_abs / target_range;
      std::vector<float> scales;
      scales.push_back(scale_factor);
      primitive_attr attr;
      attr.set_output_scales(0, scales);
      std::vector<primitive> net;

      // Create reorder primitive and then execute.
      auto reorder_pd =
          ReorderPd(cpu_engine, src.GetUsrMem()->get_desc(), cpu_engine,
                    dst.GetUsrMem()->get_desc(), attr);
      net.push_back(reorder(reorder_pd));
      std::vector<std::unordered_map<int, memory>> reorder_net_args;
      reorder_net_args.push_back({{MKLDNN_ARG_FROM, *src.GetUsrMem()},
                                  {MKLDNN_ARG_TO, *dst.GetUsrMem()}});
      execute_primitives(net, reorder_stream, reorder_net_args);
    } catch (mkldnn::error& e) {
      string error_msg = "Status: " + std::to_string(e.status) +
                         ", message: " + string(e.message) + ", in file " +
                         string(__FILE__) + ":" + std::to_string(__LINE__);
      OP_REQUIRES_OK(
          ctx, errors::Aborted("Operation received an exception:", error_msg));
    }
  }

 private:
  const size_t kSrcIndex = 0;
  const size_t kMinIndex = 1;
  const size_t kMaxIndex = 2;
};

REGISTER_KERNEL_BUILDER(Name("_MklDequantize")
                            .Device(DEVICE_CPU)
                            .TypeConstraint<quint8>("T")
                            .Label(mkl_op_registry::kMklQuantizedOpLabel),
                        MklDequantizeOp<CPUDevice, quint8>);
REGISTER_KERNEL_BUILDER(Name("_MklDequantize")
                            .Device(DEVICE_CPU)
                            .TypeConstraint<qint8>("T")
                            .Label(mkl_op_registry::kMklQuantizedOpLabel),
                        MklDequantizeOp<CPUDevice, qint8>);

}  // namespace tensorflow

#endif  // INTEL_MKL
<commit_msg>cleaning<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#ifdef INTEL_MKL

#define EIGEN_USE_THREADS

#include "mkldnn.hpp"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/type_traits.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/graph/mkl_graph_util.h"
#include "tensorflow/core/kernels/meta_support.h"
#include "tensorflow/core/kernels/quantization_utils.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/util/mkl_util.h"

using mkldnn::primitive_attr;
using mkldnn::stream;

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T>
class MklDequantizeOp : public OpKernel {
 public:
  explicit MklDequantizeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    string mode_string;
    OP_REQUIRES_OK(ctx, ctx->GetAttr("mode", &mode_string));
    OP_REQUIRES(ctx, mode_string == "SCALED",
                errors::InvalidArgument(
                    "MklDequantizeOp only supports 'SCALED' mode, but got '" +
                    mode_string + "'"));
  }

  void Compute(OpKernelContext* ctx) override {
    try {
      // Using CPU device
      auto cpu_engine = engine(engine::kind::cpu, 0);

      // Get the inputs
      const Tensor& src_tensor = MklGetInput(ctx, kSrcIndex);
      const float min_range =
          MklGetInput(ctx, kMinIndex).template flat<float>()(0);
      const float max_range =
          MklGetInput(ctx, kMaxIndex).template flat<float>()(0);

      // Get MklShape
      MklDnnShape src_mkl_shape;
      GetMklShape(ctx, kSrcIndex, &src_mkl_shape);

      // src_dims is the dimension of src_tensor
      // output_dims are same as src_dims
      auto src_dims = src_mkl_shape.IsMklTensor()
                          ? src_mkl_shape.GetSizesAsMklDnnDims()
                          : TFShapeToMklDnnDims(src_tensor.shape());
      auto output_dims = src_dims;

      // Create reorder memory for src and dst
      MklDnnData<T> src(&cpu_engine);
      MklDnnData<float> dst(&cpu_engine);

      std::shared_ptr<stream> reorder_stream;
      reorder_stream.reset(CreateStream(ctx, cpu_engine));

      // If input is in MKL layout, then simply grab input layout; otherwise,
      // construct input TF layout. For TF layout, although input shape
      // (src_dims) required is in MKL-DNN order, the layout is Tensorflow's
      // layout
      auto src_md = src_mkl_shape.IsMklTensor()
                        ? src_mkl_shape.GetMklLayout()
                        : memory::desc(src_dims, MklDnnType<T>(),
                                       src_dims.size() == 4 ? MEMORY_FORMAT::nhwc : MEMORY_FORMAT::nc);

      src.SetUsrMem(src_md, &src_tensor);
      src.SetUsrMemDataHandle(&src_tensor, reorder_stream);

      Tensor* output_tensor = nullptr;
      MklDnnShape output_mkl_shape;
      TensorShape output_tf_shape;
      memory::desc dst_md = memory::desc();
      if (src_mkl_shape.IsMklTensor()) {
        dst_md = memory::desc(src_mkl_shape.GetMklLayout().data);
        // There is no API in MKL-DNN v1.x to construct memory descriptor with
        // same .data field but different type.
        dst_md.data.data_type = memory::convert_to_c(MklDnnType<float>());
      } else {
        dst_md = memory::desc(src_dims, MklDnnType<float>(),
                              src_dims.size() == 4 ? MEMORY_FORMAT::nhwc : MEMORY_FORMAT::nc);
      }

      // If input is MKL shape, output is also MKL shape.
      // If input is TF shape, output is also TF shape.
      if (src_mkl_shape.IsMklTensor()) {
        output_mkl_shape.SetMklTensor(true);
        output_mkl_shape.SetMklLayout(&dst_md);
        output_mkl_shape.SetElemType(MklDnnType<float>());
        output_mkl_shape.SetTfLayout(src_mkl_shape.GetDimension(),
                                     src_mkl_shape.GetSizesAsMklDnnDims(),
                                     src_mkl_shape.GetTfDataFormat());
        output_tf_shape.AddDim(dst_md.get_size() / sizeof(float));
      } else {
        output_mkl_shape.SetMklTensor(false);
        output_tf_shape = MklDnnDimsToTFShape(output_dims);
      }

      // Allocate MKL or TF output shape based on the above
      AllocateOutputSetMklShape(ctx, 0, &output_tensor, output_tf_shape,
                                output_mkl_shape);
      dst.SetUsrMem(dst_md, output_tensor);
      dst.SetUsrMemDataHandle(output_tensor, reorder_stream);

      // The quantization logic here for mode SCALED is similar to the logic
      // in QuantizeAndDequantizeV2 and QuantizeAndDequantizeV3.
      static constexpr int num_bits = sizeof(T) * 8;
      const float max_abs = std::max(std::abs(min_range), std::abs(max_range));
      bool is_signed = std::is_signed<T>::value;
      // If it is signed, we try to keep 0.0 being 0 and drop one bucket. For
      // example, if it is 8 bits, we have the range [-127, 127]. So for input
      // range of [-x, x], the scale should be (2*x)/254.
      //
      // If it is unsigned and num_bits == 8, the range with 8 bits is [0, 255].
      // If the input range is [0, x], then the scale is x/255 instead of 254 as
      // in the case above.
      const int target_bits = is_signed ? (num_bits - 1) : num_bits;
      const float target_range =
          static_cast<float>((uint64_t{1} << target_bits) - 1);
      const float scale_factor = max_abs / target_range;
      std::vector<float> scales;
      scales.push_back(scale_factor);
      primitive_attr attr;
      attr.set_output_scales(0, scales);
      std::vector<primitive> net;

      // Create reorder primitive and then execute.
      auto reorder_pd =
          ReorderPd(cpu_engine, src.GetUsrMem()->get_desc(), cpu_engine,
                    dst.GetUsrMem()->get_desc(), attr);
      net.push_back(reorder(reorder_pd));
      std::vector<std::unordered_map<int, memory>> reorder_net_args;
      reorder_net_args.push_back({{MKLDNN_ARG_FROM, *src.GetUsrMem()},
                                  {MKLDNN_ARG_TO, *dst.GetUsrMem()}});
      execute_primitives(net, reorder_stream, reorder_net_args);
    } catch (mkldnn::error& e) {
      string error_msg = "Status: " + std::to_string(e.status) +
                         ", message: " + string(e.message) + ", in file " +
                         string(__FILE__) + ":" + std::to_string(__LINE__);
      OP_REQUIRES_OK(
          ctx, errors::Aborted("Operation received an exception:", error_msg));
    }
  }

 private:
  const size_t kSrcIndex = 0;
  const size_t kMinIndex = 1;
  const size_t kMaxIndex = 2;
};

REGISTER_KERNEL_BUILDER(Name("_MklDequantize")
                            .Device(DEVICE_CPU)
                            .TypeConstraint<quint8>("T")
                            .Label(mkl_op_registry::kMklQuantizedOpLabel),
                        MklDequantizeOp<CPUDevice, quint8>);
REGISTER_KERNEL_BUILDER(Name("_MklDequantize")
                            .Device(DEVICE_CPU)
                            .TypeConstraint<qint8>("T")
                            .Label(mkl_op_registry::kMklQuantizedOpLabel),
                        MklDequantizeOp<CPUDevice, qint8>);

}  // namespace tensorflow

#endif  // INTEL_MKL
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/profiler/utils/xplane_visitor.h"

#include "absl/strings/string_view.h"

namespace tensorflow {
namespace profiler {

XStatVisitor::XStatVisitor(const XPlaneVisitor* plane, const XStat* stat)
    : stat_(stat),
      metadata_(plane->GetStatMetadata(stat->metadata_id())),
      plane_(plane),
      type_(plane->GetStatType(stat->metadata_id())) {}

absl::string_view XStatVisitor::RefValue() const {
  const XStatMetadata* metadata = plane_->GetStatMetadata(stat_->ref_value());
  return metadata ? metadata->name() : "";
}

std::string XStatVisitor::ToString() const {
  switch (stat_->value_case()) {
    case XStat::kInt64Value:
      return absl::StrCat(stat_->int64_value());
    case XStat::kUint64Value:
      return absl::StrCat(stat_->uint64_value());
    case XStat::kDoubleValue:
      return absl::StrCat(stat_->double_value());
    case XStat::kStrValue:
      return stat_->str_value();
    case XStat::kBytesValue:
      return "<opaque bytes>";
    case XStat::kRefValue:
      return plane_->GetStatMetadata(stat_->ref_value())->name();
    case XStat::VALUE_NOT_SET:
      return "";
  }
}

absl::string_view XStatVisitor::StrOrRefValue() const {
  switch (stat_->value_case()) {
    case XStat::kStrValue:
      return stat_->str_value();
    case XStat::kRefValue:
      return plane_->GetStatMetadata(stat_->ref_value())->name();
    case XStat::kInt64Value:
    case XStat::kUint64Value:
    case XStat::kDoubleValue:
    case XStat::kBytesValue:
    case XStat::VALUE_NOT_SET:
      return absl::string_view();
  }
}

XEventVisitor::XEventVisitor(const XPlaneVisitor* plane, const XLine* line,
                             const XEvent* event)
    : XStatsOwner<XEvent>(plane, event),
      plane_(plane),
      line_(line),
      event_(event),
      metadata_(plane->GetEventMetadata(event_->metadata_id())),
      type_(plane->GetEventType(event_->metadata_id())) {}

XPlaneVisitor::XPlaneVisitor(const XPlane* plane,
                             const TypeGetterList& event_type_getter_list,
                             const TypeGetterList& stat_type_getter_list)
    : XStatsOwner<XPlane>(this, plane), plane_(plane) {
  for (const auto& event_type_getter : event_type_getter_list) {
    BuildEventTypeMap(plane, event_type_getter);
  }
  for (const auto& stat_type_getter : stat_type_getter_list) {
    BuildStatTypeMap(plane, stat_type_getter);
  }
}

void XPlaneVisitor::BuildEventTypeMap(const XPlane* plane,
                                      const TypeGetter& event_type_getter) {
  for (const auto& event_metadata : plane->event_metadata()) {
    uint64 metadata_id = event_metadata.first;
    const auto& metadata = event_metadata.second;
    absl::optional<int64> event_type = event_type_getter(metadata.name());
    if (event_type.has_value()) {
      auto result = event_metadata_id_map_.emplace(metadata_id, *event_type);
      DCHECK(result.second);  // inserted
      event_type_map_.emplace(*event_type, &metadata);
    }
  }
}

void XPlaneVisitor::BuildStatTypeMap(const XPlane* plane,
                                     const TypeGetter& stat_type_getter) {
  for (const auto& stat_metadata : plane->stat_metadata()) {
    uint64 metadata_id = stat_metadata.first;
    const auto& metadata = stat_metadata.second;
    absl::optional<int64> stat_type = stat_type_getter(metadata.name());
    if (stat_type.has_value()) {
      auto result = stat_metadata_id_map_.emplace(metadata_id, *stat_type);
      DCHECK(result.second);  // inserted
      stat_type_map_.emplace(*stat_type, &metadata);
    }
  }
}

const XStatMetadata* XPlaneVisitor::GetStatMetadata(
    int64 stat_metadata_id) const {
  const auto& stat_metadata_map = plane_->stat_metadata();
  const auto it = stat_metadata_map.find(stat_metadata_id);
  if (it != stat_metadata_map.end()) return &it->second;
  return &XStatMetadata::default_instance();
}

absl::optional<int64> XPlaneVisitor::GetStatType(int64 stat_metadata_id) const {
  const auto it = stat_metadata_id_map_.find(stat_metadata_id);
  if (it != stat_metadata_id_map_.end()) return it->second;
  return absl::nullopt;
}

absl::optional<int64> XPlaneVisitor::GetStatMetadataId(int64 stat_type) const {
  const auto it = stat_type_map_.find(stat_type);
  if (it != stat_type_map_.end()) return it->second->id();
  return absl::nullopt;
}

const XEventMetadata* XPlaneVisitor::GetEventMetadata(
    int64 event_metadata_id) const {
  const auto& event_metadata_map = plane_->event_metadata();
  const auto it = event_metadata_map.find(event_metadata_id);
  if (it != event_metadata_map.end()) return &it->second;
  return &XEventMetadata::default_instance();
}

absl::optional<int64> XPlaneVisitor::GetEventType(
    int64 event_metadata_id) const {
  const auto it = event_metadata_id_map_.find(event_metadata_id);
  if (it != event_metadata_id_map_.end()) return it->second;
  return absl::nullopt;
}

}  // namespace profiler
}  // namespace tensorflow
<commit_msg>Fix a subtle use-after-free issue in XStatVisitor::RefValue()<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/profiler/utils/xplane_visitor.h"

#include "absl/strings/string_view.h"

namespace tensorflow {
namespace profiler {

XStatVisitor::XStatVisitor(const XPlaneVisitor* plane, const XStat* stat)
    : stat_(stat),
      metadata_(plane->GetStatMetadata(stat->metadata_id())),
      plane_(plane),
      type_(plane->GetStatType(stat->metadata_id())) {}

absl::string_view XStatVisitor::RefValue() const {
  const XStatMetadata* metadata = plane_->GetStatMetadata(stat_->ref_value());
  return metadata ? absl::string_view(metadata->name()) : absl::string_view();
}

std::string XStatVisitor::ToString() const {
  switch (stat_->value_case()) {
    case XStat::kInt64Value:
      return absl::StrCat(stat_->int64_value());
    case XStat::kUint64Value:
      return absl::StrCat(stat_->uint64_value());
    case XStat::kDoubleValue:
      return absl::StrCat(stat_->double_value());
    case XStat::kStrValue:
      return stat_->str_value();
    case XStat::kBytesValue:
      return "<opaque bytes>";
    case XStat::kRefValue:
      return plane_->GetStatMetadata(stat_->ref_value())->name();
    case XStat::VALUE_NOT_SET:
      return "";
  }
}

absl::string_view XStatVisitor::StrOrRefValue() const {
  switch (stat_->value_case()) {
    case XStat::kStrValue:
      return stat_->str_value();
    case XStat::kRefValue:
      return plane_->GetStatMetadata(stat_->ref_value())->name();
    case XStat::kInt64Value:
    case XStat::kUint64Value:
    case XStat::kDoubleValue:
    case XStat::kBytesValue:
    case XStat::VALUE_NOT_SET:
      return absl::string_view();
  }
}

XEventVisitor::XEventVisitor(const XPlaneVisitor* plane, const XLine* line,
                             const XEvent* event)
    : XStatsOwner<XEvent>(plane, event),
      plane_(plane),
      line_(line),
      event_(event),
      metadata_(plane->GetEventMetadata(event_->metadata_id())),
      type_(plane->GetEventType(event_->metadata_id())) {}

XPlaneVisitor::XPlaneVisitor(const XPlane* plane,
                             const TypeGetterList& event_type_getter_list,
                             const TypeGetterList& stat_type_getter_list)
    : XStatsOwner<XPlane>(this, plane), plane_(plane) {
  for (const auto& event_type_getter : event_type_getter_list) {
    BuildEventTypeMap(plane, event_type_getter);
  }
  for (const auto& stat_type_getter : stat_type_getter_list) {
    BuildStatTypeMap(plane, stat_type_getter);
  }
}

void XPlaneVisitor::BuildEventTypeMap(const XPlane* plane,
                                      const TypeGetter& event_type_getter) {
  for (const auto& event_metadata : plane->event_metadata()) {
    uint64 metadata_id = event_metadata.first;
    const auto& metadata = event_metadata.second;
    absl::optional<int64> event_type = event_type_getter(metadata.name());
    if (event_type.has_value()) {
      auto result = event_metadata_id_map_.emplace(metadata_id, *event_type);
      DCHECK(result.second);  // inserted
      event_type_map_.emplace(*event_type, &metadata);
    }
  }
}

void XPlaneVisitor::BuildStatTypeMap(const XPlane* plane,
                                     const TypeGetter& stat_type_getter) {
  for (const auto& stat_metadata : plane->stat_metadata()) {
    uint64 metadata_id = stat_metadata.first;
    const auto& metadata = stat_metadata.second;
    absl::optional<int64> stat_type = stat_type_getter(metadata.name());
    if (stat_type.has_value()) {
      auto result = stat_metadata_id_map_.emplace(metadata_id, *stat_type);
      DCHECK(result.second);  // inserted
      stat_type_map_.emplace(*stat_type, &metadata);
    }
  }
}

const XStatMetadata* XPlaneVisitor::GetStatMetadata(
    int64 stat_metadata_id) const {
  const auto& stat_metadata_map = plane_->stat_metadata();
  const auto it = stat_metadata_map.find(stat_metadata_id);
  if (it != stat_metadata_map.end()) return &it->second;
  return &XStatMetadata::default_instance();
}

absl::optional<int64> XPlaneVisitor::GetStatType(int64 stat_metadata_id) const {
  const auto it = stat_metadata_id_map_.find(stat_metadata_id);
  if (it != stat_metadata_id_map_.end()) return it->second;
  return absl::nullopt;
}

absl::optional<int64> XPlaneVisitor::GetStatMetadataId(int64 stat_type) const {
  const auto it = stat_type_map_.find(stat_type);
  if (it != stat_type_map_.end()) return it->second->id();
  return absl::nullopt;
}

const XEventMetadata* XPlaneVisitor::GetEventMetadata(
    int64 event_metadata_id) const {
  const auto& event_metadata_map = plane_->event_metadata();
  const auto it = event_metadata_map.find(event_metadata_id);
  if (it != event_metadata_map.end()) return &it->second;
  return &XEventMetadata::default_instance();
}

absl::optional<int64> XPlaneVisitor::GetEventType(
    int64 event_metadata_id) const {
  const auto it = event_metadata_id_map_.find(event_metadata_id);
  if (it != event_metadata_id_map_.end()) return it->second;
  return absl::nullopt;
}

}  // namespace profiler
}  // namespace tensorflow
<|endoftext|>


<commit_before>/*
 * opencog/atoms/reduct/PlusLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Plus Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Plus Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atomspace/atom_types.h>
#include <opencog/atomspace/ClassServer.h>
#include <opencog/atoms/NumberNode.h>
#include "PlusLink.h"
#include "TimesLink.h"

using namespace opencog;

PlusLink::PlusLink(const HandleSeq& oset,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(PLUS_LINK, oset, tv, av)
{
	init();
}

PlusLink::PlusLink(Type t, const HandleSeq& oset,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(t, oset, tv, av)
{
	if (not classserver().isA(t, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

PlusLink::PlusLink(Type t, const Handle& a, const Handle& b,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(t, a, b, tv, av)
{
	if (not classserver().isA(t, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

PlusLink::PlusLink(Link& l)
    : FoldLink(l)
{
	Type tscope = l.getType();
	if (not classserver().isA(tscope, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

static double plus(double a, double b) { return a+b; }

void PlusLink::init(void)
{
	knil = 0.0;
	kons = plus;
}

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

/// re-order the contents of a PlusLink into "lexicographic" order.
///
/// The goal of the re-ordering is to simplify the reduction code,
/// by placing atoms where they are easily found.  For now, this
/// means:
/// first, all of the variables,
/// next, all compound expressions,
/// last, all number nodes (of which there should be only zero or one.)
/// We do not currently sort the variables, but maybe we should...?
/// The FoldLink::reduce() method already returns expressions that are
/// almost in the correct order.
Handle PlusLink::reorder(void)
{
	HandleSeq vars;
	HandleSeq exprs;
	HandleSeq numbers;

	for (const Handle& h : _outgoing)
	{
		if (h->getType() == VARIABLE_NODE)
			vars.push_back(h);
		else if (h->getType() == NUMBER_NODE)
			numbers.push_back(h);
		else
			exprs.push_back(h);
	}

	if (1 < numbers.size())
		throw RuntimeException(TRACE_INFO,
		      "Expecting the plus link to have already been reduced!");

	HandleSeq result;
	for (const Handle& h : vars) result.push_back(h);
	for (const Handle& h : exprs) result.push_back(h);
	for (const Handle& h : numbers) result.push_back(h);

	return Handle(createPlusLink(result));
}

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

/// Handle normalization of addition into multiplication.
/// aka "mutiplicattive reduction"
///
/// There are four cases handled here:
/// x+x ==> 2x
/// x + ax ==> (a+1) x
/// ax + x ==> (a+1) x
/// ax + bx ==> (a + b) x
///
Handle PlusLink::reduce(void)
{
	// First, let FoldLink do its stuff.
	Handle fold = FoldLink::reduce();

	if (PLUS_LINK != fold->getType()) return fold;

	PlusLinkPtr pfold(PlusLinkCast(fold));
	fold = pfold->reorder();

	// Now, look for repeated atoms, two atoms that appear twice
	// in the outgoing set. If they do, then can be mutliplied.
	LinkPtr lfold(LinkCast(fold));

	bool do_reduce = false;
	Handle reduct = Handle::UNDEFINED;

	const HandleSeq& ofs = lfold->getOutgoingSet();
	size_t fsz = ofs.size();
	for (size_t i = 0; i < fsz; i++)
	{
		const Handle& fi = ofs[i];
		for (size_t j=i+1; j < fsz; j++)
		{
			const Handle& fj = ofs[j];

			// Is atom in position i identical to atom in position j?
			// If so, then replace by 2*i
			if (fi == fj)
			{
				Handle two(createNumberNode("2"));
				reduct = Handle(createTimesLink(fi, two));
				do_reduce = true;
			}

			// If j is (TimesLink a b) and i is identical to a,
			// then create (TimesLink a (b+1))
			if (fj->getType() == TIMES_LINK)
			{
				LinkPtr jlp = LinkCast(fj);
				if (fi == jlp->getOutgoingAtom(0))
				{
					Handle one(createNumberNode("1"));
					HandleSeq rest;
					rest.push_back(one);

					const HandleSeq& jlpo = jlp->getOutgoingSet();
					size_t jlpsz = jlpo.size();
					for (size_t k=1; k<jlpsz; k++)
						rest.push_back(jlpo[k]);

					// b_plus_one is now (b+1)
					PlusLinkPtr bpo = createPlusLink(rest);
					Handle b_plus_one(bpo->reduce());

					reduct = Handle(createTimesLink(fi, b_plus_one));
					do_reduce = true;
				}
			}

			if (do_reduce)
			{
				HandleSeq norm;
				norm.push_back(reduct);

				// copy everything else, except for i and j.
				for (size_t k = 0; k< fsz; k++)
				{
					if (k == i or k == j) continue;
					norm.push_back(ofs[k]);
				}

				PlusLinkPtr plp = createPlusLink(norm);

				Handle red(plp->reduce());

				// Place the result into the same atomspace we are in.
				// XXX this is bad, buggy, uncomfortable, icky: it pollutes
				// the atomspace with intermediate results. This needs to
				// be fixed somehow. Right now, I don't know how.
				if (_atomTable)
				{
					AtomSpace* as = _atomTable->getAtomSpace();
					return as->addAtom(red);
				}
				return red;
			}
		}
	}

	return fold;
}
<commit_msg>More reduction<commit_after>/*
 * opencog/atoms/reduct/PlusLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Plus Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Plus Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atomspace/atom_types.h>
#include <opencog/atomspace/ClassServer.h>
#include <opencog/atoms/NumberNode.h>
#include "PlusLink.h"
#include "TimesLink.h"

using namespace opencog;

PlusLink::PlusLink(const HandleSeq& oset,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(PLUS_LINK, oset, tv, av)
{
	init();
}

PlusLink::PlusLink(Type t, const HandleSeq& oset,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(t, oset, tv, av)
{
	if (not classserver().isA(t, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

PlusLink::PlusLink(Type t, const Handle& a, const Handle& b,
                   TruthValuePtr tv,
                   AttentionValuePtr av)
    : FoldLink(t, a, b, tv, av)
{
	if (not classserver().isA(t, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

PlusLink::PlusLink(Link& l)
    : FoldLink(l)
{
	Type tscope = l.getType();
	if (not classserver().isA(tscope, PLUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PlusLink");
	init();
}

static double plus(double a, double b) { return a+b; }

void PlusLink::init(void)
{
	knil = 0.0;
	kons = plus;
}

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

/// re-order the contents of a PlusLink into "lexicographic" order.
///
/// The goal of the re-ordering is to simplify the reduction code,
/// by placing atoms where they are easily found.  For now, this
/// means:
/// first, all of the variables,
/// next, all compound expressions,
/// last, all number nodes (of which there should be only zero or one.)
/// We do not currently sort the variables, but maybe we should...?
/// The FoldLink::reduce() method already returns expressions that are
/// almost in the correct order.
Handle PlusLink::reorder(void)
{
	HandleSeq vars;
	HandleSeq exprs;
	HandleSeq numbers;

	for (const Handle& h : _outgoing)
	{
		if (h->getType() == VARIABLE_NODE)
			vars.push_back(h);
		else if (h->getType() == NUMBER_NODE)
			numbers.push_back(h);
		else
			exprs.push_back(h);
	}

	if (1 < numbers.size())
		throw RuntimeException(TRACE_INFO,
		      "Expecting the plus link to have already been reduced!");

	HandleSeq result;
	for (const Handle& h : vars) result.push_back(h);
	for (const Handle& h : exprs) result.push_back(h);
	for (const Handle& h : numbers) result.push_back(h);

	return Handle(createPlusLink(result));
}

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

/// Handle normalization of addition into multiplication.
/// aka "mutiplicattive reduction"
///
/// There are four cases handled here:
/// x+x ==> 2x
/// x + ax ==> (a+1) x
/// ax + x ==> (a+1) x
/// ax + bx ==> (a + b) x
///
Handle PlusLink::reduce(void)
{
	// First, let FoldLink do its stuff.
	Handle fold = FoldLink::reduce();

	if (PLUS_LINK != fold->getType()) return fold;

	PlusLinkPtr pfold(PlusLinkCast(fold));
	fold = pfold->reorder();

	// Now, look for repeated atoms, two atoms that appear twice
	// in the outgoing set. If they do, then can be mutliplied.
	LinkPtr lfold(LinkCast(fold));

	bool do_reduce = false;
	Handle reduct = Handle::UNDEFINED;

	const HandleSeq& ofs = lfold->getOutgoingSet();
	size_t fsz = ofs.size();
	for (size_t i = 0; i < fsz; i++)
	{
		const Handle& fi = ofs[i];
		for (size_t j=i+1; j < fsz; j++)
		{
			const Handle& fj = ofs[j];

			// Is atom in position i identical to atom in position j?
			// If so, then replace by 2*i
			if (fi == fj)
			{
				Handle two(createNumberNode("2"));
				reduct = Handle(createTimesLink(fi, two));
				do_reduce = true;
			}

			// If j is (TimesLink x a) and i is identical to x,
			// then create (TimesLink x (a+1))
			//
			// If j is (TimesLink x a) and i is (TimesLink x b)
			// then create (TimesLink x (a+b))
			//
			else if (fj->getType() == TIMES_LINK)
			{
				bool do_add = false;
				HandleSeq rest;

				LinkPtr ilp = LinkCast(fi);
				LinkPtr jlp = LinkCast(fj);

				// Handle the (a+1) case described above.
				if (fi == jlp->getOutgoingAtom(0))
				{
					Handle one(createNumberNode("1"));
					rest.push_back(one);
					do_add = true;
				}

				// Handle the (a+b) case described above.
				else if (ilp->getOutgoingAtom(0) == jlp->getOutgoingAtom(0))
				{
					const HandleSeq& ilpo = ilp->getOutgoingSet();
					size_t ilpsz = ilpo.size();
					for (size_t k=1; k<ilpsz; k++)
						rest.push_back(ilpo[k]);
					do_add = true;
				}

				if (do_add)
				{
					const HandleSeq& jlpo = jlp->getOutgoingSet();
					size_t jlpsz = jlpo.size();
					for (size_t k=1; k<jlpsz; k++)
						rest.push_back(jlpo[k]);

					// a_plus is now (a+1) or (a+b) as described above.
					PlusLinkPtr ap = createPlusLink(rest);
					Handle a_plus(ap->reduce());

					reduct = Handle(createTimesLink(fi, a_plus));
					do_reduce = true;
				}
			}

			if (do_reduce)
			{
				HandleSeq norm;
				norm.push_back(reduct);

				// copy everything else, except for i and j.
				for (size_t k = 0; k< fsz; k++)
				{
					if (k == i or k == j) continue;
					norm.push_back(ofs[k]);
				}

				PlusLinkPtr plp = createPlusLink(norm);

				Handle red(plp->reduce());

				// Place the result into the same atomspace we are in.
				// XXX this is bad, buggy, uncomfortable, icky: it pollutes
				// the atomspace with intermediate results. This needs to
				// be fixed somehow. Right now, I don't know how.
				if (_atomTable)
				{
					AtomSpace* as = _atomTable->getAtomSpace();
					return as->addAtom(red);
				}
				return red;
			}
		}
	}

	return fold;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015
// Author: Chrono Law
#include <std.hpp>
using namespace std;

#include <boost/core/lightweight_test.hpp>
#include <boost/utility.hpp>
#include <boost/dynamic_bitset.hpp>
using namespace boost;

//////////////////////////////////////////
void case1()
{
    dynamic_bitset<> db1;
    dynamic_bitset<> db2(10);
    dynamic_bitset<> db3(0x16,
    BOOST_BINARY(10101));       //注意这里
    dynamic_bitset<> db4(string("0100"));
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;

    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl;

}

//////////////////////////////////////////
void case2()
{
    dynamic_bitset<> db;

    db.resize(10, true);
    cout << db << endl;

    db.resize(5);
    cout << db << endl;

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();
        assert(db.empty()&& db.size()==0);

    }

    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true);
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl;             //0000000000000000000000000000010101001

    }
}

//////////////////////////////////////////
void case3()
{
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;
    db1[1] ^= 1;
    cout << db1 << endl;

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;
    cout << (db1 | db2) << endl;

}

//////////////////////////////////////////
void case4()
{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    assert(db.test(0) && !db.test(1));
    assert(db.any() && !db.none());
    assert(db.count() == 2);

    {
        dynamic_bitset<> db(4, BOOST_BINARY(0101));

        db.flip();
        assert(db.to_ulong() == BOOST_BINARY(1010));

        db.set();
        assert(!db.none());

        db.reset();
        assert(!db.any() );

        db.set(1, 1);
        assert(db.count() == 1);

    }

    {
        dynamic_bitset<> db(5, BOOST_BINARY(00101));

        auto pos = db.find_first();
        assert(pos == 0);

        pos = db.find_next(pos);
        assert(pos == 2);

    }
}

//////////////////////////////////////////
void case5()
{
    dynamic_bitset<> db(10, BOOST_BINARY(1010101));
    cout << db.to_ulong() << endl;      //85

    db.append(10);
    cout << db.to_ulong() << endl;

    db.push_back(1);
    //cout << db.to_ulong() << endl;
    BOOST_TEST_THROWS(db.to_ulong(), std::overflow_error);

    string str;
    to_string(db, str);
    cout << str << endl;

    dump_to_string(db , str);
    cout << str << endl;
}

//////////////////////////////////////////
void case6()
{
    dynamic_bitset<> db1(5, BOOST_BINARY(10101));
    dynamic_bitset<> db2(5, BOOST_BINARY(10010));

    cout << (db1 | db2) << endl;
    cout << (db1 & db2) << endl;
    cout << (db1 - db2) << endl;

    dynamic_bitset<> db3(5, BOOST_BINARY(101));
    assert(db3.is_proper_subset_of(db1));

    dynamic_bitset<> db4(db2);
    assert(db4.is_subset_of(db2));
    assert(!db4.is_proper_subset_of(db2));
}

//////////////////////////////////////////
void func(int n)
{
    //cout << "test " << n << endl;

    dynamic_bitset<> db(n);
    db.set();
    //cout << db.size() << endl;

    for (dynamic_bitset<>::size_type i = db.find_next(1);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i ) )
    {
        for (dynamic_bitset<>::size_type j = db.find_next(i);
                j != dynamic_bitset<>::npos ;
                j = db.find_next(j ))
        {
            if ( j % i == 0)
            {
                db[j] = 0;
            }
        }
    }

    cout << dec ;
    for (dynamic_bitset<>::size_type i = db.find_next(2);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i) )
    {
        cout << i << ", ";
    }

}

void case7()
{
    func(10);
    func(50);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}
<commit_msg>dynamic bitest todo 171 fix<commit_after>// Copyright (c) 2015
// Author: Chrono Law
#include <std.hpp>
using namespace std;

#include <boost/core/lightweight_test.hpp>
#include <boost/utility.hpp>
#include <boost/dynamic_bitset.hpp>
using namespace boost;

//////////////////////////////////////////
void case1()
{
    dynamic_bitset<> db1;
    dynamic_bitset<> db2(10);
    dynamic_bitset<> db3(0x16,
    BOOST_BINARY(10101));       //注意这里
    dynamic_bitset<> db4(string("0100"));
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;

    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl;

}

//////////////////////////////////////////
void case2()
{
    dynamic_bitset<> db;

    db.resize(10, true);
    cout << db << endl;

    db.resize(5);
    cout << db << endl;

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();
        assert(db.empty()&& db.size()==0);

    }

    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true);
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl;             //0000000000000000000000000000010101001

    }
}

//////////////////////////////////////////
void case3()
{
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;
    db1[1] ^= 1;
    cout << db1 << endl;

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;
    cout << (db1 | db2) << endl;

}

//////////////////////////////////////////
void case4()
{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    assert(db.test(0) && !db.test(1));
    assert(db.any() && !db.none());
    assert(db.count() == 2);

    {
        dynamic_bitset<> db(4, BOOST_BINARY(0101));

        db.flip();
        assert(db.to_ulong() == BOOST_BINARY(1010));

        db.set();
        assert(!db.none());

        db.reset();
        assert(!db.any() );

        db.set(1, 1);
        assert(db.count() == 1);

    }

    {
        dynamic_bitset<> db(5, BOOST_BINARY(00101));

        auto pos = db.find_first();
        assert(pos == 0);

        pos = db.find_next(pos);
        assert(pos == 2);

    }
}

//////////////////////////////////////////
void case5()
{
    dynamic_bitset<> db(10, BOOST_BINARY(1010101));
    cout << db.to_ulong() << endl;      //85

    db.append(10);
    cout << db.to_ulong() << endl;

    // todo 171 fix
    //db.push_back(1);
    //cout << db.to_ulong() << endl;
    //BOOST_TEST_THROWS(db.to_ulong(), std::overflow_error);

    string str;
    to_string(db, str);
    cout << str << endl;

    dump_to_string(db , str);
    cout << str << endl;
}

//////////////////////////////////////////
void case6()
{
    dynamic_bitset<> db1(5, BOOST_BINARY(10101));
    dynamic_bitset<> db2(5, BOOST_BINARY(10010));

    cout << (db1 | db2) << endl;
    cout << (db1 & db2) << endl;
    cout << (db1 - db2) << endl;

    dynamic_bitset<> db3(5, BOOST_BINARY(101));
    assert(db3.is_proper_subset_of(db1));

    dynamic_bitset<> db4(db2);
    assert(db4.is_subset_of(db2));
    assert(!db4.is_proper_subset_of(db2));
}

//////////////////////////////////////////
void func(int n)
{
    //cout << "test " << n << endl;

    dynamic_bitset<> db(n);
    db.set();
    //cout << db.size() << endl;

    for (dynamic_bitset<>::size_type i = db.find_next(1);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i ) )
    {
        for (dynamic_bitset<>::size_type j = db.find_next(i);
                j != dynamic_bitset<>::npos ;
                j = db.find_next(j ))
        {
            if ( j % i == 0)
            {
                db[j] = 0;
            }
        }
    }

    cout << dec ;
    for (dynamic_bitset<>::size_type i = db.find_next(2);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i) )
    {
        cout << i << ", ";
    }

}

void case7()
{
    func(10);
    func(50);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}
<|endoftext|>


<commit_before>/*
 * kinetic-cpp-examples
 * Copyright (C) 2014 Seagate Technology.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include <vector>

#include "kinetic/kinetic.h"

static const int kP2PBatchSize = 10;
using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticRecord;

using std::shared_ptr;
using std::make_shared;
using std::string;
using std::unique_ptr;
using std::vector;
using std::pair;
using std::make_pair;

kinetic::P2PPushRequest prepare_request(const vector<kinetic::P2PPushOperation>& operations, const vector<pair<string, int>>& destinations, size_t currentDestination) {
    kinetic::P2PPushRequest request;

    request.host = destinations[currentDestination].first;
    request.port = destinations[currentDestination].second;

    request.operations = operations;

    if (currentDestination < destinations.size() - 1) {
        // Add the pipleline request onto this request's first operation
        request.operations[request.operations.size() - 1].request = make_shared<::kinetic::P2PPushRequest>(
                prepare_request(operations, destinations, currentDestination + 1));
    }

    return request;
}

void dispatch_request(shared_ptr<kinetic::BlockingKineticConnection> connection,
        const vector<kinetic::P2PPushOperation>& operations,
        const vector<pair<string, int>>& destinations) {
    kinetic::P2PPushRequest request = prepare_request(operations, destinations, 0);

    unique_ptr<vector<kinetic::KineticStatus>> statuses(new vector<kinetic::KineticStatus>());
    auto status = connection->P2PPush(request, statuses);
    if (!status.ok()) {
        printf("Error pushing: %d, %s\n", status.statusCode(), status.message().c_str());
        exit(1);
    }

    for (auto it = statuses->begin(); it != statuses->end(); ++it) {
        if (it->ok()) {
            printf(".");
        } else {
            printf("%s", it->message().c_str());
        }
    }
    fflush(stdout);
}

int main(int argc, char* argv[]) {
    if (argc < 5 || argc % 2 != 1) {
        printf("%s: <source host> <source port> <destination host> <destination port> [<additional host> <additional port> ... ]\n", argv[0]);
        return 1;
    }

    const char* source_host = argv[1];
    int source_port = atoi(argv[2]);

    vector<pair<string, int>> destinations;

    printf("Copying from %s:%d", source_host, source_port);

    for (int i = 3; i < argc; i += 2) {
        auto destination = make_pair(argv[i], atoi(argv[i + 1]));
        destinations.push_back(destination);
        printf(" -> %s:%d", destination.first, destination.second);
    }
    printf("\n");

    kinetic::ConnectionOptions options;
    options.host = source_host;
    options.port = source_port;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    kinetic::KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    shared_ptr<kinetic::BlockingKineticConnection> blocking_connection;
    if(!kinetic_connection_factory.NewBlockingConnection(options, blocking_connection, 20).ok()){
        printf("Unable to connect\n");
        return 1;
    }

    vector<kinetic::P2PPushOperation> operations;

    // Build a key consisting of "FFFFFF...". In almost all cases this will come after the last
    // key in the drive
    string last_key;
    for (int i = 0; i < 4*1024; i++) {
        last_key += "\xFF";
    }

    // Iterate over all the keys and print them out
    for (kinetic::KeyRangeIterator it = blocking_connection->IterateKeyRange("", true, last_key, true, 100); it != kinetic::KeyRangeEnd(); ++it) {
        kinetic::P2PPushOperation op;
        op.key = *it;
        op.force = true;
        op.newKey = *it;
        operations.push_back(op);

        if (operations.size() > kP2PBatchSize) {
            dispatch_request(blocking_connection, operations, destinations);
            operations.clear();
        }
    }

    dispatch_request(blocking_connection, operations, destinations);

    printf("\n");

    return 0;
}

<commit_msg>More compiler friendly.<commit_after>/*
 * kinetic-cpp-examples
 * Copyright (C) 2014 Seagate Technology.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include <vector>

#include "kinetic/kinetic.h"

static const int kP2PBatchSize = 10;
using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticRecord;
using kinetic::P2PPushRequest;

using std::shared_ptr;
using std::make_shared;
using std::string;
using std::unique_ptr;
using std::vector;
using std::pair;
using std::make_pair;

kinetic::P2PPushRequest prepare_request(const vector<kinetic::P2PPushOperation>& operations, const vector<pair<string, int>>& destinations, size_t currentDestination) {
    kinetic::P2PPushRequest request;

    request.host = destinations[currentDestination].first;
    request.port = destinations[currentDestination].second;

    request.operations = operations;

    if (currentDestination < destinations.size() - 1) {
        // Add the pipleline request onto this request's first operation
        request.operations[request.operations.size() - 1].request = make_shared< P2PPushRequest >(
                prepare_request(operations, destinations, currentDestination + 1));
    }

    return request;
}

void dispatch_request(shared_ptr<kinetic::BlockingKineticConnection> connection,
        const vector<kinetic::P2PPushOperation>& operations,
        const vector<pair<string, int>>& destinations) {
    kinetic::P2PPushRequest request = prepare_request(operations, destinations, 0);

    unique_ptr<vector<kinetic::KineticStatus>> statuses(new vector<kinetic::KineticStatus>());
    auto status = connection->P2PPush(request, statuses);
    if (!status.ok()) {
        printf("Error pushing: %d, %s\n", status.statusCode(), status.message().c_str());
        exit(1);
    }

    for (auto it = statuses->begin(); it != statuses->end(); ++it) {
        if (it->ok()) {
            printf(".");
        } else {
            printf("%s", it->message().c_str());
        }
    }
    fflush(stdout);
}

int main(int argc, char* argv[]) {
    if (argc < 5 || argc % 2 != 1) {
        printf("%s: <source host> <source port> <destination host> <destination port> [<additional host> <additional port> ... ]\n", argv[0]);
        return 1;
    }

    const char* source_host = argv[1];
    int source_port = atoi(argv[2]);

    vector<pair<string, int>> destinations;

    printf("Copying from %s:%d", source_host, source_port);

    for (int i = 3; i < argc; i += 2) {
        auto destination = make_pair(argv[i], atoi(argv[i + 1]));
        destinations.push_back(destination);
        printf(" -> %s:%d", destination.first, destination.second);
    }
    printf("\n");

    kinetic::ConnectionOptions options;
    options.host = source_host;
    options.port = source_port;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    kinetic::KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    shared_ptr<kinetic::BlockingKineticConnection> blocking_connection;
    if(!kinetic_connection_factory.NewBlockingConnection(options, blocking_connection, 20).ok()){
        printf("Unable to connect\n");
        return 1;
    }

    vector<kinetic::P2PPushOperation> operations;

    // Build a key consisting of "FFFFFF...". In almost all cases this will come after the last
    // key in the drive
    string last_key;
    for (int i = 0; i < 4*1024; i++) {
        last_key += "\xFF";
    }

    // Iterate over all the keys and print them out
    for (kinetic::KeyRangeIterator it = blocking_connection->IterateKeyRange("", true, last_key, true, 100); it != kinetic::KeyRangeEnd(); ++it) {
        kinetic::P2PPushOperation op;
        op.key = *it;
        op.force = true;
        op.newKey = *it;
        operations.push_back(op);

        if (operations.size() > (size_t)kP2PBatchSize) {
            dispatch_request(blocking_connection, operations, destinations);
            operations.clear();
        }
    }

    dispatch_request(blocking_connection, operations, destinations);

    printf("\n");

    return 0;
}

<|endoftext|>


<commit_before>// Copyright Andrew Resch 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/ip_filter.hpp>
#include <boost/python.hpp>
#include "gil.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{
    void add_rule(ip_filter& filter, std::string start, std::string end, int flags)
    {
        return filter.add_rule(address::from_string(start), address::from_string(end), flags);
    }

    int _access(ip_filter& filter, std::string addr)
    {
        return filter.access(address::from_string(addr));
    }
}

void bind_ip_filter()
{
    class_<ip_filter>("ip_filter")
        .def("add_rule", add_rule)
        .def("access", _access)
        .def("export_filter", allow_threads(&ip_filter::export_filter))
    ;
}

<commit_msg>Fix building in windows<commit_after>// Copyright Andrew Resch 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/ip_filter.hpp>
#include <boost/python.hpp>
#include "gil.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{
    void add_rule(ip_filter& filter, std::string start, std::string end, int flags)
    {
        return filter.add_rule(address::from_string(start), address::from_string(end), flags);
    }

    int access0(ip_filter& filter, std::string addr)
    {
        return filter.access(address::from_string(addr));
    }
}

void bind_ip_filter()
{
    class_<ip_filter>("ip_filter")
        .def("add_rule", add_rule)
        .def("access", access0)
        .def("export_filter", allow_threads(&ip_filter::export_filter))
    ;
}
<|endoftext|>


<commit_before>/* Copyright 2017 R. Thomas
 * Copyright 2017 Quarkslab
 *
 * 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 "pyAbstract.hpp"

#include "LIEF/Abstract/Parser.hpp"

#include <string>

namespace LIEF {
template<>
void create<Parser>(py::module& m) {

  m.def("parse",
      [] (py::bytes bytes, const std::string& name) {
        std::string raw_str = bytes;
        std::vector<uint8_t> raw = {
          std::make_move_iterator(std::begin(raw_str)),
          std::make_move_iterator(std::end(raw_str))
        };
        return Parser::parse(std::move(raw), name);
      },
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "raw"_a, "name"_a = "",
      py::return_value_policy::take_ownership);

  m.def("parse",
      static_cast<std::unique_ptr<Binary> (*) (const std::string&)>(&Parser::parse),
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "filepath"_a,
      py::return_value_policy::take_ownership);

  m.def("parse",
      static_cast<std::unique_ptr<Binary> (*) (const std::vector<uint8_t>&, const std::string&)>(&Parser::parse),
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "raw"_a, "name"_a = "",
      py::return_value_policy::take_ownership);

  m.def("parse",
      [] (py::object byteio, const std::string& name) {
        auto&& io = py::module::import("io");
        auto&& RawIOBase = io.attr("RawIOBase");
        auto&& BufferedIOBase = io.attr("BufferedIOBase");
        auto&& TextIOBase = io.attr("TextIOBase");

        py::object rawio;

        if (py::isinstance(byteio, RawIOBase)) {
          rawio = byteio;
        }

        else if (py::isinstance(byteio, BufferedIOBase)) {
          rawio = byteio.attr("raw");
        }

        else if (py::isinstance(byteio, TextIOBase)) {
          rawio = byteio.attr("buffer").attr("raw");
        }

        else {
          throw py::type_error(py::repr(byteio).cast<std::string>().c_str());
        }

        std::string raw_str = static_cast<py::bytes>(rawio.attr("readall")());
        std::vector<uint8_t> raw = {
          std::make_move_iterator(std::begin(raw_str)),
          std::make_move_iterator(std::end(raw_str))
        };

        return Parser::parse(std::move(raw), name);
      },
      "io"_a,
      "name"_a = "",
      py::return_value_policy::take_ownership);
}
}
<commit_msg>feature: release the GIL on parse<commit_after>/* Copyright 2017 R. Thomas
 * Copyright 2017 Quarkslab
 *
 * 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 "pyAbstract.hpp"

#include "LIEF/Abstract/Parser.hpp"

#include <string>

namespace LIEF {
template<>
void create<Parser>(py::module& m) {

  m.def("parse",
      [] (py::bytes bytes, const std::string& name) {
        std::string raw_str = bytes;
        std::vector<uint8_t> raw = {
          std::make_move_iterator(std::begin(raw_str)),
          std::make_move_iterator(std::end(raw_str))
        };
        std::unique_ptr<Binary> binary;
        Py_BEGIN_ALLOW_THREADS
        binary = Parser::parse(std::move(raw), name);
        Py_END_ALLOW_THREADS
        return binary;
      },
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "raw"_a, "name"_a = "",
      py::return_value_policy::take_ownership);

  m.def("parse",
      [] (const std::string& name) {
        std::unique_ptr<Binary> binary;
        Py_BEGIN_ALLOW_THREADS
        binary = Parser::parse(name);
        Py_END_ALLOW_THREADS
        return binary;
      },
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "filepath"_a,
      py::return_value_policy::take_ownership);

  m.def("parse",
      [](const std::vector<uint8_t>& raw, const std::string& name) {
        std::unique_ptr<Binary> binary;
        Py_BEGIN_ALLOW_THREADS
        binary = Parser::parse(raw, name);
        Py_END_ALLOW_THREADS
        return binary;
      },
      "Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
      "raw"_a, "name"_a = "",
      py::return_value_policy::take_ownership);

  m.def("parse",
      [] (py::object byteio, const std::string& name) {
        auto&& io = py::module::import("io");
        auto&& RawIOBase = io.attr("RawIOBase");
        auto&& BufferedIOBase = io.attr("BufferedIOBase");
        auto&& TextIOBase = io.attr("TextIOBase");

        py::object rawio;

        if (py::isinstance(byteio, RawIOBase)) {
          rawio = byteio;
        }

        else if (py::isinstance(byteio, BufferedIOBase)) {
          rawio = byteio.attr("raw");
        }

        else if (py::isinstance(byteio, TextIOBase)) {
          rawio = byteio.attr("buffer").attr("raw");
        }

        else {
          throw py::type_error(py::repr(byteio).cast<std::string>().c_str());
        }

        std::string raw_str = static_cast<py::bytes>(rawio.attr("readall")());
        std::vector<uint8_t> raw = {
          std::make_move_iterator(std::begin(raw_str)),
          std::make_move_iterator(std::end(raw_str))
        };

        std::unique_ptr<Binary> binary;
        Py_BEGIN_ALLOW_THREADS
        binary = Parser::parse(std::move(raw), name);
        Py_END_ALLOW_THREADS
        return binary;
      },
      "io"_a,
      "name"_a = "",
      py::return_value_policy::take_ownership);
}
}
<|endoftext|>


<commit_before><commit_msg>small updates in fitting<commit_after><|endoftext|>