<commit_before>/*
    avdeviceconfig.cpp  -  Kopete Video Device Configuration Panel

    Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro   <taupter@gmail.com>
    Copyright (c) 2010      by Frank Schaefer                 <fschaefer.oss@googlemail.com>

    Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel@kde.org>

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

#include "avdeviceconfig.h"

#include <qcheckbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qbuttongroup.h>
#include <qspinbox.h>
#include <qcombobox.h>
#include <qslider.h>
//Added by qt3to4:
#include <QVBoxLayout>

#include <kplugininfo.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kpluginfactory.h>
#include <ktrader.h>
#include <kconfig.h>
#include <kcombobox.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qtabwidget.h>
#include "IdGuiElements.h"

K_PLUGIN_FACTORY( KopeteAVDeviceConfigFactory,
		registerPlugin<AVDeviceConfig>(); )
K_EXPORT_PLUGIN( KopeteAVDeviceConfigFactory("kcm_kopete_avdeviceconfig") )

AVDeviceConfig::AVDeviceConfig(QWidget *parent, const QVariantList &args)
 : KCModule( KopeteAVDeviceConfigFactory::componentData(), parent, args )
{
	kDebug() << "kopete:config (avdevice): KopeteAVDeviceConfigFactory::componentData() called. ";
// "Video" TAB ============================================================
	mPrfsVideoDevice = new Ui_AVDeviceConfig_VideoDevice();
	mPrfsVideoDevice->setupUi(this);

	// set a default image for the webcam widget, in case the user does not have a video device
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(false);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(KIcon("camera-web").pixmap(128,128));

	connect(mPrfsVideoDevice->mDeviceKComboBox,              SIGNAL(activated(int)),    this, SLOT(slotDeviceKComboBoxChanged(int)));
	connect(mPrfsVideoDevice->mInputKComboBox,               SIGNAL(activated(int)),    this, SLOT(slotInputKComboBoxChanged(int)));
	connect(mPrfsVideoDevice->mStandardKComboBox,            SIGNAL(activated(int)),    this, SLOT(slotStandardKComboBoxChanged(int)));

	mVideoDevicePool = Kopete::AV::VideoDevicePool::self();
	mVideoDevicePool->open();
	mVideoDevicePool->setSize(320, 240);

	setupControls();

	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);

	mVideoDevicePool->startCapturing();

	connect(mVideoDevicePool, SIGNAL(deviceRegistered(const QString &) ),
			SLOT(deviceRegistered(const QString &)) );
	connect(mVideoDevicePool, SIGNAL(deviceUnregistered(const QString &) ),
			SLOT(deviceUnregistered(const QString &)) );

	connect(&qtimer, SIGNAL(timeout()), this, SLOT(slotUpdateImage()) );
#define DONT_TRY_TO_GRAB 1
#if DONT_TRY_TO_GRAB
	if ( mVideoDevicePool->hasDevices() ) {
		qtimer.start(40);
		mPrfsVideoDevice->mVideoImageLabel->setScaledContents(true);
	}
#endif
}

AVDeviceConfig::~AVDeviceConfig()
{
	mVideoDevicePool->close();
	clearControlGUIElements();
}

void AVDeviceConfig::setupControls()
{
	int k = 0;
	qint32 cval = 0;
	clearControlGUIElements();

	QList<Kopete::AV::NumericVideoControl> numericCtrls;
	QList<Kopete::AV::BooleanVideoControl> booleanCtrls;
	QList<Kopete::AV::MenuVideoControl> menuCtrls;
	QList<Kopete::AV::ActionVideoControl> actionCtrls;
	numericCtrls = mVideoDevicePool->getSupportedNumericControls();
	booleanCtrls = mVideoDevicePool->getSupportedBooleanControls();
	menuCtrls = mVideoDevicePool->getSupportedMenuControls();
	actionCtrls = mVideoDevicePool->getSupportedActionControls();

	kDebug() << "Supported controls:" << numericCtrls.size() << "numeric," << booleanCtrls.size()
		<< "boolean," << menuCtrls.size() << "menus," << actionCtrls.size() << "actions.";

	/* SETUP GUI-elements */
	// Numeric Controls: => Slider
	for (k=0; k<numericCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(numericCtrls.at(k).id, &cval);
		addSliderControlElement(numericCtrls.at(k).id, numericCtrls.at(k).name, numericCtrls.at(k).value_min, numericCtrls.at(k).value_max, numericCtrls.at(k).value_step, cval);
	}
	// Boolean Controls: => Checkbox
	for (k=0; k<booleanCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(booleanCtrls.at(k).id, &cval);
		addCheckBoxControlElement(booleanCtrls.at(k).id, booleanCtrls.at(k).name, cval);
	}
	// Menu Controls: => Combobox
	for (k=0; k<menuCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(menuCtrls.at(k).id, &cval);
		addPopupMenuControlElement(menuCtrls.at(k).id, menuCtrls.at(k).name, menuCtrls.at(k).options, cval);
	}
	// Action Controls: => Button
	for (k=0; k<actionCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(actionCtrls.at(k).id, &cval);
		addButtonControlElement(actionCtrls.at(k).id, actionCtrls.at(k).name);
	}
	/* TODO: check success of mVideoDevicePool->getControlValue() */
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(1, numericCtrls.size());
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(2, booleanCtrls.size() + menuCtrls.size());
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(3, actionCtrls.size());
}

void AVDeviceConfig::clearControlGUIElements()
{
	for (int k=0; k<ctrlWidgets.size(); k++)
		delete ctrlWidgets.at(k);
	ctrlWidgets.clear();
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(1, false);
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(2, false);
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(3, false);
}

