<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program 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 program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include "Binding_BaseContext.h"
#include "Binding_Base.h"
#include "Binding_Vector.h"
#include "PythonFactory.h"
#include "PythonToSofa.inl"

#include <sofa/defaulttype/Vec3Types.h>
using namespace sofa::defaulttype;

#include <sofa/core/ObjectFactory.h>
using namespace sofa::core;

#include <sofa/core/objectmodel/BaseContext.h>
using namespace sofa::core::objectmodel;

#include <sofa/simulation/Node.h>
using namespace sofa::simulation;
using namespace sofa::defaulttype;

static PyObject * BaseContext_setGravity(PyObject *self, PyObject * args)
{
    BaseContext* obj = get_basecontext( self );
    PyPtr<Vector3>* pyVec;
    if (!PyArg_ParseTuple(args, "O",&pyVec)) {
        return NULL;
    }

    obj->setGravity(*pyVec->object);
    Py_RETURN_NONE;
}

static PyObject * BaseContext_getGravity(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return SP_BUILD_PYPTR(Vector3,Vector3,new Vector3(obj->getGravity()),true); // "true", because I manage the deletion myself
}

static PyObject * BaseContext_getTime(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return PyFloat_FromDouble(obj->getTime());
}

static PyObject * BaseContext_getDt(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return PyFloat_FromDouble(obj->getDt());
}

static PyObject * BaseContext_getRootContext(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return sofa::PythonFactory::toPython(obj->getRootContext());
}

/// This function converts an PyObject into a sofa string.
/// string that can be safely parsed in helper::vector<int> or helper::vector<double>
static std::ostream& pythonToSofaDataString(PyObject* value, std::ostream& out)
{
    /// String are just returned as string.
    if (PyString_Check(value))
    {
        return out << PyString_AsString(value) ;
    }

    if( PySequence_Check(value) )
    {
        /// It is a sequence...so we can iterate over it.
        PyObject *iterator = PyObject_GetIter(value);
        if(iterator)
        {
            bool first = true;
            while(PyObject* next = PyIter_Next(iterator))
            {
                if(first) first = false;
                else out << ' ';

                pythonToSofaDataString(next, out);
                Py_DECREF(next);
            }
            Py_DECREF(iterator);

            if (PyErr_Occurred())
            {
                msg_error("SofaPython") << "error while iterating." << msgendl
                                        << PythonEnvironment::getStackAsString() ;
            }
            return out;
        }
    }

    /// Check if the object has an explicit conversion to a Sofa path. If this is the case
    /// we use it.
    if( PyObject_HasAttrString(value, "getAsACreateObjectParameter") ){
        PyObject* retvalue = PyObject_CallMethod(value, (char*)"getAsACreateObjectParameter", nullptr) ;
        return pythonToSofaDataString(retvalue, out);
    }

    /// Default conversion for standard type:
    if( !(PyInt_Check(value) || PyLong_Check(value) || PyFloat_Check(value) || PyBool_Check(value) ))
    {
        msg_warning("SofaPython") << "You are trying to convert a non primitive type to Sofa using the 'str' operator." << msgendl
                                  << "Automatic conversion is provided for: String, Integer, Long, Float and Bool and Sequences." << msgendl
                                  << "Other objects should implement the method getAsACreateObjectParameter(). " << msgendl
                                  << "This function should return a string usable as a parameter in createObject()." << msgendl
                                  << "So to remove this message you must add a method getAsCreateObjectParameter(self) "
                                     "to the object you are passing the createObject function." << msgendl
                                  << PythonEnvironment::getStackAsString() ;
    }

    PyObject* tmpstr=PyObject_Str(value);
    out << PyString_AsString(tmpstr) ;
    Py_DECREF(tmpstr) ;
    return out ;
}

/// object factory
static PyObject * BaseContext_createObject_Impl(PyObject * self, PyObject * args, PyObject * kw, bool printWarnings)
{
    BaseContext* context = get_basecontext( self );

    char *type;
    if (!PyArg_ParseTuple(args, "s",&type))
    {
        return NULL;
    }

    /// temporarily, the name is set to the type name.
    /// if a "name" parameter is provided, it will overwrite it.
    BaseObjectDescription desc(type,type);

    bool warning = printWarnings;
    if (kw && PyDict_Size(kw)>0)
    {
        PyObject* keys = PyDict_Keys(kw);
        PyObject* values = PyDict_Values(kw);
        for (int i=0; i<PyDict_Size(kw); i++)
        {
            PyObject *key = PyList_GetItem(keys,i);
            PyObject *value = PyList_GetItem(values,i);

            if( !strcmp( PyString_AsString(key), "warning") )
            {
                if PyBool_Check(value)
                        warning = (value==Py_True);
            }
            else
            {
                std::stringstream s;
                pythonToSofaDataString(value, s) ;
                desc.setAttribute(PyString_AsString(key),s.str().c_str());
            }
        }
        Py_DecRef(keys);
        Py_DecRef(values);
    }

    BaseObject::SPtr obj = ObjectFactory::getInstance()->createObject(context,&desc);
    if (obj==0)
    {
        std::stringstream msg;
        msg << "createObject: component '" << desc.getName() << "' of type '" << desc.getAttribute("type","")<< "' in node '"<<context->getName()<<"'" ;
        for (std::vector< std::string >::const_iterator it = desc.getErrors().begin(); it != desc.getErrors().end(); ++it)
            msg << " " << *it << msgendl ;
        PyErr_SetString(PyExc_RuntimeError, msg.str().c_str()) ;
        return NULL;
    }

    if( warning )
    {
        for( auto it : desc.getAttributeMap() )
        {
            if (!it.second.isAccessed())
            {
                obj->serr <<"Unused Attribute: \""<<it.first <<"\" with value: \"" <<(std::string)it.second<<"\" (" << obj->getPathName() << ")" << obj->sendl;
            }
        }

        Node *node = static_cast<Node*>(context);
        if (node && node->isInitialized())
            msg_warning(node) << "Sofa.Node.createObject("<<type<<") called on a node("<<node->getName()<<") that is already initialized";
    }

    return sofa::PythonFactory::toPython(obj.get());
}

static PyObject * BaseContext_createObject(PyObject * self, PyObject * args, PyObject * kw)
{
    return BaseContext_createObject_Impl( self, args, kw, true );
}

static PyObject * BaseContext_createObject_noWarning(PyObject * self, PyObject * args, PyObject * kw)
{
    SP_MESSAGE_DEPRECATED("BaseContext_createObject_noWarning is deprecated, use the keyword warning=False in BaseContext_createObject instead.")
            return BaseContext_createObject_Impl( self, args, kw, false );
}

/// the complete relative path to the object must be given
/// returns None with a warning if the object is not found
static PyObject * BaseContext_getObject(PyObject * self, PyObject * args, PyObject * kw)
{
    BaseContext* context = get_basecontext( self );
    char *path;
    if (!PyArg_ParseTuple(args, "s",&path))
    {
        msg_warning(context)
                << "BaseContext_getObject: wrong argument, should be a string with the complete relative path" ;
        return NULL;
    }

    bool emitWarningMessage = true;
    if (kw && PyDict_Size(kw)>0)
    {
        PyObject* keys = PyDict_Keys(kw);
        PyObject* values = PyDict_Values(kw);
        for (int i=0; i<PyDict_Size(kw); i++)
        {
            PyObject *key = PyList_GetItem(keys,i);
            PyObject *value = PyList_GetItem(values,i);
            if( !strcmp(PyString_AsString(key),"warning") )
            {
                if PyBool_Check(value)
                        emitWarningMessage = (value==Py_True);
                break;
            }
        }
        Py_DecRef(keys);
        Py_DecRef(values);
    }

    if (!context || !path)
    {
        PyErr_BadArgument();
        return NULL;
    }
    BaseObject::SPtr sptr;
    context->get<BaseObject>(sptr,path);
    if (!sptr)
    {
        msg_warning_when(context, emitWarningMessage)
                << "BaseContext_getObject: component "<< path <<" not found (the complete relative path is needed)" ;

        return NULL;
    }

    return sofa::PythonFactory::toPython(sptr.get());
}

/// the complete relative path to the object must be given
/// returns None if the object is not found
static PyObject * BaseContext_getObject_noWarning(PyObject * self, PyObject * args)
{
    SP_MESSAGE_DEPRECATED("BaseContext_getObject_noWarning is deprecated, use the keyword warning=False in BaseContext_getObject instead.")

    BaseContext* context = get_basecontext( self );
    char *path;
    if (!PyArg_ParseTuple(args, "s",&path))
    {
        return NULL;
    }
    if (!context || !path)
    {
        PyErr_BadArgument();
        return NULL;
    }
    BaseObject::SPtr sptr;
    context->get<BaseObject>(sptr,path);
    if (!sptr) Py_RETURN_NONE;

    return sofa::PythonFactory::toPython(sptr.get());
}

