<commit_before>// First load all RTT interfaces so that we get all "extern template"
// declarations in the ToolkitImpl files
#include <rtt/Ports.hpp>
#include <rtt/Attribute.hpp>
#include <rtt/Properties.hpp>
#include <rtt/DataSource.hpp>

#include "toolkit/<%= component.name %>ToolkitC.h"
#include "<%= component.name %>ToolkitCorba.hpp"
#include "<%= component.name %>ToolkitCorbaImpl.hpp"
#include <rtt/corba/CorbaTemplateProtocol.hpp>
#include <rtt/Toolkit.hpp>
<% if has_opaques? %>
#include "<%= component.name %>ToolkitIntermediates.hpp"
<% end %>
<% toolkit.used_toolkits.each do |tk| %>
#include <toolkit/<%= tk.name %>ToolkitCorbaImpl.hpp>
<% end %>
using namespace RTT;

<% converted_types.each do |type| %>
bool orogen_toolkits::toCORBA( <%= type.corba_ref_type %> corba, <%= type.arg_type %> value )
{
<%= result = ""
	type.to_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, <%= type.corba_arg_type %> corba )
{
<%= result = ""
	type.from_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
<% end %>
<% array_types.each do |type| %>
bool orogen_toolkits::toCORBA( <%= type.corba_ref_type %> corba, <%= type.arg_type %> value, int length )
{
<%= result = ""
	type.to_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, int length, <%= type.corba_arg_type %> corba )
{
<%= result = ""
	type.from_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
<% end %>

<% opaques.each do |opdef|
    type = opdef.type
    intermediate_type = component.find_type(opdef.intermediate)
    %>
bool orogen_toolkits::toCORBA( <%= intermediate_type.corba_ref_type %> corba, <%= type.arg_type %> value )
{
<%= toolkit.code_toIntermediate(intermediate_type, opdef.needs_copy?, "    ") %>
    return toCORBA(corba, intermediate);
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, <%= intermediate_type.corba_arg_type %> corba )
{
    <% if opdef.needs_copy? %>
    <%= intermediate_type.cxx_name %> intermediate;
    if (!fromCORBA(intermediate, corba))
        return false;
<%= toolkit.code_fromIntermediate(intermediate_type, true, "    ") %>
    <% else %>
    std::auto_ptr< <%= intermediate_type.cxx_name %> > intermediate(new <%= intermediate_type.cxx_name %>);
    if (!fromCORBA(*intermediate, corba))
        return false;
<%= toolkit.code_fromIntermediate(intermediate_type, false, "    ") %>
    <% end %>
    return true;
}
<% end %>

<% registered_types.each do |type| %>
namespace orogen_toolkits {
    struct <%= type.method_name %>CorbaMarshaller
        : public RTT::detail::CorbaTemplateProtocol< <%= type.cxx_name %> >
    {
        <% if type.opaque?
             opdef = toolkit.opaque_specification(type)
             intermediate_type = toolkit.find_type(opdef.intermediate)
        %>
        typedef <%= intermediate_type.corba_name %> CorbaType;
        <% else %>
        typedef <%= type.corba_name %> CorbaType;
        <% end %>
        typedef <%= type.cxx_name %>   BaseType;

        virtual void* createBlob( RTT::DataSourceBase::shared_ptr source) const;
        virtual bool updateBlob(const void* blob, RTT::DataSourceBase::shared_ptr target) const;
    };
}

void* orogen_toolkits::<%= type.method_name %>CorbaMarshaller::createBlob( DataSourceBase::shared_ptr source) const
{
    DataSource<BaseType>* d = AdaptDataSource<BaseType>()( source );
    if ( d )
    {
        std::auto_ptr<CorbaType> corba( new CorbaType );
        if (!toCORBA(*corba, d->value()))
            return false;

        CORBA::Any_ptr ret = new CORBA::Any();
        *ret <<= corba.release();
        return ret;
    }
    return 0;
}

bool orogen_toolkits::<%= type.method_name %>CorbaMarshaller::updateBlob(const void* blob, DataSourceBase::shared_ptr target) const
{
    AssignableDataSource<BaseType>::shared_ptr ad = AssignableDataSource<BaseType>::narrow( target.get() );
    const CORBA::Any* any = static_cast<const CORBA::Any*>(blob);
    if ( ad )
    {
        <% if type.inlines_code? || type <= Typelib::EnumType %>
        CorbaType  corba;
        if (!(*any >>= corba))
            return false;
        return fromCORBA(ad->set(), corba);
        <% else %>
        CorbaType*  corba;
        if (!(*any >>= corba))
            return false;
        bool ret = fromCORBA(ad->set(), *corba);
        return ret;
        <% end %>
    }
    return false;
}
<% end %>

bool orogen_toolkits::<%= component.name %>CorbaTransportPlugin::registerTransport(std::string type_name, TypeInfo* ti)
{
    <% first_type = true;
       registered_types.each do |type| %>
    <%= 'else ' unless first_type %>if ("<%= type.name %>" == type_name)
    {
        ti->addProtocol(ORO_CORBA_PROTOCOL_ID, new orogen_toolkits::<%= type.method_name %>CorbaMarshaller());
        return true;
    }
    <% first_type = false
    end %>
    return false;
}
std::string orogen_toolkits::<%= component.name %>CorbaTransportPlugin::getTransportName() const
{ return "CORBA"; }
std::string orogen_toolkits::<%= component.name %>CorbaTransportPlugin::getName() const
{ return "/orogen/<%= component.name %>/CORBA"; }

orogen_toolkits::<%= component.name %>CorbaTransportPlugin orogen_toolkits::<%= component.name %>CorbaTransport;
ORO_TOOLKIT_PLUGIN(orogen_toolkits::<%= component.name %>CorbaTransport);

<commit_msg>fix CORBA code generation for enums<commit_after>// First load all RTT interfaces so that we get all "extern template"
// declarations in the ToolkitImpl files
#include <rtt/Ports.hpp>
#include <rtt/Attribute.hpp>
#include <rtt/Properties.hpp>
#include <rtt/DataSource.hpp>

#include "toolkit/<%= component.name %>ToolkitC.h"
#include "<%= component.name %>ToolkitCorba.hpp"
#include "<%= component.name %>ToolkitCorbaImpl.hpp"
#include <rtt/corba/CorbaTemplateProtocol.hpp>
#include <rtt/Toolkit.hpp>
<% if has_opaques? %>
#include "<%= component.name %>ToolkitIntermediates.hpp"
<% end %>
<% toolkit.used_toolkits.each do |tk| %>
#include <toolkit/<%= tk.name %>ToolkitCorbaImpl.hpp>
<% end %>
using namespace RTT;

<% converted_types.each do |type| %>
bool orogen_toolkits::toCORBA( <%= type.corba_ref_type %> corba, <%= type.arg_type %> value )
{
<%= result = ""
	type.to_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, <%= type.corba_arg_type %> corba )
{
<%= result = ""
	type.from_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
<% end %>
<% array_types.each do |type| %>
bool orogen_toolkits::toCORBA( <%= type.corba_ref_type %> corba, <%= type.arg_type %> value, int length )
{
<%= result = ""
	type.to_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, int length, <%= type.corba_arg_type %> corba )
{
<%= result = ""
	type.from_corba(toolkit, result, " " * 4)
	result
	%>
    return true;
}
<% end %>

<% opaques.each do |opdef|
    type = opdef.type
    intermediate_type = component.find_type(opdef.intermediate)
    %>
bool orogen_toolkits::toCORBA( <%= intermediate_type.corba_ref_type %> corba, <%= type.arg_type %> value )
{
<%= toolkit.code_toIntermediate(intermediate_type, opdef.needs_copy?, "    ") %>
    return toCORBA(corba, intermediate);
}
bool orogen_toolkits::fromCORBA( <%= type.ref_type %> value, <%= intermediate_type.corba_arg_type %> corba )
{
    <% if opdef.needs_copy? %>
    <%= intermediate_type.cxx_name %> intermediate;
    if (!fromCORBA(intermediate, corba))
        return false;
<%= toolkit.code_fromIntermediate(intermediate_type, true, "    ") %>
    <% else %>
    std::auto_ptr< <%= intermediate_type.cxx_name %> > intermediate(new <%= intermediate_type.cxx_name %>);
    if (!fromCORBA(*intermediate, corba))
        return false;
<%= toolkit.code_fromIntermediate(intermediate_type, false, "    ") %>
    <% end %>
    return true;
}
<% end %>

<% registered_types.each do |type| %>
namespace orogen_toolkits {
    struct <%= type.method_name %>CorbaMarshaller
        : public RTT::detail::CorbaTemplateProtocol< <%= type.cxx_name %> >
    {
        <% if type.opaque?
             opdef = toolkit.opaque_specification(type)
             intermediate_type = toolkit.find_type(opdef.intermediate)
        %>
        typedef <%= intermediate_type.corba_name %> CorbaType;
        <% else %>
        typedef <%= type.corba_name %> CorbaType;
        <% end %>
        typedef <%= type.cxx_name %>   BaseType;

        virtual void* createBlob( RTT::DataSourceBase::shared_ptr source) const;
        virtual bool updateBlob(const void* blob, RTT::DataSourceBase::shared_ptr target) const;
    };
}

void* orogen_toolkits::<%= type.method_name %>CorbaMarshaller::createBlob( DataSourceBase::shared_ptr source) const
{
    DataSource<BaseType>* d = AdaptDataSource<BaseType>()( source );
    if ( d )
    {
        <% if type.inlines_code? || type <= Typelib::EnumType %>
        CorbaType corba;
        if (!toCORBA(corba, d->value()))
            return false;
        CORBA::Any_ptr ret = new CORBA::Any();
        *ret <<= corba;
        <% else %>
        std::auto_ptr<CorbaType> corba( new CorbaType );
        if (!toCORBA(*corba, d->value()))
            return false;
        CORBA::Any_ptr ret = new CORBA::Any();
        *ret <<= corba.release();
        <% end %>
        return ret;
    }
    return 0;
}

bool orogen_toolkits::<%= type.method_name %>CorbaMarshaller::updateBlob(const void* blob, DataSourceBase::shared_ptr target) const
{
    AssignableDataSource<BaseType>::shared_ptr ad = AssignableDataSource<BaseType>::narrow( target.get() );
    const CORBA::Any* any = static_cast<const CORBA::Any*>(blob);
    if ( ad )
    {
        <% if type.inlines_code? || type <= Typelib::EnumType %>
        CorbaType  corba;
        if (!(*any >>= corba))
            return false;
        return fromCORBA(ad->set(), corba);
        <% else %>
        CorbaType*  corba;
        if (!(*any >>= corba))
            return false;
        bool ret = fromCORBA(ad->set(), *corba);
        return ret;
        <% end %>
    }
    return false;
}
<% end %>

bool orogen_toolkits::<%= component.name %>CorbaTransportPlugin::registerTransport(std::string type_name, TypeInfo* ti)
{
    <% first_type = true;
       registered_types.each do |type| %>
    <%= 'else ' unless first_type %>if ("<%= type.name %>" == type_name)
    {
        ti->addProtocol(ORO_CORBA_PROTOCOL_ID, new orogen_toolkits::<%= type.method_name %>CorbaMarshaller());
        return true;
    }
    <% first_type = false
    end %>
    return false;
}
std::string orogen_toolkits::<%= component.name %>CorbaTransportPlugin::getTransportName() const
{ return "CORBA"; }
std::string orogen_toolkits::<%= component.name %>CorbaTransportPlugin::getName() const
{ return "/orogen/<%= component.name %>/CORBA"; }

orogen_toolkits::<%= component.name %>CorbaTransportPlugin orogen_toolkits::<%= component.name %>CorbaTransport;
ORO_TOOLKIT_PLUGIN(orogen_toolkits::<%= component.name %>CorbaTransport);

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "ut_aboutbusinesslogic.h"
#include "aboutbusinesslogic.h"

#include <stdint.h>
#include <inttypes.h>
#include <QMap>
#include <QDebug>
#include <QString>
#include <QVariant>
#include <QByteArray>

#include <QSystemInfo>
#include <QSystemDeviceInfo>
#include <QSystemNetworkInfo>
#include <QNetworkInterface>

#include <QFile>
#include <QIODevice>

#include <MApplication>

#define DEBUG
#include "../../src/debug.h"

/******************************************************************************
 * Stubbing the QNetworkInfo
 */
QString qnetworkinterface_hwaddr;

QString
QNetworkInterface::hardwareAddress () const
{
    return qnetworkinterface_hwaddr;
}

bool
QNetworkInterface::isValid () const
{
    return ! qnetworkinterface_hwaddr.isNull ();
}

/******************************************************************************
 * Stubbing the QSystemDeviceInfo::imei () and QSystemInfo::version ()
 */
QString systemdeviceinfo_imei_retval;
QString systeminfo_firmware_retval;

QTM_BEGIN_NAMESPACE

QString
QSystemDeviceInfo::imei()
{
    return systemdeviceinfo_imei_retval;
}

QString
QSystemInfo::version (
    QSystemInfo::Version type,
    const QString &parameter)
{
    Q_UNUSED (type);
    Q_UNUSED (parameter);
    return systeminfo_firmware_retval;
}

QSystemNetworkInfo::QSystemNetworkInfo (QObject *parent)
{
    Q_UNUSED (parent);
}

QSystemNetworkInfo::~QSystemNetworkInfo ()
{
}

QNetworkInterface qnetif_for_testing;

QNetworkInterface
QSystemNetworkInfo::interfaceForMode (QSystemNetworkInfo::NetworkMode mode)
{
    Q_UNUSED (mode);
    return qnetif_for_testing;
}

QTM_END_NAMESPACE

/******************************************************************************
 * Stubbing the dbus interface.
 */
static QString lastCalledMethod;

bool
QDBusAbstractInterface::callWithCallback (
        const QString           &method,
        const QList<QVariant>   &args,
        QObject                 *receiver,
        const char              *returnMethod,
        const char              *errorMethod)
{
    Q_UNUSED (args);
    Q_UNUSED (receiver);
    Q_UNUSED (errorMethod);
    Q_UNUSED (returnMethod);

    SYS_DEBUG ("*** method       = %s", SYS_STR(method));
    SYS_DEBUG ("*** returnMethod = %s", returnMethod);

    lastCalledMethod = method;
    return true;
}

/******************************************************************************
 * Ut_AboutBusinessLogic implementation.
 */
void
Ut_AboutBusinessLogic::init()
{
    m_Api = new AboutBusinessLogic;
}

void
Ut_AboutBusinessLogic::cleanup()
{
    delete m_Api;
    m_Api = 0;
}

static int argc = 1;
static char *app_name = (char*) "./ut_aboutbusinesslogic";

void
Ut_AboutBusinessLogic::initTestCase()
{
    m_App = new MApplication (argc, &app_name);
}

void
Ut_AboutBusinessLogic::cleanupTestCase()
{
    m_App->deleteLater ();
}

void
Ut_AboutBusinessLogic::testImei()
{
    systemdeviceinfo_imei_retval = "AA-BBBBBB-CCCCCC-D";

    QCOMPARE (m_Api->IMEI (), systemdeviceinfo_imei_retval);
}

void
Ut_AboutBusinessLogic::testOsName ()
{
    QString name;

    name = m_Api->osName();
    QCOMPARE (name, QString ("qtn_prod_sw_version"));

}

void
Ut_AboutBusinessLogic::testOsVersion ()
{
    QString name;

    systeminfo_firmware_retval = "HARDWARE_PROGRAM_VERSION13";
    name = m_Api->osVersion();

    QVERIFY (name.contains (QString ("VERSION13")));

    // check the LSB release file version
    systeminfo_firmware_retval = "";
    system("echo  'DISTRIB_ID=Ubuntu' > ./testfile");
    system("echo  'DISTRIB_RELEASE=11.04' >> ./testfile");
    system("echo  'DISTRIB_ID=Ubuntu' >> ./testfile");

    name = m_Api->osVersion("./testfile");
    qDebug() << qPrintable(m_Api->osVersion("./testfile"));

    QVERIFY (name.contains (QString ("11.04")));
    system ("rm -f ./testfile");

}

void
Ut_AboutBusinessLogic::testBluetooth ()
{
    QSignalSpy spy (
        m_Api,
        SIGNAL (requestFinished (AboutBusinessLogic::requestType, QVariant)));

    QMap <QString, QVariant> properties;
    properties["Address"] = QString ("fake-bluetooth-address");

    /*
     * Let's initiate the Bluetooth query that will call the
     * QDBusAbstractInterface::callWithCallback() that is stubbed.
     */
    m_Api->initiateBluetoothQueries ();
    QCOMPARE (lastCalledMethod, QString ("DefaultAdapter"));

    /*
     * Let's answer the previous step by calling the DBus callback manually.
     * This will initiate an other DBus call also stubbed.
     */
    m_Api->defaultBluetoothAdapterReceived (
            QDBusObjectPath("/fakeObjectPath"));
    QCOMPARE (lastCalledMethod, QString ("GetProperties"));

    /*
     * Answering the second DBus call and checking if the businesslogic
     * processed the data as it should.
     */
    m_Api->defaultBluetoothAdapterAddressReceived (properties);

    QTest::qWait (100);
    QCOMPARE (spy.count (), 1);

    QList<QVariant> args = spy.first ();

    QCOMPARE (args.at (0).value<AboutBusinessLogic::requestType>(),
              AboutBusinessLogic::reqBtAddr);
#if 0
    /* for some strange reason it is not working :-S */
    QCOMPARE (args.at (1).toString (), QString ("fake-bluetooth-address"));
#endif

    /*
     * Let's test the failure socket. This does not do nothing...
     */
    m_Api->DBusMessagingFailure (QDBusError());

    delete m_Api;
    /*
     * Let's see what happens if we initate the data collection and instead of
     * producing answers to queries we just destroy the object.
     */
    m_Api = new AboutBusinessLogic;
    m_Api->initiateBluetoothQueries ();
    //XXX: delete m_Api; (done in cleanup ())
}

void
Ut_AboutBusinessLogic::testHwAddresses ()
{
    qnetworkinterface_hwaddr = "test-address-xxx";

    QCOMPARE (m_Api->WiFiAddress (), qnetworkinterface_hwaddr);
}

void
Ut_AboutBusinessLogic::testLicenseText ()
{
    system ("echo 'testtext' > /usr/share/about-contents/testlicensefile");
    m_Api->m_licenseFile = QString ("testlicensefile");

    QCOMPARE (m_Api->licenseText (), QString ("testtext\n"));
    system ("rm /usr/share/about-contents/testlicensefile");

    //check what if the file  doesn't exist
    QCOMPARE (m_Api->licenseText (), QString ("qtn_prod_legal"));

}

/**
 * Check that all mandatory informations are passed
 * throught the requestFinished signal...
 */
void
Ut_AboutBusinessLogic::testMultiThread ()
{
    QSignalSpy spy (
        m_Api,
        SIGNAL (requestFinished (AboutBusinessLogic::requestType, QVariant)));

    /*
     * Run the multithreaded data collection ...
     */
    m_Api->start ();

    /*
     * Hopefully this does not harm, and enough...
     */
    QTest::qWait (500);

    QList<AboutBusinessLogic::requestType> mandatoryFields;
    mandatoryFields <<
        AboutBusinessLogic::reqProdName <<
        AboutBusinessLogic::reqSwName <<
        AboutBusinessLogic::reqLicense <<
        AboutBusinessLogic::reqOsVersion <<
        AboutBusinessLogic::reqImei <<
        AboutBusinessLogic::reqWifiAddr;
    /* BtAddr also mandatory, but we stubbed that stuff here,
     * and we have a separate testcase which covers that one... */

    /*
     * Check whether that at least the mandatory field values are arrived
     */
    QVERIFY (spy.count () >= mandatoryFields.count ());

    QList<AboutBusinessLogic::requestType> arrivedFields;

    for ( ; ! spy.isEmpty () ; )
    {
        QList<QVariant> signal = spy.takeFirst ();
        arrivedFields <<
            signal.at (0).value<AboutBusinessLogic::requestType>();
    }

    foreach (AboutBusinessLogic::requestType req, mandatoryFields)
    {
        //SYS_DEBUG ("reqNr = %d", (int) req);
        QVERIFY (arrivedFields.contains (req));
    }
}

QTEST_APPLESS_MAIN(Ut_AboutBusinessLogic)
<commit_msg>Changes: adjust a testcase..<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "ut_aboutbusinesslogic.h"
#include "aboutbusinesslogic.h"

#include <stdint.h>
#include <inttypes.h>
#include <QMap>
#include <QDebug>
#include <QString>
#include <QVariant>
#include <QByteArray>

#include <QSystemInfo>
#include <QSystemDeviceInfo>
#include <QSystemNetworkInfo>
#include <QNetworkInterface>

#include <QFile>
#include <QIODevice>

#include <MApplication>

#define DEBUG
#include "../../src/debug.h"

/******************************************************************************
 * Stubbing the QNetworkInfo
 */
QString qnetworkinterface_hwaddr;

QString
QNetworkInterface::hardwareAddress () const
{
    return qnetworkinterface_hwaddr;
}

bool
QNetworkInterface::isValid () const
{
    return ! qnetworkinterface_hwaddr.isNull ();
}

/******************************************************************************
 * Stubbing the QSystemDeviceInfo::imei () and QSystemInfo::version ()
 */
QString systemdeviceinfo_imei_retval;
QString systeminfo_firmware_retval;

QTM_BEGIN_NAMESPACE

QString
QSystemDeviceInfo::imei()
{
    return systemdeviceinfo_imei_retval;
}

QString
QSystemInfo::version (
    QSystemInfo::Version type,
    const QString &parameter)
{
    Q_UNUSED (type);
    Q_UNUSED (parameter);
    return systeminfo_firmware_retval;
}

QSystemNetworkInfo::QSystemNetworkInfo (QObject *parent)
{
    Q_UNUSED (parent);
}

QSystemNetworkInfo::~QSystemNetworkInfo ()
{
}

QNetworkInterface qnetif_for_testing;

QNetworkInterface
QSystemNetworkInfo::interfaceForMode (QSystemNetworkInfo::NetworkMode mode)
{
    Q_UNUSED (mode);
    return qnetif_for_testing;
}

QTM_END_NAMESPACE

/******************************************************************************
 * Stubbing the dbus interface.
 */
static QString lastCalledMethod;

bool
QDBusAbstractInterface::callWithCallback (
        const QString           &method,
        const QList<QVariant>   &args,
        QObject                 *receiver,
        const char              *returnMethod,
        const char              *errorMethod)
{
    Q_UNUSED (args);
    Q_UNUSED (receiver);
    Q_UNUSED (errorMethod);
    Q_UNUSED (returnMethod);

    SYS_DEBUG ("*** method       = %s", SYS_STR(method));
    SYS_DEBUG ("*** returnMethod = %s", returnMethod);

    lastCalledMethod = method;
    return true;
}

/******************************************************************************
 * Ut_AboutBusinessLogic implementation.
 */
void
Ut_AboutBusinessLogic::init()
{
    m_Api = new AboutBusinessLogic;
}

void
Ut_AboutBusinessLogic::cleanup()
{
    delete m_Api;
    m_Api = 0;
}

static int argc = 1;
static char *app_name = (char*) "./ut_aboutbusinesslogic";

void
Ut_AboutBusinessLogic::initTestCase()
{
    m_App = new MApplication (argc, &app_name);
}

void
Ut_AboutBusinessLogic::cleanupTestCase()
{
    m_App->deleteLater ();
}

void
Ut_AboutBusinessLogic::testImei()
{
    systemdeviceinfo_imei_retval = "AA-BBBBBB-CCCCCC-D";

    QCOMPARE (m_Api->IMEI (), systemdeviceinfo_imei_retval);
}

void
Ut_AboutBusinessLogic::testOsName ()
{
    QString name;

    name = m_Api->osName();
    QCOMPARE (name, QString ("qtn_prod_sw_version"));

}

void
Ut_AboutBusinessLogic::testOsVersion ()
{
    QString name;

    systeminfo_firmware_retval = "HARDWARE_PROGRAM_VERSION13";
    name = m_Api->osVersion();

    QVERIFY (name.contains (QString ("VERSION13")));

    // check the LSB release file version
    systeminfo_firmware_retval = "";
    system("echo  'DISTRIB_ID=Ubuntu' > ./testfile");
    system("echo  'DISTRIB_RELEASE=11.04' >> ./testfile");
    system("echo  'DISTRIB_ID=Ubuntu' >> ./testfile");

    name = m_Api->osVersion("./testfile");
    qDebug() << qPrintable(m_Api->osVersion("./testfile"));

    QVERIFY (name.contains (QString ("11.04")));
    system ("rm -f ./testfile");

}

void
Ut_AboutBusinessLogic::testBluetooth ()
{
    QSignalSpy spy (
        m_Api,
        SIGNAL (requestFinished (AboutBusinessLogic::requestType, QVariant)));

    QMap <QString, QVariant> properties;
    properties["Address"] = QString ("fake-bluetooth-address");

    /*
     * Let's initiate the Bluetooth query that will call the
     * QDBusAbstractInterface::callWithCallback() that is stubbed.
     */
    m_Api->initiateBluetoothQueries ();
    QCOMPARE (lastCalledMethod, QString ("DefaultAdapter"));

    /*
     * Let's answer the previous step by calling the DBus callback manually.
     * This will initiate an other DBus call also stubbed.
     */
    m_Api->defaultBluetoothAdapterReceived (
            QDBusObjectPath("/fakeObjectPath"));
    QCOMPARE (lastCalledMethod, QString ("GetProperties"));

    /*
     * Answering the second DBus call and checking if the businesslogic
     * processed the data as it should.
     */
    m_Api->defaultBluetoothAdapterAddressReceived (properties);

    QTest::qWait (100);
    QCOMPARE (spy.count (), 1);

    QList<QVariant> args = spy.first ();

    QCOMPARE (args.at (0).value<AboutBusinessLogic::requestType>(),
              AboutBusinessLogic::reqBtAddr);
#if 0
    /* for some strange reason it is not working :-S */
    QCOMPARE (args.at (1).toString (), QString ("fake-bluetooth-address"));
#endif

    /*
     * Let's test the failure socket. This does not do nothing...
     */
    m_Api->DBusMessagingFailure (QDBusError());

    delete m_Api;
    /*
     * Let's see what happens if we initate the data collection and instead of
     * producing answers to queries we just destroy the object.
     */
    m_Api = new AboutBusinessLogic;
    m_Api->initiateBluetoothQueries ();
    //XXX: delete m_Api; (done in cleanup ())
}

void
Ut_AboutBusinessLogic::testHwAddresses ()
{
    qnetworkinterface_hwaddr = "test-address-xxx";

    QCOMPARE (m_Api->WiFiAddress (), qnetworkinterface_hwaddr);
}

void
Ut_AboutBusinessLogic::testLicenseText ()
{
    /*
     * FIXME: the test app may not have access to do this
     */
    system ("mkdir -p /usr/share/about-contents");
    system ("echo 'testtext' > /usr/share/about-contents/testlicensefile");
    m_Api->m_licenseFile = QString ("testlicensefile");

    QCOMPARE (m_Api->licenseText (), QString ("testtext\n"));
    system ("rm /usr/share/about-contents/testlicensefile");

    //check what if the file  doesn't exist
    QCOMPARE (m_Api->licenseText (), QString ("qtn_prod_legal"));
}

/**
 * Check that all mandatory informations are passed
 * throught the requestFinished signal...
 */
void
Ut_AboutBusinessLogic::testMultiThread ()
{
    QSignalSpy spy (
        m_Api,
        SIGNAL (requestFinished (AboutBusinessLogic::requestType, QVariant)));

    /*
     * Run the multithreaded data collection ...
     */
    m_Api->start ();

    /*
     * Hopefully this does not harm, and enough...
     */
    QTest::qWait (500);

    QList<AboutBusinessLogic::requestType> mandatoryFields;
    mandatoryFields <<
        AboutBusinessLogic::reqProdName <<
        AboutBusinessLogic::reqSwName <<
        AboutBusinessLogic::reqLicense <<
        AboutBusinessLogic::reqOsVersion <<
        AboutBusinessLogic::reqImei <<
        AboutBusinessLogic::reqWifiAddr;
    /* BtAddr also mandatory, but we stubbed that stuff here,
     * and we have a separate testcase which covers that one... */

    /*
     * Check whether that at least the mandatory field values are arrived
     */
    QVERIFY (spy.count () >= mandatoryFields.count ());

    QList<AboutBusinessLogic::requestType> arrivedFields;

    for ( ; ! spy.isEmpty () ; )
    {
        QList<QVariant> signal = spy.takeFirst ();
        arrivedFields <<
            signal.at (0).value<AboutBusinessLogic::requestType>();
    }

    foreach (AboutBusinessLogic::requestType req, mandatoryFields)
    {
        //SYS_DEBUG ("reqNr = %d", (int) req);
        QVERIFY (arrivedFields.contains (req));
    }
}

QTEST_APPLESS_MAIN(Ut_AboutBusinessLogic)
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include "paddle/framework/executor.h"

#include <algorithm>
#include <iostream>
#include <memory>
#include <set>
#include <vector>

#include "paddle/framework/lod_tensor.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/scope.h"

#include <boost/range/adaptor/reversed.hpp>

namespace paddle {
namespace framework {

const std::string kFeedOpType = "feed";
const std::string kFetchOpType = "fetch";

Executor::Executor(const std::vector<platform::Place>& places) {
  PADDLE_ENFORCE_GT(places.size(), 0);
  device_contexts_.resize(places.size());
  for (size_t i = 0; i < places.size(); i++) {
    if (platform::is_cpu_place(places[i])) {
      device_contexts_[i] = new platform::CPUDeviceContext(
          boost::get<platform::CPUPlace>(places[i]));
    } else if (platform::is_gpu_place(places[i])) {
#ifdef PADDLE_WITH_CUDA
      device_contexts_[i] = new platform::CUDADeviceContext(
          boost::get<platform::GPUPlace>(places[i]));
#else
      PADDLE_THROW(
          "'GPUPlace' is not supported, Please re-compile with WITH_GPU "
          "option");
#endif
    }
  }
}

Executor::~Executor() {
  for (auto& device_context : device_contexts_) {
    delete device_context;
  }
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_GT(pdesc.blocks_size(), block_id);
  auto& block = pdesc.blocks(block_id);
  auto& device = device_contexts_[0];

  // Instantiate all the vars in the global scope
  for (auto& var : block.vars()) {
    scope->NewVar(var.name());
  }

  Scope& local_scope = scope->NewScope();

  std::vector<bool> should_run = Prune(pdesc, block_id);
  PADDLE_ENFORCE_EQ(should_run.size(), static_cast<size_t>(block.ops_size()));
  for (size_t i = 0; i < should_run.size(); ++i) {
    if (should_run[i]) {
      for (auto& var : block.ops(i).outputs()) {
        for (auto& argu : var.arguments()) {
          if (local_scope.FindVar(argu) == nullptr) {
            local_scope.NewVar(argu);
          }
        }
      }
      auto op = paddle::framework::OpRegistry::CreateOp(block.ops(i));
      op->Run(local_scope, *device);
    }
  }

  // TODO(tonyyang-svail):
  //  - Destroy local_scope
}

std::vector<bool> Prune(const ProgramDesc& pdesc, int block_id) {
  // TODO(tonyyang-svail):
  //    - will change to use multiple blocks for RNN op and Cond Op

  auto& block = pdesc.blocks(block_id);
  auto& ops = block.ops();

  bool expect_feed = true;
  for (auto& op_desc : ops) {
    PADDLE_ENFORCE(op_desc.type() != kFeedOpType || expect_feed,
                   "All FeedOps are at the beginning of the ProgramDesc");
    expect_feed = (op_desc.type() == kFeedOpType);
  }

  bool expect_fetch = true;
  for (auto op_iter = ops.rbegin(); op_iter != ops.rend(); ++op_iter) {
    auto& op_desc = *op_iter;
    PADDLE_ENFORCE(op_desc.type() != kFetchOpType || expect_fetch,
                   "All FetchOps must at the end of the ProgramDesc");
    expect_fetch = (op_desc.type() == kFetchOpType);
  }

  std::set<std::string> dependent_vars;
  std::vector<bool> should_run;
  for (auto op_iter = ops.rbegin(); op_iter != ops.rend(); ++op_iter) {
    auto& op_desc = *op_iter;

    bool found_dependent_vars = false;
    for (auto& var : op_desc.outputs()) {
      for (auto& argu : var.arguments()) {
        if (dependent_vars.count(argu) != 0) {
          found_dependent_vars = true;
        }
      }
    }

    if (op_desc.type() == kFetchOpType || found_dependent_vars) {
      // erase its output to the dependency graph
      for (auto& var : op_desc.outputs()) {
        for (auto& argu : var.arguments()) {
          dependent_vars.erase(argu);
        }
      }

      // insert its input to the dependency graph
      for (auto& var : op_desc.inputs()) {
        for (auto& argu : var.arguments()) {
          dependent_vars.insert(argu);
        }
      }

      should_run.push_back(true);
    } else {
      should_run.push_back(false);
    }
  }

  // TODO(tonyyang-svail):
  //    - check this after integration of Init
  // PADDLE_ENFORCE(dependent_vars.empty());

  // since we are traversing the ProgramDesc in reverse order
  // we reverse the should_run vector
  std::reverse(should_run.begin(), should_run.end());

  return should_run;
}

}  // namespace framework
}  // namespace paddle
<commit_msg>fix Compile error [fatal error: boost/range/adaptor/reversed.hpp No such file or directory]<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include "paddle/framework/executor.h"

#include <algorithm>
#include <iostream>
#include <memory>
#include <set>
#include <vector>

#include "paddle/framework/lod_tensor.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/scope.h"

namespace paddle {
namespace framework {

const std::string kFeedOpType = "feed";
const std::string kFetchOpType = "fetch";

Executor::Executor(const std::vector<platform::Place>& places) {
  PADDLE_ENFORCE_GT(places.size(), 0);
  device_contexts_.resize(places.size());
  for (size_t i = 0; i < places.size(); i++) {
    if (platform::is_cpu_place(places[i])) {
      device_contexts_[i] = new platform::CPUDeviceContext(
          boost::get<platform::CPUPlace>(places[i]));
    } else if (platform::is_gpu_place(places[i])) {
#ifdef PADDLE_WITH_CUDA
      device_contexts_[i] = new platform::CUDADeviceContext(
          boost::get<platform::GPUPlace>(places[i]));
#else
      PADDLE_THROW(
          "'GPUPlace' is not supported, Please re-compile with WITH_GPU "
          "option");
#endif
    }
  }
}

Executor::~Executor() {
  for (auto& device_context : device_contexts_) {
    delete device_context;
  }
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_GT(pdesc.blocks_size(), block_id);
  auto& block = pdesc.blocks(block_id);
  auto& device = device_contexts_[0];

  // Instantiate all the vars in the global scope
  for (auto& var : block.vars()) {
    scope->NewVar(var.name());
  }

  Scope& local_scope = scope->NewScope();

  std::vector<bool> should_run = Prune(pdesc, block_id);
  PADDLE_ENFORCE_EQ(should_run.size(), static_cast<size_t>(block.ops_size()));
  for (size_t i = 0; i < should_run.size(); ++i) {
    if (should_run[i]) {
      for (auto& var : block.ops(i).outputs()) {
        for (auto& argu : var.arguments()) {
          if (local_scope.FindVar(argu) == nullptr) {
            local_scope.NewVar(argu);
          }
        }
      }
      auto op = paddle::framework::OpRegistry::CreateOp(block.ops(i));
      op->Run(local_scope, *device);
    }
  }

  // TODO(tonyyang-svail):
  //  - Destroy local_scope
}

std::vector<bool> Prune(const ProgramDesc& pdesc, int block_id) {
  // TODO(tonyyang-svail):
  //    - will change to use multiple blocks for RNN op and Cond Op

  auto& block = pdesc.blocks(block_id);
  auto& ops = block.ops();

  bool expect_feed = true;
  for (auto& op_desc : ops) {
    PADDLE_ENFORCE(op_desc.type() != kFeedOpType || expect_feed,
                   "All FeedOps are at the beginning of the ProgramDesc");
    expect_feed = (op_desc.type() == kFeedOpType);
  }

  bool expect_fetch = true;
  for (auto op_iter = ops.rbegin(); op_iter != ops.rend(); ++op_iter) {
    auto& op_desc = *op_iter;
    PADDLE_ENFORCE(op_desc.type() != kFetchOpType || expect_fetch,
                   "All FetchOps must at the end of the ProgramDesc");
    expect_fetch = (op_desc.type() == kFetchOpType);
  }

  std::set<std::string> dependent_vars;
  std::vector<bool> should_run;
  for (auto op_iter = ops.rbegin(); op_iter != ops.rend(); ++op_iter) {
    auto& op_desc = *op_iter;

    bool found_dependent_vars = false;
    for (auto& var : op_desc.outputs()) {
      for (auto& argu : var.arguments()) {
        if (dependent_vars.count(argu) != 0) {
          found_dependent_vars = true;
        }
      }
    }

    if (op_desc.type() == kFetchOpType || found_dependent_vars) {
      // erase its output to the dependency graph
      for (auto& var : op_desc.outputs()) {
        for (auto& argu : var.arguments()) {
          dependent_vars.erase(argu);
        }
      }

      // insert its input to the dependency graph
      for (auto& var : op_desc.inputs()) {
        for (auto& argu : var.arguments()) {
          dependent_vars.insert(argu);
        }
      }

      should_run.push_back(true);
    } else {
      should_run.push_back(false);
    }
  }

  // TODO(tonyyang-svail):
  //    - check this after integration of Init
  // PADDLE_ENFORCE(dependent_vars.empty());

  // since we are traversing the ProgramDesc in reverse order
  // we reverse the should_run vector
  std::reverse(should_run.begin(), should_run.end());

  return should_run;
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include <vector>
#include "paddle/framework/executor.h"
#include "paddle/framework/lod_tensor_array.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"
#include "paddle/operators/detail/safe_ref.h"

namespace paddle {
namespace operators {

using StepScopeVar = std::vector<framework::Scope *>;
using LoDTensor = framework::LoDTensor;

static constexpr char kStepBlock[] = "sub_block";
static constexpr char kCondition[] = "Condition";
static constexpr char kStepScopes[] = "StepScopes";
static constexpr char kX[] = "X";
static constexpr char kXGRAD[] = "X@GRAD";
static constexpr char kOutputs[] = "Out";

class WhileOp : public framework::OperatorBase {
 public:
  WhileOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &dev_place) const override {
    PADDLE_ENFORCE_NOT_NULL(scope.FindVar(Input(kCondition)));
    auto &cond = scope.FindVar(Input(kCondition))->Get<LoDTensor>();
    PADDLE_ENFORCE_EQ(cond.dims(), paddle::framework::make_ddim({1}));

    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);

    auto *program = block->Program();

    auto step_scopes =
        scope.FindVar(Output(kStepScopes))->GetMutable<StepScopeVar>();

    while (cond.data<bool>()[0]) {
      auto &current_scope = scope.NewScope();
      step_scopes->push_back(&current_scope);

      executor.Run(*program, &current_scope, block->ID(),
                   false /*create_local_scope*/);
    }
  }
};

class WhileOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  WhileOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kX,
             "A set of variables, which are required by operators inside the "
             "block of While Op.")
        .AsDuplicable();
    AddInput(
        kCondition,
        "(Bool) An scalar. When it's False, the While Op will be terminated.")
        .AsDuplicable();
    AddOutput(kOutputs,
              "A set of variables, which will be assigned with values "
              "generated by the operators inside the block of While Op.")
        .AsDuplicable();
    AddOutput(kStepScopes,
              "(StepScopeVar) A vector of local scope, which size equals the "
              "step number of While Op. The i'th scope storages temporary "
              "variables generated in the i'th step.");
    AddAttr<framework::BlockDesc *>(kStepBlock,
                                    "The step block inside WhileOp");
    AddComment(R"DOC(
)DOC");
  }
};

class WhileGradOp : public framework::OperatorBase {
 public:
  WhileGradOp(const std::string &type, const framework::VariableNameMap &inputs,
              const framework::VariableNameMap &outputs,
              const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &dev_place) const override {
    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);
    auto *program = block->Program();

    auto *step_scopes =
        scope.FindVar(Input(kStepScopes))->GetMutable<StepScopeVar>();

    auto outside_og_names = Inputs(framework::GradVarName(kOutputs));
    auto inside_og_names =
        Attr<std::vector<std::string>>("original_output_grad");

    PADDLE_ENFORCE_EQ(outside_og_names.size(), inside_og_names.size());

    for (auto cur_scope_iter = step_scopes->rbegin();
         cur_scope_iter != step_scopes->rend(); ++cur_scope_iter) {
      VLOG(3) << "Start backward at time_step "
              << cur_scope_iter - step_scopes->rbegin();
      framework::Scope &cur_scope = **cur_scope_iter;
      // Link OG from outside to inside
      for (size_t i = 0; i < outside_og_names.size(); ++i) {
        auto outside_og_name = outside_og_names[i];
        auto inside_og_name = inside_og_names[i];
        VLOG(10) << "Linking outside " << outside_og_name << " --> inside "
                 << inside_og_name;
        auto &og_outside =
            detail::Ref(scope.FindVar(outside_og_name),
                        "Cannot find Outside Gradient %s", outside_og_name);
        auto &og_inside =
            detail::Ref(cur_scope.Var(inside_og_name),
                        "Cannot find inside gradient %s", inside_og_name);
        if (og_outside.Type().hash_code() ==
            typeid(framework::LoDTensor).hash_code()) {
          auto &outside_tensor = og_outside.Get<framework::LoDTensor>();
          auto &inside_tensor =
              detail::Ref(og_inside.GetMutable<framework::LoDTensor>());
          inside_tensor.set_lod(outside_tensor.lod());
          inside_tensor.ShareDataWith(outside_tensor);
        } else if (og_outside.Type().hash_code() ==
                   typeid(framework::LoDTensorArray).hash_code()) {
          auto &outside_array = og_outside.Get<framework::LoDTensorArray>();
          auto &inside_array =
              detail::Ref(og_inside.GetMutable<framework::LoDTensorArray>());
          VLOG(10) << outside_og_name << " size = " << outside_array.size();
          inside_array.resize(outside_array.size());

          for (size_t j = 0; j < inside_array.size(); ++j) {
            VLOG(10) << j << " " << outside_array[j].numel();
            if (outside_array[j].numel() != 0) {
              inside_array[j].set_lod(outside_array[j].lod());
              inside_array[j].ShareDataWith(outside_array[j]);
            } else {
              PADDLE_ENFORCE_EQ(inside_array[j].numel(), 0);
            }
          }
        }
      }

      executor.Run(*program, *cur_scope_iter, block->ID(), false);

      auto &pg_names = Outputs(kXGRAD);
      auto &p_names = Inputs(kX);
      PADDLE_ENFORCE_EQ(pg_names.size(), p_names.size());
      for (size_t param_id = 0; param_id < pg_names.size(); ++param_id) {
        if (pg_names[param_id] == framework::kEmptyVarName) {
          continue;  // parameter doesn't have gradient
        }
        auto inside_grad_name = framework::GradVarName(p_names[param_id]);

        //  // TODO(tonyyang-svail): Not sure we need the following
        //  // If does not compute gradient of that variable inside rnn,
        //  just
        //  // continue
        //  if (local_var_names.find(inside_grad_name) ==
        //  local_var_names.end()) {
        //    continue;
        //  }

        // zero gradient variable in step 0
        if (cur_scope_iter == step_scopes->rbegin()) {
          auto *var = (*cur_scope_iter)->FindVar(inside_grad_name);
          PADDLE_ENFORCE_NOT_NULL(var, "Can not find var %s", inside_grad_name);
          if (var->IsType<LoDTensor>()) {
            auto &inside_tensor = var->Get<framework::LoDTensor>();
            framework::AttributeMap attrs;
            attrs["dtype"] = framework::ToDataType(inside_tensor.type());
            attrs["shape"] = framework::vectorize2int(inside_tensor.dims());
            attrs["value"] = 0.0f;

            auto zero_op = framework::OpRegistry::CreateOp(
                "fill_constant", framework::VariableNameMap{},
                {{"Out", {pg_names[param_id]}}}, attrs);
            zero_op->Run(scope, dev_place);
          }
        }

        auto new_inside_name = cur_scope.Rename(inside_grad_name);
        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {pg_names[param_id], new_inside_name}}},
            {{"Out", {pg_names[param_id]}}}, framework::AttributeMap{});
        sum_op->Run(cur_scope, dev_place);
        cur_scope.Rename(new_inside_name, inside_grad_name);
      }
    }
  }
};

class WhileGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    auto *while_grad = new framework::OpDesc();
    while_grad->SetType("while_grad");
    while_grad->SetInput(kX, Input(kX));
    while_grad->SetInput(kOutputs, Output(kOutputs));
    while_grad->SetInput(kStepScopes, Output(kStepScopes));

    auto *grad_block = this->grad_block_[0];
    auto *fwd_block = grad_block->ParentBlock();
    // auto *parent_block = fwd_block->ParentBlock();

    // Not all of IGs will be generated by inner gradient operators of while op.
    // Ignore IGs that is not generated by the inside block.
    std::unordered_set<std::string> inner_op_outputs;
    LOG(INFO) << "FUCK1";
    for (const auto *op : grad_block->AllOps()) {
      for (auto &oname : op->OutputArgumentNames()) {
        inner_op_outputs.insert(oname);
      }
    }
    LOG(INFO) << "FUCK2";
    auto igs = InputGrad(kX, /*do not drop empty gradient*/ false);
    for (auto &each_ig : igs) {
      if (inner_op_outputs.find(each_ig) == inner_op_outputs.end()) {
        VLOG(10) << "Ignore " << each_ig;
        each_ig = framework::kEmptyVarName;
      }
    }
    while_grad->SetOutput(framework::GradVarName(kX), igs);

    // OG should be re-calculated by step blocks, since many outputs of while op
    // do not need to calculate gradients.
    std::unordered_set<std::string> block_ins;
    std::copy(Input(kX).begin(), Input(kX).end(),
              std::inserter(block_ins, block_ins.end()));
    std::copy(Output(kOutputs).begin(), Output(kOutputs).end(),
              std::inserter(block_ins, block_ins.end()));

    std::unordered_set<std::string> extra_inputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &input_name : op->InputArgumentNames()) {
        // If the input of Op has been recorded or is generated by the forward
        // block, do not make it as input again.
        if (block_ins.find(input_name) != block_ins.end() ||
            fwd_block->FindVar(input_name) != nullptr) {
          continue;
        }

        /*
        if (parent_block->FindVarRecursive(input_name) == nullptr) {
          VLOG(5) << "WARNING! Variable '" << input_name
                  << "' is the input of '" << op->Type()
                  << "'. But can not be found in any block.";
          continue;
        }
        */
        extra_inputs.insert(input_name);
      }
      for (auto &output_name : op->OutputArgumentNames()) {
        block_ins.insert(output_name);
      }
    }

    std::vector<std::string> extra_inputs_list;
    extra_inputs_list.resize(extra_inputs.size());
    std::copy(extra_inputs.begin(), extra_inputs.end(),
              extra_inputs_list.begin());
    while_grad->SetInput(framework::GradVarName(kOutputs), extra_inputs_list);

    while_grad->SetAttrMap(this->Attrs());
    while_grad->SetBlockAttr(kStepBlock, *grad_block);
    // record the original output gradient names, since the gradient name of
    // while operator could be renamed.
    while_grad->SetAttr("original_output_grad", extra_inputs_list);

    return std::unique_ptr<framework::OpDesc>(while_grad);
  }
};