void AVDeviceConfig::addSliderControlElement(int cid, QString title, int min, int max, int step, int value)
{
	int insert_row = mPrfsVideoDevice->sliders_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->sliders_gridLayout->addWidget( label, insert_row, 0 );
	IdSlider *slider = new IdSlider(cid, Qt::Horizontal, mPrfsVideoDevice->VideoTabWidget);
	mPrfsVideoDevice->sliders_gridLayout->addWidget( slider, insert_row, 1 );
	slider->setMinimum( min );
	slider->setMaximum( max );
	slider->setSliderPosition( value );
	slider->setTickInterval( step );
	connect( slider, SIGNAL( valueChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(slider);
}

void AVDeviceConfig::addCheckBoxControlElement(int cid, QString title, bool value)
{
	IdCheckBox *checkbox = new IdCheckBox( cid, mPrfsVideoDevice->VideoTabWidget );
	checkbox->setText( title );
	mPrfsVideoDevice->checkboxOptions_verticalLayout->addWidget( checkbox );
	checkbox->setChecked( value );
	connect( checkbox, SIGNAL( stateChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(checkbox);
}

void AVDeviceConfig::addPopupMenuControlElement(int cid, QString title, QStringList options, int menuindex)
{
	int insert_row = mPrfsVideoDevice->menuOptions_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->menuOptions_gridLayout->addWidget( label, insert_row, 0 );
	IdComboBox *combobox = new IdComboBox( cid, mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->menuOptions_gridLayout->addWidget( combobox, insert_row, 1 );
	combobox->addItems( options );
	combobox->setCurrentIndex( menuindex );
	connect( combobox, SIGNAL( currentIndexChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(combobox);
}

void AVDeviceConfig::addButtonControlElement(int cid, QString title)
{
	int insert_row = mPrfsVideoDevice->actions_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->actions_gridLayout->addWidget( label, insert_row, 0 );
	IdPushButton *button = new IdPushButton( cid, mPrfsVideoDevice->VideoTabWidget );
	button->setText( i18n("Execute") );
	mPrfsVideoDevice->actions_gridLayout->addWidget( button, insert_row, 1 );
	connect( button, SIGNAL( pressed(uint) ), this, SLOT( changeVideoControlValue(uint) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(button);
}

/*!
    \fn VideoDeviceConfig::save()
 */
void AVDeviceConfig::save()
{
    /// @todo implement me
	kDebug() << "kopete:config (avdevice): save() called. ";
	mVideoDevicePool->saveConfig();
}

/*!
    \fn VideoDeviceConfig::load()
 */
void AVDeviceConfig::load()
{
    /// @todo implement me
}

void AVDeviceConfig::slotSettingsChanged(bool){
  emit changed(true);
}

void AVDeviceConfig::slotValueChanged(int){
  emit changed( true );
}

void AVDeviceConfig::slotDeviceKComboBoxChanged(int){
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) called. ";
	int newdevice = mPrfsVideoDevice->mDeviceKComboBox->currentIndex();
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) Current device: " << mVideoDevicePool->currentDevice() << "New device: " << newdevice;
	if ((newdevice >= 0 && newdevice < mVideoDevicePool->size()) && (newdevice != mVideoDevicePool->currentDevice()))
	{
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) should change device. ";
		mVideoDevicePool->open(newdevice);
		mVideoDevicePool->setSize(320, 240);
		mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
		mVideoDevicePool->startCapturing();
		setupControls();
		kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) called. ";
		emit changed( true );
	}
}

void AVDeviceConfig::slotInputKComboBoxChanged(int){
	int newinput = mPrfsVideoDevice->mInputKComboBox->currentIndex();
	if((newinput < mVideoDevicePool->inputs()) && ( newinput !=mVideoDevicePool->currentInput()))
	{
		mVideoDevicePool->selectInput(mPrfsVideoDevice->mInputKComboBox->currentIndex());
		mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
		setupControls(); // NOTE: supported controls+values may be different for each input !
		emit changed( true );
	}
}

// ATTENTION: The 65535.0 value must be used instead of 65535 because the trailing ".0" converts the resulting value to floating point number.
// Otherwise the resulting division operation would return 0 or 1 exclusively.

void AVDeviceConfig::slotStandardKComboBoxChanged(int){
  emit changed( true );
}

void AVDeviceConfig::changeVideoControlValue(unsigned int id, int value)
{
	mVideoDevicePool->setControlValue(id, value);
	emit changed( true );
	/* TODO: Check success, fallback */
}

void AVDeviceConfig::slotUpdateImage()
{
	mVideoDevicePool->getFrame();
	mVideoDevicePool->getImage(&qimage);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(QPixmap::fromImage(qimage));
	//kDebug() << "kopete (avdeviceconfig_videoconfig): Image updated.";
}

void AVDeviceConfig::deviceRegistered( const QString & udi )
{
	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);

	// update the mVideoImageLabel to show the camera frames
	mVideoDevicePool->open();
	mVideoDevicePool->setSize(320, 240);
	mVideoDevicePool->startCapturing();

	setupControls();

	qtimer.start(40);
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(true);
}

void AVDeviceConfig::deviceUnregistered( const QString & udi )
{
	qtimer.stop();
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(false);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(KIcon("camera-web").pixmap(128,128));
	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
	clearControlGUIElements();
}
<commit_msg>avdeviceconfig: do not read the values of action-video-controls<commit_after>/*
    avdeviceconfig.cpp  -  Kopete Video Device Configuration Panel

    Copyright (c) 2005-2006 by Cláudio da Silveira Pinheiro   <taupter@gmail.com>
    Copyright (c) 2010      by Frank Schaefer                 <fschaefer.oss@googlemail.com>

    Kopete    (c) 2002-2003      by the Kopete developers  <kopete-devel@kde.org>

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

#include "avdeviceconfig.h"

#include <qcheckbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qbuttongroup.h>
#include <qspinbox.h>
#include <qcombobox.h>
#include <qslider.h>
//Added by qt3to4:
#include <QVBoxLayout>

#include <kplugininfo.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kpluginfactory.h>
#include <ktrader.h>
#include <kconfig.h>
#include <kcombobox.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qtabwidget.h>
#include "IdGuiElements.h"

K_PLUGIN_FACTORY( KopeteAVDeviceConfigFactory,
		registerPlugin<AVDeviceConfig>(); )
K_EXPORT_PLUGIN( KopeteAVDeviceConfigFactory("kcm_kopete_avdeviceconfig") )

AVDeviceConfig::AVDeviceConfig(QWidget *parent, const QVariantList &args)
 : KCModule( KopeteAVDeviceConfigFactory::componentData(), parent, args )
{
	kDebug() << "kopete:config (avdevice): KopeteAVDeviceConfigFactory::componentData() called. ";
// "Video" TAB ============================================================
	mPrfsVideoDevice = new Ui_AVDeviceConfig_VideoDevice();
	mPrfsVideoDevice->setupUi(this);

	// set a default image for the webcam widget, in case the user does not have a video device
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(false);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(KIcon("camera-web").pixmap(128,128));

	connect(mPrfsVideoDevice->mDeviceKComboBox,              SIGNAL(activated(int)),    this, SLOT(slotDeviceKComboBoxChanged(int)));
	connect(mPrfsVideoDevice->mInputKComboBox,               SIGNAL(activated(int)),    this, SLOT(slotInputKComboBoxChanged(int)));
	connect(mPrfsVideoDevice->mStandardKComboBox,            SIGNAL(activated(int)),    this, SLOT(slotStandardKComboBoxChanged(int)));

	mVideoDevicePool = Kopete::AV::VideoDevicePool::self();
	mVideoDevicePool->open();
	mVideoDevicePool->setSize(320, 240);

	setupControls();

	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);

	mVideoDevicePool->startCapturing();

	connect(mVideoDevicePool, SIGNAL(deviceRegistered(const QString &) ),
			SLOT(deviceRegistered(const QString &)) );
	connect(mVideoDevicePool, SIGNAL(deviceUnregistered(const QString &) ),
			SLOT(deviceUnregistered(const QString &)) );

	connect(&qtimer, SIGNAL(timeout()), this, SLOT(slotUpdateImage()) );
#define DONT_TRY_TO_GRAB 1
#if DONT_TRY_TO_GRAB
	if ( mVideoDevicePool->hasDevices() ) {
		qtimer.start(40);
		mPrfsVideoDevice->mVideoImageLabel->setScaledContents(true);
	}
#endif
}

AVDeviceConfig::~AVDeviceConfig()
{
	mVideoDevicePool->close();
	clearControlGUIElements();
}

void AVDeviceConfig::setupControls()
{
	int k = 0;
	qint32 cval = 0;
	clearControlGUIElements();

	QList<Kopete::AV::NumericVideoControl> numericCtrls;
	QList<Kopete::AV::BooleanVideoControl> booleanCtrls;
	QList<Kopete::AV::MenuVideoControl> menuCtrls;
	QList<Kopete::AV::ActionVideoControl> actionCtrls;
	numericCtrls = mVideoDevicePool->getSupportedNumericControls();
	booleanCtrls = mVideoDevicePool->getSupportedBooleanControls();
	menuCtrls = mVideoDevicePool->getSupportedMenuControls();
	actionCtrls = mVideoDevicePool->getSupportedActionControls();

	kDebug() << "Supported controls:" << numericCtrls.size() << "numeric," << booleanCtrls.size()
		<< "boolean," << menuCtrls.size() << "menus," << actionCtrls.size() << "actions.";

	/* SETUP GUI-elements */
	// Numeric Controls: => Slider
	for (k=0; k<numericCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(numericCtrls.at(k).id, &cval);
		addSliderControlElement(numericCtrls.at(k).id, numericCtrls.at(k).name, numericCtrls.at(k).value_min, numericCtrls.at(k).value_max, numericCtrls.at(k).value_step, cval);
	}
	// Boolean Controls: => Checkbox
	for (k=0; k<booleanCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(booleanCtrls.at(k).id, &cval);
		addCheckBoxControlElement(booleanCtrls.at(k).id, booleanCtrls.at(k).name, cval);
	}
	// Menu Controls: => Combobox
	for (k=0; k<menuCtrls.size(); k++)
	{
		mVideoDevicePool->getControlValue(menuCtrls.at(k).id, &cval);
		addPopupMenuControlElement(menuCtrls.at(k).id, menuCtrls.at(k).name, menuCtrls.at(k).options, cval);
	}
	// Action Controls: => Button
	for (k=0; k<actionCtrls.size(); k++)
		addButtonControlElement(actionCtrls.at(k).id, actionCtrls.at(k).name);
	/* TODO: check success of mVideoDevicePool->getControlValue() */
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(1, numericCtrls.size());
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(2, booleanCtrls.size() + menuCtrls.size());
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(3, actionCtrls.size());
}

void AVDeviceConfig::clearControlGUIElements()
{
	for (int k=0; k<ctrlWidgets.size(); k++)
		delete ctrlWidgets.at(k);
	ctrlWidgets.clear();
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(1, false);
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(2, false);
	mPrfsVideoDevice->VideoTabWidget->setTabEnabled(3, false);
}

void AVDeviceConfig::addSliderControlElement(int cid, QString title, int min, int max, int step, int value)
{
	int insert_row = mPrfsVideoDevice->sliders_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->sliders_gridLayout->addWidget( label, insert_row, 0 );
	IdSlider *slider = new IdSlider(cid, Qt::Horizontal, mPrfsVideoDevice->VideoTabWidget);
	mPrfsVideoDevice->sliders_gridLayout->addWidget( slider, insert_row, 1 );
	slider->setMinimum( min );
	slider->setMaximum( max );
	slider->setSliderPosition( value );
	slider->setTickInterval( step );
	connect( slider, SIGNAL( valueChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(slider);
}

void AVDeviceConfig::addCheckBoxControlElement(int cid, QString title, bool value)
{
	IdCheckBox *checkbox = new IdCheckBox( cid, mPrfsVideoDevice->VideoTabWidget );
	checkbox->setText( title );
	mPrfsVideoDevice->checkboxOptions_verticalLayout->addWidget( checkbox );
	checkbox->setChecked( value );
	connect( checkbox, SIGNAL( stateChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(checkbox);
}

void AVDeviceConfig::addPopupMenuControlElement(int cid, QString title, QStringList options, int menuindex)
{
	int insert_row = mPrfsVideoDevice->menuOptions_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->menuOptions_gridLayout->addWidget( label, insert_row, 0 );
	IdComboBox *combobox = new IdComboBox( cid, mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->menuOptions_gridLayout->addWidget( combobox, insert_row, 1 );
	combobox->addItems( options );
	combobox->setCurrentIndex( menuindex );
	connect( combobox, SIGNAL( currentIndexChanged(uint, int) ), this, SLOT( changeVideoControlValue(uint, int) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(combobox);
}

void AVDeviceConfig::addButtonControlElement(int cid, QString title)
{
	int insert_row = mPrfsVideoDevice->actions_gridLayout->rowCount();
	QLabel *label = new QLabel( title + ":", mPrfsVideoDevice->VideoTabWidget );
	mPrfsVideoDevice->actions_gridLayout->addWidget( label, insert_row, 0 );
	IdPushButton *button = new IdPushButton( cid, mPrfsVideoDevice->VideoTabWidget );
	button->setText( i18n("Execute") );
	mPrfsVideoDevice->actions_gridLayout->addWidget( button, insert_row, 1 );
	connect( button, SIGNAL( pressed(uint) ), this, SLOT( changeVideoControlValue(uint) ) );
	ctrlWidgets.push_back(label);
	ctrlWidgets.push_back(button);
}

/*!
    \fn VideoDeviceConfig::save()
 */
void AVDeviceConfig::save()
{
    /// @todo implement me
	kDebug() << "kopete:config (avdevice): save() called. ";
	mVideoDevicePool->saveConfig();
}

/*!
    \fn VideoDeviceConfig::load()
 */
void AVDeviceConfig::load()
{
    /// @todo implement me
}

void AVDeviceConfig::slotSettingsChanged(bool){
  emit changed(true);
}

void AVDeviceConfig::slotValueChanged(int){
  emit changed( true );
}

void AVDeviceConfig::slotDeviceKComboBoxChanged(int){
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) called. ";
	int newdevice = mPrfsVideoDevice->mDeviceKComboBox->currentIndex();
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) Current device: " << mVideoDevicePool->currentDevice() << "New device: " << newdevice;
	if ((newdevice >= 0 && newdevice < mVideoDevicePool->size()) && (newdevice != mVideoDevicePool->currentDevice()))
	{
	kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) should change device. ";
		mVideoDevicePool->open(newdevice);
		mVideoDevicePool->setSize(320, 240);
		mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
		mVideoDevicePool->startCapturing();
		setupControls();
		kDebug() << "kopete:config (avdevice): slotDeviceKComboBoxChanged(int) called. ";
		emit changed( true );
	}
}

void AVDeviceConfig::slotInputKComboBoxChanged(int){
	int newinput = mPrfsVideoDevice->mInputKComboBox->currentIndex();
	if((newinput < mVideoDevicePool->inputs()) && ( newinput !=mVideoDevicePool->currentInput()))
	{
		mVideoDevicePool->selectInput(mPrfsVideoDevice->mInputKComboBox->currentIndex());
		mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
		setupControls(); // NOTE: supported controls+values may be different for each input !
		emit changed( true );
	}
}

// ATTENTION: The 65535.0 value must be used instead of 65535 because the trailing ".0" converts the resulting value to floating point number.
// Otherwise the resulting division operation would return 0 or 1 exclusively.

void AVDeviceConfig::slotStandardKComboBoxChanged(int){
  emit changed( true );
}

void AVDeviceConfig::changeVideoControlValue(unsigned int id, int value)
{
	mVideoDevicePool->setControlValue(id, value);
	emit changed( true );
	/* TODO: Check success, fallback */
}

void AVDeviceConfig::slotUpdateImage()
{
	mVideoDevicePool->getFrame();
	mVideoDevicePool->getImage(&qimage);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(QPixmap::fromImage(qimage));
	//kDebug() << "kopete (avdeviceconfig_videoconfig): Image updated.";
}

void AVDeviceConfig::deviceRegistered( const QString & udi )
{
	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);

	// update the mVideoImageLabel to show the camera frames
	mVideoDevicePool->open();
	mVideoDevicePool->setSize(320, 240);
	mVideoDevicePool->startCapturing();

	setupControls();

	qtimer.start(40);
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(true);
}

void AVDeviceConfig::deviceUnregistered( const QString & udi )
{
	qtimer.stop();
	mPrfsVideoDevice->mVideoImageLabel->setScaledContents(false);
	mPrfsVideoDevice->mVideoImageLabel->setPixmap(KIcon("camera-web").pixmap(128,128));
	mVideoDevicePool->fillDeviceKComboBox(mPrfsVideoDevice->mDeviceKComboBox);
	mVideoDevicePool->fillInputKComboBox(mPrfsVideoDevice->mInputKComboBox);
	mVideoDevicePool->fillStandardKComboBox(mPrfsVideoDevice->mStandardKComboBox);
	clearControlGUIElements();
}
<|endoftext|>


<commit_before>//-----本文件是对于maincall.h中部分函数的实现部分-----
#include "maincall.h"

void maincall::StartGame()//入口函数
{
    /*QVector<QString>addr;
    addr<<"D:/梦影测试/陈的混混/2.jpg";
    addr<<"D:/梦影测试/陈的混混/1.jpg";
    addr<<"D:/梦影测试/陈的混混/3.jpg";
    //addr<<"D:/梦影测试/陈的混混/2.jpg";
    AddPicAnimation(addr,0,0,700);
    AddTextItem("C++是垃圾语言","宋体",20,0,0,230,0,0);*/
    QPixmap *pixmap=NewQPixmap("D:/梦影测试/陈的混混/2.jpg");
    AddPixmapItem(pixmap,0,0);
    AddPixmapItem(pixmap,200,300);
}
<commit_msg>Beta v2.56<commit_after>//-----本文件是对于maincall.h中部分函数的实现部分-----
#include "maincall.h"

void maincall::StartGame()//入口函数
{

}
<|endoftext|>


<commit_before>#pragma comment(lib, "Shlwapi.lib")

#pragma warning(disable:4996)

#include "Observer.h"

#include <cstdio>
#include <cstdlib>
#include <tchar.h>
#include <string>
#include <utility>
#include <functional>
#include <concurrent_unordered_map.h>

#include <Windows.h>
#include <Shlwapi.h>
#include "bass.h"
#include "bass_fx.h"
#include "Hooker.h"
#include "Server.h"

#define AUDIO_FILE_INFO_TOKEN "AudioFilename:"

std::shared_ptr<Observer> Observer::instance;
std::once_flag Observer::once_flag;

BOOL WINAPI Observer::ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    Observer *instance = Observer::GetInstance();

    if (!instance->hookerReadFile.GetFunction()(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped))
    {
        return FALSE;
    }

    TCHAR szFilePath[MAX_PATH];
    DWORD nFilePathLength = GetFinalPathNameByHandle(hFile, szFilePath, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD dwFilePosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - (*lpNumberOfBytesRead);
    //  д  Ʈ ̰ պκ оٸ    :
    // AudioFilename պκп  /  ڵ       !
    if (wcsncmp(L".osu", &szFilePath[nFilePathLength - 4], 4) == 0 && dwFilePosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        // .osu  UTF-8(Multibyte) ڵ

		/* ٸ strtok ߶󳻼 AudioFilename:  ã. */
        char *buffer = strdup((const char*)(lpBuffer));

		for (char *line = strtok(buffer, "\n"); line != NULL; line = strtok(NULL, "\n"))
        {
            if (strnicmp(line, AUDIO_FILE_INFO_TOKEN, 14) != 0)
            {
                continue;
            }

            // AudioFilename
            TCHAR szAudioFileName[MAX_PATH];

            mbstowcs(szAudioFileName, &line[14], MAX_PATH);
            StrTrimW(szAudioFileName, L" \r");

            TCHAR szAudioFilePath[MAX_PATH];

			/* պκ ̻ ڸ ϱ 4° ں . */
            wcscpy(szAudioFilePath, &szFilePath[4]);
            PathRemoveFileSpecW(szAudioFilePath);
            PathCombineW(szAudioFilePath, szAudioFilePath, szAudioFileName);

			EnterCriticalSection(&instance->hCritiaclSection);

			instance->currentPlaying.audioPath = tstring(szAudioFilePath);
			/* պκ ̻ ڸ ϱ 4° ں . */
			instance->currentPlaying.beatmapPath = (tstring(&szFilePath[4]));

			LeaveCriticalSection(&instance->hCritiaclSection);

            break;
        }

        free(buffer);
    }
    return TRUE;
}

inline long long GetCurrentSysTime()
{
    long long t;
    GetSystemTimeAsFileTime(reinterpret_cast<LPFILETIME>(&t));
    return t;
}

BOOL WINAPI Observer::BASS_ChannelPlay(DWORD handle, BOOL restart)
{
    Observer *instance = Observer::GetInstance();

    if (!instance->hookerBASS_ChannelPlay.GetFunction()(handle, restart))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTimePos = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        float tempo; BASS_ChannelGetAttribute(handle, BASS_ATTRIB_TEMPO, &tempo);
        instance->SendInfomation(GetCurrentSysTime(), currentTimePos, tempo);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelSetPosition(DWORD handle, QWORD pos, DWORD mode)
{
    Observer *instance = Observer::GetInstance();
    if (!instance->hookerBASS_ChannelSetPosition.GetFunction()(handle, pos, mode))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, pos);
        float CurrentTempo; BASS_ChannelGetAttribute(handle, BASS_ATTRIB_TEMPO, &CurrentTempo);
        // !! pos   ,
        // ϸ BASS_ChannelPlay  Լ ȣǰ,
        // BASS_ChannelIsActive  BASS_ACTIVE_PAUSED.
        if (BASS_ChannelIsActive(handle) == BASS_ACTIVE_PAUSED)
        {
            CurrentTempo = -100;
        }

        instance->SendInfomation(GetCurrentSysTime(), currentTime, CurrentTempo);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelSetAttribute(DWORD handle, DWORD attrib, float value)
{
    Observer *instance = Observer::GetInstance();
    if (!instance->hookerBASS_ChannelSetAttribute.GetFunction()(handle, attrib, value))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if ((info.ctype & BASS_CTYPE_STREAM) && attrib == BASS_ATTRIB_TEMPO)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        instance->SendInfomation(GetCurrentSysTime(), currentTime, value);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelPause(DWORD handle)
{
    Observer *instance = Observer::GetInstance();
    if (!instance->hookerBASS_ChannelPause.GetFunction()(handle))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);
    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        instance->SendInfomation(GetCurrentSysTime(), currentTime, -100);
    }
    return TRUE;
}

void Observer::SendInfomation(long long calledAt, double currentTime, float tempo)
{
    TCHAR message[Server::nMessageLength];

    Observer *instance = Observer::GetInstance();

	/* Get Current Playing */
    EnterCriticalSection(&instance->hCritiaclSection);
    swprintf(message, L"%llx|%s|%lf|%f|%s\n",
		calledAt,
		instance->currentPlaying.audioPath.c_str(),
		currentTime,
		tempo,
		instance->currentPlaying.beatmapPath.c_str());
	LeaveCriticalSection(&instance->hCritiaclSection);

    Server::GetInstance()->PushMessage(message);
}

void Observer::Initalize()
{
    this->hookerReadFile.Hook();

    this->hookerBASS_ChannelPlay.Hook();
    this->hookerBASS_ChannelSetPosition.Hook();
    this->hookerBASS_ChannelSetAttribute.Hook();
    this->hookerBASS_ChannelPause.Hook();
}

void Observer::Release()
{
    this->hookerBASS_ChannelPause.Unhook();
    this->hookerBASS_ChannelSetAttribute.Unhook();
    this->hookerBASS_ChannelSetPosition.Unhook();
    this->hookerBASS_ChannelPlay.Unhook();

    this->hookerReadFile.Unhook();
}
<commit_msg>instance가 static이라 GetInstance 없어도 됨<commit_after>#pragma comment(lib, "Shlwapi.lib")

#pragma warning(disable:4996)

#include "Observer.h"

#include <cstdio>
#include <cstdlib>
#include <tchar.h>
#include <string>
#include <utility>
#include <functional>
#include <concurrent_unordered_map.h>

#include <Windows.h>
#include <Shlwapi.h>
#include "bass.h"
#include "bass_fx.h"
#include "Hooker.h"
#include "Server.h"

#define AUDIO_FILE_INFO_TOKEN "AudioFilename:"

std::shared_ptr<Observer> Observer::instance;
std::once_flag Observer::once_flag;

BOOL WINAPI Observer::ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    if (!instance->hookerReadFile.GetFunction()(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped))
    {
        return FALSE;
    }

    TCHAR szFilePath[MAX_PATH];
    DWORD nFilePathLength = GetFinalPathNameByHandle(hFile, szFilePath, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD dwFilePosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - (*lpNumberOfBytesRead);
    //  д  Ʈ ̰ պκ оٸ    :
    // AudioFilename պκп  /  ڵ       !
    if (wcsncmp(L".osu", &szFilePath[nFilePathLength - 4], 4) == 0 && dwFilePosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        // .osu  UTF-8(Multibyte) ڵ

		/* ٸ strtok ߶󳻼 AudioFilename:  ã. */
        char *buffer = strdup((const char*)(lpBuffer));

		for (char *line = strtok(buffer, "\n"); line != NULL; line = strtok(NULL, "\n"))
        {
            if (strnicmp(line, AUDIO_FILE_INFO_TOKEN, 14) != 0)
            {
                continue;
            }

            // AudioFilename
            TCHAR szAudioFileName[MAX_PATH];

            mbstowcs(szAudioFileName, &line[14], MAX_PATH);
            StrTrimW(szAudioFileName, L" \r");

            TCHAR szAudioFilePath[MAX_PATH];

			/* պκ ̻ ڸ ϱ 4° ں . */
            wcscpy(szAudioFilePath, &szFilePath[4]);
            PathRemoveFileSpecW(szAudioFilePath);
            PathCombineW(szAudioFilePath, szAudioFilePath, szAudioFileName);

			EnterCriticalSection(&instance->hCritiaclSection);

			instance->currentPlaying.audioPath = tstring(szAudioFilePath);
			/* պκ ̻ ڸ ϱ 4° ں . */
			instance->currentPlaying.beatmapPath = (tstring(&szFilePath[4]));

			LeaveCriticalSection(&instance->hCritiaclSection);

            break;
        }

        free(buffer);
    }
    return TRUE;
}

inline long long GetCurrentSysTime()
{
    long long t;
    GetSystemTimeAsFileTime(reinterpret_cast<LPFILETIME>(&t));
    return t;
}

BOOL WINAPI Observer::BASS_ChannelPlay(DWORD handle, BOOL restart)
{
    if (!instance->hookerBASS_ChannelPlay.GetFunction()(handle, restart))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTimePos = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        float tempo; BASS_ChannelGetAttribute(handle, BASS_ATTRIB_TEMPO, &tempo);
        instance->SendInfomation(GetCurrentSysTime(), currentTimePos, tempo);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelSetPosition(DWORD handle, QWORD pos, DWORD mode)
{
    if (!instance->hookerBASS_ChannelSetPosition.GetFunction()(handle, pos, mode))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, pos);
        float CurrentTempo; BASS_ChannelGetAttribute(handle, BASS_ATTRIB_TEMPO, &CurrentTempo);
        // !! pos   ,
        // ϸ BASS_ChannelPlay  Լ ȣǰ,
        // BASS_ChannelIsActive  BASS_ACTIVE_PAUSED.
        if (BASS_ChannelIsActive(handle) == BASS_ACTIVE_PAUSED)
        {
            CurrentTempo = -100;
        }

        instance->SendInfomation(GetCurrentSysTime(), currentTime, CurrentTempo);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelSetAttribute(DWORD handle, DWORD attrib, float value)
{
    if (!instance->hookerBASS_ChannelSetAttribute.GetFunction()(handle, attrib, value))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);

    if ((info.ctype & BASS_CTYPE_STREAM) && attrib == BASS_ATTRIB_TEMPO)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        instance->SendInfomation(GetCurrentSysTime(), currentTime, value);
    }
    return TRUE;
}

BOOL WINAPI Observer::BASS_ChannelPause(DWORD handle)
{
    if (!instance->hookerBASS_ChannelPause.GetFunction()(handle))
    {
        return FALSE;
    }

    BASS_CHANNELINFO info;
    BASS_ChannelGetInfo(handle, &info);
    if (info.ctype & BASS_CTYPE_STREAM)
    {
        double currentTime = BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetPosition(handle, BASS_POS_BYTE));
        instance->SendInfomation(GetCurrentSysTime(), currentTime, -100);
    }
    return TRUE;
}

void Observer::SendInfomation(long long calledAt, double currentTime, float tempo)
{
    TCHAR message[Server::nMessageLength];

	/* Get Current Playing */
    EnterCriticalSection(&instance->hCritiaclSection);
    swprintf(message, L"%llx|%s|%lf|%f|%s\n",
		calledAt,
		instance->currentPlaying.audioPath.c_str(),
		currentTime,
		tempo,
		instance->currentPlaying.beatmapPath.c_str());
	LeaveCriticalSection(&instance->hCritiaclSection);

    Server::GetInstance()->PushMessage(message);
}

void Observer::Initalize()
{
    this->hookerReadFile.Hook();

    this->hookerBASS_ChannelPlay.Hook();
    this->hookerBASS_ChannelSetPosition.Hook();
    this->hookerBASS_ChannelSetAttribute.Hook();
    this->hookerBASS_ChannelPause.Hook();
}

void Observer::Release()
{
    this->hookerBASS_ChannelPause.Unhook();
    this->hookerBASS_ChannelSetAttribute.Unhook();
    this->hookerBASS_ChannelSetPosition.Unhook();
    this->hookerBASS_ChannelPlay.Unhook();

    this->hookerReadFile.Unhook();
}
<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_H
#define MOZART_BOOSTENV_H

#include <csignal>
#include <exception>
#include <fstream>

#include "boostenv-decl.hh"

#include "boostvm.hh"
#include "boostenvutils.hh"
#include "boostenvtcp.hh"
#include "boostenvpipe.hh"
#include "boostenvbigint.hh"

#ifndef MOZART_GENERATOR

namespace mozart { namespace boostenv {

//////////////////////
// BoostEnvironment //
//////////////////////

namespace {
  /* TODO It might be worth, someday, to investigate how we can lift this
   * decoding to the Oz level.
   * It should somewhere in Resolve.oz and/or URL.oz.
   * But at the same time, not forgetting that this function implements
   * bootURLLoad (not a hypothetical bootFileLoad)!
   *
   * In fact it is already a duplicate of the logic in OS.oz.
   */

  inline
  char hexDigitToValue(char digit) {
    // Don't care to give meaningful results if the digit is not valid
    if (digit <= '9')
      return digit - '0';
    else if (digit <= 'Z')
      return digit - ('A'-10);
    else
      return digit - ('a'-10);
  }

  inline
  std::string decodeURL(const std::string& encoded) {
    // Fast path when there is nothing to do
    if (encoded.find('%') == std::string::npos)
      return encoded;

    // Relevant reminder: Unicode URLs are UTF-8 encoded then %-escaped

    std::string decoded;
    decoded.reserve(encoded.size());

    for (size_t i = 0; i < encoded.size(); ++i) {
      char c = encoded[i];
      if (c == '%' && (i+2 < encoded.size())) {
        char v1 = hexDigitToValue(encoded[++i]);
        char v2 = hexDigitToValue(encoded[++i]);
        decoded.push_back((v1 << 4) | v2);
      } else {
        decoded.push_back(c);
      }
    }

    return decoded;
  }

  inline
  std::string decodedURLToFilename(const std::string& url) {
    // Not sure this is the right test (why not // ?), but it was so in Mozart 1
    if (url.substr(0, 5) == "file:")
      return url.substr(5);
    else
      return url;
  }

  bool defaultBootLoader(VM vm, const std::string& url, UnstableNode& result) {
    std::string filename = decodedURLToFilename(decodeURL(url));
    std::ifstream input(filename, std::ios::binary);
    if (!input.is_open())
      return false;
    result = bootUnpickle(vm, input);
    return true;
  }
}

BoostEnvironment::BoostEnvironment(const VMStarter& vmStarter) :
  _nextVMIdentifier(InitialVMIdentifier), _exitCode(0),
  vmStarter(vmStarter) {
  // Set up a default boot loader
  setBootLoader(&defaultBootLoader);

  // Ignore SIGPIPE ourselves since Boost does not always do it
#ifdef SIGPIPE
  std::signal(SIGPIPE, SIG_IGN);
#endif
}

VMIdentifier BoostEnvironment::addVM(const std::string& app, bool isURL,
                                     VirtualMachineOptions options) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  _vms.emplace_front(*this, _nextVMIdentifier++, options, app, isURL);
  return _vms.front().identifier;
}

VMIdentifier BoostEnvironment::checkValidIdentifier(VM vm, RichNode vmIdentifier) {
  VMIdentifier identifier = getArgument<VMIdentifier>(vm, vmIdentifier);
  if (identifier > 0 && identifier < _nextVMIdentifier) {
    return identifier;
  } else {
    raiseError(vm, buildTuple(vm, "vm", "invalidVMIdent"));
  }
}

/* Calls onSuccess if a VM with the given identifier is found.
   The _vmsMutex is hold during the call, so it is safe to assume that
   the BoostVM will not be terminated during the call.
   Returns whether it found the VM represented by identifier. */
bool BoostEnvironment::findVM(VMIdentifier identifier,
                              std::function<void(BoostVM& boostVM)> onSuccess) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  for (BoostVM& vm : _vms) {
    if (vm.identifier == identifier) {
      onSuccess(vm);
      return true;
    }
  }
  return false;
}

UnstableNode BoostEnvironment::listVMs(VM vm) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  UnstableNode list = buildList(vm);
  for (BoostVM& boostVM : _vms)
    list = buildCons(vm, build(vm, boostVM.identifier), list);
  return list;
}

void BoostEnvironment::killVM(VMIdentifier identifier, nativeint exitCode,
                              const std::string& reason) {
  findVM(identifier, [this, exitCode, reason] (BoostVM& targetVM) {
    targetVM.requestTermination(exitCode, reason);
  });
}

void BoostEnvironment::removeTerminatedVM(VMIdentifier identifier,
                                          nativeint exitCode,
                                          boost::asio::io_service::work* work) {
  std::lock_guard<std::mutex> lock(_vmsMutex);

  // Warning: the BoostVM is calling its own destructor with remove_if().
  // We also need VirtualMachine destructor to do its cleanup before dying.
  _vms.remove_if([=] (const BoostVM& vm) {
    return vm.identifier == identifier;
  });

  if (identifier == InitialVMIdentifier) // only the exitCode of the initial VM is considered
    _exitCode = exitCode;

  // Tell the IO thread it does not need to wait anymore for us
  delete work;
  // Here the VM thread ends.
}

void BoostEnvironment::sendOnVMPort(VM from, VMIdentifier to, RichNode value) {
  BoostVM::forVM(from).sendOnVMPort(to, value);
}

int BoostEnvironment::runIO() {
  // This will end when all VMs are done.
  io_service.run();

  return _exitCode;
}

void BoostEnvironment::withSecondMemoryManager(const std::function<void(MemoryManager&)>& doGC) {
  // Disallow concurrent GCs, so only one has access to the second MemoryManager
  // at a time and we have a much lower maximal memory footprint.
  std::lock_guard<std::mutex> lock(_gcMutex);
  doGC(_secondMemoryManager);
}

///////////////
// Utilities //
///////////////

template <typename T>
void raiseOSError(VM vm, const char* function, nativeint errnum, T&& message) {
  raiseSystem(vm, "os", "os", function, errnum, std::forward<T>(message));
}

void raiseOSError(VM vm, const char* function, int errnum) {
  raiseOSError(vm, function, errnum, vm->getAtom(std::strerror(errnum)));
}

void raiseLastOSError(VM vm, const char* function) {
  raiseOSError(vm, function, errno);
}

void raiseOSError(VM vm, const char* function, boost::system::error_code& ec) {
  raiseOSError(vm, function, ec.value(), vm->getAtom(ec.message()));
}

void raiseOSError(VM vm, const char* function,
                  const boost::system::system_error& error) {
  raiseOSError(vm, function, error.code().value(), vm->getAtom(error.what()));
}

} }

#endif

#endif // MOZART_BOOSTENV_H
<commit_msg>Name the unnamed namespace as is it useless in a .hh<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef MOZART_BOOSTENV_H
#define MOZART_BOOSTENV_H

#include <csignal>
#include <exception>
#include <fstream>

#include "boostenv-decl.hh"

#include "boostvm.hh"
#include "boostenvutils.hh"
#include "boostenvtcp.hh"
#include "boostenvpipe.hh"
#include "boostenvbigint.hh"

#ifndef MOZART_GENERATOR

namespace mozart { namespace boostenv {

//////////////////////
// BoostEnvironment //
//////////////////////

namespace internal {
  /* TODO It might be worth, someday, to investigate how we can lift this
   * decoding to the Oz level.
   * It should somewhere in Resolve.oz and/or URL.oz.
   * But at the same time, not forgetting that this function implements
   * bootURLLoad (not a hypothetical bootFileLoad)!
   *
   * In fact it is already a duplicate of the logic in OS.oz.
   */

  inline
  char hexDigitToValue(char digit) {
    // Don't care to give meaningful results if the digit is not valid
    if (digit <= '9')
      return digit - '0';
    else if (digit <= 'Z')
      return digit - ('A'-10);
    else
      return digit - ('a'-10);
  }

  inline
  std::string decodeURL(const std::string& encoded) {
    // Fast path when there is nothing to do
    if (encoded.find('%') == std::string::npos)
      return encoded;

    // Relevant reminder: Unicode URLs are UTF-8 encoded then %-escaped

    std::string decoded;
    decoded.reserve(encoded.size());

    for (size_t i = 0; i < encoded.size(); ++i) {
      char c = encoded[i];
      if (c == '%' && (i+2 < encoded.size())) {
        char v1 = hexDigitToValue(encoded[++i]);
        char v2 = hexDigitToValue(encoded[++i]);
        decoded.push_back((v1 << 4) | v2);
      } else {
        decoded.push_back(c);
      }
    }

    return decoded;
  }

  inline
  std::string decodedURLToFilename(const std::string& url) {
    // Not sure this is the right test (why not // ?), but it was so in Mozart 1
    if (url.substr(0, 5) == "file:")
      return url.substr(5);
    else
      return url;
  }

  inline
  bool defaultBootLoader(VM vm, const std::string& url, UnstableNode& result) {
    std::string filename = decodedURLToFilename(decodeURL(url));
    std::ifstream input(filename, std::ios::binary);
    if (!input.is_open())
      return false;
    result = bootUnpickle(vm, input);
    return true;
  }
}

BoostEnvironment::BoostEnvironment(const VMStarter& vmStarter) :
  _nextVMIdentifier(InitialVMIdentifier), _exitCode(0),
  vmStarter(vmStarter) {
  // Set up a default boot loader
  setBootLoader(&internal::defaultBootLoader);

  // Ignore SIGPIPE ourselves since Boost does not always do it
#ifdef SIGPIPE
  std::signal(SIGPIPE, SIG_IGN);
#endif
}

VMIdentifier BoostEnvironment::addVM(const std::string& app, bool isURL,
                                     VirtualMachineOptions options) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  _vms.emplace_front(*this, _nextVMIdentifier++, options, app, isURL);
  return _vms.front().identifier;
}

VMIdentifier BoostEnvironment::checkValidIdentifier(VM vm, RichNode vmIdentifier) {
  VMIdentifier identifier = getArgument<VMIdentifier>(vm, vmIdentifier);
  if (identifier > 0 && identifier < _nextVMIdentifier) {
    return identifier;
  } else {
    raiseError(vm, buildTuple(vm, "vm", "invalidVMIdent"));
  }
}

/* Calls onSuccess if a VM with the given identifier is found.
   The _vmsMutex is hold during the call, so it is safe to assume that
   the BoostVM will not be terminated during the call.
   Returns whether it found the VM represented by identifier. */
bool BoostEnvironment::findVM(VMIdentifier identifier,
                              std::function<void(BoostVM& boostVM)> onSuccess) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  for (BoostVM& vm : _vms) {
    if (vm.identifier == identifier) {
      onSuccess(vm);
      return true;
    }
  }
  return false;
}

UnstableNode BoostEnvironment::listVMs(VM vm) {
  std::lock_guard<std::mutex> lock(_vmsMutex);
  UnstableNode list = buildList(vm);
  for (BoostVM& boostVM : _vms)
    list = buildCons(vm, build(vm, boostVM.identifier), list);
  return list;
}

void BoostEnvironment::killVM(VMIdentifier identifier, nativeint exitCode,
                              const std::string& reason) {
  findVM(identifier, [this, exitCode, reason] (BoostVM& targetVM) {
    targetVM.requestTermination(exitCode, reason);
  });
}

void BoostEnvironment::removeTerminatedVM(VMIdentifier identifier,
                                          nativeint exitCode,
                                          boost::asio::io_service::work* work) {
  std::lock_guard<std::mutex> lock(_vmsMutex);

  // Warning: the BoostVM is calling its own destructor with remove_if().
  // We also need VirtualMachine destructor to do its cleanup before dying.
  _vms.remove_if([=] (const BoostVM& vm) {
    return vm.identifier == identifier;
  });

  if (identifier == InitialVMIdentifier) // only the exitCode of the initial VM is considered
    _exitCode = exitCode;

  // Tell the IO thread it does not need to wait anymore for us
  delete work;
  // Here the VM thread ends.
}

void BoostEnvironment::sendOnVMPort(VM from, VMIdentifier to, RichNode value) {
  BoostVM::forVM(from).sendOnVMPort(to, value);
}

int BoostEnvironment::runIO() {
  // This will end when all VMs are done.
  io_service.run();

  return _exitCode;
}

void BoostEnvironment::withSecondMemoryManager(const std::function<void(MemoryManager&)>& doGC) {
  // Disallow concurrent GCs, so only one has access to the second MemoryManager
  // at a time and we have a much lower maximal memory footprint.
  std::lock_guard<std::mutex> lock(_gcMutex);
  doGC(_secondMemoryManager);
}

///////////////
// Utilities //
///////////////

template <typename T>
void raiseOSError(VM vm, const char* function, nativeint errnum, T&& message) {
  raiseSystem(vm, "os", "os", function, errnum, std::forward<T>(message));
}

void raiseOSError(VM vm, const char* function, int errnum) {
  raiseOSError(vm, function, errnum, vm->getAtom(std::strerror(errnum)));
}

void raiseLastOSError(VM vm, const char* function) {
  raiseOSError(vm, function, errno);
}

void raiseOSError(VM vm, const char* function, boost::system::error_code& ec) {
  raiseOSError(vm, function, ec.value(), vm->getAtom(ec.message()));
}

void raiseOSError(VM vm, const char* function,
                  const boost::system::system_error& error) {
  raiseOSError(vm, function, error.code().value(), vm->getAtom(error.what()));
}

} }