//TODO(PR:304) do it or remove  :)
// @TODO: pass keyword arguments rather than optional arguments?
static PyObject * BaseContext_getObjects(PyObject * self, PyObject * args)
{
    BaseContext* context = get_basecontext( self );
    char* search_direction= NULL;
    char* type_name= NULL;
    char* name= NULL;
    if ( !PyArg_ParseTuple ( args, "|sss", &search_direction, &type_name, &name ) ) {
        PyErr_SetString(PyExc_TypeError, "BaseContext_getObjects: wrong arguments! Expected format: getObjects ( OPTIONAL STRING searchDirection, OPTIONAL STRING typeName, OPTIONAL STRING name )" );
        return NULL;
    }

    if (!context)
    {
        PyErr_BadArgument();
        return NULL;
    }

    sofa::core::objectmodel::BaseContext::SearchDirection search_direction_enum= sofa::core::objectmodel::BaseContext::Local;
    if ( search_direction )
    {
        std::string search_direction_str ( search_direction );
        if ( search_direction_str == "SearchUp" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchUp;
        }
        else if ( search_direction_str == "Local" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::Local;
        }
        else if ( search_direction_str == "SearchDown" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchDown;
        }
        else if ( search_direction_str == "SearchRoot" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchRoot;
        }
        else if ( search_direction_str == "SearchParents" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchParents;
        }
        else
        {
            msg_warning(context) << "BaseContext_getObjects: Invalid search direction, using 'Local'. Expected: 'SearchUp', 'Local', 'SearchDown', 'SearchRoot', or 'SearchParents'." ;
        }
    }

    sofa::helper::vector< boost::intrusive_ptr<BaseObject> > list;
    context->get<BaseObject>(&list,search_direction_enum);

    PyObject *pyList = PyList_New(0);
    for (size_t i=0; i<list.size(); i++)
    {
        BaseObject* o = list[i].get();

        if( !type_name || o->getClass()->hasParent( type_name ) )
        {
            if ( !name || name == o->getName() )
            {
                PyObject* obj=sofa::PythonFactory::toPython(o); // ref 1
                PyList_Append(pyList,obj); // ref 2
                Py_DECREF(obj); // ref 1 (now owned by list)
            }
        }
    }

    return pyList;
}

SP_CLASS_METHODS_BEGIN(BaseContext)
SP_CLASS_METHOD(BaseContext,getRootContext)
SP_CLASS_METHOD(BaseContext,getTime)
SP_CLASS_METHOD(BaseContext,getDt)
SP_CLASS_METHOD(BaseContext,getGravity)
SP_CLASS_METHOD(BaseContext,setGravity)
SP_CLASS_METHOD_KW(BaseContext,createObject)
SP_CLASS_METHOD_KW(BaseContext,createObject_noWarning) // deprecated
SP_CLASS_METHOD_KW(BaseContext,getObject)
SP_CLASS_METHOD(BaseContext,getObject_noWarning) // deprecated
SP_CLASS_METHOD(BaseContext,getObjects)
SP_CLASS_METHODS_END

static PyObject * BaseContext_getAttr_animate(PyObject *self, void*)
{
    BaseContext* obj = get_basecontext( self );
    return PyBool_FromLong(obj->getAnimate());
}
static int BaseContext_setAttr_animate(PyObject *self, PyObject * args, void*)
{
    BaseContext* obj = get_basecontext( self );
    if (!PyBool_Check(args))
    {
        PyErr_BadArgument();
        return -1;
    }
    obj->setAnimate(args==Py_True);
    return 0;
}

static PyObject * BaseContext_getAttr_active(PyObject *self, void*)
{
    BaseContext* obj = get_basecontext( self );
    return PyBool_FromLong(obj->isActive());
}

static int BaseContext_setAttr_active(PyObject *self, PyObject * args, void*)
{
    BaseContext* obj = get_basecontext( self );
    if (!PyBool_Check(args))
    {
        PyErr_BadArgument();
        return -1;
    }
    obj->setActive(args==Py_True);
    return 0;
}

SP_CLASS_ATTRS_BEGIN(BaseContext)
SP_CLASS_ATTR(BaseContext,active)
SP_CLASS_ATTR(BaseContext,animate)
SP_CLASS_ATTRS_END

SP_CLASS_TYPE_SPTR_ATTR(BaseContext,BaseContext,Base)
<commit_msg>[SofaPython] Replace SP_MESSAGE_WARNING... with msg_warning<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program 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 program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include "Binding_BaseContext.h"
#include "Binding_Base.h"
#include "Binding_Vector.h"
#include "PythonFactory.h"
#include "PythonToSofa.inl"

#include <sofa/defaulttype/Vec3Types.h>
using namespace sofa::defaulttype;

#include <sofa/core/ObjectFactory.h>
using namespace sofa::core;

#include <sofa/core/objectmodel/BaseContext.h>
using namespace sofa::core::objectmodel;

#include <sofa/simulation/Node.h>
using namespace sofa::simulation;
using namespace sofa::defaulttype;

static PyObject * BaseContext_setGravity(PyObject *self, PyObject * args)
{
    BaseContext* obj = get_basecontext( self );
    PyPtr<Vector3>* pyVec;
    if (!PyArg_ParseTuple(args, "O",&pyVec)) {
        return NULL;
    }

    obj->setGravity(*pyVec->object);
    Py_RETURN_NONE;
}

static PyObject * BaseContext_getGravity(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return SP_BUILD_PYPTR(Vector3,Vector3,new Vector3(obj->getGravity()),true); // "true", because I manage the deletion myself
}

static PyObject * BaseContext_getTime(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return PyFloat_FromDouble(obj->getTime());
}

static PyObject * BaseContext_getDt(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return PyFloat_FromDouble(obj->getDt());
}

static PyObject * BaseContext_getRootContext(PyObject *self, PyObject * /*args*/)
{
    BaseContext* obj = get_basecontext( self );
    return sofa::PythonFactory::toPython(obj->getRootContext());
}

/// This function converts an PyObject into a sofa string.
/// string that can be safely parsed in helper::vector<int> or helper::vector<double>
static std::ostream& pythonToSofaDataString(PyObject* value, std::ostream& out)
{
    /// String are just returned as string.
    if (PyString_Check(value))
    {
        return out << PyString_AsString(value) ;
    }

    if( PySequence_Check(value) )
    {
        /// It is a sequence...so we can iterate over it.
        PyObject *iterator = PyObject_GetIter(value);
        if(iterator)
        {
            bool first = true;
            while(PyObject* next = PyIter_Next(iterator))
            {
                if(first) first = false;
                else out << ' ';

                pythonToSofaDataString(next, out);
                Py_DECREF(next);
            }
            Py_DECREF(iterator);

            if (PyErr_Occurred())
            {
                msg_error("SofaPython") << "error while iterating." << msgendl
                                        << PythonEnvironment::getStackAsString() ;
            }
            return out;
        }
    }

    /// Check if the object has an explicit conversion to a Sofa path. If this is the case
    /// we use it.
    if( PyObject_HasAttrString(value, "getAsACreateObjectParameter") ){
        PyObject* retvalue = PyObject_CallMethod(value, (char*)"getAsACreateObjectParameter", nullptr) ;
        return pythonToSofaDataString(retvalue, out);
    }

    /// Default conversion for standard type:
    if( !(PyInt_Check(value) || PyLong_Check(value) || PyFloat_Check(value) || PyBool_Check(value) ))
    {
        msg_warning("SofaPython") << "You are trying to convert a non primitive type to Sofa using the 'str' operator." << msgendl
                                  << "Automatic conversion is provided for: String, Integer, Long, Float and Bool and Sequences." << msgendl
                                  << "Other objects should implement the method getAsACreateObjectParameter(). " << msgendl
                                  << "This function should return a string usable as a parameter in createObject()." << msgendl
                                  << "So to remove this message you must add a method getAsCreateObjectParameter(self) "
                                     "to the object you are passing the createObject function." << msgendl
                                  << PythonEnvironment::getStackAsString() ;
    }

    PyObject* tmpstr=PyObject_Str(value);
    out << PyString_AsString(tmpstr) ;
    Py_DECREF(tmpstr) ;
    return out ;
}

/// object factory
static PyObject * BaseContext_createObject_Impl(PyObject * self, PyObject * args, PyObject * kw, bool printWarnings)
{
    BaseContext* context = get_basecontext( self );

    char *type;
    if (!PyArg_ParseTuple(args, "s",&type))
    {
        return NULL;
    }

    /// temporarily, the name is set to the type name.
    /// if a "name" parameter is provided, it will overwrite it.
    BaseObjectDescription desc(type,type);

    bool warning = printWarnings;
    if (kw && PyDict_Size(kw)>0)
    {
        PyObject* keys = PyDict_Keys(kw);
        PyObject* values = PyDict_Values(kw);
        for (int i=0; i<PyDict_Size(kw); i++)
        {
            PyObject *key = PyList_GetItem(keys,i);
            PyObject *value = PyList_GetItem(values,i);

            if( !strcmp( PyString_AsString(key), "warning") )
            {
                if PyBool_Check(value)
                        warning = (value==Py_True);
            }
            else
            {
                std::stringstream s;
                pythonToSofaDataString(value, s) ;
                desc.setAttribute(PyString_AsString(key),s.str().c_str());
            }
        }
        Py_DecRef(keys);
        Py_DecRef(values);
    }

    BaseObject::SPtr obj = ObjectFactory::getInstance()->createObject(context,&desc);
    if (obj==0)
    {
        std::stringstream msg;
        msg << "createObject: component '" << desc.getName() << "' of type '" << desc.getAttribute("type","")<< "' in node '"<<context->getName()<<"'" ;
        for (std::vector< std::string >::const_iterator it = desc.getErrors().begin(); it != desc.getErrors().end(); ++it)
            msg << " " << *it << msgendl ;
        PyErr_SetString(PyExc_RuntimeError, msg.str().c_str()) ;
        return NULL;
    }

    if( warning )
    {
        for( auto it : desc.getAttributeMap() )
        {
            if (!it.second.isAccessed())
            {
                obj->serr <<"Unused Attribute: \""<<it.first <<"\" with value: \"" <<(std::string)it.second<<"\" (" << obj->getPathName() << ")" << obj->sendl;
            }
        }

        Node *node = static_cast<Node*>(context);
        if (node && node->isInitialized())
            msg_warning(node) << "Sofa.Node.createObject("<<type<<") called on a node("<<node->getName()<<") that is already initialized";
    }

    return sofa::PythonFactory::toPython(obj.get());
}

