<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/component/collision/DefaultContactManager.h>
#include <sofa/core/visual/VisualParams.h>
#include <sofa/core/ObjectFactory.h>

namespace sofa
{

namespace component
{

namespace collision
{

SOFA_DECL_CLASS(DefaultContactManager)

int DefaultContactManagerClass = core::RegisterObject("Default class to create reactions to the collisions")
        .add< DefaultContactManager >()
        .addAlias("CollisionResponse")
        ;

DefaultContactManager::DefaultContactManager()
    : response(initData(&response, "response", "contact response class"))
{
}

DefaultContactManager::~DefaultContactManager()
{
    // Contacts are now attached to the graph.
    // So they will be deleted by the DeleteVisitor
    // FIX crash on unload bug. -- J. Allard
    //clear();
}

sofa::helper::OptionsGroup DefaultContactManager::initializeResponseOptions(core::collision::Pipeline *pipeline)
{
    helper::set<std::string> listResponse;
    if (pipeline) listResponse=pipeline->getResponseList();
    else
    {
        core::collision::Contact::Factory::iterator it;
        for (it=core::collision::Contact::Factory::getInstance()->begin(); it!=core::collision::Contact::Factory::getInstance()->end(); ++it)
        {
            listResponse.insert(it->first);
        }
    }
    sofa::helper::OptionsGroup responseOptions(listResponse);
    if (listResponse.find("default") != listResponse.end())
        responseOptions.setSelectedItem("default");
    return responseOptions;
}

void DefaultContactManager::init()
{
    if (response.getValue().size() == 0)
    {
        core::collision::Pipeline *pipeline=static_cast<simulation::Node*>(getContext())->collisionPipeline;
        response.setValue(initializeResponseOptions(pipeline));
    }
}
void DefaultContactManager::cleanup()
{
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it=contacts.begin(); it!=contacts.end(); ++it)
    {
        (*it)->removeResponse();
        (*it)->cleanup();
        //delete *it;
        it->reset();
    }
    contacts.clear();
    contactMap.clear();
}

void DefaultContactManager::createContacts(DetectionOutputMap& outputsMap)
{
    //serr<<"DefaultContactManager::createContacts"<<sendl;

    //outputsMap.clear();
    //for (sofa::helper::vector<core::collision::DetectionOutput*>::const_iterator it = outputs.begin(); it!=outputs.end(); ++it)
    //{
    //	core::collision::DetectionOutput* o = *it;
    //	outputsMap[std::make_pair(o->elem.first.getCollisionModel(),o->elem.second.getCollisionModel())].push_back(o);
    //}

    // Remove any inactive contacts or add any new contact
    DetectionOutputMap::iterator outputsIt = outputsMap.begin();
    std::map< std::pair<core::CollisionModel*,core::CollisionModel*>, core::collision::Contact::SPtr >::iterator contactIt = contactMap.begin();
    int nbContact = 0;
    //static DetectionOutputVector emptyContacts;
    while (outputsIt!=outputsMap.end() || contactIt!=contactMap.end())
    {
        if (outputsIt!=outputsMap.end() && (contactIt == contactMap.end() || outputsIt->first < contactIt->first))
        {
            // new contact
            //sout << "Creation new "<<contacttype<<" contact"<<sendl;
            core::CollisionModel* model1 = outputsIt->first.first;
            core::CollisionModel* model2 = outputsIt->first.second;
            std::string responseUsed = getContactResponse(model1, model2);
            core::collision::Contact::SPtr contact = core::collision::Contact::Create(responseUsed, model1, model2, intersectionMethod);
            if (contact == NULL) serr << "Contact "<<responseUsed<<" between " << model1->getClassName()<<" and "<<model2->getClassName() << " creation failed"<<sendl;
            else
            {
                contactMap[std::make_pair(model1, model2)] = contact;
                contact->setName(model1->getName()+std::string("-")+model2->getName());
                contact->f_printLog.setValue(this->f_printLog.getValue());
                contact->init();
                contact->setDetectionOutputs(outputsIt->second);
                ++nbContact;
            }
            ++outputsIt;
        }
        else if (contactIt!=contactMap.end() && (outputsIt == outputsMap.end() || contactIt->first < outputsIt->first))
        {
            // inactive contact
            //sout << "Deleting inactive "<<contacttype<<" contact"<<sendl;
            if (contactIt->second->keepAlive())
            {
                contactIt->second->setDetectionOutputs(NULL);
                ++nbContact;
                ++contactIt;
            }
            else
            {
                std::map< std::pair<core::CollisionModel*,core::CollisionModel*>, core::collision::Contact::SPtr >::iterator contactIt2 = contactIt;
                ++contactIt2;
                contactIt->second->removeResponse();
                contactIt->second->cleanup();
                contactIt->second.reset();
                contactMap.erase(contactIt);
                contactIt = contactIt2;
            }
        }
        else
        {
            // corresponding contact and outputs
            contactIt->second->setDetectionOutputs(outputsIt->second);
            ++nbContact;
            ++outputsIt;
            ++contactIt;
        }
    }
    // now update contactVec
    contacts.clear();
    contacts.reserve(nbContact);
    contactIt = contactMap.begin();
    while (contactIt!=contactMap.end())
    {
        contacts.push_back(contactIt->second);
        ++contactIt;
    }
    // compute number of contacts attached to each collision model
    std::map<core::CollisionModel*,int> nbContactsMap;
    for (unsigned int i=0; i<contacts.size(); ++i)
    {
        std::pair< core::CollisionModel*, core::CollisionModel* > cms = contacts[i]->getCollisionModels();
        nbContactsMap[cms.first]++;
        if (cms.second != cms.first)
            nbContactsMap[cms.second]++;
    }
    sofa::helper::vector<core::CollisionModel*> collisionModels;
    simulation::Node* context = dynamic_cast<simulation::Node*>(getContext());
    context->getTreeObjects<core::CollisionModel>(&collisionModels);
    for (unsigned int i=0; i<collisionModels.size(); ++i)
    {
        collisionModels[i]->setNumberOfContacts(nbContactsMap[collisionModels[i]]);
    }
}

std::string DefaultContactManager::getContactResponse(core::CollisionModel* model1, core::CollisionModel* model2)
{
    std::string responseUsed = response.getValue().getSelectedItem();
    std::string response1 = model1->getContactResponse();
    std::string response2 = model2->getContactResponse();

    if (response1.empty()  &&  response2.empty()) return responseUsed;
    if (response1.empty()  && !response2.empty()) return response2;
    if (!response1.empty() &&  response2.empty()) return response1;

    if (response1 != response2) return responseUsed;
    else return response1;
}

void DefaultContactManager::draw(const core::visual::VisualParams* vparams)
{
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it = contacts.begin(); it!=contacts.end(); it++)
    {
        if ((*it)!=NULL)
            (*it)->draw(vparams);
    }
}

void DefaultContactManager::removeContacts(const ContactVector &c)
{
    ContactVector::const_iterator remove_it = c.begin();
    ContactVector::const_iterator remove_itEnd = c.end();

    ContactVector::iterator it;
    ContactVector::iterator itEnd;

    ContactMap::iterator map_it;
    ContactMap::iterator map_itEnd;

    while (remove_it != remove_itEnd)
    {
        // Whole scene contacts
        it = contacts.begin();
        itEnd = contacts.end();

        while (it != itEnd)
        {
            if (*it == *remove_it)
            {
                contacts.erase(it);
                break;
            }

            ++it;
        }

        // Stored contacts (keeping alive)
        map_it = contactMap.begin();
        map_itEnd = contactMap.end();

        while (map_it != map_itEnd)
        {
            if (map_it->second == *remove_it)
            {
                ContactMap::iterator erase_it = map_it;
                ++map_it;
                contactMap.erase(erase_it);
            }
            else
            {
                ++map_it;
            }
        }

        ++remove_it;
    }

}

} // namespace collision

} // namespace component

} // namespace sofa
<commit_msg>r11845/sofa-dev : ADD : creating a collision rule with "null" will create no response.<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/component/collision/DefaultContactManager.h>
#include <sofa/core/visual/VisualParams.h>
#include <sofa/core/ObjectFactory.h>