#endif

#endif // MOZART_BOOSTENV_H
<|endoftext|>


<commit_before>#include "motor/multirotor_tri_motor_mapper.hpp"

#include <array>
#include <cstddef>
#include "protocol/messages.hpp"
#include "util/time.hpp"
#include <chprintf.h>

MultirotorTriMotorMapper::MultirotorTriMotorMapper(PWMDeviceGroup<3>& motors, PWMDeviceGroup<1>& servos, Communicator& communicator, Logger& logger)
  : motors(motors),
    servos(servos),
    throttleStream(communicator, 5),
    logger(logger){
}

void MultirotorTriMotorMapper::run(bool armed, ActuatorSetpoint& input) {
  // TODO(yoos): comment on motor indexing convention starting from positive
  // X in counterclockwise order.
  // Calculate servo output
  std::array<float, 1> sOutputs;
  sOutputs[0] = 0.540 - 0.5*input.yaw;   // Magic number servo bias for pusher yaw prop.
  sOutputs[0] = std::min(1.0, std::max(-1.0, sOutputs[0]));
  servos.set(armed, sOutputs);

  // Calculate motor outputs
  std::array<float, 3> mOutputs;
  mOutputs[0] = input.throttle + 0.866025*input.roll - 0.5*input.pitch;   // Left
  mOutputs[1] = input.throttle                       +     input.pitch;   // Tail
  mOutputs[2] = input.throttle - 0.866025*input.roll - 0.5*input.pitch;   // Right
  motors.set(armed, mOutputs);

  // Scale tail thrust per servo tilt
  // TODO(yoos): Again, resolve magic number.
  mOutputs[1] /= std::cos(3.1415926535/4*input.yaw);

  // DEBUG
  //static int loop=0;
  //if (loop == 0) {
  //  chprintf((BaseSequentialStream*)&SD4, "MM %f %f %f %f\r\n", mOutputs[0], mOutputs[1], mOutputs[2], sOutputs[0]);
  //}
  //loop = (loop+1) % 50;

  protocol::message::motor_throttle_message_t m {
    .time = ST2MS(chibios_rt::System::getTime()),
    .throttles = { mOutputs[0], mOutputs[1], mOutputs[2], sOutputs[0] }
  };

  if(throttleStream.ready()) {
    throttleStream.publish(m);
  }
  logger.write(m);
}
<commit_msg>Scale throttle to compensate for tilt.<commit_after>#include "motor/multirotor_tri_motor_mapper.hpp"