class WhileGradOpVarTypeInference : public framework::VarTypeInference {
 public:
  void operator()(const framework::OpDesc &op_desc,
                  framework::BlockDesc *block) const override {
    auto p_names = op_desc.Input(kX);
    auto pg_names = op_desc.Output(framework::GradVarName(kX));

    for (size_t i = 0; i < p_names.size(); ++i) {
      auto &p_var = detail::Ref(block->FindVarRecursive(p_names[i]));
      auto *g_var = block->FindVarRecursive(pg_names[i]);
      if (g_var != nullptr) {  // Gradient could be @EMPTY@
        VLOG(5) << "Setting " << pg_names[i] << " following " << p_names[i]
                << " type: " << p_var.GetType();
        g_var->SetType(p_var.GetType());
        g_var->SetDataType(p_var.GetDataType());
      }
    }
  }
};

class WhileGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    ctx->HasInputs(kX);
    ctx->HasOutputs(framework::GradVarName(kX));
    ctx->HasInputs(kOutputs);
    ctx->HasInputs(framework::GradVarName(kOutputs));

    auto p_names = ctx->Inputs(kX);
    auto pg_names = ctx->Outputs(kXGRAD);
    auto var_types = ctx->GetInputsVarType(kX);
    std::vector<std::string> names_to_set;
    std::vector<framework::DDim> dims_to_set;
    for (size_t i = 0; i < p_names.size(); ++i) {
      if (pg_names[i] == framework::kEmptyVarName) {
        continue;
      }
      auto dims = ctx->GetInputsElementDim(kX, i);
      if (var_types[i] == framework::proto::VarDesc::LOD_TENSOR) {
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      } else if (var_types[i] == framework::proto::VarDesc::LOD_TENSOR_ARRAY) {
        // not sure how to set the dim of LOD_TENSOR_ARRAY
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      }
    }
    ctx->SetDims(names_to_set, dims_to_set);
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(while, paddle::operators::WhileOp,
                  paddle::operators::WhileOpMaker,
                  paddle::operators::WhileGradOpDescMaker);