namespace sofa
{

namespace component
{

namespace collision
{

SOFA_DECL_CLASS(DefaultContactManager)

int DefaultContactManagerClass = core::RegisterObject("Default class to create reactions to the collisions")
        .add< DefaultContactManager >()
        .addAlias("CollisionResponse")
        ;

DefaultContactManager::DefaultContactManager()
    : response(initData(&response, "response", "contact response class"))
{
}

DefaultContactManager::~DefaultContactManager()
{
    // Contacts are now attached to the graph.
    // So they will be deleted by the DeleteVisitor
    // FIX crash on unload bug. -- J. Allard
    //clear();
}

sofa::helper::OptionsGroup DefaultContactManager::initializeResponseOptions(core::collision::Pipeline *pipeline)
{
    helper::set<std::string> listResponse;
    if (pipeline) listResponse=pipeline->getResponseList();
    else
    {
        core::collision::Contact::Factory::iterator it;
        for (it=core::collision::Contact::Factory::getInstance()->begin(); it!=core::collision::Contact::Factory::getInstance()->end(); ++it)
        {
            listResponse.insert(it->first);
        }
    }
    sofa::helper::OptionsGroup responseOptions(listResponse);
    if (listResponse.find("default") != listResponse.end())
        responseOptions.setSelectedItem("default");
    return responseOptions;
}

void DefaultContactManager::init()
{
    if (response.getValue().size() == 0)
    {
        core::collision::Pipeline *pipeline=static_cast<simulation::Node*>(getContext())->collisionPipeline;
        response.setValue(initializeResponseOptions(pipeline));
    }
}
void DefaultContactManager::cleanup()
{
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it=contacts.begin(); it!=contacts.end(); ++it)
    {
        (*it)->removeResponse();
        (*it)->cleanup();
        //delete *it;
        it->reset();
    }
    contacts.clear();
    contactMap.clear();
}

void DefaultContactManager::createContacts(DetectionOutputMap& outputsMap)
{
    //serr<<"DefaultContactManager::createContacts"<<sendl;

    //outputsMap.clear();
    //for (sofa::helper::vector<core::collision::DetectionOutput*>::const_iterator it = outputs.begin(); it!=outputs.end(); ++it)
    //{
    //	core::collision::DetectionOutput* o = *it;
    //	outputsMap[std::make_pair(o->elem.first.getCollisionModel(),o->elem.second.getCollisionModel())].push_back(o);
    //}

    // Remove any inactive contacts or add any new contact
    DetectionOutputMap::iterator outputsIt = outputsMap.begin();
    std::map< std::pair<core::CollisionModel*,core::CollisionModel*>, core::collision::Contact::SPtr >::iterator contactIt = contactMap.begin();
    int nbContact = 0;
    //static DetectionOutputVector emptyContacts;
    while (outputsIt!=outputsMap.end() || contactIt!=contactMap.end())
    {
        if (outputsIt!=outputsMap.end() && (contactIt == contactMap.end() || outputsIt->first < contactIt->first))
        {
            // new contact
            //sout << "Creation new "<<contacttype<<" contact"<<sendl;
            core::CollisionModel* model1 = outputsIt->first.first;
            core::CollisionModel* model2 = outputsIt->first.second;
            std::string responseUsed = getContactResponse(model1, model2);
            if(! responseUsed.compare("null") ) // We can create rules in order to not respond to specific collisions
            {
                ++outputsIt;
                continue;
            }
            core::collision::Contact::SPtr contact = core::collision::Contact::Create(responseUsed, model1, model2, intersectionMethod);
            if (contact == NULL) serr << "Contact "<<responseUsed<<" between " << model1->getClassName()<<" and "<<model2->getClassName() << " creation failed"<<sendl;
            else
            {
                contactMap[std::make_pair(model1, model2)] = contact;
                contact->setName(model1->getName()+std::string("-")+model2->getName());
                contact->f_printLog.setValue(this->f_printLog.getValue());
                contact->init();
                contact->setDetectionOutputs(outputsIt->second);
                ++nbContact;
            }
            ++outputsIt;
        }
        else if (contactIt!=contactMap.end() && (outputsIt == outputsMap.end() || contactIt->first < outputsIt->first))
        {
            // inactive contact
            //sout << "Deleting inactive "<<contacttype<<" contact"<<sendl;
            if (contactIt->second->keepAlive())
            {
                contactIt->second->setDetectionOutputs(NULL);
                ++nbContact;
                ++contactIt;
            }
            else
            {
                std::map< std::pair<core::CollisionModel*,core::CollisionModel*>, core::collision::Contact::SPtr >::iterator contactIt2 = contactIt;
                ++contactIt2;
                contactIt->second->removeResponse();
                contactIt->second->cleanup();
                contactIt->second.reset();
                contactMap.erase(contactIt);
                contactIt = contactIt2;
            }
        }
        else
        {
            // corresponding contact and outputs
            contactIt->second->setDetectionOutputs(outputsIt->second);
            ++nbContact;
            ++outputsIt;
            ++contactIt;
        }
    }
    // now update contactVec
    contacts.clear();
    contacts.reserve(nbContact);
    contactIt = contactMap.begin();
    while (contactIt!=contactMap.end())
    {
        contacts.push_back(contactIt->second);
        ++contactIt;
    }
    // compute number of contacts attached to each collision model
    std::map<core::CollisionModel*,int> nbContactsMap;
    for (unsigned int i=0; i<contacts.size(); ++i)
    {
        std::pair< core::CollisionModel*, core::CollisionModel* > cms = contacts[i]->getCollisionModels();
        nbContactsMap[cms.first]++;
        if (cms.second != cms.first)
            nbContactsMap[cms.second]++;
    }
    sofa::helper::vector<core::CollisionModel*> collisionModels;
    simulation::Node* context = dynamic_cast<simulation::Node*>(getContext());
    context->getTreeObjects<core::CollisionModel>(&collisionModels);
    for (unsigned int i=0; i<collisionModels.size(); ++i)
    {
        collisionModels[i]->setNumberOfContacts(nbContactsMap[collisionModels[i]]);
    }
}

std::string DefaultContactManager::getContactResponse(core::CollisionModel* model1, core::CollisionModel* model2)
{
    std::string responseUsed = response.getValue().getSelectedItem();
    std::string response1 = model1->getContactResponse();
    std::string response2 = model2->getContactResponse();

    if (response1.empty()  &&  response2.empty()) return responseUsed;
    if (response1.empty()  && !response2.empty()) return response2;
    if (!response1.empty() &&  response2.empty()) return response1;

    if (response1 != response2) return responseUsed;
    else return response1;
}

void DefaultContactManager::draw(const core::visual::VisualParams* vparams)
{
    for (sofa::helper::vector<core::collision::Contact::SPtr>::iterator it = contacts.begin(); it!=contacts.end(); it++)
    {
        if ((*it)!=NULL)
            (*it)->draw(vparams);
    }
}

void DefaultContactManager::removeContacts(const ContactVector &c)
{
    ContactVector::const_iterator remove_it = c.begin();
    ContactVector::const_iterator remove_itEnd = c.end();

    ContactVector::iterator it;
    ContactVector::iterator itEnd;

    ContactMap::iterator map_it;
    ContactMap::iterator map_itEnd;

    while (remove_it != remove_itEnd)
    {
        // Whole scene contacts
        it = contacts.begin();
        itEnd = contacts.end();

        while (it != itEnd)
        {
            if (*it == *remove_it)
            {
                contacts.erase(it);
                break;
            }

            ++it;
        }

        // Stored contacts (keeping alive)
        map_it = contactMap.begin();
        map_itEnd = contactMap.end();

        while (map_it != map_itEnd)
        {
            if (map_it->second == *remove_it)
            {
                ContactMap::iterator erase_it = map_it;
                ++map_it;
                contactMap.erase(erase_it);
            }
            else
            {
                ++map_it;
            }
        }

        ++remove_it;
    }

}

} // namespace collision

} // namespace component

} // namespace sofa
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file includes definitions for IPv6 network interfaces.
 */

#ifndef NET_NETIF_HPP_
#define NET_NETIF_HPP_

#include "openthread-core-config.h"

#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/tasklet.hpp"
#include "mac/mac_types.hpp"
#include "net/ip6_address.hpp"
#include "net/socket.hpp"

namespace ot {
namespace Ip6 {

class Ip6;

/**
 * @addtogroup core-ip6-netif
 *
 * @brief
 *   This module includes definitions for IPv6 network interfaces.
 *
 * @{
 *
 */

/**
 * This class represents an IPv6 Link Address.
 *
 */
class LinkAddress
{
public:
    /**
     * Hardware types.
     *
     */
    enum HardwareType
    {
        kEui64 = 27,
    };
    HardwareType    mType;       ///< Link address type.
    uint8_t         mLength;     ///< Length of link address.
    Mac::ExtAddress mExtAddress; ///< Link address.
};

/**
 * This class implements an IPv6 network interface unicast address.
 *
 */
class NetifUnicastAddress : public otNetifAddress
{
    friend class Netif;

public:
    /**
     * This method returns the unicast address.
     *
     * @returns The unicast address.
     *
     */
    const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }

    /**
     * This method returns the unicast address.
     *
     * @returns The unicast address.
     *
     */
    Address &GetAddress(void) { return static_cast<Address &>(mAddress); }

    /**
     * This method returns the IPv6 scope value.
     *
     * @returns The IPv6 scope value.
     *
     */
    uint8_t GetScope(void) const
    {
        return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope();
    }

    /**
     * This method returns the next unicast address assigned to the interface.
     *
     * @returns A pointer to the next unicast address.
     *
     */
    const NetifUnicastAddress *GetNext(void) const { return static_cast<const NetifUnicastAddress *>(mNext); }

    /**
     * This method returns the next unicast address assigned to the interface.
     *
     * @returns A pointer to the next unicast address.
     *
     */
    NetifUnicastAddress *GetNext(void) { return static_cast<NetifUnicastAddress *>(mNext); }
};

/**
 * This class implements an IPv6 network interface multicast address.
 *
 */
class NetifMulticastAddress : public otNetifMulticastAddress
{
    friend class Netif;

public:
    /**
     * This method returns the multicast address.
     *
     * @returns The multicast address.
     *
     */
    const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }

    /**
     * This method returns the multicast address.
     *
     * @returns The multicast address.
     *
     */
    Address &GetAddress(void) { return static_cast<Address &>(mAddress); }

    /**
     * This method returns the next multicast address subscribed to the interface.
     *
     * @returns A pointer to the next multicast address.
     *
     */
    const NetifMulticastAddress *GetNext(void) const { return static_cast<const NetifMulticastAddress *>(mNext); }

    /**
     * This method returns the next multicast address subscribed to the interface.
     *
     * @returns A pointer to the next multicast address.
     *
     */
    NetifMulticastAddress *GetNext(void)
    {
        return static_cast<NetifMulticastAddress *>(const_cast<otNetifMulticastAddress *>(mNext));
    }
};

/**
 * This class implements an IPv6 network interface.
 *
 */
class Netif : public InstanceLocator
{
    friend class Ip6;

public:
    /**
     * This constructor initializes the network interface.
     *
     * @param[in]  aInstance        A reference to the OpenThread instance.
     *
     */
    Netif(Instance &aInstance);

    /**
     * This method returns the next network interface in the list.
     *
     * @returns A pointer to the next network interface.
     */
    Netif *GetNext(void) const { return mNext; }