#include <array>
#include <cstddef>
#include "protocol/messages.hpp"
#include "util/time.hpp"
#include <unit_config.hpp>
#include <chprintf.h>

MultirotorTriMotorMapper::MultirotorTriMotorMapper(PWMDeviceGroup<3>& motors, PWMDeviceGroup<1>& servos, Communicator& communicator, Logger& logger)
  : motors(motors),
    servos(servos),
    throttleStream(communicator, 5),
    logger(logger){
}

void MultirotorTriMotorMapper::run(bool armed, ActuatorSetpoint& input) {
  // TODO(yoos): comment on motor indexing convention starting from positive
  // X in counterclockwise order.
  // Calculate servo output
  std::array<float, 1> sOutputs;
  sOutputs[0] = 0.540 - 0.5*input.yaw;   // Magic number servo bias for pusher yaw prop.
  sOutputs[0] = std::min(1.0, std::max(-1.0, sOutputs[0]));
  servos.set(armed, sOutputs);

  // Scale throttle to compensate for roll and pitch up to max angles
  input.throttle /= std::cos(std::min(std::fabs(input.roll), unit_config::MAX_PITCH_ROLL_POS));
  input.throttle /= std::cos(std::min(std::fabs(input.pitch), unit_config::MAX_PITCH_ROLL_POS));
  input.throttle = std::min(input.throttle, 1.0);   // Not entirely necessary, but perhaps preserve some control authority.

  // Calculate motor outputs
  std::array<float, 3> mOutputs;
  mOutputs[0] = input.throttle + 0.866025*input.roll - 0.5*input.pitch;   // Left
  mOutputs[1] = input.throttle                       +     input.pitch;   // Tail
  mOutputs[2] = input.throttle - 0.866025*input.roll - 0.5*input.pitch;   // Right
  motors.set(armed, mOutputs);

  // Scale tail thrust per servo tilt
  // TODO(yoos): Again, resolve magic number.
  mOutputs[1] /= std::cos(3.1415926535/4*input.yaw);

  // DEBUG
  //static int loop=0;
  //if (loop == 0) {
  //  chprintf((BaseSequentialStream*)&SD4, "MM %f %f %f %f\r\n", mOutputs[0], mOutputs[1], mOutputs[2], sOutputs[0]);
  //}
  //loop = (loop+1) % 50;

  protocol::message::motor_throttle_message_t m {
    .time = ST2MS(chibios_rt::System::getTime()),
    .throttles = { mOutputs[0], mOutputs[1], mOutputs[2], sOutputs[0] }
  };

  if(throttleStream.ready()) {
    throttleStream.publish(m);
  }
  logger.write(m);
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_
#define _Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include    <type_traits>

#include    "../Math/Common.h"
#include    "../Execution/Exceptions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             *********************** DataExchangeFormat::Private_ ***************************
             ********************************************************************************
             */
            namespace Private_ {
                template    <typename T>
                inline  typename std::enable_if < !std::is_floating_point<T>::value, T >::type CheckedConverter_Range_Helper_Pinner_ (T t, T lower, T upper)
                {
                    return t;
                }
                template    <typename T>
                inline  typename std::enable_if<std::is_floating_point<T>::value, T>::type  CheckedConverter_Range_Helper_Pinner_ (T t, T lower, T upper)
                {
                    return Math::PinToSpecialPoint (PinToSpecialPoint (t, lower), upper);
                }
            }

            /*
             ********************************************************************************
             ************** DataExchangeFormat::CheckedConverter_Range **********************
             ********************************************************************************
             */
            template    <typename   RANGE_TYPE>
            RANGE_TYPE  CheckedConverter_Range (const typename RANGE_TYPE::ElementType& s, const typename RANGE_TYPE::ElementType& e)
            {
                typename    RANGE_TYPE::ElementType useS    =   Private_::CheckedConverter_Range_Helper_Pinner_ (s, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                typename    RANGE_TYPE::ElementType useE    =   Private_::CheckedConverter_Range_Helper_Pinner_ (e, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                if (not (RANGE_TYPE::TraitsType::kMin <= useS)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useS <= useE)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useE <= RANGE_TYPE::TraitsType::kMax)) {
                    Execution::DoThrow (BadFormatException ());
                }
                return RANGE_TYPE (useS, useE);
            }

            /*
             ********************************************************************************
             ********* DataExchangeFormat::CheckedConverter_ValueInRange ********************
             ********************************************************************************
             */
            template    <typename   RANGE_TYPE>
            typename RANGE_TYPE::ElementType  CheckedConverter_ValueInRange (typename RANGE_TYPE::ElementType val, const RANGE_TYPE& r)
            {
                typename    RANGE_TYPE::ElementType useVal    =   Private_::CheckedConverter_Range_Helper_Pinner_ (val, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                if (not (RANGE_TYPE::TraitsType::kMin <= useVal)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useVal <= RANGE_TYPE::TraitsType::kMax)) {
                    Execution::DoThrow (BadFormatException ());
                }
                return useVal;
            }

        }

    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_*/