REGISTER_OPERATOR(while_grad, paddle::operators::WhileGradOp,
                  paddle::operators::WhileGradOpShapeInference,
                  paddle::operators::WhileGradOpVarTypeInference);
<commit_msg>refine WhileGradOp code<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include <vector>
#include "paddle/framework/executor.h"
#include "paddle/framework/lod_tensor_array.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"
#include "paddle/operators/detail/safe_ref.h"

namespace paddle {
namespace operators {

using StepScopeVar = std::vector<framework::Scope *>;
using LoDTensor = framework::LoDTensor;

static constexpr char kStepBlock[] = "sub_block";
static constexpr char kCondition[] = "Condition";
static constexpr char kStepScopes[] = "StepScopes";
static constexpr char kX[] = "X";
static constexpr char kXGRAD[] = "X@GRAD";
static constexpr char kOutputs[] = "Out";

class WhileOp : public framework::OperatorBase {
 public:
  WhileOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &dev_place) const override {
    PADDLE_ENFORCE_NOT_NULL(scope.FindVar(Input(kCondition)));
    auto &cond = scope.FindVar(Input(kCondition))->Get<LoDTensor>();
    PADDLE_ENFORCE_EQ(cond.dims(), paddle::framework::make_ddim({1}));

    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);

    auto *program = block->Program();