    /**
     * This method registers a callback to notify internal IPv6 address changes.
     *
     * @param[in]  aCallback         A pointer to a function that is called when an IPv6 address is added or removed.
     * @param[in]  aCallbackContext  A pointer to application-specific context.
     *
     */
    void SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext);

    /**
     * This method returns a pointer to the list of unicast addresses.
     *
     * @returns A pointer to the list of unicast addresses.
     *
     */
    const NetifUnicastAddress *GetUnicastAddresses(void) const { return mUnicastAddresses; }

    /**
     * This method adds a unicast address to the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE      Successfully added the unicast address.
     * @retval OT_ERROR_ALREADY  The unicast address was already added.
     *
     */
    otError AddUnicastAddress(NetifUnicastAddress &aAddress);

    /**
     * This method removes a unicast address from the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE       Successfully removed the unicast address.
     * @retval OT_ERROR_NOT_FOUND  The unicast address wasn't found to be removed.
     *
     */
    otError RemoveUnicastAddress(const NetifUnicastAddress &aAddress);

    /**
     * This method adds an external (to OpenThread) unicast address to the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE          Successfully added (or updated) the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NO_BUFS       The maximum number of allowed external addresses are already added.
     *
     */
    otError AddExternalUnicastAddress(const NetifUnicastAddress &aAddress);

    /**
     * This method removes a external (to OpenThread) unicast address from the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE          Successfully removed the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NOT_FOUND     The unicast address was not found.
     *
     */
    otError RemoveExternalUnicastAddress(const Address &aAddress);

    /**
     * This method removes all the previously added external (to OpenThread) unicast addresses from the
     * network interface.
     *
     */
    void RemoveAllExternalUnicastAddresses(void);

    /**
     * This method indicates whether or not an address is assigned to this interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @returns TRUE if @p aAddress is assigned to this interface, FALSE otherwise.
     *
     */
    bool IsUnicastAddress(const Address &aAddress) const;

    /**
     * This method indicates whether or not the network interface is subscribed to a multicast address.
     *
     * @param[in]  aAddress  The multicast address to check.
     *
     * @retval TRUE   If the network interface is subscribed to @p aAddress.
     * @retval FALSE  If the network interface is not subscribed to @p aAddress.
     *
     */
    bool IsMulticastSubscribed(const Address &aAddress) const;

    /**
     * This method subscribes the network interface to the link-local and realm-local all routers address.
     *
     * @retval OT_ERROR_NONE     Successfully subscribed to the link-local and realm-local all routers address
     * @retval OT_ERROR_ALREADY  The multicast addresses are already subscribed.
     *
     */
    otError SubscribeAllRoutersMulticast(void);

    /**
     * This method unsubscribes the network interface to the link-local and realm-local all routers address.
     *
     * @retval OT_ERROR_NONE       Successfully unsubscribed from the link-local and realm-local all routers address
     * @retval OT_ERROR_NOT_FOUND  The multicast addresses were not found.
     *
     */
    otError UnsubscribeAllRoutersMulticast(void);

    /**
     * This method returns a pointer to the list of multicast addresses.
     *
     * @returns A pointer to the list of multicast addresses.
     *
     */
    const NetifMulticastAddress *GetMulticastAddresses(void) const { return mMulticastAddresses; }

    /**
     * This method subscribes the network interface to a multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE     Successfully subscribed to @p aAddress.
     * @retval OT_ERROR_ALREADY  The multicast address is already subscribed.
     *
     */
    otError SubscribeMulticast(NetifMulticastAddress &aAddress);

    /**
     * This method unsubscribes the network interface to a multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE       Successfully unsubscribed @p aAddress.
     * @retval OT_ERROR_NOT_FOUND  The multicast address was not found.
     *
     */
    otError UnsubscribeMulticast(const NetifMulticastAddress &aAddress);

    /**
     * This method provides the next external multicast address that the network interface subscribed.
     * It is used to iterate through the entries of the external multicast address table.
     *
     * @param[inout] aIterator A reference to the iterator context. To get the first
     *                         external multicast address, it should be set to 0.
     * @param[out]   aAddress  A reference where to place the external multicast address.
     *
     * @retval OT_ERROR_NONE       Successfully found the next external multicast address.
     * @retval OT_ERROR_NOT_FOUND  No subsequent external multicast address.
     *
     */
    otError GetNextExternalMulticast(uint8_t &aIterator, Address &aAddress) const;

    /**
     * This method subscribes the network interface to the external (to OpenThread) multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE           Successfully subscribed to @p aAddress.
     * @retval OT_ERROR_ALREADY        The multicast address is already subscribed.
     * @retval OT_ERROR_INVALID_ARGS   The address indicated by @p aAddress is an internal multicast address.
     * @retval OT_ERROR_INVALID_STATE  The Network Interface is not up.
     * @retval OT_ERROR_NO_BUFS        The maximum number of allowed external multicast addresses are already added.
     *
     */
    otError SubscribeExternalMulticast(const Address &aAddress);

    /**
     * This method unsubscribes the network interface to the external (to OpenThread) multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE          Successfully unsubscribed to the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NOT_FOUND     The multicast address was not found.
     *
     */
    otError UnsubscribeExternalMulticast(const Address &aAddress);

    /**
     * This method unsubscribes the network interface from all previously added external (to OpenThread) multicast
     * addresses.
     */
    void UnsubscribeAllExternalMulticastAddresses(void);

    /**
     * This method checks if multicast promiscuous mode is enabled on the network interface.
     *
     * @retval TRUE   If the multicast promiscuous mode is enabled.
     * @retval FALSE  If the multicast promiscuous mode is disabled.
     */
    bool IsMulticastPromiscuousEnabled(void) const { return mMulticastPromiscuous; }

    /**
     * This method enables multicast promiscuous mode on the network interface.
     *
     * @param[in]  aEnabled  TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise.
     *
     */
    void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; }

protected:
    /**
     * This method subscribes the network interface to the realm-local all MPL forwarders, link-local and
     * realm-local all nodes address.
     *
     */
    void SubscribeAllNodesMulticast(void);

    /**
     * This method unsubscribes the network interface from the realm-local all MPL forwarders, link-local and
     * realm-local all nodes address.
     *
     */
    void UnsubscribeAllNodesMulticast(void);

private:
    enum
    {
        kMulticastPrefixLength = 128, ///< Multicast prefix length used to notify internal address changes.
    };

    NetifUnicastAddress *  mUnicastAddresses;
    NetifMulticastAddress *mMulticastAddresses;
    bool                   mMulticastPromiscuous;
    Netif *                mNext;

    otIp6AddressCallback mAddressCallback;
    void *               mAddressCallbackContext;

    NetifUnicastAddress   mExtUnicastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS];
    NetifMulticastAddress mExtMulticastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS];

    static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress;
    static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress;
    static const otNetifMulticastAddress kRealmLocalAllNodesMulticastAddress;
    static const otNetifMulticastAddress kLinkLocalAllRoutersMulticastAddress;
    static const otNetifMulticastAddress kRealmLocalAllRoutersMulticastAddress;
};

/**
 * @}
 *
 */

} // namespace Ip6
} // namespace ot