<commit_msg>use new Math::PinToSpecialPoint () in DataExchangeFormat/CheckedConverter<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_
#define _Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include    <type_traits>

#include    "../Math/Common.h"
#include    "../Execution/Exceptions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             *********************** DataExchangeFormat::Private_ ***************************
             ********************************************************************************
             */
            namespace Private_ {
                template    <typename T>
                inline  typename std::enable_if < !std::is_floating_point<T>::value, T >::type CheckedConverter_Range_Helper_Pinner_ (T t, T lower, T upper)
                {
                    return t;
                }
                template    <typename T>
                inline  typename std::enable_if<std::is_floating_point<T>::value, T>::type  CheckedConverter_Range_Helper_Pinner_ (T t, T lower, T upper)
                {
                    return Math::PinToSpecialPoint (Math::PinToSpecialPoint (t, lower), upper);
                }
            }

            /*
             ********************************************************************************
             ************** DataExchangeFormat::CheckedConverter_Range **********************
             ********************************************************************************
             */
            template    <typename   RANGE_TYPE>
            RANGE_TYPE  CheckedConverter_Range (const typename RANGE_TYPE::ElementType& s, const typename RANGE_TYPE::ElementType& e)
            {
                typename    RANGE_TYPE::ElementType useS    =   Private_::CheckedConverter_Range_Helper_Pinner_ (s, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                typename    RANGE_TYPE::ElementType useE    =   Private_::CheckedConverter_Range_Helper_Pinner_ (e, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                if (not (RANGE_TYPE::TraitsType::kMin <= useS)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useS <= useE)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useE <= RANGE_TYPE::TraitsType::kMax)) {
                    Execution::DoThrow (BadFormatException ());
                }
                return RANGE_TYPE (useS, useE);
            }

            /*
             ********************************************************************************
             ********* DataExchangeFormat::CheckedConverter_ValueInRange ********************
             ********************************************************************************
             */
            template    <typename   RANGE_TYPE>
            typename RANGE_TYPE::ElementType  CheckedConverter_ValueInRange (typename RANGE_TYPE::ElementType val, const RANGE_TYPE& r)
            {
                typename    RANGE_TYPE::ElementType useVal    =   Private_::CheckedConverter_Range_Helper_Pinner_ (val, RANGE_TYPE::TraitsType::kMin, RANGE_TYPE::TraitsType::kMax);
                if (not (RANGE_TYPE::TraitsType::kMin <= useVal)) {
                    Execution::DoThrow (BadFormatException ());
                }
                if (not (useVal <= RANGE_TYPE::TraitsType::kMax)) {
                    Execution::DoThrow (BadFormatException ());
                }
                return useVal;
            }

        }

    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_CheckedConverter_inl_*/
