<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2009-2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2009-2010 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/ConnectionCapabilities>

#include "TelepathyQt4/future-internal.h"

#include <TelepathyQt4/Constants>
#include <TelepathyQt4/Types>

namespace Tp
{

/**
 * \class ConnectionCapabilities
 * \ingroup clientconn
 * \headerfile TelepathyQt4/connection-capabilities.h <TelepathyQt4/ConnectionCapabilities>
 *
 * \brief The ConnectionCapabilities class provides an object representing the
 * capabilities of a Connection.
 */

/**
 * Construct a new ConnectionCapabilities object.
 */
ConnectionCapabilities::ConnectionCapabilities()
    : CapabilitiesBase(false)
{
}

/**
 * Construct a new ConnectionCapabilities object using the give \a rccs.
 *
 * \param rccs RequestableChannelClassList representing the capabilities of a
 *             Connection.
 */
ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassList &rccs)
    : CapabilitiesBase(rccs, false)
{
}

/**
 * Construct a new ConnectionCapabilities object using the give \a rccSpecs.
 *
 * \param rccSpecs RequestableChannelClassSpecList representing the capabilities of a
 *                 Connection.
 */
ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassSpecList &rccSpecs)
    : CapabilitiesBase(rccSpecs, false)
{
}

/**
 * Class destructor.
 */
ConnectionCapabilities::~ConnectionCapabilities()
{
}

/**
 * Return true if named text chatrooms can be joined by providing a
 * chatroom identifier.
 *
 * If the protocol is such that chatrooms can be joined, but only via
 * a more elaborate D-Bus API than normal (because more information is needed),
 * then this method will return false.
 *
 * \return \c true if Account::ensureTextChatroom() can be expected to work.
 */
bool ConnectionCapabilities::textChatrooms() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (!rccSpec.fixedProperties().size() == 2) {
            continue;
        }

        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference media calls is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceStreamedMediaCalls() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference media calls is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference media call
 * channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference media
 * calls with fewer than two (even zero) already established media calls.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceStreamedMediaCallsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels"))) &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chats is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChats() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_TEXT &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chats is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference text chat
 * channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference text
 * chats with fewer than two (even zero) already established text chats.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_TEXT &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels"))) &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chat rooms is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatrooms() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chat rooms is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference text chat
 * room channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference text
 * chat rooms with fewer than two (even zero) already established text chat rooms.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatroomsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialChannels"))) &&
            (rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(QLatin1String(TPQT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE_ASCII ".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearch()
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel specifying a server is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearchWithSpecificServer() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH &&
            rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH_ASCII ".Server"))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel specifying a limit is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearchWithLimit() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TPQT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH &&
            rccSpec.allowsProperty(QLatin1String(TPQT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH_ASCII ".Limit"))) {
            return true;
        }
    }
    return false;
}

/**
 * \deprecated Use textChatrooms() instead.
 */
bool ConnectionCapabilities::supportsTextChatrooms() const
{
    return textChatrooms();
}

/**
 * \deprecated Use conferenceStreamedMediaCalls() or conferenceStreamedMediaCallsWithInvitees()
 * instead.
 */
bool ConnectionCapabilities::supportsConferenceMediaCalls(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceStreamedMediaCallsWithInvitees();
    }
    return conferenceStreamedMediaCalls();
}

/**
 * \deprecated Use conferenceTextChats() instead.
 */
bool ConnectionCapabilities::supportsConferenceTextChats(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceTextChatsWithInvitees();
    }
    return conferenceTextChats();
}

/**
 * \deprecated Use conferenceTextChatrooms() instead.
 */
bool ConnectionCapabilities::supportsConferenceTextChatrooms(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceTextChatroomsWithInvitees();
    }
    return conferenceTextChatrooms();
}

/**
 * \deprecated Use contactSearch() instead.
 */
bool ConnectionCapabilities::supportsContactSearch()
{
    return contactSearch();
}

/**
 * \deprecated Use contactSearchWithSpecificServer() instead.
 */
bool ConnectionCapabilities::supportsContactSearchWithSpecificServer() const
{
    return contactSearchWithSpecificServer();
}

/**
 * \deprecated Use contactSearchWithLimit() instead.
 */
bool ConnectionCapabilities::supportsContactSearchWithLimit() const
{
    return contactSearchWithLimit();
}

} // Tp
<commit_msg>ConnectionCapabilities: Use new macros.<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2009-2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2009-2010 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/ConnectionCapabilities>

#include "TelepathyQt4/future-internal.h"

#include <TelepathyQt4/Constants>
#include <TelepathyQt4/Types>

namespace Tp
{

/**
 * \class ConnectionCapabilities
 * \ingroup clientconn
 * \headerfile TelepathyQt4/connection-capabilities.h <TelepathyQt4/ConnectionCapabilities>
 *
 * \brief The ConnectionCapabilities class provides an object representing the
 * capabilities of a Connection.
 */

/**
 * Construct a new ConnectionCapabilities object.
 */
ConnectionCapabilities::ConnectionCapabilities()
    : CapabilitiesBase(false)
{
}

/**
 * Construct a new ConnectionCapabilities object using the give \a rccs.
 *
 * \param rccs RequestableChannelClassList representing the capabilities of a
 *             Connection.
 */
ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassList &rccs)
    : CapabilitiesBase(rccs, false)
{
}

/**
 * Construct a new ConnectionCapabilities object using the give \a rccSpecs.
 *
 * \param rccSpecs RequestableChannelClassSpecList representing the capabilities of a
 *                 Connection.
 */
ConnectionCapabilities::ConnectionCapabilities(const RequestableChannelClassSpecList &rccSpecs)
    : CapabilitiesBase(rccSpecs, false)
{
}

/**
 * Class destructor.
 */
ConnectionCapabilities::~ConnectionCapabilities()
{
}

/**
 * Return true if named text chatrooms can be joined by providing a
 * chatroom identifier.
 *
 * If the protocol is such that chatrooms can be joined, but only via
 * a more elaborate D-Bus API than normal (because more information is needed),
 * then this method will return false.
 *
 * \return \c true if Account::ensureTextChatroom() can be expected to work.
 */
bool ConnectionCapabilities::textChatrooms() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (!rccSpec.fixedProperties().size() == 2) {
            continue;
        }

        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference media calls is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceStreamedMediaCalls() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference media calls is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference media call
 * channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference media
 * calls with fewer than two (even zero) already established media calls.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceStreamedMediaCallsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels"))) &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chats is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChats() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_TEXT &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chats is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference text chat
 * channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference text
 * chats with fewer than two (even zero) already established text chats.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_TEXT &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels"))) &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chat rooms is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatrooms() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating conference text chat rooms is supported.
 *
 * This method will also check whether inviting new contacts when creating a conference text chat
 * room channel by providing additional members to initial invitees (as opposed to merging several
 * channels into one new conference channel) is supported.
 *
 * If providing additional members is supported, it is also possible to request conference text
 * chat rooms with fewer than two (even zero) already established text chat rooms.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::conferenceTextChatroomsWithInvitees() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_TEXT &&
            rccSpec.targetHandleType() == HandleTypeRoom &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialChannels"))) &&
            (rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")) ||
             rccSpec.allowsProperty(TP_QT4_FUTURE_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeHandles")))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearch()
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel specifying a server is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearchWithSpecificServer() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH &&
            rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Server"))) {
            return true;
        }
    }
    return false;
}

/**
 * Return whether creating a ContactSearch channel specifying a limit is supported.
 *
 * \return \c true if supported, \c false otherwise.
 */
bool ConnectionCapabilities::contactSearchWithLimit() const
{
    RequestableChannelClassSpecList rccSpecs = allClassSpecs();
    foreach (const RequestableChannelClassSpec &rccSpec, rccSpecs) {
        if (rccSpec.channelType() == TP_QT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH &&
            rccSpec.allowsProperty(TP_QT4_IFACE_CHANNEL_TYPE_CONTACT_SEARCH + QLatin1String(".Limit"))) {
            return true;
        }
    }
    return false;
}

/**
 * \deprecated Use textChatrooms() instead.
 */
bool ConnectionCapabilities::supportsTextChatrooms() const
{
    return textChatrooms();
}

/**
 * \deprecated Use conferenceStreamedMediaCalls() or conferenceStreamedMediaCallsWithInvitees()
 * instead.
 */
bool ConnectionCapabilities::supportsConferenceMediaCalls(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceStreamedMediaCallsWithInvitees();
    }
    return conferenceStreamedMediaCalls();
}