static PyObject * BaseContext_createObject(PyObject * self, PyObject * args, PyObject * kw)
{
    return BaseContext_createObject_Impl( self, args, kw, true );
}

static PyObject * BaseContext_createObject_noWarning(PyObject * self, PyObject * args, PyObject * kw)
{
    BaseContext* context = get_basecontext( self );
    msg_deprecated(context)
            << "BaseContext_createObject_noWarning is deprecated, use the keyword warning=False in BaseContext_createObject instead." ;

    return BaseContext_createObject_Impl( self, args, kw, false );
}

/// the complete relative path to the object must be given
/// returns None with a warning if the object is not found
static PyObject * BaseContext_getObject(PyObject * self, PyObject * args, PyObject * kw)
{
    BaseContext* context = get_basecontext( self );
    char *path;
    if (!PyArg_ParseTuple(args, "s",&path))
    {
        msg_warning(context)
                << "BaseContext_getObject: wrong argument, should be a string with the complete relative path" ;
        return NULL;
    }

    bool emitWarningMessage = true;
    if (kw && PyDict_Size(kw)>0)
    {
        PyObject* keys = PyDict_Keys(kw);
        PyObject* values = PyDict_Values(kw);
        for (int i=0; i<PyDict_Size(kw); i++)
        {
            PyObject *key = PyList_GetItem(keys,i);
            PyObject *value = PyList_GetItem(values,i);
            if( !strcmp(PyString_AsString(key),"warning") )
            {
                if PyBool_Check(value)
                        emitWarningMessage = (value==Py_True);
                break;
            }
        }
        Py_DecRef(keys);
        Py_DecRef(values);
    }

    if (!context || !path)
    {
        PyErr_BadArgument();
        return NULL;
    }
    BaseObject::SPtr sptr;
    context->get<BaseObject>(sptr,path);
    if (!sptr)
    {
        msg_warning_when(emitWarningMessage, context)
                << "BaseContext_getObject: component "<< path <<" not found (the complete relative path is needed)" ;

        return NULL;
    }

    return sofa::PythonFactory::toPython(sptr.get());
}

/// the complete relative path to the object must be given
/// returns None if the object is not found
static PyObject * BaseContext_getObject_noWarning(PyObject * self, PyObject * args)
{
    BaseContext* context = get_basecontext( self );
    msg_deprecated(context)
            << "BaseContext_getObject_noWarning is deprecated, use the keyword warning=False in BaseContext_getObject instead." ;

    char *path;
    if (!PyArg_ParseTuple(args, "s",&path))
    {
        return NULL;
    }
    if (!context || !path)
    {
        PyErr_BadArgument();
        return NULL;
    }
    BaseObject::SPtr sptr;
    context->get<BaseObject>(sptr,path);
    if (!sptr) Py_RETURN_NONE;

    return sofa::PythonFactory::toPython(sptr.get());
}

//TODO(PR:304) do it or remove  :)
// @TODO: pass keyword arguments rather than optional arguments?
static PyObject * BaseContext_getObjects(PyObject * self, PyObject * args)
{
    BaseContext* context = get_basecontext( self );
    char* search_direction= NULL;
    char* type_name= NULL;
    char* name= NULL;
    if ( !PyArg_ParseTuple ( args, "|sss", &search_direction, &type_name, &name ) ) {
        PyErr_SetString(PyExc_TypeError, "BaseContext_getObjects: wrong arguments! Expected format: getObjects ( OPTIONAL STRING searchDirection, OPTIONAL STRING typeName, OPTIONAL STRING name )" );
        return NULL;
    }

    if (!context)
    {
        PyErr_BadArgument();
        return NULL;
    }

    sofa::core::objectmodel::BaseContext::SearchDirection search_direction_enum= sofa::core::objectmodel::BaseContext::Local;
    if ( search_direction )
    {
        std::string search_direction_str ( search_direction );
        if ( search_direction_str == "SearchUp" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchUp;
        }
        else if ( search_direction_str == "Local" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::Local;
        }
        else if ( search_direction_str == "SearchDown" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchDown;
        }
        else if ( search_direction_str == "SearchRoot" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchRoot;
        }
        else if ( search_direction_str == "SearchParents" )
        {
            search_direction_enum= sofa::core::objectmodel::BaseContext::SearchParents;
        }
        else
        {
            msg_warning(context) << "BaseContext_getObjects: Invalid search direction, using 'Local'. Expected: 'SearchUp', 'Local', 'SearchDown', 'SearchRoot', or 'SearchParents'." ;
        }
    }

    sofa::helper::vector< boost::intrusive_ptr<BaseObject> > list;
    context->get<BaseObject>(&list,search_direction_enum);

    PyObject *pyList = PyList_New(0);
    for (size_t i=0; i<list.size(); i++)
    {
        BaseObject* o = list[i].get();

        if( !type_name || o->getClass()->hasParent( type_name ) )
        {
            if ( !name || name == o->getName() )
            {
                PyObject* obj=sofa::PythonFactory::toPython(o); // ref 1
                PyList_Append(pyList,obj); // ref 2
                Py_DECREF(obj); // ref 1 (now owned by list)
            }
        }
    }

    return pyList;
}

SP_CLASS_METHODS_BEGIN(BaseContext)
SP_CLASS_METHOD(BaseContext,getRootContext)
SP_CLASS_METHOD(BaseContext,getTime)
SP_CLASS_METHOD(BaseContext,getDt)
SP_CLASS_METHOD(BaseContext,getGravity)
SP_CLASS_METHOD(BaseContext,setGravity)
SP_CLASS_METHOD_KW(BaseContext,createObject)
SP_CLASS_METHOD_KW(BaseContext,createObject_noWarning) // deprecated
SP_CLASS_METHOD_KW(BaseContext,getObject)
SP_CLASS_METHOD(BaseContext,getObject_noWarning) // deprecated
SP_CLASS_METHOD(BaseContext,getObjects)
SP_CLASS_METHODS_END

static PyObject * BaseContext_getAttr_animate(PyObject *self, void*)
{
    BaseContext* obj = get_basecontext( self );
    return PyBool_FromLong(obj->getAnimate());
}
static int BaseContext_setAttr_animate(PyObject *self, PyObject * args, void*)
{
    BaseContext* obj = get_basecontext( self );
    if (!PyBool_Check(args))
    {
        PyErr_BadArgument();
        return -1;
    }
    obj->setAnimate(args==Py_True);
    return 0;
}

static PyObject * BaseContext_getAttr_active(PyObject *self, void*)
{
    BaseContext* obj = get_basecontext( self );
    return PyBool_FromLong(obj->isActive());
}

static int BaseContext_setAttr_active(PyObject *self, PyObject * args, void*)
{
    BaseContext* obj = get_basecontext( self );
    if (!PyBool_Check(args))
    {
        PyErr_BadArgument();
        return -1;
    }
    obj->setActive(args==Py_True);
    return 0;
}

SP_CLASS_ATTRS_BEGIN(BaseContext)
SP_CLASS_ATTR(BaseContext,active)
SP_CLASS_ATTR(BaseContext,animate)
SP_CLASS_ATTRS_END

SP_CLASS_TYPE_SPTR_ATTR(BaseContext,BaseContext,Base)
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "AnnularMeshGenerator.h"
#include "CastUniquePointer.h"

#include "libmesh/replicated_mesh.h"
#include "libmesh/face_quad4.h"
#include "libmesh/face_tri3.h"

registerMooseObject("MooseApp", AnnularMeshGenerator);