<|endoftext|>


<commit_before>
// Bindings
#include "CPyCppyy.h"
#include "PyROOTPythonize.h"
#include "CPPInstance.h"
#include "ProxyWrappers.h"
#include "Converters.h"
#include "Utility.h"

// ROOT
#include "TClass.h"
#include "TTree.h"
#include "TBranch.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TLeaf.h"
#include "TLeafElement.h"
#include "TLeafObject.h"
#include "TStreamerElement.h"
#include "TStreamerInfo.h"

using namespace CPyCppyy;

static TClass *GetClass(const CPPInstance *pyobj)
{
   return TClass::GetClass(Cppyy::GetFinalName(pyobj->ObjectIsA()).c_str());
}

static TBranch *SearchForBranch(TTree *tree, const char *name)
{
   TBranch *branch = tree->GetBranch(name);
   if (!branch) {
      // for benefit of naming of sub-branches, the actual name may have a trailing '.'
      branch = tree->GetBranch((std::string(name) + '.').c_str());
   }
   return branch;
}

static TLeaf *SearchForLeaf(TTree *tree, const char *name, TBranch *branch)
{
   TLeaf *leaf = tree->GetLeaf(name);
   if (branch && !leaf) {
      leaf = branch->GetLeaf(name);
      if (!leaf) {
         TObjArray *leaves = branch->GetListOfLeaves();
         if (leaves->GetSize() && (leaves->First() == leaves->Last())) {
            // i.e., if unambiguously only this one
            leaf = (TLeaf *)leaves->At(0);
         }
      }
   }
   return leaf;
}