    auto step_scopes =
        scope.FindVar(Output(kStepScopes))->GetMutable<StepScopeVar>();

    while (cond.data<bool>()[0]) {
      auto &current_scope = scope.NewScope();
      step_scopes->push_back(&current_scope);

      executor.Run(*program, &current_scope, block->ID(),
                   false /*create_local_scope*/);
    }
  }
};

class WhileOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  WhileOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kX,
             "A set of variables, which are required by operators inside the "
             "block of While Op.")
        .AsDuplicable();
    AddInput(
        kCondition,
        "(Bool) An scalar. When it's False, the While Op will be terminated.")
        .AsDuplicable();
    AddOutput(kOutputs,
              "A set of variables, which will be assigned with values "
              "generated by the operators inside the block of While Op.")
        .AsDuplicable();
    AddOutput(kStepScopes,
              "(StepScopeVar) A vector of local scope, which size equals the "
              "step number of While Op. The i'th scope storages temporary "
              "variables generated in the i'th step.");
    AddAttr<framework::BlockDesc *>(kStepBlock,
                                    "The step block inside WhileOp");
    AddComment(R"DOC(
)DOC");
  }
};

class WhileGradOp : public framework::OperatorBase {
 public:
  WhileGradOp(const std::string &type, const framework::VariableNameMap &inputs,
              const framework::VariableNameMap &outputs,
              const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &dev_place) const override {
    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);
    auto *program = block->Program();