/**
 * \deprecated Use conferenceTextChats() instead.
 */
bool ConnectionCapabilities::supportsConferenceTextChats(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceTextChatsWithInvitees();
    }
    return conferenceTextChats();
}

/**
 * \deprecated Use conferenceTextChatrooms() instead.
 */
bool ConnectionCapabilities::supportsConferenceTextChatrooms(bool withInitialInvitees) const
{
    if (withInitialInvitees) {
        return conferenceTextChatroomsWithInvitees();
    }
    return conferenceTextChatrooms();
}

/**
 * \deprecated Use contactSearch() instead.
 */
bool ConnectionCapabilities::supportsContactSearch()
{
    return contactSearch();
}

/**
 * \deprecated Use contactSearchWithSpecificServer() instead.
 */
bool ConnectionCapabilities::supportsContactSearchWithSpecificServer() const
{
    return contactSearchWithSpecificServer();
}

/**
 * \deprecated Use contactSearchWithLimit() instead.
 */
bool ConnectionCapabilities::supportsContactSearchWithLimit() const
{
    return contactSearchWithLimit();
}

} // Tp
<|endoftext|>


<commit_before>//===- JITTest.cpp - Unit tests for the JIT -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/BasicBlock.h"
#include "llvm/Constant.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/Function.h"
#include "llvm/GlobalValue.h"
#include "llvm/GlobalVariable.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/TypeBuilder.h"
#include "llvm/Target/TargetSelect.h"
#include "llvm/Type.h"

using namespace llvm;

namespace {

Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
  std::vector<const Type*> params;
  const FunctionType *FTy = FunctionType::get(G->getType()->getElementType(),
                                              params, false);
  Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
  BasicBlock *Entry = BasicBlock::Create(M->getContext(), "entry", F);
  IRBuilder<> builder(Entry);
  Value *Load = builder.CreateLoad(G);
  const Type *GTy = G->getType()->getElementType();
  Value *Add = builder.CreateAdd(Load, ConstantInt::get(GTy, 1LL));
  builder.CreateStore(Add, G);
  builder.CreateRet(Add);
  return F;
}

class JITTest : public testing::Test {
 protected:
  virtual void SetUp() {
    M = new Module("<main>", Context);
    std::string Error;
    TheJIT.reset(EngineBuilder(M).setEngineKind(EngineKind::JIT)
                 .setErrorStr(&Error).create());
    ASSERT_TRUE(TheJIT.get() != NULL) << Error;
  }

  LLVMContext Context;
  Module *M;  // Owned by ExecutionEngine.
  OwningPtr<ExecutionEngine> TheJIT;
};

// Regression test for a bug.  The JIT used to allocate globals inside the same
// memory block used for the function, and when the function code was freed,
// the global was left in the same place.  This test allocates a function
// that uses and global, deallocates it, and then makes sure that the global
// stays alive after that.
TEST(JIT, GlobalInFunction) {
  LLVMContext context;
  Module *M = new Module("<main>", context);
  ExistingModuleProvider *MP = new ExistingModuleProvider(M);

  JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
  // Tell the memory manager to poison freed memory so that accessing freed
  // memory is more easily tested.
  MemMgr->setPoisonMemory(true);
  std::string Error;
  OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
                                 .setEngineKind(EngineKind::JIT)
                                 .setErrorStr(&Error)
                                 .setJITMemoryManager(MemMgr)
                                 // The next line enables the fix:
                                 .setAllocateGVsWithCode(false)
                                 .create());
  ASSERT_EQ(Error, "");

  // Create a global variable.
  const Type *GTy = Type::getInt32Ty(context);
  GlobalVariable *G = new GlobalVariable(
      *M,
      GTy,
      false,  // Not constant.
      GlobalValue::InternalLinkage,
      Constant::getNullValue(GTy),
      "myglobal");

  // Make a function that points to a global.
  Function *F1 = makeReturnGlobal("F1", G, M);

  // Get the pointer to the native code to force it to JIT the function and
  // allocate space for the global.
  void (*F1Ptr)() =
      reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F1));

  // Since F1 was codegen'd, a pointer to G should be available.
  int32_t *GPtr = (int32_t*)JIT->getPointerToGlobalIfAvailable(G);
  ASSERT_NE((int32_t*)NULL, GPtr);
  EXPECT_EQ(0, *GPtr);

  // F1() should increment G.
  F1Ptr();
  EXPECT_EQ(1, *GPtr);

  // Make a second function identical to the first, referring to the same
  // global.
  Function *F2 = makeReturnGlobal("F2", G, M);
  void (*F2Ptr)() =
      reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F2));

  // F2() should increment G.
  F2Ptr();
  EXPECT_EQ(2, *GPtr);

  // Deallocate F1.
  JIT->freeMachineCodeForFunction(F1);

  // F2() should *still* increment G.
  F2Ptr();
  EXPECT_EQ(3, *GPtr);
}

int PlusOne(int arg) {
  return arg + 1;
}

TEST_F(JITTest, FarCallToKnownFunction) {
  // x86-64 can only make direct calls to functions within 32 bits of
  // the current PC.  To call anything farther away, we have to load
  // the address into a register and call through the register.  The
  // current JIT does this by allocating a stub for any far call.
  // There was a bug in which the JIT tried to emit a direct call when
  // the target was already in the JIT's global mappings and lazy
  // compilation was disabled.

  Function *KnownFunction = Function::Create(
      TypeBuilder<int(int), false>::get(Context),
      GlobalValue::ExternalLinkage, "known", M);
  TheJIT->addGlobalMapping(KnownFunction, (void*)(intptr_t)PlusOne);

  // int test() { return known(7); }
  Function *TestFunction = Function::Create(
      TypeBuilder<int(), false>::get(Context),
      GlobalValue::ExternalLinkage, "test", M);
  BasicBlock *Entry = BasicBlock::Create(Context, "entry", TestFunction);
  IRBuilder<> Builder(Entry);
  Value *result = Builder.CreateCall(
      KnownFunction,
      ConstantInt::get(TypeBuilder<int, false>::get(Context), 7));
  Builder.CreateRet(result);

  TheJIT->EnableDlsymStubs(false);
  TheJIT->DisableLazyCompilation();
  int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
      (intptr_t)TheJIT->getPointerToFunction(TestFunction));
  // This used to crash in trying to call PlusOne().
  EXPECT_EQ(8, TestFunctionPtr());
}

#if !defined(__arm__) && !defined(__powerpc__)
// Test a function C which calls A and B which call each other.
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
  TheJIT->DisableLazyCompilation();

  const FunctionType *Func1Ty =
      cast<FunctionType>(TypeBuilder<void(void), false>::get(Context));
  std::vector<const Type*> arg_types;
  arg_types.push_back(Type::getInt1Ty(Context));
  const FunctionType *FuncTy = FunctionType::get(
      Type::getVoidTy(Context), arg_types, false);
  Function *Func1 = Function::Create(Func1Ty, Function::ExternalLinkage,
                                     "func1", M);
  Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func2", M);
  Function *Func3 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func3", M);
  BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
  BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);
  BasicBlock *True2 = BasicBlock::Create(Context, "cond_true", Func2);
  BasicBlock *False2 = BasicBlock::Create(Context, "cond_false", Func2);
  BasicBlock *Block3 = BasicBlock::Create(Context, "block3", Func3);
  BasicBlock *True3 = BasicBlock::Create(Context, "cond_true", Func3);
  BasicBlock *False3 = BasicBlock::Create(Context, "cond_false", Func3);

  // Make Func1 call Func2(0) and Func3(0).
  IRBuilder<> Builder(Block1);
  Builder.CreateCall(Func2, ConstantInt::getTrue(Context));
  Builder.CreateCall(Func3, ConstantInt::getTrue(Context));
  Builder.CreateRetVoid();

  // void Func2(bool b) { if (b) { Func3(false); return; } return; }
  Builder.SetInsertPoint(Block2);
  Builder.CreateCondBr(Func2->arg_begin(), True2, False2);
  Builder.SetInsertPoint(True2);
  Builder.CreateCall(Func3, ConstantInt::getFalse(Context));
  Builder.CreateRetVoid();
  Builder.SetInsertPoint(False2);
  Builder.CreateRetVoid();

  // void Func3(bool b) { if (b) { Func2(false); return; } return; }
  Builder.SetInsertPoint(Block3);
  Builder.CreateCondBr(Func3->arg_begin(), True3, False3);
  Builder.SetInsertPoint(True3);
  Builder.CreateCall(Func2, ConstantInt::getFalse(Context));
  Builder.CreateRetVoid();
  Builder.SetInsertPoint(False3);
  Builder.CreateRetVoid();

  // Compile the function to native code
  void (*F1Ptr)() =
     reinterpret_cast<void(*)()>((intptr_t)TheJIT->getPointerToFunction(Func1));

  F1Ptr();
}