static PyObject *BindBranchToProxy(TTree *tree, const char *name, TBranch *branch)
{
   // for partial return of a split object
   if (branch->InheritsFrom(TBranchElement::Class())) {
      TBranchElement *be = (TBranchElement *)branch;
      if (be->GetCurrentClass() && (be->GetCurrentClass() != be->GetTargetClass()) && (0 <= be->GetID())) {
         Long_t offset = ((TStreamerElement *)be->GetInfo()->GetElements()->At(be->GetID()))->GetOffset();
         return BindCppObjectNoCast(be->GetObject() + offset, Cppyy::GetScope(be->GetCurrentClass()->GetName()));
      }
   }

   // for return of a full object
   if (branch->IsA() == TBranchElement::Class() || branch->IsA() == TBranchObject::Class()) {
      TClass *klass = TClass::GetClass(branch->GetClassName());
      if (klass && branch->GetAddress())
         return BindCppObjectNoCast(*(void **)branch->GetAddress(), Cppyy::GetScope(branch->GetClassName()));

      // try leaf, otherwise indicate failure by returning a typed null-object
      TObjArray *leaves = branch->GetListOfLeaves();
      if (klass && !tree->GetLeaf(name) && !(leaves->GetSize() && (leaves->First() == leaves->Last())))
         return BindCppObjectNoCast(nullptr, Cppyy::GetScope(branch->GetClassName()));
   }

   return nullptr;
}

static PyObject *WrapLeaf(TLeaf *leaf)
{
   if (1 < leaf->GetLenStatic() || leaf->GetLeafCount()) {
      // array types
      std::string typeName = leaf->GetTypeName();
      Converter *pcnv = CreateConverter(typeName + '*', leaf->GetNdata());

      void *address = 0;
      if (leaf->GetBranch())
         address = (void *)leaf->GetBranch()->GetAddress();
      if (!address)
         address = (void *)leaf->GetValuePointer();

      PyObject *value = pcnv->FromMemory(&address);
      delete pcnv;

      return value;
   } else if (leaf->GetValuePointer()) {
      // value types
      Converter *pcnv = CreateConverter(leaf->GetTypeName());
      PyObject *value = 0;
      if (leaf->IsA() == TLeafElement::Class() || leaf->IsA() == TLeafObject::Class())
         value = pcnv->FromMemory((void *)*(void **)leaf->GetValuePointer());
      else
         value = pcnv->FromMemory((void *)leaf->GetValuePointer());
      delete pcnv;

      return value;
   }

   return nullptr;
}

// Allow access to branches/leaves as if they were data members
PyObject *GetAttr(const CPPInstance *self, PyObject *pyname)
{
   const char *name_possibly_alias = CPyCppyy_PyUnicode_AsString(pyname);
   if (!name_possibly_alias)
      return 0;

   // get hold of actual tree
   TTree *tree = (TTree *)GetClass(self)->DynamicCast(TTree::Class(), self->GetObject());

   if (!tree) {
      PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
      return 0;
   }

   // deal with possible aliasing
   const char *name = tree->GetAlias(name_possibly_alias);
   if (!name)
      name = name_possibly_alias;

   // search for branch first (typical for objects)
   TBranch *branch = SearchForBranch(tree, name);

   if (branch) {
      // found a branched object, wrap its address for the object it represents
      auto proxy = BindBranchToProxy(tree, name, branch);
      if (proxy != nullptr)
         return proxy;
   }

   // if not, try leaf
   TLeaf *leaf = SearchForLeaf(tree, name, branch);

   if (leaf) {
      // found a leaf, extract value and wrap with a Python object according to its type
      auto wrapper = WrapLeaf(leaf);
      if (wrapper != nullptr)
         return wrapper;
   }

   // confused
   PyErr_Format(PyExc_AttributeError, "\'%s\' object has no attribute \'%s\'", tree->IsA()->GetName(), name);
   return 0;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Allow branches to be accessed as attributes of a tree.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Allow access to branches/leaves as if they were Python data attributes of the tree
/// (e.g. mytree.branch)
PyObject *PyROOT::AddBranchAttrSyntax(PyObject * /* self */, PyObject *args)
{
   PyObject *pyclass = PyTuple_GetItem(args, 0);
   Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)GetAttr, METH_O);
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::SetBranchAddress.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of SetBranchAddress so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.SetBranchAddress("my_vector_branch", v)
/// ~~~
PyObject *PyROOT::SetBranchAddressPyz(PyObject * /* self */, PyObject *args)
{
   PyObject *treeObj = nullptr, *name = nullptr, *address = nullptr;

   int argc = PyTuple_GET_SIZE(args);

// Look for the (const char*, void*) overload
#if PY_VERSION_HEX < 0x03000000
   auto argParseStr = "OSO:SetBranchAddress";
#else
   auto argParseStr = "OUO:SetBranchAddress";
#endif
   if (argc == 3 && PyArg_ParseTuple(args, const_cast<char *>(argParseStr), &treeObj, &name, &address)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());

      if (!tree) {
         PyErr_SetString(PyExc_TypeError,
                         "TTree::SetBranchAddress must be called with a TTree instance as first argument");
         return nullptr;
      }

      auto branchName = CPyCppyy_PyUnicode_AsString(name);
      auto branch = tree->GetBranch(branchName);
      if (!branch) {
         PyErr_SetString(PyExc_TypeError, "TTree::SetBranchAddress must be called with a valid branch name");
         return nullptr;
      }

      bool isLeafList = branch->IsA() == TBranch::Class();

      void *buf = 0;
      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference || isLeafList)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf != nullptr) {
         auto res = tree->SetBranchAddress(CPyCppyy_PyUnicode_AsString(name), buf);
         return PyInt_FromLong(res);
      }
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}

// Try ( const char*, void*, const char*, Int_t = 32000 )
PyObject *TryBranchLeafListOverload(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *address = nullptr, *leaflist = nullptr, *bufsize = nullptr;

   if (PyArg_ParseTuple(args, const_cast<char *>("OO!OO!|O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &address,
                        &CPyCppyy_PyUnicode_Type, &leaflist,
                        &PyInt_Type, &bufsize)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      void *buf = nullptr;
      if (CPPInstance_Check(address))
         buf = (void *)((CPPInstance *)address)->GetObject();
      else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf) {
         TBranch *branch = nullptr;
         if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist),
                                  PyInt_AS_LONG(bufsize));
         } else {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }
   PyErr_Clear();

   Py_RETURN_NONE;
}

// Try ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
// or  ( const char*,              T**, Int_t = 32000, Int_t = 99 )
PyObject *TryBranchPtrToPtrOverloads(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *clName = nullptr, *address = nullptr, *bufsize = nullptr, *splitlevel = nullptr;

   auto bIsMatch = false;
   if (PyArg_ParseTuple(args, const_cast<char *>("OO!O!O|O!O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &CPyCppyy_PyUnicode_Type, &clName,
                        &address,
                        &PyInt_Type, &bufsize,
                        &PyInt_Type, &splitlevel)) {
      bIsMatch = true;
   } else {
      PyErr_Clear();
      if (PyArg_ParseTuple(args, const_cast<char *>("OO!O|O!O!"),
                           &treeObj,
                           &CPyCppyy_PyUnicode_Type, &name,
                           &address,
                           &PyInt_Type, &bufsize,
                           &PyInt_Type, &splitlevel)) {
         bIsMatch = true;
      } else
         PyErr_Clear();
   }

   if (bIsMatch) {
      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      std::string klName = clName ? CPyCppyy_PyUnicode_AsString(clName) : "";
      void *buf = nullptr;

      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;

         if (!clName) {
            klName = GetClass((CPPInstance *)address)->GetName();
            argc += 1;
         }
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf && !klName.empty()) {
         TBranch *branch = 0;
         if (argc == 4) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf);
         } else if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize));
         } else if (argc == 6) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize),
                                  PyInt_AS_LONG(splitlevel));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::Branch.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of Branch so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.Branch('my_vector_branch', v)