    auto *step_scopes =
        scope.FindVar(Input(kStepScopes))->GetMutable<StepScopeVar>();

    auto outside_og_names = Inputs(framework::GradVarName(kOutputs));
    auto inside_og_names =
        Attr<std::vector<std::string>>("original_output_grad");

    PADDLE_ENFORCE_EQ(outside_og_names.size(), inside_og_names.size());

    for (auto cur_scope_iter = step_scopes->rbegin();
         cur_scope_iter != step_scopes->rend(); ++cur_scope_iter) {
      VLOG(3) << "Start backward at time_step "
              << cur_scope_iter - step_scopes->rbegin();
      framework::Scope &cur_scope = **cur_scope_iter;
      // Link OG from outside to inside
      for (size_t i = 0; i < outside_og_names.size(); ++i) {
        auto outside_og_name = outside_og_names[i];
        auto inside_og_name = inside_og_names[i];
        VLOG(10) << "Linking outside " << outside_og_name << " --> inside "
                 << inside_og_name;
        auto &og_outside =
            detail::Ref(scope.FindVar(outside_og_name),
                        "Cannot find Outside Gradient %s", outside_og_name);
        auto &og_inside =
            detail::Ref(cur_scope.Var(inside_og_name),
                        "Cannot find inside gradient %s", inside_og_name);
        if (og_outside.Type().hash_code() ==
            typeid(framework::LoDTensor).hash_code()) {
          auto &outside_tensor = og_outside.Get<framework::LoDTensor>();
          auto &inside_tensor =
              detail::Ref(og_inside.GetMutable<framework::LoDTensor>());
          inside_tensor.set_lod(outside_tensor.lod());
          inside_tensor.ShareDataWith(outside_tensor);
        } else if (og_outside.Type().hash_code() ==
                   typeid(framework::LoDTensorArray).hash_code()) {
          auto &outside_array = og_outside.Get<framework::LoDTensorArray>();
          auto &inside_array =
              detail::Ref(og_inside.GetMutable<framework::LoDTensorArray>());
          VLOG(10) << outside_og_name << " size = " << outside_array.size();
          inside_array.resize(outside_array.size());

          for (size_t j = 0; j < inside_array.size(); ++j) {
            VLOG(10) << j << " " << outside_array[j].numel();
            if (outside_array[j].numel() != 0) {
              inside_array[j].set_lod(outside_array[j].lod());
              inside_array[j].ShareDataWith(outside_array[j]);
            } else {
              PADDLE_ENFORCE_EQ(inside_array[j].numel(), 0);
            }
          }
        }
      }

      executor.Run(*program, *cur_scope_iter, block->ID(), false);

      auto &pg_names = Outputs(kXGRAD);
      auto &p_names = Inputs(kX);
      PADDLE_ENFORCE_EQ(pg_names.size(), p_names.size());
      for (size_t param_id = 0; param_id < pg_names.size(); ++param_id) {
        if (pg_names[param_id] == framework::kEmptyVarName) {
          continue;  // parameter doesn't have gradient
        }
        auto inside_grad_name = framework::GradVarName(p_names[param_id]);

        //  // TODO(tonyyang-svail): Not sure we need the following
        //  // If does not compute gradient of that variable inside rnn,
        //  just
        //  // continue
        //  if (local_var_names.find(inside_grad_name) ==
        //  local_var_names.end()) {
        //    continue;
        //  }

        // zero gradient variable in step 0
        if (cur_scope_iter == step_scopes->rbegin()) {
          auto *var = (*cur_scope_iter)->FindVar(inside_grad_name);
          PADDLE_ENFORCE_NOT_NULL(var, "Can not find var %s", inside_grad_name);
          if (var->IsType<LoDTensor>()) {
            auto &inside_tensor = var->Get<framework::LoDTensor>();
            framework::AttributeMap attrs;
            attrs["dtype"] = framework::ToDataType(inside_tensor.type());
            attrs["shape"] = framework::vectorize2int(inside_tensor.dims());
            attrs["value"] = 0.0f;

            auto zero_op = framework::OpRegistry::CreateOp(
                "fill_constant", framework::VariableNameMap{},
                {{"Out", {pg_names[param_id]}}}, attrs);
            zero_op->Run(scope, dev_place);
          }
        }

        auto new_inside_name = cur_scope.Rename(inside_grad_name);
        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {pg_names[param_id], new_inside_name}}},
            {{"Out", {pg_names[param_id]}}}, framework::AttributeMap{});
        sum_op->Run(cur_scope, dev_place);
        cur_scope.Rename(new_inside_name, inside_grad_name);
      }
    }
  }
};

class WhileGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    auto *while_grad = new framework::OpDesc();
    while_grad->SetType("while_grad");
    while_grad->SetInput(kX, Input(kX));
    while_grad->SetInput(kOutputs, Output(kOutputs));
    while_grad->SetInput(kStepScopes, Output(kStepScopes));

    auto *grad_block = this->grad_block_[0];
    auto *fwd_block = grad_block->ParentBlock();

    // Not all of IGs will be generated by inner gradient operators of while op.
    // Ignore IGs that is not generated by the inside block.
    std::unordered_set<std::string> inner_op_outputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &oname : op->OutputArgumentNames()) {
        inner_op_outputs.insert(oname);
      }
    }
    auto igs = InputGrad(kX, /*do not drop empty gradient*/ false);
    for (auto &each_ig : igs) {
      if (inner_op_outputs.find(each_ig) == inner_op_outputs.end()) {
        VLOG(10) << "Ignore " << each_ig;
        each_ig = framework::kEmptyVarName;
      }
    }
    while_grad->SetOutput(framework::GradVarName(kX), igs);

    // OG should be re-calculated by step blocks, since many outputs of while op
    // do not need to calculate gradients.
    std::unordered_set<std::string> block_ins;
    block_ins.reserve(Input(kX).size() + Output(kOutputs).size());
    for (auto &p : Input(kX)) {
      block_ins.insert(p);
    }
    for (auto &o : Output(kOutputs)) {
      block_ins.insert(o);
    }
    std::unordered_set<std::string> extra_inputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &input_name : op->InputArgumentNames()) {
        // If the input of Op has been recorded or is generated by the forward
        // block, do not make it as input again.
        if (block_ins.find(input_name) != block_ins.end() ||
            fwd_block->FindVar(input_name) != nullptr) {
          continue;
        }
        extra_inputs.insert(input_name);
      }
      for (auto &output_name : op->OutputArgumentNames()) {
        block_ins.insert(output_name);
      }
    }

    std::vector<std::string> extra_inputs_list;
    extra_inputs_list.resize(extra_inputs.size());
    std::copy(extra_inputs.begin(), extra_inputs.end(),
              extra_inputs_list.begin());
    while_grad->SetInput(framework::GradVarName(kOutputs), extra_inputs_list);

    while_grad->SetAttrMap(this->Attrs());
    while_grad->SetBlockAttr(kStepBlock, *grad_block);
    // record the original output gradient names, since the gradient name of
    // while operator could be renamed.
    while_grad->SetAttr("original_output_grad", extra_inputs_list);

    return std::unique_ptr<framework::OpDesc>(while_grad);
  }
};

class WhileGradOpVarTypeInference : public framework::VarTypeInference {
 public:
  void operator()(const framework::OpDesc &op_desc,
                  framework::BlockDesc *block) const override {
    auto p_names = op_desc.Input(kX);
    auto pg_names = op_desc.Output(framework::GradVarName(kX));

    for (size_t i = 0; i < p_names.size(); ++i) {
      auto &p_var = detail::Ref(block->FindVarRecursive(p_names[i]));
      auto *g_var = block->FindVarRecursive(pg_names[i]);
      if (g_var != nullptr) {  // Gradient could be @EMPTY@
        VLOG(5) << "Setting " << pg_names[i] << " following " << p_names[i]
                << " type: " << p_var.GetType();
        g_var->SetType(p_var.GetType());
        g_var->SetDataType(p_var.GetDataType());
      }
    }
  }
};

class WhileGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    ctx->HasInputs(kX);
    ctx->HasOutputs(framework::GradVarName(kX));
    ctx->HasInputs(kOutputs);
    ctx->HasInputs(framework::GradVarName(kOutputs));

    auto p_names = ctx->Inputs(kX);
    auto pg_names = ctx->Outputs(kXGRAD);
    auto var_types = ctx->GetInputsVarType(kX);
    std::vector<std::string> names_to_set;
    std::vector<framework::DDim> dims_to_set;
    for (size_t i = 0; i < p_names.size(); ++i) {
      if (pg_names[i] == framework::kEmptyVarName) {
        continue;
      }
      auto dims = ctx->GetInputsElementDim(kX, i);
      if (var_types[i] == framework::proto::VarDesc::LOD_TENSOR) {
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      } else if (var_types[i] == framework::proto::VarDesc::LOD_TENSOR_ARRAY) {
        // not sure how to set the dim of LOD_TENSOR_ARRAY
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      }
    }
    ctx->SetDims(names_to_set, dims_to_set);
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(while, paddle::operators::WhileOp,
                  paddle::operators::WhileOpMaker,
                  paddle::operators::WhileGradOpDescMaker);