// Regression test for PR5162.  This used to trigger an AssertingVH inside the
// JIT's Function to stub mapping.
TEST_F(JITTest, NonLazyLeaksNoStubs) {
  TheJIT->DisableLazyCompilation();

  // Create two functions with a single basic block each.
  const FunctionType *FuncTy =
      cast<FunctionType>(TypeBuilder<int(), false>::get(Context));
  Function *Func1 = Function::Create(FuncTy, Function::ExternalLinkage,
                                     "func1", M);
  Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func2", M);
  BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
  BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);

  // The first function calls the second and returns the result
  IRBuilder<> Builder(Block1);
  Value *Result = Builder.CreateCall(Func2);
  Builder.CreateRet(Result);

  // The second function just returns a constant
  Builder.SetInsertPoint(Block2);
  Builder.CreateRet(ConstantInt::get(TypeBuilder<int, false>::get(Context),42));

  // Compile the function to native code
  (void)TheJIT->getPointerToFunction(Func1);

  // Free the JIT state for the functions
  TheJIT->freeMachineCodeForFunction(Func1);
  TheJIT->freeMachineCodeForFunction(Func2);

  // Delete the first function (and show that is has no users)
  EXPECT_EQ(Func1->getNumUses(), 0u);
  Func1->eraseFromParent();

  // Delete the second function (and show that it has no users - it had one,
  // func1 but that's gone now)
  EXPECT_EQ(Func2->getNumUses(), 0u);
  Func2->eraseFromParent();
}
#endif

// This code is copied from JITEventListenerTest, but it only runs once for all
// the tests in this directory.  Everything seems fine, but that's strange
// behavior.
class JITEnvironment : public testing::Environment {
  virtual void SetUp() {
    // Required to create a JIT.
    InitializeNativeTarget();
  }
};
testing::Environment* const jit_env =
  testing::AddGlobalTestEnvironment(new JITEnvironment);

}
<commit_msg>PowerPC ifdef'ing considered more complicated than one might like.<commit_after>//===- JITTest.cpp - Unit tests for the JIT -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/BasicBlock.h"
#include "llvm/Constant.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/Function.h"
#include "llvm/GlobalValue.h"
#include "llvm/GlobalVariable.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/TypeBuilder.h"
#include "llvm/Target/TargetSelect.h"
#include "llvm/Type.h"

using namespace llvm;

namespace {

Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
  std::vector<const Type*> params;
  const FunctionType *FTy = FunctionType::get(G->getType()->getElementType(),
                                              params, false);
  Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
  BasicBlock *Entry = BasicBlock::Create(M->getContext(), "entry", F);
  IRBuilder<> builder(Entry);
  Value *Load = builder.CreateLoad(G);
  const Type *GTy = G->getType()->getElementType();
  Value *Add = builder.CreateAdd(Load, ConstantInt::get(GTy, 1LL));
  builder.CreateStore(Add, G);
  builder.CreateRet(Add);
  return F;
}

class JITTest : public testing::Test {
 protected:
  virtual void SetUp() {
    M = new Module("<main>", Context);
    std::string Error;
    TheJIT.reset(EngineBuilder(M).setEngineKind(EngineKind::JIT)
                 .setErrorStr(&Error).create());
    ASSERT_TRUE(TheJIT.get() != NULL) << Error;
  }

  LLVMContext Context;
  Module *M;  // Owned by ExecutionEngine.
  OwningPtr<ExecutionEngine> TheJIT;
};

// Regression test for a bug.  The JIT used to allocate globals inside the same
// memory block used for the function, and when the function code was freed,
// the global was left in the same place.  This test allocates a function
// that uses and global, deallocates it, and then makes sure that the global
// stays alive after that.
TEST(JIT, GlobalInFunction) {
  LLVMContext context;
  Module *M = new Module("<main>", context);
  ExistingModuleProvider *MP = new ExistingModuleProvider(M);

  JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
  // Tell the memory manager to poison freed memory so that accessing freed
  // memory is more easily tested.
  MemMgr->setPoisonMemory(true);
  std::string Error;
  OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
                                 .setEngineKind(EngineKind::JIT)
                                 .setErrorStr(&Error)
                                 .setJITMemoryManager(MemMgr)
                                 // The next line enables the fix:
                                 .setAllocateGVsWithCode(false)
                                 .create());
  ASSERT_EQ(Error, "");

  // Create a global variable.
  const Type *GTy = Type::getInt32Ty(context);
  GlobalVariable *G = new GlobalVariable(
      *M,
      GTy,
      false,  // Not constant.
      GlobalValue::InternalLinkage,
      Constant::getNullValue(GTy),
      "myglobal");

  // Make a function that points to a global.
  Function *F1 = makeReturnGlobal("F1", G, M);

  // Get the pointer to the native code to force it to JIT the function and
  // allocate space for the global.
  void (*F1Ptr)() =
      reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F1));

  // Since F1 was codegen'd, a pointer to G should be available.
  int32_t *GPtr = (int32_t*)JIT->getPointerToGlobalIfAvailable(G);
  ASSERT_NE((int32_t*)NULL, GPtr);
  EXPECT_EQ(0, *GPtr);

  // F1() should increment G.
  F1Ptr();
  EXPECT_EQ(1, *GPtr);

  // Make a second function identical to the first, referring to the same
  // global.
  Function *F2 = makeReturnGlobal("F2", G, M);
  void (*F2Ptr)() =
      reinterpret_cast<void(*)()>((intptr_t)JIT->getPointerToFunction(F2));

  // F2() should increment G.
  F2Ptr();
  EXPECT_EQ(2, *GPtr);

  // Deallocate F1.
  JIT->freeMachineCodeForFunction(F1);

  // F2() should *still* increment G.
  F2Ptr();
  EXPECT_EQ(3, *GPtr);
}

int PlusOne(int arg) {
  return arg + 1;
}

TEST_F(JITTest, FarCallToKnownFunction) {
  // x86-64 can only make direct calls to functions within 32 bits of
  // the current PC.  To call anything farther away, we have to load
  // the address into a register and call through the register.  The
  // current JIT does this by allocating a stub for any far call.
  // There was a bug in which the JIT tried to emit a direct call when
  // the target was already in the JIT's global mappings and lazy
  // compilation was disabled.

  Function *KnownFunction = Function::Create(
      TypeBuilder<int(int), false>::get(Context),
      GlobalValue::ExternalLinkage, "known", M);
  TheJIT->addGlobalMapping(KnownFunction, (void*)(intptr_t)PlusOne);

  // int test() { return known(7); }
  Function *TestFunction = Function::Create(
      TypeBuilder<int(), false>::get(Context),
      GlobalValue::ExternalLinkage, "test", M);
  BasicBlock *Entry = BasicBlock::Create(Context, "entry", TestFunction);
  IRBuilder<> Builder(Entry);
  Value *result = Builder.CreateCall(
      KnownFunction,
      ConstantInt::get(TypeBuilder<int, false>::get(Context), 7));
  Builder.CreateRet(result);

  TheJIT->EnableDlsymStubs(false);
  TheJIT->DisableLazyCompilation();
  int (*TestFunctionPtr)() = reinterpret_cast<int(*)()>(
      (intptr_t)TheJIT->getPointerToFunction(TestFunction));
  // This used to crash in trying to call PlusOne().
  EXPECT_EQ(8, TestFunctionPtr());
}