#endif // NET_NETIF_HPP_
<commit_msg>[netif] remove unused type LinkAddress (#4308)<commit_after>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file includes definitions for IPv6 network interfaces.
 */

#ifndef NET_NETIF_HPP_
#define NET_NETIF_HPP_

#include "openthread-core-config.h"

#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/tasklet.hpp"
#include "mac/mac_types.hpp"
#include "net/ip6_address.hpp"
#include "net/socket.hpp"

namespace ot {
namespace Ip6 {

class Ip6;

/**
 * @addtogroup core-ip6-netif
 *
 * @brief
 *   This module includes definitions for IPv6 network interfaces.
 *
 * @{
 *
 */

/**
 * This class implements an IPv6 network interface unicast address.
 *
 */
class NetifUnicastAddress : public otNetifAddress
{
    friend class Netif;

public:
    /**
     * This method returns the unicast address.
     *
     * @returns The unicast address.
     *
     */
    const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }

    /**
     * This method returns the unicast address.
     *
     * @returns The unicast address.
     *
     */
    Address &GetAddress(void) { return static_cast<Address &>(mAddress); }

    /**
     * This method returns the IPv6 scope value.
     *
     * @returns The IPv6 scope value.
     *
     */
    uint8_t GetScope(void) const
    {
        return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope();
    }

    /**
     * This method returns the next unicast address assigned to the interface.
     *
     * @returns A pointer to the next unicast address.
     *
     */
    const NetifUnicastAddress *GetNext(void) const { return static_cast<const NetifUnicastAddress *>(mNext); }

    /**
     * This method returns the next unicast address assigned to the interface.
     *
     * @returns A pointer to the next unicast address.
     *
     */
    NetifUnicastAddress *GetNext(void) { return static_cast<NetifUnicastAddress *>(mNext); }
};

/**
 * This class implements an IPv6 network interface multicast address.
 *
 */
class NetifMulticastAddress : public otNetifMulticastAddress
{
    friend class Netif;

public:
    /**
     * This method returns the multicast address.
     *
     * @returns The multicast address.
     *
     */
    const Address &GetAddress(void) const { return static_cast<const Address &>(mAddress); }

    /**
     * This method returns the multicast address.
     *
     * @returns The multicast address.
     *
     */
    Address &GetAddress(void) { return static_cast<Address &>(mAddress); }

    /**
     * This method returns the next multicast address subscribed to the interface.
     *
     * @returns A pointer to the next multicast address.
     *
     */
    const NetifMulticastAddress *GetNext(void) const { return static_cast<const NetifMulticastAddress *>(mNext); }

    /**
     * This method returns the next multicast address subscribed to the interface.
     *
     * @returns A pointer to the next multicast address.
     *
     */
    NetifMulticastAddress *GetNext(void)
    {
        return static_cast<NetifMulticastAddress *>(const_cast<otNetifMulticastAddress *>(mNext));
    }
};

/**
 * This class implements an IPv6 network interface.
 *
 */
class Netif : public InstanceLocator
{
    friend class Ip6;

public:
    /**
     * This constructor initializes the network interface.
     *
     * @param[in]  aInstance        A reference to the OpenThread instance.
     *
     */
    Netif(Instance &aInstance);

    /**
     * This method returns the next network interface in the list.
     *
     * @returns A pointer to the next network interface.
     */
    Netif *GetNext(void) const { return mNext; }

    /**
     * This method registers a callback to notify internal IPv6 address changes.
     *
     * @param[in]  aCallback         A pointer to a function that is called when an IPv6 address is added or removed.
     * @param[in]  aCallbackContext  A pointer to application-specific context.
     *
     */
    void SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext);

    /**
     * This method returns a pointer to the list of unicast addresses.
     *
     * @returns A pointer to the list of unicast addresses.
     *
     */
    const NetifUnicastAddress *GetUnicastAddresses(void) const { return mUnicastAddresses; }

    /**
     * This method adds a unicast address to the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE      Successfully added the unicast address.
     * @retval OT_ERROR_ALREADY  The unicast address was already added.
     *
     */
    otError AddUnicastAddress(NetifUnicastAddress &aAddress);

    /**
     * This method removes a unicast address from the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE       Successfully removed the unicast address.
     * @retval OT_ERROR_NOT_FOUND  The unicast address wasn't found to be removed.
     *
     */
    otError RemoveUnicastAddress(const NetifUnicastAddress &aAddress);

    /**
     * This method adds an external (to OpenThread) unicast address to the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE          Successfully added (or updated) the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NO_BUFS       The maximum number of allowed external addresses are already added.
     *
     */
    otError AddExternalUnicastAddress(const NetifUnicastAddress &aAddress);

    /**
     * This method removes a external (to OpenThread) unicast address from the network interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @retval OT_ERROR_NONE          Successfully removed the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NOT_FOUND     The unicast address was not found.
     *
     */
    otError RemoveExternalUnicastAddress(const Address &aAddress);

    /**
     * This method removes all the previously added external (to OpenThread) unicast addresses from the
     * network interface.
     *
     */
    void RemoveAllExternalUnicastAddresses(void);

    /**
     * This method indicates whether or not an address is assigned to this interface.
     *
     * @param[in]  aAddress  A reference to the unicast address.
     *
     * @returns TRUE if @p aAddress is assigned to this interface, FALSE otherwise.
     *
     */
    bool IsUnicastAddress(const Address &aAddress) const;

    /**
     * This method indicates whether or not the network interface is subscribed to a multicast address.
     *
     * @param[in]  aAddress  The multicast address to check.
     *
     * @retval TRUE   If the network interface is subscribed to @p aAddress.
     * @retval FALSE  If the network interface is not subscribed to @p aAddress.
     *
     */
    bool IsMulticastSubscribed(const Address &aAddress) const;

    /**
     * This method subscribes the network interface to the link-local and realm-local all routers address.
     *
     * @retval OT_ERROR_NONE     Successfully subscribed to the link-local and realm-local all routers address
     * @retval OT_ERROR_ALREADY  The multicast addresses are already subscribed.
     *
     */
    otError SubscribeAllRoutersMulticast(void);

    /**
     * This method unsubscribes the network interface to the link-local and realm-local all routers address.
     *
     * @retval OT_ERROR_NONE       Successfully unsubscribed from the link-local and realm-local all routers address
     * @retval OT_ERROR_NOT_FOUND  The multicast addresses were not found.
     *
     */
    otError UnsubscribeAllRoutersMulticast(void);

    /**
     * This method returns a pointer to the list of multicast addresses.
     *
     * @returns A pointer to the list of multicast addresses.
     *
     */
    const NetifMulticastAddress *GetMulticastAddresses(void) const { return mMulticastAddresses; }

    /**
     * This method subscribes the network interface to a multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE     Successfully subscribed to @p aAddress.
     * @retval OT_ERROR_ALREADY  The multicast address is already subscribed.
     *
     */
    otError SubscribeMulticast(NetifMulticastAddress &aAddress);

    /**
     * This method unsubscribes the network interface to a multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE       Successfully unsubscribed @p aAddress.
     * @retval OT_ERROR_NOT_FOUND  The multicast address was not found.
     *
     */
    otError UnsubscribeMulticast(const NetifMulticastAddress &aAddress);

    /**
     * This method provides the next external multicast address that the network interface subscribed.
     * It is used to iterate through the entries of the external multicast address table.
     *
     * @param[inout] aIterator A reference to the iterator context. To get the first
     *                         external multicast address, it should be set to 0.
     * @param[out]   aAddress  A reference where to place the external multicast address.
     *
     * @retval OT_ERROR_NONE       Successfully found the next external multicast address.
     * @retval OT_ERROR_NOT_FOUND  No subsequent external multicast address.
     *
     */
    otError GetNextExternalMulticast(uint8_t &aIterator, Address &aAddress) const;

    /**
     * This method subscribes the network interface to the external (to OpenThread) multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE           Successfully subscribed to @p aAddress.
     * @retval OT_ERROR_ALREADY        The multicast address is already subscribed.
     * @retval OT_ERROR_INVALID_ARGS   The address indicated by @p aAddress is an internal multicast address.
     * @retval OT_ERROR_INVALID_STATE  The Network Interface is not up.
     * @retval OT_ERROR_NO_BUFS        The maximum number of allowed external multicast addresses are already added.
     *
     */
    otError SubscribeExternalMulticast(const Address &aAddress);

    /**
     * This method unsubscribes the network interface to the external (to OpenThread) multicast address.
     *
     * @param[in]  aAddress  A reference to the multicast address.
     *
     * @retval OT_ERROR_NONE          Successfully unsubscribed to the unicast address.
     * @retval OT_ERROR_INVALID_ARGS  The address indicated by @p aAddress is an internal address.
     * @retval OT_ERROR_NOT_FOUND     The multicast address was not found.
     *
     */
    otError UnsubscribeExternalMulticast(const Address &aAddress);

    /**
     * This method unsubscribes the network interface from all previously added external (to OpenThread) multicast
     * addresses.
     */
    void UnsubscribeAllExternalMulticastAddresses(void);

    /**
     * This method checks if multicast promiscuous mode is enabled on the network interface.
     *
     * @retval TRUE   If the multicast promiscuous mode is enabled.
     * @retval FALSE  If the multicast promiscuous mode is disabled.
     */
    bool IsMulticastPromiscuousEnabled(void) const { return mMulticastPromiscuous; }

    /**
     * This method enables multicast promiscuous mode on the network interface.
     *
     * @param[in]  aEnabled  TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise.
     *
     */
    void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; }

protected:
    /**
     * This method subscribes the network interface to the realm-local all MPL forwarders, link-local and
     * realm-local all nodes address.
     *
     */
    void SubscribeAllNodesMulticast(void);

    /**
     * This method unsubscribes the network interface from the realm-local all MPL forwarders, link-local and
     * realm-local all nodes address.
     *
     */
    void UnsubscribeAllNodesMulticast(void);

private:
    enum
    {
        kMulticastPrefixLength = 128, ///< Multicast prefix length used to notify internal address changes.
    };

    NetifUnicastAddress *  mUnicastAddresses;
    NetifMulticastAddress *mMulticastAddresses;
    bool                   mMulticastPromiscuous;
    Netif *                mNext;

    otIp6AddressCallback mAddressCallback;
    void *               mAddressCallbackContext;

    NetifUnicastAddress   mExtUnicastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS];
    NetifMulticastAddress mExtMulticastAddresses[OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS];

    static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress;
    static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress;
    static const otNetifMulticastAddress kRealmLocalAllNodesMulticastAddress;
    static const otNetifMulticastAddress kLinkLocalAllRoutersMulticastAddress;
    static const otNetifMulticastAddress kRealmLocalAllRoutersMulticastAddress;
};

/**
 * @}
 *
 */

} // namespace Ip6
} // namespace ot

#endif // NET_NETIF_HPP_
<|endoftext|>


<commit_before>#include <libport/finally.hh>

#include <ast/parametric-ast.hh>
#include <flower/flower.hh>
#include <object/urbi-exception.hh>
#include <parser/parse.hh>
#include <parser/parser-impl.hh>

namespace flower
{
  using ast::ParametricAst;
  using libport::Finally;
  using libport::scoped_set;

  Flower::Flower()
    : in_function_(false)
    , in_loop_(false)
  {}

  void
  Flower::visit(const ast::Break* b)
  {
    if (!in_loop_)
      errors_.error(b->location_get(), "break: outside a loop");

    has_break_ = true;

    static ParametricAst res("'$loopBreakTag'.stop");
    result_ = exp(res);
    result_->original_set(b);
  }

  void
  Flower::visit(const ast::Continue* c)
  {
    if (!in_loop_)
      errors_.error(c->location_get(), "continue: outside a loop");

    has_continue_ = true;

    static ParametricAst res("'$loopContinueTag'.stop");
    result_ = exp(res);
    result_->original_set(c);
  }

  static inline
  ast::rExp
  brk(ast::rExp e)
  {
    static ParametricAst brk(
      "{var '$loopBreakTag' = Tag.newFlowControl(\"loopBreakTag\") |"
      "'$loopBreakTag': %exp:1}");

    return exp(brk % e);
  }

  static inline
  ast::rExp
  cont(ast::rExp e)
  {
    static ParametricAst cont(
      "{var '$loopContinueTag' = Tag.newFlowControl(\"loopContinueTag\") |"
      "'$loopContinueTag': %exp:1}");

    return exp(cont % e);
  }

  // The expansion of a try/catch block looks as follow:
  //    try
  //    {
  //     computation
  //    }
  //    catch (Proto e1)
  //    {
  //      use(e1);
  //    }
  //    catch (e2)
  //    {
  //      use(e2);
  //    }
  // becomes
  //    var $previousHandlerTag = currentRunner.exceptionHandlerTag |
  //    var $noExceptionTag = Tag.newFlowControl("noExceptionTag") |
  //    currentRunner.exceptionHandlerTag = Tag.newFlowControl("handlerTag") |
  //    $noExceptionTag: {
  //      var $exception = {
  //        currentRunner.exceptionHandlerTag: {
  //          var $res = computation |
  //          /* No exception occurred, restore handler */
  //          currentRunner.exceptionHandlerTag = $previousHandlerTag |
  //          $noExceptionTag.stop($res)
  //        }
  //      }
  //      /* An exception occurred, restore handler and handle it */
  //      currentRunner.exceptionHandlerTag = $previousHandlerTag |
  //      if ($exception.isA(Proto)) {
  //        var e1 = $exception |
  //        $noExceptionTag.stop(use(e1))
  //      } |
  //      var e2 = $exception |
  //      use(e2) |
  //      throw $exception
  //    }
  //
  // The expansion of
  //    throw(exc)
  // gives
  //    currentRunner.exceptionHandlerTag.stop(exc)