template <>
InputParameters
validParams<AnnularMeshGenerator>()
{
  InputParameters params = validParams<MeshGenerator>();

  params.addRangeCheckedParam<unsigned int>(
      "nr", 1, "nr>0", "Number of elements in the radial direction");
  params.addRequiredRangeCheckedParam<unsigned int>(
      "nt", "nt>0", "Number of elements in the angular direction");
  params.addRequiredRangeCheckedParam<Real>(
      "rmin",
      "rmin>=0.0",
      "Inner radius.  If rmin=0 then a disc mesh (with no central hole) will be created.");
  params.addRequiredParam<Real>("rmax", "Outer radius");
  params.addParam<Real>("tmin", 0.0, "Minimum angle, measured anticlockwise from x axis");
  params.addParam<Real>("tmax",
                        2 * M_PI,
                        "Maximum angle, measured anticlockwise from x axis.  If "
                        "tmin=0 and tmax=2Pi an annular mesh is created.  "
                        "Otherwise, only a sector of an annulus is created");
  params.addRangeCheckedParam<Real>(
      "growth_r", 1.0, "growth_r>0.0", "The ratio of radial sizes of successive rings of elements");
  params.addParam<SubdomainID>(
      "quad_subdomain_id", 0, "The subdomain ID given to the QUAD4 elements");
  params.addParam<SubdomainID>("tri_subdomain_id",
                               1,
                               "The subdomain ID given to the TRI3 elements "
                               "(these exist only if rmin=0, and they exist "
                               "at the center of the disc");
  params.addClassDescription("For rmin>0: creates an annular mesh of QUAD4 elements.  For rmin=0: "
                             "creates a disc mesh of QUAD4 and TRI3 elements.  Boundary sidesets "
                             "are created at rmax and rmin, and given these names.  If tmin!=0 and "
                             "tmax!=2Pi, a sector of an annulus or disc is created.  In this case "
                             "boundary sidesets are also created a tmin and tmax, and "
                             "given these names");

  return params;
}

AnnularMeshGenerator::AnnularMeshGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _nr(getParam<unsigned int>("nr")),
    _nt(getParam<unsigned int>("nt")),
    _rmin(getParam<Real>("rmin")),
    _rmax(getParam<Real>("rmax")),
    _tmin(getParam<Real>("tmin")),
    _tmax(getParam<Real>("tmax")),
    _growth_r(getParam<Real>("growth_r")),
    _len(_growth_r == 1.0 ? (_rmax - _rmin) / _nr
                          : (_rmax - _rmin) * (1.0 - _growth_r) / (1.0 - std::pow(_growth_r, _nr))),
    _full_annulus(_tmin == 0.0 && _tmax == 2 * M_PI),
    _quad_subdomain_id(getParam<SubdomainID>("quad_subdomain_id")),
    _tri_subdomain_id(getParam<SubdomainID>("tri_subdomain_id"))
{
  // catch likely user errors
  if (_rmax <= _rmin)
    mooseError("AnnularMesh: rmax must be greater than rmin");
  if (_tmax <= _tmin)
    mooseError("AnnularMesh: tmax must be greater than tmin");
  if (_tmax - _tmin > 2 * M_PI)
    mooseError("AnnularMesh: tmax - tmin must be <= 2 Pi");
  if (_nt <= (_tmax - _tmin) / M_PI)
    mooseError("AnnularMesh: nt must be greater than (tmax - tmin) / Pi in order to avoid inverted "
               "elements");
  if (_quad_subdomain_id == _tri_subdomain_id)
    mooseError("AnnularMesh: quad_subdomain_id must not equal tri_subdomain_id");
}

std::unique_ptr<MeshBase>
AnnularMeshGenerator::generate()
{
  std::unique_ptr<ReplicatedMesh> mesh = libmesh_make_unique<ReplicatedMesh>(comm(), 2);

  const Real dt = (_tmax - _tmin) / _nt;

  mesh->set_mesh_dimension(2);
  mesh->set_spatial_dimension(2);
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  const unsigned num_angular_nodes = (_full_annulus ? _nt : _nt + 1);
  const unsigned num_nodes =
      (_rmin > 0.0 ? (_nr + 1) * num_angular_nodes : _nr * num_angular_nodes + 1);
  const unsigned min_nonzero_layer_num = (_rmin > 0.0 ? 0 : 1);
  std::vector<Node *> nodes(num_nodes);
  unsigned node_id = 0;

  // add nodes at rmax that aren't yet connected to any elements
  Real current_r = _rmax;
  for (unsigned angle_num = 0; angle_num < num_angular_nodes; ++angle_num)
  {
    const Real angle = _tmin + angle_num * dt;
    const Real x = current_r * std::cos(angle);
    const Real y = current_r * std::sin(angle);
    nodes[node_id] = mesh->add_point(Point(x, y, 0.0), node_id);
    node_id++;
  }

  // add nodes at smaller radii, and connect them with elements
  for (unsigned layer_num = _nr; layer_num > min_nonzero_layer_num; --layer_num)
  {
    if (layer_num == 1)
      current_r = _rmin; // account for precision loss
    else
      current_r -= _len * std::pow(_growth_r, layer_num - 1);

    // add node at angle = _tmin
    nodes[node_id] = mesh->add_point(
        Point(current_r * std::cos(_tmin), current_r * std::sin(_tmin), 0.0), node_id);
    node_id++;
    for (unsigned angle_num = 1; angle_num < num_angular_nodes; ++angle_num)
    {
      const Real angle = _tmin + angle_num * dt;
      const Real x = current_r * std::cos(angle);
      const Real y = current_r * std::sin(angle);
      nodes[node_id] = mesh->add_point(Point(x, y, 0.0), node_id);
      Elem * elem = mesh->add_elem(new Quad4);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
      elem->set_node(3) = nodes[node_id - num_angular_nodes];
      elem->subdomain_id() = _quad_subdomain_id;
      node_id++;

      if (layer_num == _nr)
        // add outer boundary (boundary_id = 1)
        boundary_info.add_side(elem, 2, 1);
      if (layer_num == 1)
        // add inner boundary (boundary_id = 0)
        boundary_info.add_side(elem, 0, 0);
      if (!_full_annulus && angle_num == 1)
        // add tmin boundary (boundary_id = 2)
        boundary_info.add_side(elem, 1, 2);
      if (!_full_annulus && angle_num == num_angular_nodes - 1)
        // add tmin boundary (boundary_id = 3)
        boundary_info.add_side(elem, 3, 3);
    }
    if (_full_annulus)
    {
      // add element connecting to node at angle=0
      Elem * elem = mesh->add_elem(new Quad4);
      elem->set_node(0) = nodes[node_id - num_angular_nodes];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
      elem->set_node(3) = nodes[node_id - 2 * num_angular_nodes];
      elem->subdomain_id() = _quad_subdomain_id;

      if (layer_num == _nr)
        // add outer boundary (boundary_id = 1)
        boundary_info.add_side(elem, 2, 1);
      if (layer_num == 1)
        // add inner boundary (boundary_id = 0)
        boundary_info.add_side(elem, 0, 0);
    }
  }

  // add single node at origin, if relevant
  if (_rmin == 0.0)
  {
    nodes[node_id] = mesh->add_point(Point(0.0, 0.0, 0.0), node_id);
    boundary_info.add_node(node_id, 0); // boundary_id=0 is centre
    for (unsigned angle_num = 0; angle_num < num_angular_nodes - 1; ++angle_num)
    {
      Elem * elem = mesh->add_elem(new Tri3);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - num_angular_nodes + angle_num];
      elem->set_node(2) = nodes[node_id - num_angular_nodes + angle_num + 1];
      elem->subdomain_id() = _tri_subdomain_id;
    }
    if (_full_annulus)
    {
      Elem * elem = mesh->add_elem(new Tri3);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes];
      elem->subdomain_id() = _tri_subdomain_id;
    }
  }

  boundary_info.sideset_name(0) = "rmin";
  boundary_info.sideset_name(1) = "rmax";
  boundary_info.nodeset_name(0) = "rmin";
  boundary_info.nodeset_name(1) = "rmax";
  if (!_full_annulus)
  {
    boundary_info.sideset_name(2) = "tmin";
    boundary_info.sideset_name(3) = "tmax";
    boundary_info.nodeset_name(2) = "tmin";
    boundary_info.nodeset_name(3) = "tmax";
  }

  mesh->prepare_for_use(false);

  return dynamic_pointer_cast<MeshBase>(mesh);
}
<commit_msg>AnnualMeshes can be DistributedMeshes<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "AnnularMeshGenerator.h"
#include "CastUniquePointer.h"

#include "libmesh/replicated_mesh.h"
#include "libmesh/face_quad4.h"
#include "libmesh/face_tri3.h"

registerMooseObject("MooseApp", AnnularMeshGenerator);

template <>
InputParameters
validParams<AnnularMeshGenerator>()
{
  InputParameters params = validParams<MeshGenerator>();

  params.addRangeCheckedParam<unsigned int>(
      "nr", 1, "nr>0", "Number of elements in the radial direction");
  params.addRequiredRangeCheckedParam<unsigned int>(
      "nt", "nt>0", "Number of elements in the angular direction");
  params.addRequiredRangeCheckedParam<Real>(
      "rmin",
      "rmin>=0.0",
      "Inner radius.  If rmin=0 then a disc mesh (with no central hole) will be created.");
  params.addRequiredParam<Real>("rmax", "Outer radius");
  params.addParam<Real>("tmin", 0.0, "Minimum angle, measured anticlockwise from x axis");
  params.addParam<Real>("tmax",
                        2 * M_PI,
                        "Maximum angle, measured anticlockwise from x axis.  If "
                        "tmin=0 and tmax=2Pi an annular mesh is created.  "
                        "Otherwise, only a sector of an annulus is created");
  params.addRangeCheckedParam<Real>(
      "growth_r", 1.0, "growth_r>0.0", "The ratio of radial sizes of successive rings of elements");
  params.addParam<SubdomainID>(
      "quad_subdomain_id", 0, "The subdomain ID given to the QUAD4 elements");
  params.addParam<SubdomainID>("tri_subdomain_id",
                               1,
                               "The subdomain ID given to the TRI3 elements "
                               "(these exist only if rmin=0, and they exist "
                               "at the center of the disc");
  params.addClassDescription("For rmin>0: creates an annular mesh of QUAD4 elements.  For rmin=0: "
                             "creates a disc mesh of QUAD4 and TRI3 elements.  Boundary sidesets "
                             "are created at rmax and rmin, and given these names.  If tmin!=0 and "
                             "tmax!=2Pi, a sector of an annulus or disc is created.  In this case "
                             "boundary sidesets are also created a tmin and tmax, and "
                             "given these names");

  return params;
}