#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
// Test a function C which calls A and B which call each other.
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
  TheJIT->DisableLazyCompilation();

  const FunctionType *Func1Ty =
      cast<FunctionType>(TypeBuilder<void(void), false>::get(Context));
  std::vector<const Type*> arg_types;
  arg_types.push_back(Type::getInt1Ty(Context));
  const FunctionType *FuncTy = FunctionType::get(
      Type::getVoidTy(Context), arg_types, false);
  Function *Func1 = Function::Create(Func1Ty, Function::ExternalLinkage,
                                     "func1", M);
  Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func2", M);
  Function *Func3 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func3", M);
  BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
  BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);
  BasicBlock *True2 = BasicBlock::Create(Context, "cond_true", Func2);
  BasicBlock *False2 = BasicBlock::Create(Context, "cond_false", Func2);
  BasicBlock *Block3 = BasicBlock::Create(Context, "block3", Func3);
  BasicBlock *True3 = BasicBlock::Create(Context, "cond_true", Func3);
  BasicBlock *False3 = BasicBlock::Create(Context, "cond_false", Func3);

  // Make Func1 call Func2(0) and Func3(0).
  IRBuilder<> Builder(Block1);
  Builder.CreateCall(Func2, ConstantInt::getTrue(Context));
  Builder.CreateCall(Func3, ConstantInt::getTrue(Context));
  Builder.CreateRetVoid();

  // void Func2(bool b) { if (b) { Func3(false); return; } return; }
  Builder.SetInsertPoint(Block2);
  Builder.CreateCondBr(Func2->arg_begin(), True2, False2);
  Builder.SetInsertPoint(True2);
  Builder.CreateCall(Func3, ConstantInt::getFalse(Context));
  Builder.CreateRetVoid();
  Builder.SetInsertPoint(False2);
  Builder.CreateRetVoid();

  // void Func3(bool b) { if (b) { Func2(false); return; } return; }
  Builder.SetInsertPoint(Block3);
  Builder.CreateCondBr(Func3->arg_begin(), True3, False3);
  Builder.SetInsertPoint(True3);
  Builder.CreateCall(Func2, ConstantInt::getFalse(Context));
  Builder.CreateRetVoid();
  Builder.SetInsertPoint(False3);
  Builder.CreateRetVoid();

  // Compile the function to native code
  void (*F1Ptr)() =
     reinterpret_cast<void(*)()>((intptr_t)TheJIT->getPointerToFunction(Func1));

  F1Ptr();
}

// Regression test for PR5162.  This used to trigger an AssertingVH inside the
// JIT's Function to stub mapping.
TEST_F(JITTest, NonLazyLeaksNoStubs) {
  TheJIT->DisableLazyCompilation();

  // Create two functions with a single basic block each.
  const FunctionType *FuncTy =
      cast<FunctionType>(TypeBuilder<int(), false>::get(Context));
  Function *Func1 = Function::Create(FuncTy, Function::ExternalLinkage,
                                     "func1", M);
  Function *Func2 = Function::Create(FuncTy, Function::InternalLinkage,
                                     "func2", M);
  BasicBlock *Block1 = BasicBlock::Create(Context, "block1", Func1);
  BasicBlock *Block2 = BasicBlock::Create(Context, "block2", Func2);

  // The first function calls the second and returns the result
  IRBuilder<> Builder(Block1);
  Value *Result = Builder.CreateCall(Func2);
  Builder.CreateRet(Result);

  // The second function just returns a constant
  Builder.SetInsertPoint(Block2);
  Builder.CreateRet(ConstantInt::get(TypeBuilder<int, false>::get(Context),42));

  // Compile the function to native code
  (void)TheJIT->getPointerToFunction(Func1);

  // Free the JIT state for the functions
  TheJIT->freeMachineCodeForFunction(Func1);
  TheJIT->freeMachineCodeForFunction(Func2);

  // Delete the first function (and show that is has no users)
  EXPECT_EQ(Func1->getNumUses(), 0u);
  Func1->eraseFromParent();

  // Delete the second function (and show that it has no users - it had one,
  // func1 but that's gone now)
  EXPECT_EQ(Func2->getNumUses(), 0u);
  Func2->eraseFromParent();
}
#endif

// This code is copied from JITEventListenerTest, but it only runs once for all
// the tests in this directory.  Everything seems fine, but that's strange
// behavior.
class JITEnvironment : public testing::Environment {
  virtual void SetUp() {
    // Required to create a JIT.
    InitializeNativeTarget();
  }
};
testing::Environment* const jit_env =
  testing::AddGlobalTestEnvironment(new JITEnvironment);

}
<|endoftext|>


<commit_before>#include <iostream>

class Fracao {
  private:
    int num;
    int den;

    friend std::ostream &operator<<( std::ostream &saida, const Fracao &a );
    friend std::istream &operator>>( std::istream &entrada, Fracao &a );

  public:
    void imprimir( void ) const {
        std::cout << *this << '\n';
    }

    void setNum( const int num ) {
        this->num = num;
    }

    void setDen( const int den ) {
        if( den != 0 ) {
            this->den = den;
        } else {
            std::cout << "Erro denominador" << '\n';
            this->den = 1;
        }
    }

    int getNum( void ) const {
        return num;
    }

    int getDen( void ) const {
        return den;
    }

    Fracao( const int num, const int den ) {
        setNum( num );
        setDen( den );

        imprimir();
    }

    ~Fracao( void ) {
        std::cout << "Destrutor: ";
        imprimir();
        std::cout << '\n';
    }

    Fracao operator*( const Fracao &b ) const {
        return Fracao( this->getNum() * b.getNum(), this->getDen() * b.getDen() );
    }

    Fracao operator*( const int &b ) const {
        return Fracao( this->getNum() * b, this->getDen() );
    }

    Fracao operator+( const Fracao &b ) const {
        if( this->getDen() == b.getDen() ) {
            return Fracao( this->getNum() + b.getNum(), this->getDen() );
        } else {
            return Fracao( this->getNum() * b.getDen() + b.getNum() * this->getDen(),
                           this->getDen() * b.getDen() );
        }
    }

    Fracao operator+( const int &a ) const {
        return Fracao( a * this->getDen() + this->getNum(), this->getDen() );
    }

    Fracao operator-( const Fracao &b ) const {
        if( this->getDen() == b.getDen() ) {
            return Fracao( this->getNum() - b.getNum(), this->getDen() );
        } else {
            return Fracao( this->getNum() * b.getDen() + b.getNum() * this->getDen(),
                           this->getDen() * b.getDen() );
        }
    }

    Fracao operator-( const int &a ) const {
        return Fracao( this->getNum() - a * this->getDen(), this->getDen() );
    }

    Fracao operator/( const Fracao &b ) const {
        return Fracao( this->getNum() * b.getDen(), this->getDen() * b.getNum() );
    }

    Fracao operator/( const int &a ) const {
        return Fracao( this->getNum(), a * this->getDen() );
    }
};

Fracao operator*( const int &b, const Fracao &a ) {
    return Fracao( a.getNum() * b, a.getDen() );
}

Fracao operator+( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen() + b.getNum(), b.getDen() );
}

Fracao operator-( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen() - b.getNum(), b.getDen() );
}

Fracao operator/( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen(), b.getNum() );
}

std::istream &operator>>( std::istream &entrada, Fracao &a ) {
    int numerador, denominador;
    char barra;

    entrada >> numerador >> barra >> denominador;

    a.setNum( numerador );
    a.setDen( denominador );

    return entrada;
}

std::ostream &operator<<( std::ostream &saida, const Fracao &a ) {
    saida << a.num << "/" << a.den;
    return saida;
}

int main( void ) {
    Fracao a( 1, 2 );
    Fracao b( 2, 4 );

    std::cout << "A:" << a << '\n';

    Fracao resultado = a * b;

    std::cin >> b;
    std::cout << b << '\n';

    return 0;
}
<commit_msg>Sobrecarga operadores relacionais<commit_after>#include <iostream>

class Fracao {
  private:
    int num;
    int den;

    friend std::ostream &operator<<( std::ostream &saida, const Fracao &a );
    friend std::istream &operator>>( std::istream &entrada, Fracao &a );

  public:
    void imprimir( void ) const {
        std::cout << *this << '\n';
    }

    void setNum( const int num ) {
        this->num = num;
    }

    void setDen( const int den ) {
        if( den != 0 ) {
            this->den = den;
        } else {
            std::cout << "Erro denominador" << '\n';
            this->den = 1;
        }
    }

    int getNum( void ) const {
        return num;
    }

    int getDen( void ) const {
        return den;
    }

    Fracao( const int num, const int den ) {
        setNum( num );
        setDen( den );

        imprimir();
    }

    ~Fracao( void ) {
        std::cout << "Destrutor: ";
        imprimir();
        std::cout << '\n';
    }

    Fracao operator*( const Fracao &b ) const {
        return Fracao( this->getNum() * b.getNum(), this->getDen() * b.getDen() );
    }

    Fracao operator*( const int &b ) const {
        return Fracao( this->getNum() * b, this->getDen() );
    }

    Fracao operator+( const Fracao &b ) const {
        if( this->getDen() == b.getDen() ) {
            return Fracao( this->getNum() + b.getNum(), this->getDen() );
        } else {
            return Fracao( this->getNum() * b.getDen() + b.getNum() * this->getDen(),
                           this->getDen() * b.getDen() );
        }
    }