  void
  Flower::visit(const ast::Try* n)
  {
    if (n->handlers_get().empty())
      errors_.error(n->location_get(), "invalid: `try' without 'catch'");

    Finally finally;
    finally << scoped_set(catch_all_, 0U);

    ast::rNary new_handlers = new ast::Nary;
    foreach(const ast::rConstExp e, n->handlers_get())
      new_handlers->push_back(recurse(e));

    static ParametricAst try_block
      ("var '$previousHandlerTag' = currentRunner.exceptionHandlerTag |"
       "var '$noExceptionTag' = Tag.newFlowControl(\"noExceptionTag\") |"
       "currentRunner.exceptionHandlerTag = Tag.newFlowControl(\"handlerTag\") |"
       "'$noExceptionTag': {"
       "  var '$exception' = {"
       "    currentRunner.exceptionHandlerTag: {"
       "      var '$res' = %exp:1 |"
       "      currentRunner.exceptionHandlerTag = '$previousHandlerTag' |"
       "      '$noExceptionTag'.stop('$res')"
       "    }"
       "  } |"
       "  currentRunner.exceptionHandlerTag = '$previousHandlerTag' |"
       "  %exp:2 |"
       "  currentRunner.exceptionHandlerTag.stop('$exception')"
       "}");

    result_ = exp(try_block % recurse(n->body_get()) % new_handlers);
    result_->original_set(n);
  }

  void
  Flower::visit(const ast::Catch* c)
  {
    if (catch_all_)
      errors_.error(c->location_get(), "`catch' clause after catch-all clause");

    if (!c->match_get())
      ++catch_all_;

    static ParametricAst body("var %id:1 = '$exception' | "
			      "'$noExceptionTag'.stop(%exp:2)");
    ast::rExp res = exp(body % c->name_get() % recurse(c->body_get()));

    if (c->match_get())
    {
      static ParametricAst test("if ('$exception'.isA(%exp:1)) %exp:2");
      res = exp(test % recurse(c->match_get()) % res);
    }

    result_ = res;
    result_->original_set(c);
  }

  void
  Flower::visit(const ast::Throw* t)
  {
    static ParametricAst res("currentRunner.exceptionHandlerTag.stop(%exp:1)");
    result_ = exp(res % recurse(t->value_get()));
    result_->original_set(t);
  }

  void
  Flower::visit(const ast::While* code)
  {
    Finally finally;
    finally << scoped_set(in_loop_, true)
            << scoped_set(has_break_, false)
            << scoped_set(has_continue_, false);

    ast::rExp res = recurse(code->body_get()->body_get());

    if (has_continue_)
      res = cont(res.get());

    static ParametricAst whle("while (%exp:1) %exp:2");
    res = exp(whle % recurse(code->test_get()) % res);
    res.unchecked_cast<ast::While>()->flavor_set(code->flavor_get());

    if (has_break_)
      res = brk(res);

    result_ = res;
    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Foreach* code)
  {
    Finally finally;
    finally << scoped_set(in_loop_, true)
            << scoped_set(has_break_, false)
            << scoped_set(has_continue_, false);

    static ParametricAst each("%exp:1 . %id:2 (%exp:3)");
    each % recurse(code->list_get());

    switch (code->flavor_get())
    {
    case ast::flavor_none:
    case ast::flavor_semicolon:
    case ast::flavor_pipe:
      each % SYMBOL(each);
      break;
    case ast::flavor_and:
      each % SYMBOL(each_AMPERSAND);
      break;
    case ast::flavor_comma:
      each.clear();
      errors_.error(code->location_get(), "invalid flavor: `for,'");
      return;
    }

    ast::rExp body = recurse(code->body_get());
    if (has_continue_)
      body = cont(body);

    // 'fillme' is a placeholder filled later. Parametric ASTs can't
    // parametrize formal arguments for now.
    static ParametricAst closure("closure (fillme) {%exp:1}");
    ast::rClosure c = (closure % body).result<ast::Closure>();
    // Rename the 'fillme' closure formal argument
    c->formals_get()->front()->what_set(code->index_get()->what_get());
    each % c;

    if (has_break_)
      result_ = brk(exp(each));
    else
      result_ = exp(each);

    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Function* code)
  {
    Finally finally;
    finally << scoped_set(in_function_, true)
            << scoped_set(has_return_, false);
    super_type::visit(code);
    if (has_return_)
    {
      static ast::ParametricAst a("var '$returnTag' = "
				  "Tag.newFlowControl(\"returnTag\") | "
                                  "'$returnTag': %exp:1");
      ast::rScope copy =
        result_.unsafe_cast<ast::Function>()->body_get();
      copy->body_set(exp(a % copy->body_get()));
    }
    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Return* ret)
  {
    if (!in_function_)
      errors_.error(ret->location_get(), "return: outside a function");

    has_return_ = true;

    if (ast::rExp e = ret->value_get())
    {
      static ParametricAst a("'$returnTag'.stop(%exp:1)");
      result_ = exp(a % e);
    }
    else
    {
      static ParametricAst a("'$returnTag'.stop");
      result_ = exp(a);
    }

    result_->original_set(ret);
  }

} // namespace flower
<commit_msg>Fix speed compilation: include cloner.hxx.<commit_after>#include <libport/finally.hh>

#include <ast/cloner.hxx>
#include <ast/parametric-ast.hh>

#include <flower/flower.hh>

#include <object/urbi-exception.hh>

#include <parser/parse.hh>
#include <parser/parser-impl.hh>

namespace flower
{
  using ast::ParametricAst;
  using libport::Finally;
  using libport::scoped_set;

  Flower::Flower()
    : in_function_(false)
    , in_loop_(false)
  {}

  void
  Flower::visit(const ast::Break* b)
  {
    if (!in_loop_)
      errors_.error(b->location_get(), "break: outside a loop");

    has_break_ = true;

    static ParametricAst res("'$loopBreakTag'.stop");
    result_ = exp(res);
    result_->original_set(b);
  }

  void
  Flower::visit(const ast::Continue* c)
  {
    if (!in_loop_)
      errors_.error(c->location_get(), "continue: outside a loop");

    has_continue_ = true;

    static ParametricAst res("'$loopContinueTag'.stop");
    result_ = exp(res);
    result_->original_set(c);
  }

  static inline
  ast::rExp
  brk(ast::rExp e)
  {
    static ParametricAst brk(
      "{var '$loopBreakTag' = Tag.newFlowControl(\"loopBreakTag\") |"
      "'$loopBreakTag': %exp:1}");

    return exp(brk % e);
  }

  static inline
  ast::rExp
  cont(ast::rExp e)
  {
    static ParametricAst cont(
      "{var '$loopContinueTag' = Tag.newFlowControl(\"loopContinueTag\") |"
      "'$loopContinueTag': %exp:1}");

    return exp(cont % e);
  }

  // The expansion of a try/catch block looks as follow:
  //    try
  //    {
  //     computation
  //    }
  //    catch (Proto e1)
  //    {
  //      use(e1);
  //    }
  //    catch (e2)
  //    {
  //      use(e2);
  //    }
  // becomes
  //    var $previousHandlerTag = currentRunner.exceptionHandlerTag |
  //    var $noExceptionTag = Tag.newFlowControl("noExceptionTag") |
  //    currentRunner.exceptionHandlerTag = Tag.newFlowControl("handlerTag") |
  //    $noExceptionTag: {
  //      var $exception = {
  //        currentRunner.exceptionHandlerTag: {
  //          var $res = computation |
  //          /* No exception occurred, restore handler */
  //          currentRunner.exceptionHandlerTag = $previousHandlerTag |
  //          $noExceptionTag.stop($res)
  //        }
  //      }
  //      /* An exception occurred, restore handler and handle it */
  //      currentRunner.exceptionHandlerTag = $previousHandlerTag |
  //      if ($exception.isA(Proto)) {
  //        var e1 = $exception |
  //        $noExceptionTag.stop(use(e1))
  //      } |
  //      var e2 = $exception |
  //      use(e2) |
  //      throw $exception
  //    }
  //
  // The expansion of
  //    throw(exc)
  // gives
  //    currentRunner.exceptionHandlerTag.stop(exc)

  void
  Flower::visit(const ast::Try* n)
  {
    if (n->handlers_get().empty())
      errors_.error(n->location_get(), "invalid: `try' without 'catch'");

    Finally finally;
    finally << scoped_set(catch_all_, 0U);

    ast::rNary new_handlers = new ast::Nary;
    foreach(const ast::rConstExp e, n->handlers_get())
      new_handlers->push_back(recurse(e));

    static ParametricAst try_block
      ("var '$previousHandlerTag' = currentRunner.exceptionHandlerTag |"
       "var '$noExceptionTag' = Tag.newFlowControl(\"noExceptionTag\") |"
       "currentRunner.exceptionHandlerTag = Tag.newFlowControl(\"handlerTag\") |"
       "'$noExceptionTag': {"
       "  var '$exception' = {"
       "    currentRunner.exceptionHandlerTag: {"
       "      var '$res' = %exp:1 |"
       "      currentRunner.exceptionHandlerTag = '$previousHandlerTag' |"
       "      '$noExceptionTag'.stop('$res')"
       "    }"
       "  } |"
       "  currentRunner.exceptionHandlerTag = '$previousHandlerTag' |"
       "  %exp:2 |"
       "  currentRunner.exceptionHandlerTag.stop('$exception')"
       "}");

    result_ = exp(try_block % recurse(n->body_get()) % new_handlers);
    result_->original_set(n);
  }

  void
  Flower::visit(const ast::Catch* c)
  {
    if (catch_all_)
      errors_.error(c->location_get(), "`catch' clause after catch-all clause");

    if (!c->match_get())
      ++catch_all_;

    static ParametricAst body("var %id:1 = '$exception' | "
			      "'$noExceptionTag'.stop(%exp:2)");
    ast::rExp res = exp(body % c->name_get() % recurse(c->body_get()));

    if (c->match_get())
    {
      static ParametricAst test("if ('$exception'.isA(%exp:1)) %exp:2");
      res = exp(test % recurse(c->match_get()) % res);
    }

    result_ = res;
    result_->original_set(c);
  }

  void
  Flower::visit(const ast::Throw* t)
  {
    static ParametricAst res("currentRunner.exceptionHandlerTag.stop(%exp:1)");
    result_ = exp(res % recurse(t->value_get()));
    result_->original_set(t);
  }