AnnularMeshGenerator::AnnularMeshGenerator(const InputParameters & parameters)
  : MeshGenerator(parameters),
    _nr(getParam<unsigned int>("nr")),
    _nt(getParam<unsigned int>("nt")),
    _rmin(getParam<Real>("rmin")),
    _rmax(getParam<Real>("rmax")),
    _tmin(getParam<Real>("tmin")),
    _tmax(getParam<Real>("tmax")),
    _growth_r(getParam<Real>("growth_r")),
    _len(_growth_r == 1.0 ? (_rmax - _rmin) / _nr
                          : (_rmax - _rmin) * (1.0 - _growth_r) / (1.0 - std::pow(_growth_r, _nr))),
    _full_annulus(_tmin == 0.0 && _tmax == 2 * M_PI),
    _quad_subdomain_id(getParam<SubdomainID>("quad_subdomain_id")),
    _tri_subdomain_id(getParam<SubdomainID>("tri_subdomain_id"))
{
  // catch likely user errors
  if (_rmax <= _rmin)
    mooseError("AnnularMesh: rmax must be greater than rmin");
  if (_tmax <= _tmin)
    mooseError("AnnularMesh: tmax must be greater than tmin");
  if (_tmax - _tmin > 2 * M_PI)
    mooseError("AnnularMesh: tmax - tmin must be <= 2 Pi");
  if (_nt <= (_tmax - _tmin) / M_PI)
    mooseError("AnnularMesh: nt must be greater than (tmax - tmin) / Pi in order to avoid inverted "
               "elements");
  if (_quad_subdomain_id == _tri_subdomain_id)
    mooseError("AnnularMesh: quad_subdomain_id must not equal tri_subdomain_id");
}

std::unique_ptr<MeshBase>
AnnularMeshGenerator::generate()
{
  // Have MOOSE construct the correct libMesh::Mesh object using Mesh block and CLI parameters.
  auto mesh = _mesh->buildMeshBaseObject();

  const Real dt = (_tmax - _tmin) / _nt;

  mesh->set_mesh_dimension(2);
  mesh->set_spatial_dimension(2);
  BoundaryInfo & boundary_info = mesh->get_boundary_info();

  const unsigned num_angular_nodes = (_full_annulus ? _nt : _nt + 1);
  const unsigned num_nodes =
      (_rmin > 0.0 ? (_nr + 1) * num_angular_nodes : _nr * num_angular_nodes + 1);
  const unsigned min_nonzero_layer_num = (_rmin > 0.0 ? 0 : 1);
  std::vector<Node *> nodes(num_nodes);
  unsigned node_id = 0;

  // add nodes at rmax that aren't yet connected to any elements
  Real current_r = _rmax;
  for (unsigned angle_num = 0; angle_num < num_angular_nodes; ++angle_num)
  {
    const Real angle = _tmin + angle_num * dt;
    const Real x = current_r * std::cos(angle);
    const Real y = current_r * std::sin(angle);
    nodes[node_id] = mesh->add_point(Point(x, y, 0.0), node_id);
    node_id++;
  }

  // add nodes at smaller radii, and connect them with elements
  for (unsigned layer_num = _nr; layer_num > min_nonzero_layer_num; --layer_num)
  {
    if (layer_num == 1)
      current_r = _rmin; // account for precision loss
    else
      current_r -= _len * std::pow(_growth_r, layer_num - 1);

    // add node at angle = _tmin
    nodes[node_id] = mesh->add_point(
        Point(current_r * std::cos(_tmin), current_r * std::sin(_tmin), 0.0), node_id);
    node_id++;
    for (unsigned angle_num = 1; angle_num < num_angular_nodes; ++angle_num)
    {
      const Real angle = _tmin + angle_num * dt;
      const Real x = current_r * std::cos(angle);
      const Real y = current_r * std::sin(angle);
      nodes[node_id] = mesh->add_point(Point(x, y, 0.0), node_id);
      Elem * elem = mesh->add_elem(new Quad4);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
      elem->set_node(3) = nodes[node_id - num_angular_nodes];
      elem->subdomain_id() = _quad_subdomain_id;
      node_id++;

      if (layer_num == _nr)
        // add outer boundary (boundary_id = 1)
        boundary_info.add_side(elem, 2, 1);
      if (layer_num == 1)
        // add inner boundary (boundary_id = 0)
        boundary_info.add_side(elem, 0, 0);
      if (!_full_annulus && angle_num == 1)
        // add tmin boundary (boundary_id = 2)
        boundary_info.add_side(elem, 1, 2);
      if (!_full_annulus && angle_num == num_angular_nodes - 1)
        // add tmin boundary (boundary_id = 3)
        boundary_info.add_side(elem, 3, 3);
    }
    if (_full_annulus)
    {
      // add element connecting to node at angle=0
      Elem * elem = mesh->add_elem(new Quad4);
      elem->set_node(0) = nodes[node_id - num_angular_nodes];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes - 1];
      elem->set_node(3) = nodes[node_id - 2 * num_angular_nodes];
      elem->subdomain_id() = _quad_subdomain_id;

      if (layer_num == _nr)
        // add outer boundary (boundary_id = 1)
        boundary_info.add_side(elem, 2, 1);
      if (layer_num == 1)
        // add inner boundary (boundary_id = 0)
        boundary_info.add_side(elem, 0, 0);
    }
  }

  // add single node at origin, if relevant
  if (_rmin == 0.0)
  {
    nodes[node_id] = mesh->add_point(Point(0.0, 0.0, 0.0), node_id);
    boundary_info.add_node(node_id, 0); // boundary_id=0 is centre
    for (unsigned angle_num = 0; angle_num < num_angular_nodes - 1; ++angle_num)
    {
      Elem * elem = mesh->add_elem(new Tri3);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - num_angular_nodes + angle_num];
      elem->set_node(2) = nodes[node_id - num_angular_nodes + angle_num + 1];
      elem->subdomain_id() = _tri_subdomain_id;
    }
    if (_full_annulus)
    {
      Elem * elem = mesh->add_elem(new Tri3);
      elem->set_node(0) = nodes[node_id];
      elem->set_node(1) = nodes[node_id - 1];
      elem->set_node(2) = nodes[node_id - num_angular_nodes];
      elem->subdomain_id() = _tri_subdomain_id;
    }
  }

  boundary_info.sideset_name(0) = "rmin";
  boundary_info.sideset_name(1) = "rmax";
  boundary_info.nodeset_name(0) = "rmin";
  boundary_info.nodeset_name(1) = "rmax";
  if (!_full_annulus)
  {
    boundary_info.sideset_name(2) = "tmin";
    boundary_info.sideset_name(3) = "tmax";
    boundary_info.nodeset_name(2) = "tmin";
    boundary_info.nodeset_name(3) = "tmax";
  }

  mesh->prepare_for_use(false);

  return dynamic_pointer_cast<MeshBase>(mesh);
}
<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include <array>

#include <folly/Memory.h>
#include <folly/io/Cursor.h>
#include <folly/io/IOBuf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/ConnectionAutomaton.h"
#include "src/Frame.h"
#include "src/framed/FramedDuplexConnection.h"
#include "src/framed/FramedWriter.h"
#include "test/InlineConnection.h"
#include "test/ReactiveStreamsMocksCompat.h"

using namespace ::testing;
using namespace ::reactivesocket;

static std::unique_ptr<folly::IOBuf> makeInvalidFrameHeader() {
   // Create a header without the stream id
   folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength());
   queue.append(folly::IOBuf::create(FrameHeader::kSize - sizeof(StreamId)));

   folly::io::QueueAppender appender(&queue, /* do not grow */ 0);
   appender.writeBE<uint16_t>(static_cast<uint16_t>(FrameType::REQUEST_N));
   appender.writeBE<uint16_t>(FrameFlags_EMPTY);
   return queue.move();
 }