    Fracao operator+( const int &a ) const {
        return Fracao( a * this->getDen() + this->getNum(), this->getDen() );
    }

    Fracao operator-( const Fracao &b ) const {
        if( this->getDen() == b.getDen() ) {
            return Fracao( this->getNum() - b.getNum(), this->getDen() );
        } else {
            return Fracao( this->getNum() * b.getDen() + b.getNum() * this->getDen(),
                           this->getDen() * b.getDen() );
        }
    }

    Fracao operator-( const int &a ) const {
        return Fracao( this->getNum() - a * this->getDen(), this->getDen() );
    }

    Fracao operator/( const Fracao &b ) const {
        return Fracao( this->getNum() * b.getDen(), this->getDen() * b.getNum() );
    }

    Fracao operator/( const int &a ) const {
        return Fracao( this->getNum(), a * this->getDen() );
    }

    bool operator>( const Fracao &b ) const {
        return ( (float)this->num / this->den > (float)b.num / b.den );
    }

    bool operator==( const Fracao &b ) const {
        return ( (float)this->num / this->den == (float)b.num / b.den );
    }

    bool operator<( const Fracao &b ) const {
        return ( (float)this->num / this->den < (float)b.num / b.den );
    }

    bool operator!=( const Fracao &b ) const {
        return ( !( *this == b ) );
    }
};

Fracao operator*( const int &b, const Fracao &a ) {
    return Fracao( a.getNum() * b, a.getDen() );
}

Fracao operator+( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen() + b.getNum(), b.getDen() );
}

Fracao operator-( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen() - b.getNum(), b.getDen() );
}

Fracao operator/( const int &a, const Fracao &b ) {
    return Fracao( a * b.getDen(), b.getNum() );
}

std::istream &operator>>( std::istream &entrada, Fracao &a ) {
    int numerador, denominador;
    char barra;

    entrada >> numerador >> barra >> denominador;

    a.setNum( numerador );
    a.setDen( denominador );

    return entrada;
}

std::ostream &operator<<( std::ostream &saida, const Fracao &a ) {
    saida << a.num << "/" << a.den;
    return saida;
}

int main( void ) {
    Fracao a( 1, 2 );
    Fracao b( 1, 4 );

    std::cout << "A:" << a << '\n';

    if( b > a ) {
        std::cout << "B>A" << '\n';
    } else {
        std::cout << "B<=A" << '\n';
    }

    Fracao resultado = a * b;

    std::cin >> b;
    std::cout << b << '\n';

    return 0;
}
<|endoftext|>


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

#include "vast/system/partition.hpp"

#include <caf/event_based_actor.hpp>
#include <caf/local_actor.hpp>
#include <caf/make_counted.hpp>
#include <caf/stateful_actor.hpp>

#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/concept/printable/vast/uuid.hpp"
#include "vast/detail/assert.hpp"
#include "vast/event.hpp"
#include "vast/expression_visitors.hpp"
#include "vast/ids.hpp"
#include "vast/load.hpp"
#include "vast/logger.hpp"
#include "vast/save.hpp"
#include "vast/system/atoms.hpp"
#include "vast/system/index.hpp"
#include "vast/system/spawn_indexer.hpp"
#include "vast/system/table_indexer.hpp"
#include "vast/time.hpp"

using namespace std::chrono;
using namespace caf;

namespace vast::system {

partition::partition(index_state* state, uuid id, size_t max_capacity)
  : state_(state),
    id_(std::move(id)),
    capacity_(max_capacity) {
  // If the directory already exists, we must have some state from the past and
  // are pre-loading all INDEXER types we are aware of.
  VAST_ASSERT(state != nullptr);
}

partition::~partition() noexcept {
  flush_to_disk();
}

// -- persistence --------------------------------------------------------------

caf::error partition::init() {
  VAST_TRACE("");
  auto file_path = meta_file();
  if (!exists(file_path))
    return ec::no_such_file;
  if (auto err = load(nullptr, file_path , meta_data_))
    return err;
  VAST_DEBUG(state_->self, "loaded partition", id_, "from disk with",
             meta_data_.types.size(), "layouts");
  return caf::none;
}

caf::error partition::flush_to_disk() {
  if (meta_data_.dirty) {
    // Write all layouts to disk.
    if (auto err = save(nullptr, meta_file(), meta_data_))
      return err;
    meta_data_.dirty = false;
  }
  // Write state for each layout to disk.
  for (auto& kvp : table_indexers_)
    if (auto err = kvp.second.flush_to_disk())
      return err;
  return caf::none;
}

// -- properties ---------------------------------------------------------------

namespace {

using eval_mapping = evaluation_map::mapped_type;

caf::actor fetch_indexer(table_indexer& tbl, const data_extractor& dx,
                         [[maybe_unused]] relational_operator op,
                         [[maybe_unused]] const data& x) {
  VAST_TRACE(VAST_ARG(tbl), VAST_ARG(dx), VAST_ARG(op), VAST_ARG(x));
  // Sanity check.
  if (dx.offset.empty())
    return nullptr;
  auto& r = caf::get<record_type>(dx.type);
  auto k = r.resolve(dx.offset);
  VAST_ASSERT(k);
  auto index = r.flat_index_at(dx.offset);
  if (!index) {
    VAST_DEBUG(tbl.state().self, "got invalid offset for record type", dx.type);
    return nullptr;
  }
  return tbl.indexer_at(*index);
}

caf::actor fetch_indexer(table_indexer& tbl, const attribute_extractor& ex,
                         relational_operator op, const data& x) {
  VAST_TRACE(VAST_ARG(tbl), VAST_ARG(ex), VAST_ARG(op), VAST_ARG(x));
  auto& layout = tbl.layout();
  // Predicate of form "&type == ..."
  if (ex.attr == system::type_atom::value) {
    VAST_ASSERT(caf::holds_alternative<std::string>(x));
    // Doesn't apply if the query name doesn't match our type.
    if (layout.name() != caf::get<std::string>(x))
      return nullptr;
    // We know the answer immediately: all IDs that are part of the table.
    // However, we still have to "lift" this result into an actor for the
    // EVALUATOR.
    // TODO: Spawning a one-shot actor is quite expensive. Maybe the
    //       table_indexer could instead maintain this actor lazily.
    auto row_ids = tbl.row_ids();
    return tbl.state().self->spawn([row_ids]() -> caf::behavior {
      return [=](const curried_predicate&) { return row_ids; };
    });
  }
  if (ex.attr == system::time_atom::value) {
    // TODO: reconsider whether we still want to support "&time ..." queries.
    VAST_ASSERT(caf::holds_alternative<timestamp>(x));
    if (layout.fields.empty() || layout.fields[0].type != timestamp_type{})
      return nullptr;
    record_type rs_rec{{"timestamp", timestamp_type{}}};
    type t = rs_rec;
    data_extractor dx{t, vast::offset{0}};
    // Redirect to "ordinary data lookup" on column 0.
    return fetch_indexer(tbl, dx, op, x);
  }
  VAST_WARNING(tbl.state().self, "got unsupported attribute:", ex.attr);
  return nullptr;
}

} // namespace

evaluation_map partition::eval(const expression& expr) {
  evaluation_map result;
  // Step #1: use the expression to select matching layouts.
  for (auto layout : layouts()) {
    // Step #2: Split the resolved expression into its predicates and select
    // all matching INDEXER actors per predicate.
    auto resolved = resolve(expr, layout);
    // Skip any layout that we cannot resolve.
    if (resolved.empty())
      continue;
    // Add triples (offset, curried predicate, and INDEXER) to evaluation map.
    auto& triples = result[layout];
    for (auto& kvp: resolved) {
      auto& pred = kvp.second;
      auto hdl = caf::visit(detail::overload(
                              [&](const attribute_extractor& ex,
                                  const data& x) {
                                return fetch_indexer(get_or_add(layout).first,
                                                     ex, pred.op, x);
                              },
                              [&](const data_extractor& dx, const data& x) {
                                return fetch_indexer(get_or_add(layout).first,
                                                     dx, pred.op, x);
                              },
                              [](const auto&, const auto&) {
                                return caf::actor{};
                              }),
                            pred.lhs, pred.rhs);
      if (hdl != nullptr) {
        VAST_DEBUG_ANON(__func__, "adds INDEXER", hdl, "to the evaluation map");
        triples.emplace_back(kvp.first, curried(pred), std::move(hdl));
      }
    }
  }
  return result;
}

std::vector<record_type> partition::layouts() const {
  std::vector<record_type> result;
  auto& ts = meta_data_.types;
  result.reserve(ts.size());
  std::transform(ts.begin(), ts.end(), std::back_inserter(result),
                 [](auto& kvp) { return kvp.second; });
  return result;
}

path partition::base_dir() const {
  return state_->dir / to_string(id_);
}

path partition::meta_file() const {
  return base_dir() / "meta";
}

std::pair<table_indexer&, bool> partition::get_or_add(const record_type& key) {
  VAST_TRACE(VAST_ARG(key));
  auto i = table_indexers_.find(key);
  if (i != table_indexers_.end())
    return {i->second, false};
  auto digest = to_digest(key);
  add_layout(digest, key);
  auto result = table_indexers_.emplace(key, table_indexer{this, key});
  VAST_ASSERT(result.second == true);
  return {result.first->second, true};

}

} // namespace vast::system