  void
  Flower::visit(const ast::While* code)
  {
    Finally finally;
    finally << scoped_set(in_loop_, true)
            << scoped_set(has_break_, false)
            << scoped_set(has_continue_, false);

    ast::rExp res = recurse(code->body_get()->body_get());

    if (has_continue_)
      res = cont(res.get());

    static ParametricAst whle("while (%exp:1) %exp:2");
    res = exp(whle % recurse(code->test_get()) % res);
    res.unchecked_cast<ast::While>()->flavor_set(code->flavor_get());

    if (has_break_)
      res = brk(res);

    result_ = res;
    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Foreach* code)
  {
    Finally finally;
    finally << scoped_set(in_loop_, true)
            << scoped_set(has_break_, false)
            << scoped_set(has_continue_, false);

    static ParametricAst each("%exp:1 . %id:2 (%exp:3)");
    each % recurse(code->list_get());

    switch (code->flavor_get())
    {
    case ast::flavor_none:
    case ast::flavor_semicolon:
    case ast::flavor_pipe:
      each % SYMBOL(each);
      break;
    case ast::flavor_and:
      each % SYMBOL(each_AMPERSAND);
      break;
    case ast::flavor_comma:
      each.clear();
      errors_.error(code->location_get(), "invalid flavor: `for,'");
      return;
    }

    ast::rExp body = recurse(code->body_get());
    if (has_continue_)
      body = cont(body);

    // 'fillme' is a placeholder filled later. Parametric ASTs can't
    // parametrize formal arguments for now.
    static ParametricAst closure("closure (fillme) {%exp:1}");
    ast::rClosure c = (closure % body).result<ast::Closure>();
    // Rename the 'fillme' closure formal argument
    c->formals_get()->front()->what_set(code->index_get()->what_get());
    each % c;

    if (has_break_)
      result_ = brk(exp(each));
    else
      result_ = exp(each);

    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Function* code)
  {
    Finally finally;
    finally << scoped_set(in_function_, true)
            << scoped_set(has_return_, false);
    super_type::visit(code);
    if (has_return_)
    {
      static ast::ParametricAst a("var '$returnTag' = "
				  "Tag.newFlowControl(\"returnTag\") | "
                                  "'$returnTag': %exp:1");
      ast::rScope copy =
        result_.unsafe_cast<ast::Function>()->body_get();
      copy->body_set(exp(a % copy->body_get()));
    }
    result_->original_set(code);
  }

  void
  Flower::visit(const ast::Return* ret)
  {
    if (!in_function_)
      errors_.error(ret->location_get(), "return: outside a function");

    has_return_ = true;

    if (ast::rExp e = ret->value_get())
    {
      static ParametricAst a("'$returnTag'.stop(%exp:1)");
      result_ = exp(a % e);
    }
    else
    {
      static ParametricAst a("'$returnTag'.stop");
      result_ = exp(a);
    }

    result_->original_set(ret);
  }

} // namespace flower
<|endoftext|>


<commit_before>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiDrawContext.h"
#include "nuiImageDecoration.h"

nuiImageDecoration::nuiImageDecoration(const nglString& rName)
: nuiDecoration(rName),
  mpTexture(NULL),
  mPosition(nuiCenter),
  mColor(255,255,255,255),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();
}

nuiImageDecoration::nuiImageDecoration(const nglString& rName, nuiTexture* pTexture, const nuiRect& rClientRect, nuiPosition position, const nuiColor& rColor)
: nuiDecoration(rName),
  mpTexture(pTexture),
  mPosition(position),
  mClientRect(rClientRect),
  mColor(rColor),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();
}

nuiImageDecoration::nuiImageDecoration(const nglString& rName, const nglPath& rTexturePath, const nuiRect& rClientRect, nuiPosition position, const nuiColor& rColor)
: nuiDecoration(rName),
  mpTexture(NULL),
  mPosition(position),
  mClientRect(rClientRect),
  mColor(rColor),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();

  mpTexture = nuiTexture::GetTexture(rTexturePath);
  if (mpTexture)
    SetProperty(_T("Texture"), rTexturePath.GetPathName());
}

void nuiImageDecoration::InitAttributes()
{
  AddAttribute(new nuiAttribute<const nuiRect&>
   (nglString(_T("ClientRect")), nuiUnitNone,
    nuiAttribute<const nuiRect&>::GetterDelegate(this, &nuiImageDecoration::GetSourceClientRect),
    nuiAttribute<const nuiRect&>::SetterDelegate(this, &nuiImageDecoration::SetSourceClientRect)));

  AddAttribute(new nuiAttribute<nglPath>
   (nglString(_T("Texture")), nuiUnitNone,
    nuiMakeDelegate(this, &nuiImageDecoration::GetTexturePath),
    nuiMakeDelegate(this, &nuiImageDecoration::SetTexturePath)));

  AddAttribute(new nuiAttribute<nuiPosition>
   (nglString(_T("Position")), nuiUnitPosition,
    nuiMakeDelegate(this, &nuiImageDecoration::GetPosition),
    nuiMakeDelegate(this, &nuiImageDecoration::SetPosition)));

  AddAttribute(new nuiAttribute<const nuiColor&>
               (nglString(_T("Color")), nuiUnitNone,
                nuiAttribute<const nuiColor&>::GetterDelegate(this, &nuiImageDecoration::GetColor),
                nuiAttribute<const nuiColor&>::SetterDelegate(this, &nuiImageDecoration::SetColor)));

  AddAttribute(new nuiAttribute<bool>
               (nglString(_T("RepeatX")), nuiUnitBoolean,
                nuiAttribute<bool>::GetterDelegate(this, &nuiImageDecoration::GetRepeatX),
                nuiAttribute<bool>::SetterDelegate(this, &nuiImageDecoration::SetRepeatX)));

  AddAttribute(new nuiAttribute<bool>
               (nglString(_T("RepeatY")), nuiUnitBoolean,
                nuiAttribute<bool>::GetterDelegate(this, &nuiImageDecoration::GetRepeatY),
                nuiAttribute<bool>::SetterDelegate(this, &nuiImageDecoration::SetRepeatY)));
}

nuiImageDecoration::~nuiImageDecoration()
{
  mpTexture->Release();
}

bool nuiImageDecoration::Load(const nuiXMLNode* pNode)
{
  mClientRect.SetValue(nuiGetString(pNode, _T("ClientRect"), _T("{0,0,0,0}")));
  mpTexture = nuiTexture::GetTexture(nglPath(nuiGetString(pNode, _T("Texture"), nglString::Empty)));
  return true;
}

nuiXMLNode* nuiImageDecoration::Serialize(nuiXMLNode* pNode)
{
  pNode->SetName(_T("nuiImageDecoration"));
  pNode->SetAttribute(_T("ClientRect"), mClientRect.GetValue());

  pNode->SetAttribute(_T("Texture"), GetTexturePath());
  return pNode;
}

bool nuiImageDecoration::GetRepeatX() const
{
  return mRepeatX;
}

void nuiImageDecoration::SetRepeatX(bool set)
{
  mRepeatX = set;
  if (mpTexture && set)
    mpTexture->SetWrapS(GL_REPEAT);
  else if (mpTexture && !set)
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapS(GL_CLAMP);
  #else
      mpTexture->SetWrapS(GL_CLAMP_TO_EDGE);
  #endif
  }
}

bool nuiImageDecoration::GetRepeatY() const
{
  return mRepeatY;
}

void nuiImageDecoration::SetRepeatY(bool set)
{
  mRepeatY = set;
  if (mpTexture && set)
    mpTexture->SetWrapT(GL_REPEAT);
  else if (mpTexture && !set)
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapT(GL_CLAMP);
  #else
      mpTexture->SetWrapT(GL_CLAMP_TO_EDGE);
  #endif
  }
}

nuiPosition nuiImageDecoration::GetPosition()
{
  return mPosition;
}

void nuiImageDecoration::SetPosition(nuiPosition pos)
{
  mPosition = pos;
  Changed();
}

nglPath nuiImageDecoration::GetTexturePath() const
{
  if (HasProperty(_T("Texture")))
    return GetProperty(_T("Texture"));

  return mpTexture->GetSource();
}

void nuiImageDecoration::SetTexturePath(nglPath path)
{
  SetProperty(_T("Texture"), path.GetPathName());
  nuiTexture* pOld = mpTexture;
  mpTexture = nuiTexture::GetTexture(path);
  if (!mpTexture || !mpTexture->IsValid())
  {
    NGL_OUT(_T("nuiImageDecoration::SetTexturePath warning : could not load graphic resource '%ls'\n"), path.GetChars());
    return;
  }

  if (GetSourceClientRect() == nuiRect(0,0,0,0))
    SetSourceClientRect(nuiRect(0, 0, mpTexture->GetWidth(), mpTexture->GetHeight()));
  if (pOld)
    pOld->Release();

  if (mRepeatX)
    mpTexture->SetWrapS(GL_REPEAT);
  else
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapS(GL_CLAMP);
  #else
      mpTexture->SetWrapS(GL_CLAMP_TO_EDGE);
  #endif
  }

  if (mRepeatY)
    mpTexture->SetWrapT(GL_REPEAT);
  else
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapT(GL_CLAMP);
  #else
      mpTexture->SetWrapT(GL_CLAMP_TO_EDGE);
  #endif
  }

  Changed();
}

const nuiColor& nuiImageDecoration::GetColor() const
{
  return mColor;
}

void nuiImageDecoration::SetColor(const nuiColor& rColor)
{
  mColor = rColor;
  Changed();
}

void nuiImageDecoration::Draw(nuiDrawContext* pContext, nuiWidget* pWidget, const nuiRect& rDestRect)
{
  if (!mpTexture || !mpTexture->GetImage() || !mpTexture->GetImage()->GetPixelSize())
    return;

  pContext->PushState();
  pContext->ResetState();

  nuiRect rect = mClientRect;

  rect.SetPosition(mPosition, rDestRect);
  rect.RoundToBelow();

  pContext->EnableTexturing(true);
  pContext->EnableBlending(true);
  pContext->SetBlendFunc(nuiBlendTransp);
  pContext->SetTexture(mpTexture);
  nuiColor col(mColor);
  if (mUseWidgetAlpha && pWidget)
    col.Alpha() *= pWidget->GetAlpha();

  pContext->SetFillColor(col);

  nuiRect SrcRect = rect;
  if (mRepeatX)
    SrcRect.SetWidth(rDestRect.GetWidth());
  if (mRepeatY)
    SrcRect.SetHeight(rDestRect.GetHeight());
  if (mRepeatX || mRepeatY)
    SrcRect.MoveTo(0, 0);

  pContext->DrawImage(rDestRect, SrcRect);

  pContext->PopState();
}