TEST(ConnectionAutomatonTest, InvalidFrameHeader) {
   auto automatonConnection = folly::make_unique<InlineConnection>();
   auto testConnection = folly::make_unique<InlineConnection>();

   automatonConnection->connectTo(*testConnection);

   auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
       std::move(automatonConnection));

   auto framedTestConnection =
       folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

   // Dump 1 invalid frame and expect an error

   auto inputSubscription = std::make_shared<MockSubscription>();

   Sequence s;

   EXPECT_CALL(*inputSubscription, request_(_))
       .InSequence(s)
       .WillOnce(Invoke([&](size_t n) {
         framedTestConnection->getOutput()->onNext(makeInvalidFrameHeader());
       }));

   auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
   EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
       .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
         // allow receiving frames from the automaton
         subscription->request(std::numeric_limits<size_t>::max());
       }));
   EXPECT_CALL(*testOutputSubscriber, onNext_(_))
       .InSequence(s)
       .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
         auto frameType = FrameHeader::peekType(*frame);
         Frame_ERROR error;
         ASSERT_EQ(FrameType::ERROR, frameType);
         ASSERT_TRUE(error.deserializeFrom(std::move(frame)));
         ASSERT_EQ("invalid frame", error.payload_.moveDataToString());
       }));
   EXPECT_CALL(*testOutputSubscriber, onComplete_()).Times(1).InSequence(s);
   EXPECT_CALL(*inputSubscription, cancel_()).Times(1).InSequence(s);

   framedTestConnection->setInput(testOutputSubscriber);
   framedTestConnection->getOutput()->onSubscribe(inputSubscription);

   auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
       std::move(framedAutomatonConnection),
       [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
       nullptr,
       Stats::noop(),
       false);
   connectionAutomaton->connect();
}

static void terminateTest(bool inOnSubscribe, bool inOnNext, bool inOnComplete, bool inRequest) {
  auto automatonConnection = folly::make_unique<InlineConnection>();
  auto testConnection = folly::make_unique<InlineConnection>();

  automatonConnection->connectTo(*testConnection);

  auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
      std::move(automatonConnection));

  auto framedTestConnection =
      folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

  auto inputSubscription = std::make_shared<MockSubscription>();

  Sequence s;

  if (inOnSubscribe) {
    EXPECT_CALL(*inputSubscription, request_(_)).Times(0);
  } else {
    EXPECT_CALL(*inputSubscription, request_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](size_t n) {
          if (inRequest) {
            framedTestConnection->getOutput()->onComplete();
          } else {
            framedTestConnection->getOutput()->onNext(makeInvalidFrameHeader());
          }
        }));
  }

  auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
  EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
      .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
        if (inOnSubscribe) {
          subscription->cancel();
        } else {
          // allow receiving frames from the automaton
          subscription->request(std::numeric_limits<size_t>::max());
        }
      }));
  if (!inOnSubscribe && !inRequest) {
    EXPECT_CALL(*testOutputSubscriber, onNext_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
          if (inOnNext) {
            testOutputSubscriber->subscription()->cancel();
          }
        }));
  }
  EXPECT_CALL(*testOutputSubscriber, onComplete_()).InSequence(s)
      .WillOnce(Invoke([&]() {
        if (inOnComplete) {
          testOutputSubscriber->subscription()->cancel();
        }
      }));

  EXPECT_CALL(*inputSubscription, cancel_()).Times(1).InSequence(s);

  framedTestConnection->setInput(testOutputSubscriber);
  framedTestConnection->getOutput()->onSubscribe(inputSubscription);

  auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
      std::move(framedAutomatonConnection),
      [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
      nullptr,
      Stats::noop(),
      false);
  connectionAutomaton->connect();
}

TEST(ConnectionAutomatonTest, CleanTerminateOnSubscribe) {
  terminateTest(true, false, false, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateOnNext) {
  terminateTest(false, true, false, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateOnComplete) {
  terminateTest(true, true, true, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateRequest) {
  terminateTest(false, true, false, true);
}

TEST(ConnectionAutomatonTest, RefuseFrame) {
    auto automatonConnection = folly::make_unique<InlineConnection>();
    auto testConnection = folly::make_unique<InlineConnection>();

    automatonConnection->connectTo(*testConnection);

    auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
        std::move(automatonConnection));

    auto framedTestConnection =
        folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

    // dump 3 frames to ConnectionAutomaton
    // the first frame should be refused and the connection closed
    // the last 2 frames should be ignored
    // everything should die gracefully

    static const int streamId = 1;
    auto inputSubscription = std::make_shared<MockSubscription>();

    Sequence s;

    auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
    EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
          // allow receiving frames from the automaton
          subscription->request(std::numeric_limits<size_t>::max());
        }));

    EXPECT_CALL(*inputSubscription, request_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](size_t n) {
          auto framedWriter = std::dynamic_pointer_cast<FramedWriter>(framedTestConnection->getOutput());
          CHECK(framedWriter);

          std::vector<std::unique_ptr<folly::IOBuf>> frames;
          frames.push_back(Frame_REQUEST_N(streamId, 1).serializeOut());
          frames.push_back(Frame_REQUEST_N(streamId + 1, 1).serializeOut());
          frames.push_back(Frame_REQUEST_N(streamId + 2, 1).serializeOut());

          framedWriter->onNextMultiple(std::move(frames));
        }));
    EXPECT_CALL(*testOutputSubscriber, onNext_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
          auto frameType = FrameHeader::peekType(*frame);
          ASSERT_EQ(FrameType::ERROR, frameType);
        }));
    EXPECT_CALL(*testOutputSubscriber, onComplete_()).Times(1).InSequence(s);
    EXPECT_CALL(*inputSubscription, cancel_()).Times(1).InSequence(s);

    framedTestConnection->setInput(testOutputSubscriber);
    framedTestConnection->getOutput()->onSubscribe(inputSubscription);

    auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
        std::move(framedAutomatonConnection),
        [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
        nullptr,
        Stats::noop(),
        false);
    connectionAutomaton->connect();
    new int;
}
<commit_msg>disable Sequence in InvalidFrameHeader unit test<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include <array>

#include <folly/Memory.h>
#include <folly/io/Cursor.h>
#include <folly/io/IOBuf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/ConnectionAutomaton.h"
#include "src/Frame.h"
#include "src/framed/FramedDuplexConnection.h"
#include "src/framed/FramedWriter.h"
#include "test/InlineConnection.h"
#include "test/ReactiveStreamsMocksCompat.h"

using namespace ::testing;
using namespace ::reactivesocket;

static std::unique_ptr<folly::IOBuf> makeInvalidFrameHeader() {
   // Create a header without the stream id
   folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength());
   queue.append(folly::IOBuf::create(FrameHeader::kSize - sizeof(StreamId)));

   folly::io::QueueAppender appender(&queue, /* do not grow */ 0);
   appender.writeBE<uint16_t>(static_cast<uint16_t>(FrameType::REQUEST_N));
   appender.writeBE<uint16_t>(FrameFlags_EMPTY);
   return queue.move();
 }

TEST(ConnectionAutomatonTest, InvalidFrameHeader) {
   auto automatonConnection = folly::make_unique<InlineConnection>();
   auto testConnection = folly::make_unique<InlineConnection>();

   automatonConnection->connectTo(*testConnection);

   auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
       std::move(automatonConnection));

   auto framedTestConnection =
       folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

   // Dump 1 invalid frame and expect an error

   auto inputSubscription = std::make_shared<MockSubscription>();

   // TODO: enable Sequence..
   //Sequence s;

   EXPECT_CALL(*inputSubscription, request_(_))
//       .InSequence(s)
       .WillOnce(Invoke([&](size_t n) {
         framedTestConnection->getOutput()->onNext(makeInvalidFrameHeader());
       }));

   auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
   EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
       .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
         // allow receiving frames from the automaton
         subscription->request(std::numeric_limits<size_t>::max());
       }));
   EXPECT_CALL(*testOutputSubscriber, onNext_(_))
//       .InSequence(s)
       .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
         auto frameType = FrameHeader::peekType(*frame);
         Frame_ERROR error;
         ASSERT_EQ(FrameType::ERROR, frameType);
         ASSERT_TRUE(error.deserializeFrom(std::move(frame)));
         ASSERT_EQ("invalid frame", error.payload_.moveDataToString());
       }));
   EXPECT_CALL(*testOutputSubscriber, onComplete_()).Times(1)/*.InSequence(s)*/;
   EXPECT_CALL(*inputSubscription, cancel_()).Times(1)/*.InSequence(s)*/;

   framedTestConnection->setInput(testOutputSubscriber);
   framedTestConnection->getOutput()->onSubscribe(inputSubscription);

   auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
       std::move(framedAutomatonConnection),
       [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
       nullptr,
       Stats::noop(),
       false);
   connectionAutomaton->connect();
}

static void terminateTest(bool inOnSubscribe, bool inOnNext, bool inOnComplete, bool inRequest) {
  auto automatonConnection = folly::make_unique<InlineConnection>();
  auto testConnection = folly::make_unique<InlineConnection>();

  automatonConnection->connectTo(*testConnection);

  auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
      std::move(automatonConnection));

  auto framedTestConnection =
      folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

  auto inputSubscription = std::make_shared<MockSubscription>();

  Sequence s;

  if (inOnSubscribe) {
    EXPECT_CALL(*inputSubscription, request_(_)).Times(0);
  } else {
    EXPECT_CALL(*inputSubscription, request_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](size_t n) {
          if (inRequest) {
            framedTestConnection->getOutput()->onComplete();
          } else {
            framedTestConnection->getOutput()->onNext(makeInvalidFrameHeader());
          }
        }));
  }

  auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
  EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
      .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
        if (inOnSubscribe) {
          subscription->cancel();
        } else {
          // allow receiving frames from the automaton
          subscription->request(std::numeric_limits<size_t>::max());
        }
      }));
  if (!inOnSubscribe && !inRequest) {
    EXPECT_CALL(*testOutputSubscriber, onNext_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
          if (inOnNext) {
            testOutputSubscriber->subscription()->cancel();
          }
        }));
  }
  EXPECT_CALL(*testOutputSubscriber, onComplete_()).InSequence(s)
      .WillOnce(Invoke([&]() {
        if (inOnComplete) {
          testOutputSubscriber->subscription()->cancel();
        }
      }));

  EXPECT_CALL(*inputSubscription, cancel_()).Times(1).InSequence(s);

  framedTestConnection->setInput(testOutputSubscriber);
  framedTestConnection->getOutput()->onSubscribe(inputSubscription);

  auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
      std::move(framedAutomatonConnection),
      [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
      nullptr,
      Stats::noop(),
      false);
  connectionAutomaton->connect();
}