/// ~~~
PyObject *PyROOT::BranchPyz(PyObject * /* self */, PyObject *args)
{
   // Acceptable signatures:
   // ( const char*, void*, const char*, Int_t = 32000 )
   // ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
   // ( const char*, T**, Int_t = 32000, Int_t = 99 )

   int argc = PyTuple_GET_SIZE(args);

   if (argc >= 3) { // We count the TTree proxy object too
      auto branch = TryBranchLeafListOverload(argc, args);
      if (branch != Py_None)
         return branch;

      branch = TryBranchPtrToPtrOverloads(argc, args);
      if (branch != Py_None)
         return branch;
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}
<commit_msg>[Exp PyROOT] Add doxygen documentation to helper functions<commit_after>
// Bindings
#include "CPyCppyy.h"
#include "PyROOTPythonize.h"
#include "CPPInstance.h"
#include "ProxyWrappers.h"
#include "Converters.h"
#include "Utility.h"

// ROOT
#include "TClass.h"
#include "TTree.h"
#include "TBranch.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TLeaf.h"
#include "TLeafElement.h"
#include "TLeafObject.h"
#include "TStreamerElement.h"
#include "TStreamerInfo.h"

using namespace CPyCppyy;

static TClass *GetClass(const CPPInstance *pyobj)
{
   return TClass::GetClass(Cppyy::GetFinalName(pyobj->ObjectIsA()).c_str());
}

static TBranch *SearchForBranch(TTree *tree, const char *name)
{
   TBranch *branch = tree->GetBranch(name);
   if (!branch) {
      // for benefit of naming of sub-branches, the actual name may have a trailing '.'
      branch = tree->GetBranch((std::string(name) + '.').c_str());
   }
   return branch;
}

static TLeaf *SearchForLeaf(TTree *tree, const char *name, TBranch *branch)
{
   TLeaf *leaf = tree->GetLeaf(name);
   if (branch && !leaf) {
      leaf = branch->GetLeaf(name);
      if (!leaf) {
         TObjArray *leaves = branch->GetListOfLeaves();
         if (leaves->GetSize() && (leaves->First() == leaves->Last())) {
            // i.e., if unambiguously only this one
            leaf = (TLeaf *)leaves->At(0);
         }
      }
   }
   return leaf;
}

static PyObject *BindBranchToProxy(TTree *tree, const char *name, TBranch *branch)
{
   // for partial return of a split object
   if (branch->InheritsFrom(TBranchElement::Class())) {
      TBranchElement *be = (TBranchElement *)branch;
      if (be->GetCurrentClass() && (be->GetCurrentClass() != be->GetTargetClass()) && (0 <= be->GetID())) {
         Long_t offset = ((TStreamerElement *)be->GetInfo()->GetElements()->At(be->GetID()))->GetOffset();
         return BindCppObjectNoCast(be->GetObject() + offset, Cppyy::GetScope(be->GetCurrentClass()->GetName()));
      }
   }

   // for return of a full object
   if (branch->IsA() == TBranchElement::Class() || branch->IsA() == TBranchObject::Class()) {
      TClass *klass = TClass::GetClass(branch->GetClassName());
      if (klass && branch->GetAddress())
         return BindCppObjectNoCast(*(void **)branch->GetAddress(), Cppyy::GetScope(branch->GetClassName()));

      // try leaf, otherwise indicate failure by returning a typed null-object
      TObjArray *leaves = branch->GetListOfLeaves();
      if (klass && !tree->GetLeaf(name) && !(leaves->GetSize() && (leaves->First() == leaves->Last())))
         return BindCppObjectNoCast(nullptr, Cppyy::GetScope(branch->GetClassName()));
   }

   return nullptr;
}

static PyObject *WrapLeaf(TLeaf *leaf)
{
   if (1 < leaf->GetLenStatic() || leaf->GetLeafCount()) {
      // array types
      std::string typeName = leaf->GetTypeName();
      Converter *pcnv = CreateConverter(typeName + '*', leaf->GetNdata());

      void *address = 0;
      if (leaf->GetBranch())
         address = (void *)leaf->GetBranch()->GetAddress();
      if (!address)
         address = (void *)leaf->GetValuePointer();

      PyObject *value = pcnv->FromMemory(&address);
      delete pcnv;

      return value;
   } else if (leaf->GetValuePointer()) {
      // value types
      Converter *pcnv = CreateConverter(leaf->GetTypeName());
      PyObject *value = 0;
      if (leaf->IsA() == TLeafElement::Class() || leaf->IsA() == TLeafObject::Class())
         value = pcnv->FromMemory((void *)*(void **)leaf->GetValuePointer());
      else
         value = pcnv->FromMemory((void *)leaf->GetValuePointer());
      delete pcnv;

      return value;
   }

   return nullptr;
}

// Allow access to branches/leaves as if they were data members
PyObject *GetAttr(const CPPInstance *self, PyObject *pyname)
{
   const char *name_possibly_alias = CPyCppyy_PyUnicode_AsString(pyname);
   if (!name_possibly_alias)
      return 0;

   // get hold of actual tree
   TTree *tree = (TTree *)GetClass(self)->DynamicCast(TTree::Class(), self->GetObject());

   if (!tree) {
      PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
      return 0;
   }

   // deal with possible aliasing
   const char *name = tree->GetAlias(name_possibly_alias);
   if (!name)
      name = name_possibly_alias;

   // search for branch first (typical for objects)
   TBranch *branch = SearchForBranch(tree, name);

   if (branch) {
      // found a branched object, wrap its address for the object it represents
      auto proxy = BindBranchToProxy(tree, name, branch);
      if (proxy != nullptr)
         return proxy;
   }

   // if not, try leaf
   TLeaf *leaf = SearchForLeaf(tree, name, branch);

   if (leaf) {
      // found a leaf, extract value and wrap with a Python object according to its type
      auto wrapper = WrapLeaf(leaf);
      if (wrapper != nullptr)
         return wrapper;
   }

   // confused
   PyErr_Format(PyExc_AttributeError, "\'%s\' object has no attribute \'%s\'", tree->IsA()->GetName(), name);
   return 0;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Allow branches to be accessed as attributes of a tree.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Allow access to branches/leaves as if they were Python data attributes of the tree
/// (e.g. mytree.branch)
PyObject *PyROOT::AddBranchAttrSyntax(PyObject * /* self */, PyObject *args)
{
   PyObject *pyclass = PyTuple_GetItem(args, 0);
   Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)GetAttr, METH_O);
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::SetBranchAddress.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of SetBranchAddress so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.SetBranchAddress("my_vector_branch", v)
/// ~~~
PyObject *PyROOT::SetBranchAddressPyz(PyObject * /* self */, PyObject *args)
{
   PyObject *treeObj = nullptr, *name = nullptr, *address = nullptr;

   int argc = PyTuple_GET_SIZE(args);

// Look for the (const char*, void*) overload
#if PY_VERSION_HEX < 0x03000000
   auto argParseStr = "OSO:SetBranchAddress";
#else
   auto argParseStr = "OUO:SetBranchAddress";
#endif
   if (argc == 3 && PyArg_ParseTuple(args, const_cast<char *>(argParseStr), &treeObj, &name, &address)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());

      if (!tree) {
         PyErr_SetString(PyExc_TypeError,
                         "TTree::SetBranchAddress must be called with a TTree instance as first argument");
         return nullptr;
      }

      auto branchName = CPyCppyy_PyUnicode_AsString(name);
      auto branch = tree->GetBranch(branchName);
      if (!branch) {
         PyErr_SetString(PyExc_TypeError, "TTree::SetBranchAddress must be called with a valid branch name");
         return nullptr;
      }

      bool isLeafList = branch->IsA() == TBranch::Class();

      void *buf = 0;
      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference || isLeafList)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf != nullptr) {
         auto res = tree->SetBranchAddress(CPyCppyy_PyUnicode_AsString(name), buf);
         return PyInt_FromLong(res);
      }
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to the following overload:
/// - ( const char*, void*, const char*, Int_t = 32000 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchLeafListOverload(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *address = nullptr, *leaflist = nullptr, *bufsize = nullptr;

   if (PyArg_ParseTuple(args, const_cast<char *>("OO!OO!|O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &address,
                        &CPyCppyy_PyUnicode_Type, &leaflist,
                        &PyInt_Type, &bufsize)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      void *buf = nullptr;
      if (CPPInstance_Check(address))
         buf = (void *)((CPPInstance *)address)->GetObject();
      else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf) {
         TBranch *branch = nullptr;
         if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist),
                                  PyInt_AS_LONG(bufsize));
         } else {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }
   PyErr_Clear();

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to one of the following
/// overloads:
/// - ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
/// - ( const char*,              T**, Int_t = 32000, Int_t = 99 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchPtrToPtrOverloads(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *clName = nullptr, *address = nullptr, *bufsize = nullptr, *splitlevel = nullptr;

   auto bIsMatch = false;
   if (PyArg_ParseTuple(args, const_cast<char *>("OO!O!O|O!O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &CPyCppyy_PyUnicode_Type, &clName,
                        &address,
                        &PyInt_Type, &bufsize,
                        &PyInt_Type, &splitlevel)) {
      bIsMatch = true;
   } else {
      PyErr_Clear();
      if (PyArg_ParseTuple(args, const_cast<char *>("OO!O|O!O!"),
                           &treeObj,
                           &CPyCppyy_PyUnicode_Type, &name,
                           &address,
                           &PyInt_Type, &bufsize,
                           &PyInt_Type, &splitlevel)) {
         bIsMatch = true;
      } else
         PyErr_Clear();
   }

   if (bIsMatch) {
      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      std::string klName = clName ? CPyCppyy_PyUnicode_AsString(clName) : "";
      void *buf = nullptr;

      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;

         if (!clName) {
            klName = GetClass((CPPInstance *)address)->GetName();
            argc += 1;
         }
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf && !klName.empty()) {
         TBranch *branch = 0;
         if (argc == 4) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf);
         } else if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize));
         } else if (argc == 6) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize),
                                  PyInt_AS_LONG(splitlevel));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::Branch.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of Branch so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.Branch('my_vector_branch', v)
/// ~~~
PyObject *PyROOT::BranchPyz(PyObject * /* self */, PyObject *args)
{
   // Acceptable signatures:
   // ( const char*, void*, const char*, Int_t = 32000 )
   // ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
   // ( const char*, T**, Int_t = 32000, Int_t = 99 )

   int argc = PyTuple_GET_SIZE(args);

   if (argc >= 3) { // We count the TTree proxy object too
      auto branch = TryBranchLeafListOverload(argc, args);
      if (branch != Py_None)
         return branch;

      branch = TryBranchPtrToPtrOverloads(argc, args);
      if (branch != Py_None)
         return branch;
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}
<|endoftext|>


<commit_before><commit_msg>Add extra blank line after ctor definition.<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2011  Timo Savola
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

#include <cstddef>
#include <memory>

namespace concrete {

template <typename ResourceType, typename... Args>
ResourceManager::Allocation<ResourceType> ResourceManager::new_resource(Args... args)
{
	std::auto_ptr<ResourceType> resource(new ResourceType(args...));
	auto id = append_resource(resource.get());
	auto ptr = resource.get();
	resource.release();

	return Allocation<ResourceType> {
		id,
		*ptr,
	};
}

template <typename ResourceType>
ResourceType &ResourceManager::resource(ResourceId id) const
{
	auto plain = find_resource(id);
	if (plain == NULL)
		throw ResourceError();

	auto typed = dynamic_cast<ResourceType *> (plain);
	if (typed == NULL)
		throw ResourceError();

	return *typed;
}

} // namespace
<commit_msg>use unique_ptr instead of auto_ptr<commit_after>/*
 * Copyright (c) 2011  Timo Savola
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */

#include <cstddef>
#include <memory>

namespace concrete {

template <typename ResourceType, typename... Args>
ResourceManager::Allocation<ResourceType> ResourceManager::new_resource(Args... args)
{
	std::unique_ptr<ResourceType> resource(new ResourceType(args...));
	auto id = append_resource(resource.get());
	auto ptr = resource.get();
	resource.release();

	return Allocation<ResourceType> {
		id,
		*ptr,
	};
}

template <typename ResourceType>
ResourceType &ResourceManager::resource(ResourceId id) const
{
	auto plain = find_resource(id);
	if (plain == NULL)
		throw ResourceError();

	auto typed = dynamic_cast<ResourceType *> (plain);
	if (typed == NULL)
		throw ResourceError();

	return *typed;
}

} // namespace
<|endoftext|>