namespace std {

namespace {

using pptr = vast::system::partition_ptr;

} // namespace <anonymous>

size_t hash<pptr>::operator()(const pptr& ptr) const {
  hash<vast::uuid> f;
  return ptr != nullptr ? f(ptr->id()) : 0u;
}

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

#include "vast/system/partition.hpp"

#include <caf/event_based_actor.hpp>
#include <caf/local_actor.hpp>
#include <caf/make_counted.hpp>
#include <caf/stateful_actor.hpp>

#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/concept/printable/vast/uuid.hpp"
#include "vast/detail/assert.hpp"
#include "vast/event.hpp"
#include "vast/expression_visitors.hpp"
#include "vast/ids.hpp"
#include "vast/load.hpp"
#include "vast/logger.hpp"
#include "vast/save.hpp"
#include "vast/system/atoms.hpp"
#include "vast/system/index.hpp"
#include "vast/system/spawn_indexer.hpp"
#include "vast/system/table_indexer.hpp"
#include "vast/time.hpp"

using namespace std::chrono;
using namespace caf;

namespace vast::system {

partition::partition(index_state* state, uuid id, size_t max_capacity)
  : state_(state),
    id_(std::move(id)),
    capacity_(max_capacity) {
  // If the directory already exists, we must have some state from the past and
  // are pre-loading all INDEXER types we are aware of.
  VAST_ASSERT(state != nullptr);
}

partition::~partition() noexcept {
  flush_to_disk();
}

// -- persistence --------------------------------------------------------------

caf::error partition::init() {
  VAST_TRACE("");
  auto file_path = meta_file();
  if (!exists(file_path))
    return ec::no_such_file;
  if (auto err = load(nullptr, file_path , meta_data_))
    return err;
  VAST_DEBUG(state_->self, "loaded partition", id_, "from disk with",
             meta_data_.types.size(), "layouts");
  return caf::none;
}

caf::error partition::flush_to_disk() {
  if (meta_data_.dirty) {
    // Write all layouts to disk.
    if (auto err = save(nullptr, meta_file(), meta_data_))
      return err;
    meta_data_.dirty = false;
  }
  // Write state for each layout to disk.
  for (auto& kvp : table_indexers_)
    if (auto err = kvp.second.flush_to_disk())
      return err;
  return caf::none;
}

// -- properties ---------------------------------------------------------------

namespace {

using eval_mapping = evaluation_map::mapped_type;

caf::actor fetch_indexer(table_indexer& tbl, const data_extractor& dx,
                         [[maybe_unused]] relational_operator op,
                         [[maybe_unused]] const data& x) {
  VAST_TRACE(VAST_ARG(tbl), VAST_ARG(dx), VAST_ARG(op), VAST_ARG(x));
  // Sanity check.
  if (dx.offset.empty())
    return nullptr;
  auto& r = caf::get<record_type>(dx.type);
  auto k = r.resolve(dx.offset);
  VAST_ASSERT(k);
  auto index = r.flat_index_at(dx.offset);
  if (!index) {
    VAST_DEBUG(tbl.state().self, "got invalid offset for record type", dx.type);
    return nullptr;
  }
  return tbl.indexer_at(*index);
}

caf::actor fetch_indexer(table_indexer& tbl, const attribute_extractor& ex,
                         relational_operator op, const data& x) {
  VAST_TRACE(VAST_ARG(tbl), VAST_ARG(ex), VAST_ARG(op), VAST_ARG(x));
  auto& layout = tbl.layout();
  // Predicate of form "&type == ..."
  if (ex.attr == system::type_atom::value) {
    VAST_ASSERT(caf::holds_alternative<std::string>(x));
    // Doesn't apply if the query name doesn't match our type.
    if (layout.name() != caf::get<std::string>(x))
      return nullptr;
    // We know the answer immediately: all IDs that are part of the table.
    // However, we still have to "lift" this result into an actor for the
    // EVALUATOR.
    // TODO: Spawning a one-shot actor is quite expensive. Maybe the
    //       table_indexer could instead maintain this actor lazily.
    auto row_ids = tbl.row_ids();
    return tbl.state().self->spawn([row_ids]() -> caf::behavior {
      return [=](const curried_predicate&) { return row_ids; };
    });
  }
  // Predicate of form "&time == ..."
  if (ex.attr == system::time_atom::value) {
    VAST_ASSERT(caf::holds_alternative<timestamp>(x));
    // Find the column with attribute 'time'.
    auto pred = [](auto& x) {
      return caf::holds_alternative<timestamp_type>(x.type)
             && has_attribute(x.type, "time");
    };
    auto& fs = layout.fields;
    auto i = std::find_if(fs.begin(), fs.end(), pred);
    if (i == fs.end())
      return nullptr;
    // Redirect to "ordinary data lookup".
    auto pos = static_cast<size_t>(std::distance(fs.begin(), i));
    data_extractor dx{layout, vast::offset{pos}};
    return fetch_indexer(tbl, dx, op, x);
  }
  VAST_WARNING(tbl.state().self, "got unsupported attribute:", ex.attr);
  return nullptr;
}

} // namespace

evaluation_map partition::eval(const expression& expr) {
  evaluation_map result;
  // Step #1: use the expression to select matching layouts.
  for (auto layout : layouts()) {
    // Step #2: Split the resolved expression into its predicates and select
    // all matching INDEXER actors per predicate.
    auto resolved = resolve(expr, layout);
    // Skip any layout that we cannot resolve.
    if (resolved.empty())
      continue;
    // Add triples (offset, curried predicate, and INDEXER) to evaluation map.
    auto& triples = result[layout];
    for (auto& kvp: resolved) {
      auto& pred = kvp.second;
      auto hdl = caf::visit(detail::overload(
                              [&](const attribute_extractor& ex,
                                  const data& x) {
                                return fetch_indexer(get_or_add(layout).first,
                                                     ex, pred.op, x);
                              },
                              [&](const data_extractor& dx, const data& x) {
                                return fetch_indexer(get_or_add(layout).first,
                                                     dx, pred.op, x);
                              },
                              [](const auto&, const auto&) {
                                return caf::actor{};
                              }),
                            pred.lhs, pred.rhs);
      if (hdl != nullptr) {
        VAST_DEBUG_ANON(__func__, "adds INDEXER", hdl, "to the evaluation map");
        triples.emplace_back(kvp.first, curried(pred), std::move(hdl));
      }
    }
  }
  return result;
}

std::vector<record_type> partition::layouts() const {
  std::vector<record_type> result;
  auto& ts = meta_data_.types;
  result.reserve(ts.size());
  std::transform(ts.begin(), ts.end(), std::back_inserter(result),
                 [](auto& kvp) { return kvp.second; });
  return result;
}

path partition::base_dir() const {
  return state_->dir / to_string(id_);
}

path partition::meta_file() const {
  return base_dir() / "meta";
}

std::pair<table_indexer&, bool> partition::get_or_add(const record_type& key) {
  VAST_TRACE(VAST_ARG(key));
  auto i = table_indexers_.find(key);
  if (i != table_indexers_.end())
    return {i->second, false};
  auto digest = to_digest(key);
  add_layout(digest, key);
  auto result = table_indexers_.emplace(key, table_indexer{this, key});
  VAST_ASSERT(result.second == true);
  return {result.first->second, true};

}

} // namespace vast::system

namespace std {

namespace {

using pptr = vast::system::partition_ptr;

} // namespace <anonymous>

size_t hash<pptr>::operator()(const pptr& ptr) const {
  hash<vast::uuid> f;
  return ptr != nullptr ? f(ptr->id()) : 0u;
}

} // namespace std
<|endoftext|>


<commit_before>/**
 * @file sparse_autoencoder_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the SparseAutoencoder class.
 */
#include <mlpack/methods/sparse_autoencoder/sparse_autoencoder.hpp>
#include <mlpack/methods/sparse_autoencoder/sparse_autoencoder_function.hpp>
#include <mlpack/methods/sparse_autoencoder/activation_functions/logistic_function.hpp>

#include <mlpack/core.hpp>
#include <mlpack/methods/sparse_autoencoder/layer/base_layer.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace arma;

using SigmoidLayer = nn::SigmoidLayer<nn::LogisticFunction>;

//sparse autoencoder function
using SAEF = nn::SparseAutoencoderFunction<SigmoidLayer, SigmoidLayer>;
//sparse autoencoder function greedy
using SAEFG = nn::SparseAutoencoderFunction<SigmoidLayer, SigmoidLayer, std::true_type>;

BOOST_AUTO_TEST_SUITE(SparseAutoencoderTest2);

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionEvaluate)
{
  const size_t vSize = 5;
  const size_t hSize = 3;
  const size_t r = 2 * hSize + 1;
  const size_t c = vSize + 1;

  // Simple fake dataset.
  arma::mat data1("0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5");
  // Transpose of the above dataset.
  arma::mat data2 = data1.t();

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf1(data1, vSize, hSize, 0, 0);

  // Test using first dataset. Values were calculated using Octave.
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(arma::ones(r, c)), 1.190472606540, 1e-5);
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(arma::zeros(r, c)), 0.150000000000, 1e-5);
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(-arma::ones(r, c)), 0.048800332266, 1e-5);

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf2(data2, vSize, hSize, 0, 0);

  // Test using second dataset. Values were calculated using Octave.
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(arma::ones(r, c)), 1.197585812647, 1e-5);
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(arma::zeros(r, c)), 0.150000000000, 1e-5);
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(-arma::ones(r, c)), 0.063466617408, 1e-5);
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionRandomEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l1 = hSize;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf(data, vSize, hSize, 0, 0);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    double reconstructionError = 0;

    // Compute error for each training example.
    for (size_t j = 0; j < points; j++)
    {
      arma::mat hiddenLayer, outputLayer, diff;

      hiddenLayer = 1.0 /
                   (1 + arma::exp(-(parameters.submat(0, 0, l1 - 1, l2 - 1) *
                                  data.col(j) + parameters.submat(0, l2, l1 - 1, l2))));
      outputLayer = 1.0 /
                    (1 + arma::exp(-(parameters.submat(l1, 0, l3 - 1,l2 - 1).t()
                                   * hiddenLayer + parameters.submat(l3, 0, l3, l2 - 1).t())));
      diff = outputLayer - data.col(j);

      reconstructionError += 0.5 * arma::sum(arma::sum(diff % diff));
    }
    reconstructionError /= points;

    // Compare with the value returned by the function.
    BOOST_REQUIRE_CLOSE(saf.Evaluate(parameters), reconstructionError, 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionRegularizationEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for comparing regularization costs.
  SAEF safNoReg(data, vSize, hSize, 0, 0);
  SAEF safSmallReg(data, vSize, hSize, 0.5, 0);
  SAEF safBigReg(data, vSize, hSize, 20, 0);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    double wL2SquaredNorm;

    wL2SquaredNorm = arma::accu(parameters.submat(0, 0, l3 - 1, l2 - 1) %
                                parameters.submat(0, 0, l3 - 1, l2 - 1));

    // Calculate regularization terms.
    const double smallRegTerm = 0.25 * wL2SquaredNorm;
    const double bigRegTerm = 10 * wL2SquaredNorm;

    BOOST_REQUIRE_CLOSE(safNoReg.Evaluate(parameters) + smallRegTerm,
                        safSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(safNoReg.Evaluate(parameters) + bigRegTerm,
                        safBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionKLDivergenceEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l1 = hSize;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  const double rho = 0.01;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for comparing divergence costs.
  SAEF safNoDiv(data, vSize, hSize, 0, 0, rho);
  SAEF safSmallDiv(data, vSize, hSize, 0, 5, rho);
  SAEF safBigDiv(data, vSize, hSize, 0, 20, rho);

  // Run a number of trials.
  for(size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    arma::mat rhoCap;
    rhoCap.zeros(hSize, 1);

    // Compute hidden layer activations for each example.
    for (size_t j = 0; j < points; j++)
    {
      arma::mat hiddenLayer;

      hiddenLayer = 1.0 / (1 +
                           arma::exp(-(parameters.submat(0, 0, l1 - 1, l2 - 1) *
                                       data.col(j) + parameters.submat(0, l2, l1 - 1, l2))));
      rhoCap += hiddenLayer;
    }
    rhoCap /= points;

    // Calculate divergence terms.
    const double smallDivTerm = 5 * arma::accu(rho * arma::log(rho / rhoCap) +
                                               (1 - rho) * arma::log((1 - rho) / (1 - rhoCap)));
    const double bigDivTerm = 20 * arma::accu(rho * arma::log(rho / rhoCap) +
                                              (1 - rho) * arma::log((1 - rho) / (1 - rhoCap)));

    BOOST_REQUIRE_CLOSE(safNoDiv.Evaluate(parameters) + smallDivTerm,
                        safSmallDiv.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(safNoDiv.Evaluate(parameters) + bigDivTerm,
                        safBigDiv.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionGradient)
{
  const size_t points = 1000;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for 3 terms in the cost function. Each term contributes towards
  // the gradient and thus need to be checked independently.
  SAEFG saf1(data, vSize, hSize, 0, 0);
  SAEFG saf2(data, vSize, hSize, 20, 0);
  SAEFG saf3(data, vSize, hSize, 20, 20);

  // Create a random set of parameters.
  arma::mat parameters;
  parameters.randu(l3 + 1, l2 + 1);

  // Get gradients for the current parameters.
  arma::mat gradient1, gradient2, gradient3;
  saf1.Gradient(parameters, gradient1);
  saf2.Gradient(parameters, gradient2);
  saf3.Gradient(parameters, gradient3);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;
  double costPlus3, costMinus3, numGradient3;

  // For each parameter.
  for (size_t i = 0; i <= l3; i++)
  {
    for (size_t j = 0; j <= l2; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = saf1.Evaluate(parameters);
      costPlus2 = saf2.Evaluate(parameters);
      costPlus3 = saf3.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = saf1.Evaluate(parameters);
      costMinus2 = saf2.Evaluate(parameters);
      costMinus3 = saf3.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);
      numGradient3 = (costPlus3 - costMinus3) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient3, gradient3(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderMoveTest)
{
  using SAE = mlpack::nn::SparseAutoencoder<>;
  SAE sae1(2, 2);
  SAE sae2(std::move(sae1));
  BOOST_REQUIRE(sae1.Parameters().n_elem == 0);
  BOOST_REQUIRE(sae1.VisibleSize(), sae2.VisibleSize());
  BOOST_REQUIRE(sae1.HiddenSize(), sae2.HiddenSize());
  BOOST_REQUIRE_CLOSE(sae1.Lambda(), sae2.Lambda(), 1e-5);
  BOOST_REQUIRE_CLOSE(sae1.Beta(), sae2.Beta(), 1e-5);
  BOOST_REQUIRE_CLOSE(sae1.Rho(), sae2.Rho(), 1e-5);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>refine test case of move<commit_after>/**
 * @file sparse_autoencoder_test.cpp
 * @author Siddharth Agrawal
 *
 * Test the SparseAutoencoder class.
 */
#include <mlpack/methods/sparse_autoencoder/sparse_autoencoder.hpp>
#include <mlpack/methods/sparse_autoencoder/sparse_autoencoder_function.hpp>
#include <mlpack/methods/sparse_autoencoder/activation_functions/logistic_function.hpp>

#include <mlpack/core.hpp>
#include <mlpack/methods/sparse_autoencoder/layer/base_layer.hpp>

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace mlpack;
using namespace arma;

using SigmoidLayer = nn::SigmoidLayer<nn::LogisticFunction>;

//sparse autoencoder function
using SAEF = nn::SparseAutoencoderFunction<SigmoidLayer, SigmoidLayer>;
//sparse autoencoder function greedy
using SAEFG = nn::SparseAutoencoderFunction<SigmoidLayer, SigmoidLayer, std::true_type>;

BOOST_AUTO_TEST_SUITE(SparseAutoencoderTest2);

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionEvaluate)
{
  const size_t vSize = 5;
  const size_t hSize = 3;
  const size_t r = 2 * hSize + 1;
  const size_t c = vSize + 1;

  // Simple fake dataset.
  arma::mat data1("0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5;"
                  "0.1 0.2 0.3 0.4 0.5");
  // Transpose of the above dataset.
  arma::mat data2 = data1.t();

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf1(data1, vSize, hSize, 0, 0);

  // Test using first dataset. Values were calculated using Octave.
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(arma::ones(r, c)), 1.190472606540, 1e-5);
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(arma::zeros(r, c)), 0.150000000000, 1e-5);
  BOOST_REQUIRE_CLOSE(saf1.Evaluate(-arma::ones(r, c)), 0.048800332266, 1e-5);

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf2(data2, vSize, hSize, 0, 0);

  // Test using second dataset. Values were calculated using Octave.
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(arma::ones(r, c)), 1.197585812647, 1e-5);
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(arma::zeros(r, c)), 0.150000000000, 1e-5);
  BOOST_REQUIRE_CLOSE(saf2.Evaluate(-arma::ones(r, c)), 0.063466617408, 1e-5);
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionRandomEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l1 = hSize;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // Create a SparseAutoencoderFunction. Regularization and KL divergence terms
  // ignored.
  SAEF saf(data, vSize, hSize, 0, 0);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    double reconstructionError = 0;

    // Compute error for each training example.
    for (size_t j = 0; j < points; j++)
    {
      arma::mat hiddenLayer, outputLayer, diff;

      hiddenLayer = 1.0 /
                   (1 + arma::exp(-(parameters.submat(0, 0, l1 - 1, l2 - 1) *
                                  data.col(j) + parameters.submat(0, l2, l1 - 1, l2))));
      outputLayer = 1.0 /
                    (1 + arma::exp(-(parameters.submat(l1, 0, l3 - 1,l2 - 1).t()
                                   * hiddenLayer + parameters.submat(l3, 0, l3, l2 - 1).t())));
      diff = outputLayer - data.col(j);

      reconstructionError += 0.5 * arma::sum(arma::sum(diff % diff));
    }
    reconstructionError /= points;

    // Compare with the value returned by the function.
    BOOST_REQUIRE_CLOSE(saf.Evaluate(parameters), reconstructionError, 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionRegularizationEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for comparing regularization costs.
  SAEF safNoReg(data, vSize, hSize, 0, 0);
  SAEF safSmallReg(data, vSize, hSize, 0.5, 0);
  SAEF safBigReg(data, vSize, hSize, 20, 0);

  // Run a number of trials.
  for (size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    double wL2SquaredNorm;

    wL2SquaredNorm = arma::accu(parameters.submat(0, 0, l3 - 1, l2 - 1) %
                                parameters.submat(0, 0, l3 - 1, l2 - 1));

    // Calculate regularization terms.
    const double smallRegTerm = 0.25 * wL2SquaredNorm;
    const double bigRegTerm = 10 * wL2SquaredNorm;

    BOOST_REQUIRE_CLOSE(safNoReg.Evaluate(parameters) + smallRegTerm,
                        safSmallReg.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(safNoReg.Evaluate(parameters) + bigRegTerm,
                        safBigReg.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionKLDivergenceEvaluate)
{
  const size_t points = 1000;
  const size_t trials = 50;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l1 = hSize;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  const double rho = 0.01;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for comparing divergence costs.
  SAEF safNoDiv(data, vSize, hSize, 0, 0, rho);
  SAEF safSmallDiv(data, vSize, hSize, 0, 5, rho);
  SAEF safBigDiv(data, vSize, hSize, 0, 20, rho);

  // Run a number of trials.
  for(size_t i = 0; i < trials; i++)
  {
    // Create a random set of parameters.
    arma::mat parameters;
    parameters.randu(l3 + 1, l2 + 1);

    arma::mat rhoCap;
    rhoCap.zeros(hSize, 1);

    // Compute hidden layer activations for each example.
    for (size_t j = 0; j < points; j++)
    {
      arma::mat hiddenLayer;

      hiddenLayer = 1.0 / (1 +
                           arma::exp(-(parameters.submat(0, 0, l1 - 1, l2 - 1) *
                                       data.col(j) + parameters.submat(0, l2, l1 - 1, l2))));
      rhoCap += hiddenLayer;
    }
    rhoCap /= points;

    // Calculate divergence terms.
    const double smallDivTerm = 5 * arma::accu(rho * arma::log(rho / rhoCap) +
                                               (1 - rho) * arma::log((1 - rho) / (1 - rhoCap)));
    const double bigDivTerm = 20 * arma::accu(rho * arma::log(rho / rhoCap) +
                                              (1 - rho) * arma::log((1 - rho) / (1 - rhoCap)));

    BOOST_REQUIRE_CLOSE(safNoDiv.Evaluate(parameters) + smallDivTerm,
                        safSmallDiv.Evaluate(parameters), 1e-5);
    BOOST_REQUIRE_CLOSE(safNoDiv.Evaluate(parameters) + bigDivTerm,
                        safBigDiv.Evaluate(parameters), 1e-5);
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderFunctionGradient)
{
  const size_t points = 1000;
  const size_t vSize = 20;
  const size_t hSize = 10;
  const size_t l2 = vSize;
  const size_t l3 = 2 * hSize;

  // Initialize a random dataset.
  arma::mat data;
  data.randu(vSize, points);

  // 3 objects for 3 terms in the cost function. Each term contributes towards
  // the gradient and thus need to be checked independently.
  SAEFG saf1(data, vSize, hSize, 0, 0);
  SAEFG saf2(data, vSize, hSize, 20, 0);
  SAEFG saf3(data, vSize, hSize, 20, 20);

  // Create a random set of parameters.
  arma::mat parameters;
  parameters.randu(l3 + 1, l2 + 1);

  // Get gradients for the current parameters.
  arma::mat gradient1, gradient2, gradient3;
  saf1.Gradient(parameters, gradient1);
  saf2.Gradient(parameters, gradient2);
  saf3.Gradient(parameters, gradient3);

  // Perturbation constant.
  const double epsilon = 0.0001;
  double costPlus1, costMinus1, numGradient1;
  double costPlus2, costMinus2, numGradient2;
  double costPlus3, costMinus3, numGradient3;

  // For each parameter.
  for (size_t i = 0; i <= l3; i++)
  {
    for (size_t j = 0; j <= l2; j++)
    {
      // Perturb parameter with a positive constant and get costs.
      parameters(i, j) += epsilon;
      costPlus1 = saf1.Evaluate(parameters);
      costPlus2 = saf2.Evaluate(parameters);
      costPlus3 = saf3.Evaluate(parameters);

      // Perturb parameter with a negative constant and get costs.
      parameters(i, j) -= 2 * epsilon;
      costMinus1 = saf1.Evaluate(parameters);
      costMinus2 = saf2.Evaluate(parameters);
      costMinus3 = saf3.Evaluate(parameters);

      // Compute numerical gradients using the costs calculated above.
      numGradient1 = (costPlus1 - costMinus1) / (2 * epsilon);
      numGradient2 = (costPlus2 - costMinus2) / (2 * epsilon);
      numGradient3 = (costPlus3 - costMinus3) / (2 * epsilon);

      // Restore the parameter value.
      parameters(i, j) += epsilon;

      // Compare numerical and backpropagation gradient values.
      BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 1e-2);
      BOOST_REQUIRE_CLOSE(numGradient3, gradient3(i, j), 1e-2);
    }
  }
}

BOOST_AUTO_TEST_CASE(SparseAutoencoderMoveTest)
{
  using SAE = mlpack::nn::SparseAutoencoder<>;

  SAE sae1(2, 2);
  sae1.Lambda(0.45);
  sae1.Beta(0.33);
  sae1.Rho(0.11);
  const auto Params = sae1.Parameters();

  SAE sae2(std::move(sae1));
  BOOST_REQUIRE(sae1.Parameters().n_elem == 0);
  BOOST_REQUIRE(sae1.VisibleSize() == sae2.VisibleSize());
  BOOST_REQUIRE(sae1.HiddenSize() == sae2.HiddenSize());
  BOOST_REQUIRE_CLOSE(sae1.Lambda(), sae2.Lambda(), 1e-5);
  BOOST_REQUIRE_CLOSE(sae1.Beta(), sae2.Beta(), 1e-5);
  BOOST_REQUIRE_CLOSE(sae1.Rho(), sae2.Rho(), 1e-5);

  const auto Params2 = sae2.Parameters();
  auto func = [](double lhs, double rhs)
  {
    BOOST_REQUIRE_CLOSE(lhs, rhs, 1e-5);
    return true;
  };
  std::equal(std::begin(Params), std::end(Params),
             std::begin(Params2),
             func);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>