TEST(ConnectionAutomatonTest, CleanTerminateOnSubscribe) {
  terminateTest(true, false, false, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateOnNext) {
  terminateTest(false, true, false, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateOnComplete) {
  terminateTest(true, true, true, false);
}

TEST(ConnectionAutomatonTest, CleanTerminateRequest) {
  terminateTest(false, true, false, true);
}

TEST(ConnectionAutomatonTest, RefuseFrame) {
    auto automatonConnection = folly::make_unique<InlineConnection>();
    auto testConnection = folly::make_unique<InlineConnection>();

    automatonConnection->connectTo(*testConnection);

    auto framedAutomatonConnection = folly::make_unique<FramedDuplexConnection>(
        std::move(automatonConnection));

    auto framedTestConnection =
        folly::make_unique<FramedDuplexConnection>(std::move(testConnection));

    // dump 3 frames to ConnectionAutomaton
    // the first frame should be refused and the connection closed
    // the last 2 frames should be ignored
    // everything should die gracefully

    static const int streamId = 1;
    auto inputSubscription = std::make_shared<MockSubscription>();

    Sequence s;

    auto testOutputSubscriber = std::make_shared<MockSubscriber<std::unique_ptr<folly::IOBuf>>>();
    EXPECT_CALL(*testOutputSubscriber, onSubscribe_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::shared_ptr<Subscription> subscription) {
          // allow receiving frames from the automaton
          subscription->request(std::numeric_limits<size_t>::max());
        }));

    EXPECT_CALL(*inputSubscription, request_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](size_t n) {
          auto framedWriter = std::dynamic_pointer_cast<FramedWriter>(framedTestConnection->getOutput());
          CHECK(framedWriter);

          std::vector<std::unique_ptr<folly::IOBuf>> frames;
          frames.push_back(Frame_REQUEST_N(streamId, 1).serializeOut());
          frames.push_back(Frame_REQUEST_N(streamId + 1, 1).serializeOut());
          frames.push_back(Frame_REQUEST_N(streamId + 2, 1).serializeOut());

          framedWriter->onNextMultiple(std::move(frames));
        }));
    EXPECT_CALL(*testOutputSubscriber, onNext_(_))
        .InSequence(s)
        .WillOnce(Invoke([&](std::unique_ptr<folly::IOBuf>& frame) {
          auto frameType = FrameHeader::peekType(*frame);
          ASSERT_EQ(FrameType::ERROR, frameType);
        }));
    EXPECT_CALL(*testOutputSubscriber, onComplete_()).Times(1).InSequence(s);
    EXPECT_CALL(*inputSubscription, cancel_()).Times(1).InSequence(s);

    framedTestConnection->setInput(testOutputSubscriber);
    framedTestConnection->getOutput()->onSubscribe(inputSubscription);

    auto connectionAutomaton = std::make_shared<ConnectionAutomaton>(
        std::move(framedAutomatonConnection),
        [](StreamId, std::unique_ptr<folly::IOBuf>) { return false; },
        nullptr,
        Stats::noop(),
        false);
    connectionAutomaton->connect();
    new int;
}
<|endoftext|>


<commit_before>// @(#)root/base:$Id$
// Author: Rene Brun   05/02/2007
/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualStreamerInfo   Abstract Interface class                      //
//                                                                      //
// Abstract Interface describing Streamer information for one class.    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TClass.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"
#include "TVirtualStreamerInfo.h"
#include "TPluginManager.h"
#include "TStreamerElement.h"
#include "TError.h"

TVirtualStreamerInfo *TVirtualStreamerInfo::fgInfoFactory    = 0;

Bool_t  TVirtualStreamerInfo::fgCanDelete        = kTRUE;
Bool_t  TVirtualStreamerInfo::fgOptimize         = kTRUE;
Bool_t  TVirtualStreamerInfo::fgStreamMemberWise = kTRUE;

ClassImp(TVirtualStreamerInfo)

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo() : fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   // Default constructor.

}

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo(TClass *cl)
   : TNamed(cl->GetName(),""), fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   // Default constructor.

}

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo(const TVirtualStreamerInfo& info)
  : TNamed(info), fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   //copy constructor
}

//______________________________________________________________________________
TVirtualStreamerInfo& TVirtualStreamerInfo::operator=(const TVirtualStreamerInfo& info)
{
   //assignment operator
   if(this!=&info) {
      TNamed::operator=(info);
   }
   return *this;
}