const nuiRect& nuiImageDecoration::GetSourceClientRect() const
{
  return mClientRect;
}

void nuiImageDecoration::SetSourceClientRect(const nuiRect& rRect)
{
  mClientRect = rRect;
  Changed();
}

nuiSize nuiImageDecoration::GetBorder(nuiPosition position, const nuiWidget* pWidget) const
{
  if (!mBorderEnabled)
    return 0;

  nuiSize w = 1.0, h = 1.0;
  mpTexture->TextureToImageCoord(w, h);
  switch (position)
  {
    case nuiLeft:
      return mClientRect.Left();
      break;
    case nuiRight:
      return w - mClientRect.Right();
      break;
    case nuiTop:
      return mClientRect.Top();
      break;
    case nuiBottom:
      return h - mClientRect.Bottom();
      break;
    case nuiFillHorizontal:
      return w - mClientRect.GetWidth();
      break;
    case nuiFillVertical:
      return h - mClientRect.GetHeight();
      break;
    case nuiNoPosition: break;
    case nuiTopLeft: break;
    case nuiTopRight: break;
    case nuiBottomLeft: break;
    case nuiBottomRight: break;
    case nuiCenter: break;
    case nuiTile: break;
    case nuiFill: break;
    case nuiFillLeft: break;
    case nuiFillRight: break;
    case nuiFillTop: break;
    case nuiFillBottom: break;
  }
  //we should'nt arrive here
  return NULL;
}

nuiTexture* nuiImageDecoration::GetTexture() const
{
  return mpTexture;
}

nuiRect nuiImageDecoration::GetIdealClientRect(const nuiWidget* pWidget) const
{
  return mClientRect.Size();
}

<commit_msg>started to fix nuiImageDecoration<commit_after>/*
 NUI3 - C++ cross-platform GUI framework for OpenGL based applications
 Copyright (C) 2002-2003 Sebastien Metrot

 licence: see nui3/LICENCE.TXT
 */

#include "nui.h"
#include "nuiDrawContext.h"
#include "nuiImageDecoration.h"

nuiImageDecoration::nuiImageDecoration(const nglString& rName)
: nuiDecoration(rName),
  mpTexture(NULL),
  mPosition(nuiCenter),
  mColor(255,255,255,255),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();
}

nuiImageDecoration::nuiImageDecoration(const nglString& rName, nuiTexture* pTexture, const nuiRect& rClientRect, nuiPosition position, const nuiColor& rColor)
: nuiDecoration(rName),
  mpTexture(pTexture),
  mPosition(position),
  mClientRect(rClientRect),
  mColor(rColor),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();
}

nuiImageDecoration::nuiImageDecoration(const nglString& rName, const nglPath& rTexturePath, const nuiRect& rClientRect, nuiPosition position, const nuiColor& rColor)
: nuiDecoration(rName),
  mpTexture(NULL),
  mPosition(position),
  mClientRect(rClientRect),
  mColor(rColor),
  mRepeatX(false),
  mRepeatY(false)
{
  if (SetObjectClass(_T("nuiImageDecoration")))
    InitAttributes();

  mpTexture = nuiTexture::GetTexture(rTexturePath);
  if (mpTexture)
    SetProperty(_T("Texture"), rTexturePath.GetPathName());
}

void nuiImageDecoration::InitAttributes()
{
  AddAttribute(new nuiAttribute<const nuiRect&>
               (nglString(_T("ClientRect")), nuiUnitNone,
                nuiAttribute<const nuiRect&>::GetterDelegate(this, &nuiImageDecoration::GetSourceClientRect),
                nuiAttribute<const nuiRect&>::SetterDelegate(this, &nuiImageDecoration::SetSourceClientRect)));

  AddAttribute(new nuiAttribute<nglPath>
               (nglString(_T("Texture")), nuiUnitNone,
                nuiMakeDelegate(this, &nuiImageDecoration::GetTexturePath),
                nuiMakeDelegate(this, &nuiImageDecoration::SetTexturePath)));

  AddAttribute(new nuiAttribute<nuiPosition>
               (nglString(_T("Position")), nuiUnitPosition,
                nuiMakeDelegate(this, &nuiImageDecoration::GetPosition),
                nuiMakeDelegate(this, &nuiImageDecoration::SetPosition)));

  AddAttribute(new nuiAttribute<const nuiColor&>
               (nglString(_T("Color")), nuiUnitNone,
                nuiMakeDelegate(this, &nuiImageDecoration::GetColor),
                nuiMakeDelegate(this, &nuiImageDecoration::SetColor)));

  AddAttribute(new nuiAttribute<bool>
               (nglString(_T("RepeatX")), nuiUnitBoolean,
                nuiMakeDelegate(this, &nuiImageDecoration::GetRepeatX),
                nuiMakeDelegate(this, &nuiImageDecoration::SetRepeatX)));

  AddAttribute(new nuiAttribute<bool>
               (nglString(_T("RepeatY")), nuiUnitBoolean,
                nuiMakeDelegate(this, &nuiImageDecoration::GetRepeatY),
                nuiMakeDelegate(this, &nuiImageDecoration::SetRepeatY)));
}

nuiImageDecoration::~nuiImageDecoration()
{
  mpTexture->Release();
}

bool nuiImageDecoration::Load(const nuiXMLNode* pNode)
{
  mClientRect.SetValue(nuiGetString(pNode, _T("ClientRect"), _T("{0,0,0,0}")));
  mpTexture = nuiTexture::GetTexture(nglPath(nuiGetString(pNode, _T("Texture"), nglString::Empty)));
  return true;
}

nuiXMLNode* nuiImageDecoration::Serialize(nuiXMLNode* pNode)
{
  pNode->SetName(_T("nuiImageDecoration"));
  pNode->SetAttribute(_T("ClientRect"), mClientRect.GetValue());

  pNode->SetAttribute(_T("Texture"), GetTexturePath());
  return pNode;
}

bool nuiImageDecoration::GetRepeatX() const
{
  return mRepeatX;
}

void nuiImageDecoration::SetRepeatX(bool set)
{
  mRepeatX = set;
  if (mpTexture && set)
    mpTexture->SetWrapS(GL_REPEAT);
  else if (mpTexture && !set)
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapS(GL_CLAMP);
  #else
      mpTexture->SetWrapS(GL_CLAMP_TO_EDGE);
  #endif
  }
}

bool nuiImageDecoration::GetRepeatY() const
{
  return mRepeatY;
}

void nuiImageDecoration::SetRepeatY(bool set)
{
  mRepeatY = set;
  if (mpTexture && set)
    mpTexture->SetWrapT(GL_REPEAT);
  else if (mpTexture && !set)
  {
  #ifndef _OPENGL_ES_
      mpTexture->SetWrapT(GL_CLAMP);
  #else
      mpTexture->SetWrapT(GL_CLAMP_TO_EDGE);
  #endif
  }
}

nuiPosition nuiImageDecoration::GetPosition()
{
  return mPosition;
}

void nuiImageDecoration::SetPosition(nuiPosition pos)
{
  mPosition = pos;
  Changed();
}

nglPath nuiImageDecoration::GetTexturePath() const
{
  if (HasProperty(_T("Texture")))
    return GetProperty(_T("Texture"));

  return mpTexture->GetSource();
}

void nuiImageDecoration::SetTexturePath(nglPath path)
{
  SetProperty(_T("Texture"), path.GetPathName());
  nuiTexture* pOld = mpTexture;
  mpTexture = nuiTexture::GetTexture(path);
  if (!mpTexture || !mpTexture->IsValid())
  {
    NGL_OUT(_T("nuiImageDecoration::SetTexturePath warning : could not load graphic resource '%ls'\n"), path.GetChars());
    return;
  }

  if (GetSourceClientRect() == nuiRect(0,0,0,0))
    SetSourceClientRect(nuiRect(0, 0, mpTexture->GetWidth(), mpTexture->GetHeight()));
  if (pOld)
    pOld->Release();

  SetRepeatX(mRepeatX);
  SetRepeatY(mRepeatY);

  Changed();
}

const nuiColor& nuiImageDecoration::GetColor() const
{
  return mColor;
}

void nuiImageDecoration::SetColor(const nuiColor& rColor)
{
  mColor = rColor;
  Changed();
}

void nuiImageDecoration::Draw(nuiDrawContext* pContext, nuiWidget* pWidget, const nuiRect& rDestRect)
{
  if (!mpTexture || !mpTexture->GetImage() || !mpTexture->GetImage()->GetPixelSize())
    return;

  pContext->PushState();
  pContext->ResetState();

  nuiRect rect = mClientRect;
  rect.SetPosition(mPosition, rDestRect);
  rect.RoundToBelow();

  pContext->EnableTexturing(true);
  pContext->EnableBlending(true);
  pContext->SetBlendFunc(nuiBlendTransp);
  pContext->SetTexture(mpTexture);
  nuiColor col(mColor);
  if (mUseWidgetAlpha && pWidget)
    col.Alpha() *= pWidget->GetAlpha();

  pContext->SetFillColor(col);

  nuiRect srcrect(mClientRect);
  if (mRepeatX)
  {
    srcrect.SetWidth(rDestRect.GetWidth());
    srcrect.MoveTo(0, srcrect.Top());
  }

  if (mRepeatY)
  {
    srcrect.SetHeight(rDestRect.GetHeight());
    srcrect.MoveTo(srcrect.Left(), 0);
  }

  if (mRepeatX || mRepeatY)
    rect = rDestRect;

  pContext->DrawImage(rect, srcrect);
  //pContext->DrawRect(rDestRect, eStrokeShape);
  pContext->PopState();
}

const nuiRect& nuiImageDecoration::GetSourceClientRect() const
{
  return mClientRect;
}

void nuiImageDecoration::SetSourceClientRect(const nuiRect& rRect)
{
  mClientRect = rRect;
  Changed();
}