REGISTER_OPERATOR(while_grad, paddle::operators::WhileGradOp,
                  paddle::operators::WhileGradOpShapeInference,
                  paddle::operators::WhileGradOpVarTypeInference);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "artifacts",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "artifacts path",
      "<path>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  WhitelistVFS vfs;

  /* start http server */
  fnord::thread::EventLoop ev;
  fnord::thread::ThreadPool tpool;
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  /* sstable servlet */
  sstable::SSTableServlet sstable_servlet("/sstable", &vfs);
  http_router.addRouteByPrefixMatch("/sstable", &sstable_servlet);

  /* file servlet */
  http::VFSFileServlet file_servlet("/file", &vfs);
  http_router.addRouteByPrefixMatch("/file", &file_servlet);

  /* add all files to whitelist vfs */
  auto dir = flags.getString("artifacts");
  FileUtil::ls(dir, [&vfs, &dir] (const String& file) -> bool {
    vfs.registerFile(file, FileUtil::joinPaths(dir, file));
    fnord::logInfo("cm.reportserver", "[VFS] Adding file: $0", file);
    return true;
  });

  /* eventdb */
  auto replica = flags.getString("replica");

  eventdb::TableRepository table_repo;
  table_repo.addTable(
      new eventdb::Table(
          "dawanda_joined_sessions",
          replica,
          dir,
          joinedSessionsSchema()));

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(8, &vfs);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();
  return 0;
}

<commit_msg>analyticsqueryengine...<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/VFS.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-http/VFSFileServlet.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/SSTableServlet.h"
#include "fnord-eventdb/EventDBServlet.h"
#include "fnord-eventdb/TableRepository.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "common.h"
#include "schemas.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "analytics/AnalyticsServlet.h"
#include "analytics/CTRByPageServlet.h"
#include "analytics/CTRStatsServlet.h"
#include "analytics/CTRByPositionQuery.h"
#include "analytics/CTRByPageQuery.h"
#include "analytics/TopSearchQueriesQuery.h"
#include "analytics/DiscoveryKPIQuery.h"
#include "analytics/DiscoveryCategoryStatsQuery.h"
#include "analytics/AnalyticsQueryEngine.h"
#include "analytics/AnalyticsQueryEngine.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "http_port",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8000",
      "Start the public http server on this port",
      "<port>");

  flags.defineFlag(
      "replica",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "replica id",
      "<id>");

  flags.defineFlag(
      "artifacts",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "artifacts path",
      "<path>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  WhitelistVFS vfs;

  /* start http server */
  fnord::thread::EventLoop ev;
  fnord::thread::ThreadPool tpool;
  fnord::http::HTTPRouter http_router;
  fnord::http::HTTPServer http_server(&http_router, &ev);
  http_server.listen(flags.getInt("http_port"));

  /* sstable servlet */
  sstable::SSTableServlet sstable_servlet("/sstable", &vfs);
  http_router.addRouteByPrefixMatch("/sstable", &sstable_servlet);

  /* file servlet */
  http::VFSFileServlet file_servlet("/file", &vfs);
  http_router.addRouteByPrefixMatch("/file", &file_servlet);

  /* add all files to whitelist vfs */
  auto dir = flags.getString("artifacts");
  FileUtil::ls(dir, [&vfs, &dir] (const String& file) -> bool {
    vfs.registerFile(file, FileUtil::joinPaths(dir, file));
    fnord::logInfo("cm.reportserver", "[VFS] Adding file: $0", file);
    return true;
  });

  /* eventdb */
  auto replica = flags.getString("replica");

  eventdb::TableRepository table_repo;
  table_repo.addTable(
      new eventdb::Table(
          "dawanda_joined_sessions",
          replica,
          dir,
          joinedSessionsSchema()));

  eventdb::EventDBServlet eventdb_servlet(&table_repo);

  /* analytics */
  cm::AnalyticsQueryEngine analytics(8, dir);
  cm::AnalyticsServlet analytics_servlet(&analytics);
  http_router.addRouteByPrefixMatch("/analytics", &analytics_servlet, &tpool);
  http_router.addRouteByPrefixMatch("/eventdb", &eventdb_servlet, &tpool);

  analytics.registerQueryFactory("ctr_by_position", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPositionQuery(scan, segments);
  });

  analytics.registerQueryFactory("ctr_by_page", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::CTRByPageQuery(scan, segments);
  });

  analytics.registerQueryFactory("discovery_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryKPIQuery(
        scan,
        segments,
        query.start_time,
        query.end_time);
  });

  analytics.registerQueryFactory("discovery_category0_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category1",
        "queries.category1",
        params);
  });

  analytics.registerQueryFactory("discovery_category1_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category1",
        "queries.category2",
        params);
  });

  analytics.registerQueryFactory("discovery_category2_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category2",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("discovery_category3_kpis", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::DiscoveryCategoryStatsQuery(
        scan,
        segments,
        "queries.category3",
        "queries.category3",
        params);
  });

  analytics.registerQueryFactory("top_search_queries", [] (
      const cm::AnalyticsQuery& query,
      const cm::AnalyticsQuery::SubQueryParams params,
      const Vector<RefPtr<cm::TrafficSegment>>& segments,
      cm::AnalyticsTableScan* scan) {
    return new cm::TopSearchQueriesQuery(scan, segments, params);
  });

  ev.run();
  return 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <iterator>

#include <cstdlib> //malloc, realloc
#include <cstring> //memcpy, memmove
#include <exception> //bad_alloc
#include <type_traits>
#include <utility>

namespace tyti {
template<typename T>
class any_iterator : std::iterator<std::bidirectional_iterator_tag, T>
{
    //functionpointer save structurez
    struct TypeInfos
    {
        void(*const inc_fn)(void*);
        void(*const dec_fn)(void*);
        const bool(*const equal_fn)(const void*,const void*);
        const T*(*const deref_fn)(const void*);
        void(*const dtor_fn)(void*);
        void(*const copy_ctor_fn)(void*,const void*);
        void(*const move_ctor_fn)(void*, const void*);
        const size_t size;
    };

    template<typename IterType>
    TypeInfos* getFunctionInfos()
    {
        static TypeInfos ti =
        {
            &any_iterator::inc<IterType>,
            &any_iterator::dec<IterType>,
            &any_iterator::equal<IterType>,
            &any_iterator::deref<IterType>,
            //(std::is_trivially_destructible<IterType>::value) ?
            //static_cast<void(*)(void*)>(nullptr) :
            &any_iterator::dtor<IterType>,
            //(std::is_trivially_copy_constructible<IterType>::value) ?
            //static_cast<void(*)(void*,const void*)>(nullptr) :
            &any_iterator::copyConstructor<IterType>,
            &any_iterator::moveConstructor<IterType>,
            sizeof(IterType)
        };
        return &ti;
    }

    // used to destruct nothing e.g. used when the l-value should not destruct anything
    struct NoDestruct
    {
        NoDestruct(const NoDestruct&){}
        NoDestruct(NoDestruct&&){}
        NoDestruct operator++() { return *this; }
        NoDestruct operator--() { return *this; }
        bool operator==(const NoDestruct&) { return false; }
        bool operator!=(const NoDestruct&) { return false; }
        ~NoDestruct() {}
        T* operator*() { return nullptr; }
    };

    //access functions
    template<typename Iter>
    static void inc(void* _ptr)
    {
        ++(*reinterpret_cast<Iter*>(_ptr));
    }

    template<typename Iter>
    static void dec(void* _ptr)
    {
        --(*reinterpret_cast<Iter*>(_ptr));
    }

    template<typename Iter>
    static const T* deref(const void* _ptr)
    {
        return &(*(*reinterpret_cast<const Iter*>(_ptr)));
    }

    template<typename Iter>
    static const bool equal(const void* _lhs, const void* _rhs)
    {
        return *reinterpret_cast<const Iter*>(_lhs) == *reinterpret_cast<const Iter*>(_rhs);
    }
    template<typename Iter>
    static void dtor(void* _ptr)
    {
        reinterpret_cast<Iter*>(_ptr)->~Iter();
    }
    template<typename Iter>
    static void copyConstructor(void* _dst, const void* _src)
    {
        new (_dst) Iter(*reinterpret_cast<const Iter*>(_src));
    }
    template<typename Iter>
    static void moveConstructor(void* _dst, const void* _src)
    {
        new (_dst) Iter(std::move(*reinterpret_cast<const Iter*>(_src)));
    }

    // helper functions
    inline void destruct()
    {
        ti_->dtor_fn(ptr_);
    }

    void switch_type(const TypeInfos* _newType)
    {
        destruct();
        if (ti_->size < _newType->size)
        {
            ptr_ = std::realloc(ptr_, _newType->size);
            if (!ptr_)
                throw std::bad_alloc();
        }
        ti_ = _newType;
    }

    inline void copy_and_assign(const void* _src)
    {
        ti_->copy_ctor_fn(ptr_, _src);
    }

    inline void move_iter(const void* _src)
    {
        ti_->move_ctor_fn(ptr_, _src);
    }

    // member variables
    void* ptr_;
    const TypeInfos* ti_;

    /// Interface
public:
    template <typename IterType, class = typename std::enable_if<!std::is_rvalue_reference<IterType>::value>::type>
    explicit any_iterator(const IterType& _iter)
        : ptr_(std::malloc(sizeof(IterType))), ti_(getFunctionInfos<IterType>())
    {
        if (!ptr_)
            throw std::bad_alloc();
        copy_and_assign(&_iter);
    }

    template<typename IterType, class = typename std::enable_if<std::is_rvalue_reference<IterType>::value>::type>
        explicit any_iterator(IterType&& _iter)
        : ptr_(std::malloc(_iter.ti_->size)), ti_(std::move(_iter.ti_))
    {
        if (!ptr_)
            throw std::bad_alloc();
        move_iter(_iter.ptr_);
    }

    any_iterator(const any_iterator& _iter)
        : ptr_(std::malloc(_iter.ti_->size)), ti_(_iter.ti_)
    {
        if (!ptr_)
            throw std::bad_alloc();
        copy_and_assign(_iter.ptr_);
    }

    any_iterator(any_iterator&& _iter)
        :ptr_(_iter.ptr_), ti_(_iter.ti_)
    {
        _iter.ti_ = getFunctionInfos<NoDestruct>();
    }

    template <typename IterType, class = typename std::enable_if<!std::is_rvalue_reference<IterType>::value>::type >
    const any_iterator& operator=(const IterType& _iter)
    {
        switch_type(getFunctionInfos<IterType>());
        copy_and_assign(&_iter);
        return *this;
    }

    template <typename IterType, class = typename std::enable_if<std::is_rvalue_reference<IterType>::value>::type>
        const any_iterator& operator=(IterType&& _iter)
    {
        switch_type(getFunctionInfos<IterType>());
        move_iter(&_iter);
        return *this;
    }

    const any_iterator& operator=(const any_iterator& _iter)
    {
        switch_type(_iter.ti_);
        copy_and_assign(_iter.ptr_);
        return *this;
    }