//______________________________________________________________________________
TVirtualStreamerInfo::~TVirtualStreamerInfo()
{
   // Destructor

}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::CanDelete()
{
   // static function returning true if ReadBuffer can delete object
   return fgCanDelete;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::CanOptimize()
{
   // static function returning true if optimization can be on
   return fgOptimize;
}

//______________________________________________________________________________
const char *TVirtualStreamerInfo::GetElementCounterStart(const char *dmTitle)
{
   // Given a comment/title declaring an array counter, for example:
   //    //[fArraySize] array of size fArraySize
   // return the start of the array dimension declaration start in the string
   // (so the location of the 'f'.

   for (const char *lbracket = dmTitle; *lbracket; ++lbracket) {
      // = ::strchr(dmTitle, '[');
      if ( (*lbracket) == '[' ) return lbracket;
      if ( (*lbracket) != '/' && !isspace(*lbracket) ) {
         // Allow only comment delimiters and white spaces
         // before the array information.
         return 0;
      }
   }
   return 0;
}

//______________________________________________________________________________
TStreamerBasicType *TVirtualStreamerInfo::GetElementCounter(const char *countName, TClass *cl)
{
   // Get pointer to a TStreamerBasicType in TClass *cl
   //static function

<<<<<<< HEAD
   const TObjArray *sinfos = cl->GetStreamerInfos();
   TVirtualStreamerInfo *info = (TVirtualStreamerInfo *)sinfos->At(cl->GetClassVersion());
=======
   TVirtualStreamerInfo *info;
   {
      R__LOCKGUARD(gInterpreterMutex);
      TObjArray *sinfos = cl->GetStreamerInfos();
      info = (TVirtualStreamerInfo *)sinfos->At(cl->GetClassVersion());
   }
>>>>>>> 55252ea... Protected threaded access to TClass::GetStreamerInfos()

   if (!info || !info->IsBuilt()) {
      // Even if the streamerInfo exist, it could still need to be 'build'
      // It is important to figure this out, because
      //   a) if it is not build, we need to build
      //   b) if is build, we should not build it (or we could end up in an
      //      infinite loop, if the element and its counter are in the same
      //      class!

      info = cl->GetStreamerInfo();
   }
   if (!info) return 0;
   TStreamerElement *element = (TStreamerElement *)info->GetElements()->FindObject(countName);
   if (!element) return 0;
   if (element->IsA() == TStreamerBasicType::Class()) return (TStreamerBasicType*)element;
   return 0;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::GetStreamMemberWise()
{
   // Return whether the TStreamerInfos will save the collections in
   // "member-wise" order whenever possible.    The default is to store member-wise.
   // kTRUE indicates member-wise storing
   // kFALSE inddicates object-wise storing
   //
   // A collection can be saved member wise when it contain is guaranteed to be
   // homogeneous.  For example std::vector<THit> can be stored member wise,
   // while std::vector<THit*> can not (possible use of polymorphism).

   return fgStreamMemberWise;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::Optimize(Bool_t opt)
{
   //  This is a static function.
   //  Set optimization option.
   //  When this option is activated (default), consecutive data members
   //  of the same type are merged into an array (faster).
   //  Optimization must be off in TTree split mode.

   fgOptimize = opt;
}

//______________________________________________________________________________
TVirtualStreamerInfo *TVirtualStreamerInfo::Factory()
{
   // Static function returning a pointer to a new TVirtualStreamerInfo object.
   // If the Info factory does not exist, it is created via the plugin manager.
   // In reality the factory is an empty TStreamerInfo object.

   if (!fgInfoFactory) {
      TPluginHandler *h;
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualStreamerInfo","TStreamerInfo"))) {
         if (h->LoadPlugin() == -1) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "The plugin handler for TVirtualStreamerInfo was found but failed to load!");
         }
         fgInfoFactory = (TVirtualStreamerInfo*) h->ExecPlugin(0);
         if (fgInfoFactory == 0) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "The plugin handler for TVirtualStreamerInfo was found but failed to create the factory object!");
         }
      } else {
         TString filename("$ROOTSYS/etc/plugins/TVirtualStreamerInfo");
         gSystem->ExpandPathName(filename);
         if (gSystem->AccessPathName(filename)) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "Cannot find the plugin handler for TVirtualStreamerInfo! "
                    "$ROOTSYS/etc/plugins/TVirtualStreamerInfo does not exist "
                    "or is inaccessible.");
         } else {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "Cannot find the plugin handler for TVirtualStreamerInfo! "
                    "However $ROOTSYS/etc/plugins/TVirtualStreamerInfo is accessible, "
                    "Check the content of this directory!");
         }
      }
   }

   return fgInfoFactory;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::SetCanDelete(Bool_t opt)
{
   //  This is a static function.
   //  Set object delete option.
   //  When this option is activated (default), ReadBuffer automatically
   //  delete objects when a data member is a pointer to an object.
   //  If your constructor is not presetting pointers to 0, you must
   //  call this static function TStreamerInfo::SetCanDelete(kFALSE);

   fgCanDelete = opt;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::SetFactory(TVirtualStreamerInfo *factory)
{
   //static function: Set the StreamerInfo factory
   fgInfoFactory = factory;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::SetStreamMemberWise(Bool_t enable)
{
   // Set whether the TStreamerInfos will save the collections in
   // "member-wise" order whenever possible.  The default is to store member-wise.
   // kTRUE indicates member-wise storing
   // kFALSE inddicates object-wise storing
   // This function returns the previous value of fgStreamMemberWise.

   // A collection can be saved member wise when it contain is guaranteed to be
   // homogeneous.  For example std::vector<THit> can be stored member wise,
   // while std::vector<THit*> can not (possible use of polymorphism).

   Bool_t prev = fgStreamMemberWise;
   fgStreamMemberWise = enable;
   return prev;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::Streamer(TBuffer &R__b)
{
   // Stream an object of class TVirtualStreamerInfo.

   TNamed::Streamer(R__b);
}
<commit_msg>Finish conflict resolution<commit_after>// @(#)root/base:$Id$
// Author: Rene Brun   05/02/2007
/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualStreamerInfo   Abstract Interface class                      //
//                                                                      //
// Abstract Interface describing Streamer information for one class.    //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TClass.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"
#include "TVirtualStreamerInfo.h"
#include "TPluginManager.h"
#include "TStreamerElement.h"
#include "TError.h"

TVirtualStreamerInfo *TVirtualStreamerInfo::fgInfoFactory    = 0;

Bool_t  TVirtualStreamerInfo::fgCanDelete        = kTRUE;
Bool_t  TVirtualStreamerInfo::fgOptimize         = kTRUE;
Bool_t  TVirtualStreamerInfo::fgStreamMemberWise = kTRUE;

ClassImp(TVirtualStreamerInfo)

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo() : fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   // Default constructor.

}

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo(TClass *cl)
   : TNamed(cl->GetName(),""), fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   // Default constructor.

}

//______________________________________________________________________________
TVirtualStreamerInfo::TVirtualStreamerInfo(const TVirtualStreamerInfo& info)
  : TNamed(info), fOptimized(kFALSE), fIsBuilt(kFALSE)
{
   //copy constructor
}

//______________________________________________________________________________
TVirtualStreamerInfo& TVirtualStreamerInfo::operator=(const TVirtualStreamerInfo& info)
{
   //assignment operator
   if(this!=&info) {
      TNamed::operator=(info);
   }
   return *this;
}

//______________________________________________________________________________
TVirtualStreamerInfo::~TVirtualStreamerInfo()
{
   // Destructor

}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::CanDelete()
{
   // static function returning true if ReadBuffer can delete object
   return fgCanDelete;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::CanOptimize()
{
   // static function returning true if optimization can be on
   return fgOptimize;
}

//______________________________________________________________________________
const char *TVirtualStreamerInfo::GetElementCounterStart(const char *dmTitle)
{
   // Given a comment/title declaring an array counter, for example:
   //    //[fArraySize] array of size fArraySize
   // return the start of the array dimension declaration start in the string
   // (so the location of the 'f'.

   for (const char *lbracket = dmTitle; *lbracket; ++lbracket) {
      // = ::strchr(dmTitle, '[');
      if ( (*lbracket) == '[' ) return lbracket;
      if ( (*lbracket) != '/' && !isspace(*lbracket) ) {
         // Allow only comment delimiters and white spaces
         // before the array information.
         return 0;
      }
   }
   return 0;
}

//______________________________________________________________________________
TStreamerBasicType *TVirtualStreamerInfo::GetElementCounter(const char *countName, TClass *cl)
{
   // Get pointer to a TStreamerBasicType in TClass *cl
   //static function

   TVirtualStreamerInfo *info;
   {
      R__LOCKGUARD(gInterpreterMutex);
      const TObjArray *sinfos = cl->GetStreamerInfos();
      info = (TVirtualStreamerInfo *)sinfos->At(cl->GetClassVersion());
   }

   if (!info || !info->IsBuilt()) {
      // Even if the streamerInfo exist, it could still need to be 'build'
      // It is important to figure this out, because
      //   a) if it is not build, we need to build
      //   b) if is build, we should not build it (or we could end up in an
      //      infinite loop, if the element and its counter are in the same
      //      class!

      info = cl->GetStreamerInfo();
   }
   if (!info) return 0;
   TStreamerElement *element = (TStreamerElement *)info->GetElements()->FindObject(countName);
   if (!element) return 0;
   if (element->IsA() == TStreamerBasicType::Class()) return (TStreamerBasicType*)element;
   return 0;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::GetStreamMemberWise()
{
   // Return whether the TStreamerInfos will save the collections in
   // "member-wise" order whenever possible.    The default is to store member-wise.
   // kTRUE indicates member-wise storing
   // kFALSE inddicates object-wise storing
   //
   // A collection can be saved member wise when it contain is guaranteed to be
   // homogeneous.  For example std::vector<THit> can be stored member wise,
   // while std::vector<THit*> can not (possible use of polymorphism).

   return fgStreamMemberWise;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::Optimize(Bool_t opt)
{
   //  This is a static function.
   //  Set optimization option.
   //  When this option is activated (default), consecutive data members
   //  of the same type are merged into an array (faster).
   //  Optimization must be off in TTree split mode.

   fgOptimize = opt;
}

//______________________________________________________________________________
TVirtualStreamerInfo *TVirtualStreamerInfo::Factory()
{
   // Static function returning a pointer to a new TVirtualStreamerInfo object.
   // If the Info factory does not exist, it is created via the plugin manager.
   // In reality the factory is an empty TStreamerInfo object.

   if (!fgInfoFactory) {
      TPluginHandler *h;
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualStreamerInfo","TStreamerInfo"))) {
         if (h->LoadPlugin() == -1) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "The plugin handler for TVirtualStreamerInfo was found but failed to load!");
         }
         fgInfoFactory = (TVirtualStreamerInfo*) h->ExecPlugin(0);
         if (fgInfoFactory == 0) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "The plugin handler for TVirtualStreamerInfo was found but failed to create the factory object!");
         }
      } else {
         TString filename("$ROOTSYS/etc/plugins/TVirtualStreamerInfo");
         gSystem->ExpandPathName(filename);
         if (gSystem->AccessPathName(filename)) {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "Cannot find the plugin handler for TVirtualStreamerInfo! "
                    "$ROOTSYS/etc/plugins/TVirtualStreamerInfo does not exist "
                    "or is inaccessible.");
         } else {
            ::Fatal("TVirtualStreamerInfo::Factory",
                    "Cannot find the plugin handler for TVirtualStreamerInfo! "
                    "However $ROOTSYS/etc/plugins/TVirtualStreamerInfo is accessible, "
                    "Check the content of this directory!");
         }
      }
   }

   return fgInfoFactory;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::SetCanDelete(Bool_t opt)
{
   //  This is a static function.
   //  Set object delete option.
   //  When this option is activated (default), ReadBuffer automatically
   //  delete objects when a data member is a pointer to an object.
   //  If your constructor is not presetting pointers to 0, you must
   //  call this static function TStreamerInfo::SetCanDelete(kFALSE);

   fgCanDelete = opt;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::SetFactory(TVirtualStreamerInfo *factory)
{
   //static function: Set the StreamerInfo factory
   fgInfoFactory = factory;
}

//______________________________________________________________________________
Bool_t TVirtualStreamerInfo::SetStreamMemberWise(Bool_t enable)
{
   // Set whether the TStreamerInfos will save the collections in
   // "member-wise" order whenever possible.  The default is to store member-wise.
   // kTRUE indicates member-wise storing
   // kFALSE inddicates object-wise storing
   // This function returns the previous value of fgStreamMemberWise.

   // A collection can be saved member wise when it contain is guaranteed to be
   // homogeneous.  For example std::vector<THit> can be stored member wise,
   // while std::vector<THit*> can not (possible use of polymorphism).

   Bool_t prev = fgStreamMemberWise;
   fgStreamMemberWise = enable;
   return prev;
}

//______________________________________________________________________________
void TVirtualStreamerInfo::Streamer(TBuffer &R__b)
{
   // Stream an object of class TVirtualStreamerInfo.

   TNamed::Streamer(R__b);
}
<|endoftext|>


<commit_before>#include <list>

using namespace std;

//list<int> foo1();
//list<double> foo2();

void foo3(list<float>);
<commit_msg>removal of accidentally added file<commit_after><|endoftext|>