nuiSize nuiImageDecoration::GetBorder(nuiPosition position, const nuiWidget* pWidget) const
{
  if (!mBorderEnabled)
    return 0;

  nuiSize w = 1.0, h = 1.0;
  mpTexture->TextureToImageCoord(w, h);
  switch (position)
  {
    case nuiLeft:
      return mClientRect.Left();
      break;
    case nuiRight:
      return w - mClientRect.Right();
      break;
    case nuiTop:
      return mClientRect.Top();
      break;
    case nuiBottom:
      return h - mClientRect.Bottom();
      break;
    case nuiFillHorizontal:
      return w - mClientRect.GetWidth();
      break;
    case nuiFillVertical:
      return h - mClientRect.GetHeight();
      break;
    case nuiNoPosition: break;
    case nuiTopLeft: break;
    case nuiTopRight: break;
    case nuiBottomLeft: break;
    case nuiBottomRight: break;
    case nuiCenter: break;
    case nuiTile: break;
    case nuiFill: break;
    case nuiFillLeft: break;
    case nuiFillRight: break;
    case nuiFillTop: break;
    case nuiFillBottom: break;
  }
  //we should'nt arrive here
  return NULL;
}

nuiTexture* nuiImageDecoration::GetTexture() const
{
  return mpTexture;
}

nuiRect nuiImageDecoration::GetIdealClientRect(const nuiWidget* pWidget) const
{
  return mClientRect.Size();
}

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"
#include "boost/python/raw_function.hpp"
#include "boost/format.hpp"

#include "IECore/SimpleTypedData.h"
#include "IECorePython/ScopedGILLock.h"

#include "Gaffer/Plug.h"
#include "Gaffer/Node.h"
#include "Gaffer/Metadata.h"

#include "GafferBindings/MetadataBinding.h"
#include "GafferBindings/DataBinding.h"

using namespace boost::python;
using namespace IECore;
using namespace Gaffer;
using namespace GafferBindings;

namespace GafferBindings
{

void metadataModuleDependencies( const Gaffer::Node *node, std::set<std::string> &modules )
{
	/// \todo Derive from the registered values so we can support
	/// datatypes from other modules.
	modules.insert( "IECore" );
	modules.insert( "Gaffer" );
}

void metadataModuleDependencies( const Gaffer::Plug *plug, std::set<std::string> &modules )
{
	/// \todo Derive from the registered values so we can support
	/// datatypes from other modules.
	modules.insert( "IECore" );
	modules.insert( "Gaffer" );
}

std::string metadataSerialisation( const Gaffer::Node *node, const std::string &identifier )
{
	std::vector<InternedString> keys;
	Metadata::registeredValues( node, keys, /* instanceOnly = */ true, /* persistentOnly = */ true );

	std::string result;
	for( std::vector<InternedString>::const_iterator it = keys.begin(), eIt = keys.end(); it != eIt; ++it )
	{
		object pythonKey( it->c_str() );
		std::string key = extract<std::string>( pythonKey.attr( "__repr__" )() );

		ConstDataPtr value = Metadata::value( node, *it );
		object pythonValue = dataToPython( value.get(), /* copy = */ false );
		std::string stringValue = extract<std::string>( pythonValue.attr( "__repr__" )() );

		result += boost::str(
			boost::format( "Gaffer.Metadata.registerNodeValue( %s, %s, %s )\n" ) %
				identifier %
				key %
				stringValue
		);
	}

	return result;
}

std::string metadataSerialisation( const Plug *plug, const std::string &identifier )
{
	std::vector<InternedString> keys;
	Metadata::registeredValues( plug, keys, /* instanceOnly = */ true, /* persistentOnly = */ true );

	std::string result;
	for( std::vector<InternedString>::const_iterator it = keys.begin(), eIt = keys.end(); it != eIt; ++it )
	{
		object pythonKey( it->c_str() );
		std::string key = extract<std::string>( pythonKey.attr( "__repr__" )() );

		ConstDataPtr value = Metadata::value( plug, *it );
		object pythonValue = dataToPython( value.get(), /* copy = */ false );
		std::string stringValue = extract<std::string>( pythonValue.attr( "__repr__" )() );

		result += boost::str(
			boost::format( "Gaffer.Metadata.registerPlugValue( %s, %s, %s )\n" ) %
				identifier %
				key %
				stringValue
		);
	}

	return result;
}

} // namespace GafferBindings
<commit_msg>MetadataBinding : Fix serialisation of Imath values<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2013, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"
#include "boost/python/raw_function.hpp"
#include "boost/format.hpp"

#include "IECore/SimpleTypedData.h"
#include "IECorePython/ScopedGILLock.h"

#include "Gaffer/Plug.h"
#include "Gaffer/Node.h"
#include "Gaffer/Metadata.h"

#include "GafferBindings/MetadataBinding.h"
#include "GafferBindings/DataBinding.h"
#include "GafferBindings/Serialisation.h"

using namespace boost::python;
using namespace IECore;
using namespace Gaffer;
using namespace GafferBindings;

namespace GafferBindings
{

void metadataModuleDependencies( const Gaffer::Node *node, std::set<std::string> &modules )
{
	/// \todo Derive from the registered values so we can support
	/// datatypes from other modules.
	modules.insert( "imath" );
	modules.insert( "IECore" );
	modules.insert( "Gaffer" );
}

void metadataModuleDependencies( const Gaffer::Plug *plug, std::set<std::string> &modules )
{
	/// \todo Derive from the registered values so we can support
	/// datatypes from other modules.
	modules.insert( "imath" );
	modules.insert( "IECore" );
	modules.insert( "Gaffer" );
}

std::string metadataSerialisation( const Gaffer::Node *node, const std::string &identifier )
{
	std::vector<InternedString> keys;
	Metadata::registeredValues( node, keys, /* instanceOnly = */ true, /* persistentOnly = */ true );

	std::string result;
	for( std::vector<InternedString>::const_iterator it = keys.begin(), eIt = keys.end(); it != eIt; ++it )
	{
		object pythonKey( it->c_str() );
		std::string key = extract<std::string>( pythonKey.attr( "__repr__" )() );

		ConstDataPtr value = Metadata::value( node, *it );
		object pythonValue = dataToPython( value.get(), /* copy = */ false );

		object repr = boost::python::import( "IECore" ).attr( "repr" );
		std::string stringValue = extract<std::string>( repr( pythonValue ) );

		result += boost::str(
			boost::format( "Gaffer.Metadata.registerNodeValue( %s, %s, %s )\n" ) %
				identifier %
				key %
				stringValue
		);
	}

	return result;
}

std::string metadataSerialisation( const Plug *plug, const std::string &identifier )
{
	std::vector<InternedString> keys;
	Metadata::registeredValues( plug, keys, /* instanceOnly = */ true, /* persistentOnly = */ true );

	std::string result;
	for( std::vector<InternedString>::const_iterator it = keys.begin(), eIt = keys.end(); it != eIt; ++it )
	{
		object pythonKey( it->c_str() );
		std::string key = extract<std::string>( pythonKey.attr( "__repr__" )() );

		ConstDataPtr value = Metadata::value( plug, *it );
		object pythonValue = dataToPython( value.get(), /* copy = */ false );
		std::string stringValue = extract<std::string>( pythonValue.attr( "__repr__" )() );
		const std::string modulePath = Serialisation::modulePath( pythonValue );
		if( modulePath == "imath" )
		{
			stringValue = modulePath + "." + stringValue;
		}

		result += boost::str(
			boost::format( "Gaffer.Metadata.registerPlugValue( %s, %s, %s )\n" ) %
				identifier %
				key %
				stringValue
		);
	}

	return result;
}

} // namespace GafferBindings
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2019, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"

#include "ValuePlugTest.h"

#include "GafferTest/MultiplyNode.h"

#include "Gaffer/ValuePlug.h"

#include "tbb/parallel_for.h"

#include "IECorePython/ScopedGILRelease.h"

using namespace boost::python;
using namespace Gaffer;
using namespace GafferTest;

namespace
{

// Call getValue() on the given plug many times in parallel.
//
// Evaluating the same value over and over again is obviously not useful,
// but it can help turn up performance issues that can happen when a
// downstream graph ends up repeatedly evaluating something which turn out
// not to vary.
void parallelGetValue( const IntPlug *plug, int iterations )
{
	IECorePython::ScopedGILRelease gilRelease;
	tbb::parallel_for(
		tbb::blocked_range<int>( 0, iterations ),
		[&plug]( const tbb::blocked_range<int> &r ) {
			for( int i = r.begin(); i < r.end(); ++i )
			{
				plug->getValue();
			}
		}
	);
}

} // namespace

void GafferTestModule::bindValuePlugTest()
{
	def( "parallelGetValue", &parallelGetValue );
}
<commit_msg>ValuePlugTest : parallelGetValue which sets a context variable<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2019, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/python.hpp"

#include "ValuePlugTest.h"

#include "Gaffer/Context.h"
#include "Gaffer/NumericPlug.h"
#include "Gaffer/ValuePlug.h"

#include "tbb/parallel_for.h"

#include "IECorePython/ScopedGILRelease.h"

using namespace boost::python;
using namespace Gaffer;

namespace
{

// Call getValue() on the given plug many times in parallel.
//
// Evaluating the same value over and over again is obviously not useful,
// but it can help turn up performance issues that can happen when a
// downstream graph ends up repeatedly evaluating something which turn out
// not to vary.
void parallelGetValue( const IntPlug *plug, int iterations )
{
	IECorePython::ScopedGILRelease gilRelease;
	tbb::parallel_for(
		tbb::blocked_range<int>( 0, iterations ),
		[&plug]( const tbb::blocked_range<int> &r ) {
			for( int i = r.begin(); i < r.end(); ++i )
			{
				plug->getValue();
			}
		}
	);
}

// Variant of the above which stores the iteration in a context variable, allowing
// the parallel evaluates to vary
void parallelGetValueWithVar( const IntPlug *plug, int iterations, const IECore::InternedString iterationVar )
{
	IECorePython::ScopedGILRelease gilRelease;
	const ThreadState &threadState = ThreadState::current();
	tbb::parallel_for(
		tbb::blocked_range<int>( 0, iterations ),
		[&plug, &iterationVar, &threadState]( const tbb::blocked_range<int> &r ) {
			Context::EditableScope scope( threadState );
			for( int i = r.begin(); i < r.end(); ++i )
			{
				scope.set( iterationVar, i );
				plug->getValue();
			}
		}
	);
}

} // namespace

void GafferTestModule::bindValuePlugTest()
{
	def( "parallelGetValue", &parallelGetValue );
	def( "parallelGetValue", &parallelGetValueWithVar );
}
<|endoftext|>