    const any_iterator& operator=(any_iterator&& _iter)
    {
        std::swap(ti_, _iter.ti_);
        std::swap(ptr_, _iter.ptr_);
        //old ptr gets destructed via _iter
        return *this;
    }

    ~any_iterator()
    {
        destruct();
        std::free(ptr_);
    }

    bool operator==(const any_iterator& _rhs) const
    {
        if (ti_ != _rhs.ti_) //different types
            return false;
        return ti_->equal_fn(ptr_, _rhs.ptr_);
    }

    template <typename IterType>
    bool operator==(const IterType& _rhs) const {
        return ti_->equal_fn(ptr_, reinterpret_cast<const void*>(&_rhs));
    }

    template <typename IterType>
    bool operator!=(const IterType& _rhs) const{
        return !operator==(_rhs);
    }

    /// Standard pre-increment operator
    any_iterator& operator++() {
        ti_->inc_fn(ptr_);
        return *this;
    }

    /// Standard post-increment operator
    any_iterator operator++(int) {
        any_iterator cpy(*this);
        ti_->inc_fn(ptr_);
        return cpy;
    }

    /// Standard pre-decrement operator
    any_iterator& operator--() {
        ti_->dec_fn(ptr_);
        return *this;
    }

    /// Standard post-decrement operator
    any_iterator operator--(int) {
        any_iterator cpy(*this);
        ti_->dec_fn(ptr_);
        return cpy;
    }

    const T& operator*() const {
        return *(ti_->deref_fn(ptr_));
    }

    /// Standard pointer operator.
    const T* operator->() const {
        return ti_->deref_fn(ptr_);
    }
};

// C++17 todo:
//if msvc >= 2017 or gcc with c++17 support
//#include <any>
//using AnyIterator = AnyIteratorT<std::any>;
//endif

} // end namespace tyti

template<typename IterT, typename T>
bool operator==(const IterT&& _lhs, const tyti::any_iterator<T>&& _rhs)
{
    return _rhs.operator==(std::forward<IterT>(_lhs));
}

template<typename IterT, typename T>
bool operator!=(IterT&& _lhs, tyti::any_iterator<T>&& _rhs)
{
    return _rhs.operator!=(std::forward<IterT>(_lhs));
}<commit_msg>fixed never used deref operator adding hitns, that the NoDestruct is never used<commit_after>#pragma once

#include <iterator>

#include <cstdlib> //malloc, realloc
#include <cstring> //memcpy, memmove
#include <exception> //bad_alloc
#include <type_traits>
#include <utility>

#include <cassert>

namespace tyti {
template<typename T>
class any_iterator : std::iterator<std::bidirectional_iterator_tag, T>
{
    //functionpointer save structurez
    struct TypeInfos
    {
        void(*const inc_fn)(void*);
        void(*const dec_fn)(void*);
        const bool(*const equal_fn)(const void*,const void*);
        const T*(*const deref_fn)(const void*);
        void(*const dtor_fn)(void*);
        void(*const copy_ctor_fn)(void*,const void*);
        void(*const move_ctor_fn)(void*, const void*);
        const size_t size;
    };

    template<typename IterType>
    TypeInfos* getFunctionInfos()
    {
        static TypeInfos ti =
        {
            &any_iterator::inc<IterType>,
            &any_iterator::dec<IterType>,
            &any_iterator::equal<IterType>,
            &any_iterator::deref<IterType>,
            //(std::is_trivially_destructible<IterType>::value) ?
            //static_cast<void(*)(void*)>(nullptr) :
            &any_iterator::dtor<IterType>,
            //(std::is_trivially_copy_constructible<IterType>::value) ?
            //static_cast<void(*)(void*,const void*)>(nullptr) :
            &any_iterator::copyConstructor<IterType>,
            &any_iterator::moveConstructor<IterType>,
            sizeof(IterType)
        };
        return &ti;
    }

    // used to destruct nothing e.g. used when the l-value should not destruct anything
    // Do not provide it to the user.
    struct NoDestruct
    {
        ~NoDestruct() {} //only destructor is used

        NoDestruct(const NoDestruct&) { assert(false); }
        NoDestruct(NoDestruct&&) { assert(false); }
        NoDestruct operator++() { assert(false); return *this; }
        NoDestruct operator--() { assert(false); return *this; }
        bool operator==(const NoDestruct&) const { assert(false); return false; }
        bool operator!=(const NoDestruct&) const { assert(false); return false; }
        //this function will never be called. just for compile correctness
        const T& operator*() const { assert(false); return *(reinterpret_cast<T*>(this)); }
    };

    //access functions
    template<typename Iter>
    static void inc(void* _ptr)
    {
        ++(*reinterpret_cast<Iter*>(_ptr));
    }

    template<typename Iter>
    static void dec(void* _ptr)
    {
        --(*reinterpret_cast<Iter*>(_ptr));
    }

    template<typename Iter>
    static const T* deref(const void* _ptr)
    {
        return &(*(*reinterpret_cast<const Iter*>(_ptr)));
    }

    template<typename Iter>
    static const bool equal(const void* _lhs, const void* _rhs)
    {
        return *reinterpret_cast<const Iter*>(_lhs) == *reinterpret_cast<const Iter*>(_rhs);
    }
    template<typename Iter>
    static void dtor(void* _ptr)
    {
        reinterpret_cast<Iter*>(_ptr)->~Iter();
    }
    template<typename Iter>
    static void copyConstructor(void* _dst, const void* _src)
    {
        new (_dst) Iter(*reinterpret_cast<const Iter*>(_src));
    }
    template<typename Iter>
    static void moveConstructor(void* _dst, const void* _src)
    {
        new (_dst) Iter(std::move(*reinterpret_cast<const Iter*>(_src)));
    }

    // helper functions
    inline void destruct()
    {
        ti_->dtor_fn(ptr_);
    }

    void switch_type(const TypeInfos* _newType)
    {
        destruct();
        if (ti_->size < _newType->size)
        {
            ptr_ = std::realloc(ptr_, _newType->size);
            if (!ptr_)
                throw std::bad_alloc();
        }
        ti_ = _newType;
    }

    inline void copy_and_assign(const void* _src)
    {
        ti_->copy_ctor_fn(ptr_, _src);
    }

    inline void move_iter(const void* _src)
    {
        ti_->move_ctor_fn(ptr_, _src);
    }

    // member variables
    void* ptr_;
    const TypeInfos* ti_;

    /// Interface
public:
    template <typename IterType, class = typename std::enable_if<!std::is_rvalue_reference<IterType>::value>::type>
    explicit any_iterator(const IterType& _iter)
        : ptr_(std::malloc(sizeof(IterType))), ti_(getFunctionInfos<IterType>())
    {
        if (!ptr_)
            throw std::bad_alloc();
        copy_and_assign(&_iter);
    }

    template<typename IterType, class = typename std::enable_if<std::is_rvalue_reference<IterType>::value>::type>
        explicit any_iterator(IterType&& _iter)
        : ptr_(std::malloc(_iter.ti_->size)), ti_(std::move(_iter.ti_))
    {
        if (!ptr_)
            throw std::bad_alloc();
        move_iter(_iter.ptr_);
    }

    any_iterator(const any_iterator& _iter)
        : ptr_(std::malloc(_iter.ti_->size)), ti_(_iter.ti_)
    {
        if (!ptr_)
            throw std::bad_alloc();
        copy_and_assign(_iter.ptr_);
    }

    any_iterator(any_iterator&& _iter)
        :ptr_(_iter.ptr_), ti_(_iter.ti_)
    {
        _iter.ti_ = getFunctionInfos<NoDestruct>();
    }

    template <typename IterType, class = typename std::enable_if<!std::is_rvalue_reference<IterType>::value>::type >
    const any_iterator& operator=(const IterType& _iter)
    {
        switch_type(getFunctionInfos<IterType>());
        copy_and_assign(&_iter);
        return *this;
    }

    template <typename IterType, class = typename std::enable_if<std::is_rvalue_reference<IterType>::value>::type>
        const any_iterator& operator=(IterType&& _iter)
    {
        switch_type(getFunctionInfos<IterType>());
        move_iter(&_iter);
        return *this;
    }

    const any_iterator& operator=(const any_iterator& _iter)
    {
        switch_type(_iter.ti_);
        copy_and_assign(_iter.ptr_);
        return *this;
    }

    const any_iterator& operator=(any_iterator&& _iter)
    {
        std::swap(ti_, _iter.ti_);
        std::swap(ptr_, _iter.ptr_);
        //old ptr gets destructed via _iter
        return *this;
    }

    ~any_iterator()
    {
        destruct();
        std::free(ptr_);
    }

    bool operator==(const any_iterator& _rhs) const
    {
        if (ti_ != _rhs.ti_) //different types
            return false;
        return ti_->equal_fn(ptr_, _rhs.ptr_);
    }

    template <typename IterType>
    bool operator==(const IterType& _rhs) const {
        return ti_->equal_fn(ptr_, reinterpret_cast<const void*>(&_rhs));
    }

    template <typename IterType>
    bool operator!=(const IterType& _rhs) const{
        return !operator==(_rhs);
    }

    /// Standard pre-increment operator
    any_iterator& operator++() {
        ti_->inc_fn(ptr_);
        return *this;
    }

    /// Standard post-increment operator
    any_iterator operator++(int) {
        any_iterator cpy(*this);
        ti_->inc_fn(ptr_);
        return cpy;
    }

    /// Standard pre-decrement operator
    any_iterator& operator--() {
        ti_->dec_fn(ptr_);
        return *this;
    }

    /// Standard post-decrement operator
    any_iterator operator--(int) {
        any_iterator cpy(*this);
        ti_->dec_fn(ptr_);
        return cpy;
    }

    const T& operator*() const {
        return *(ti_->deref_fn(ptr_));
    }

    /// Standard pointer operator.
    const T* operator->() const {
        return ti_->deref_fn(ptr_);
    }
};

// C++17 todo:
//if msvc >= 2017 or gcc with c++17 support
//#include <any>
//using AnyIterator = AnyIteratorT<std::any>;
//endif

} // end namespace tyti

template<typename IterT, typename T>
bool operator==(const IterT&& _lhs, const tyti::any_iterator<T>&& _rhs)
{
    return _rhs.operator==(std::forward<IterT>(_lhs));
}

template<typename IterT, typename T>
bool operator!=(IterT&& _lhs, tyti::any_iterator<T>&& _rhs)
{
    return _rhs.operator!=(std::forward<IterT>(_lhs));
}<|endoftext|>