<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unocontrolmodel.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:52:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_
#define _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_

#ifndef _COM_SUN_STAR_AWT_XCONTROLMODEL_HPP_
#include <com/sun/star/awt/XControlModel.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSTATE_HPP_
#include <com/sun/star/beans/XPropertyState.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XPERSISTOBJECT_HPP_
#include <com/sun/star/io/XPersistObject.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLONEABLE_HPP_
#include <com/sun/star/util/XCloneable.hpp>
#endif

#ifndef _CPPUHELPER_WEAKAGG_HXX_
#include <cppuhelper/weakagg.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#include <toolkit/helper/mutexandbroadcasthelper.hxx>
#include <toolkit/helper/listenermultiplexer.hxx>

#include <cppuhelper/propshlp.hxx>
#include <cppuhelper/interfacecontainer.hxx>

class ImplPropertyTable;

//  ----------------------------------------------------
//  class UnoControlModel
//  ----------------------------------------------------

class UnoControlModel : public ::com::sun::star::awt::XControlModel,
                        public ::com::sun::star::beans::XPropertyState,
                        public ::com::sun::star::io::XPersistObject,
                        public ::com::sun::star::lang::XComponent,
                        public ::com::sun::star::lang::XServiceInfo,
                        public ::com::sun::star::lang::XTypeProvider,
                        public ::com::sun::star::lang::XUnoTunnel,
                        public ::com::sun::star::util::XCloneable,
                        public MutexAndBroadcastHelper,
                        public ::cppu::OPropertySetHelper,
                        public ::cppu::OWeakAggObject
{
private:
    ImplPropertyTable*          mpData;
    EventListenerMultiplexer    maDisposeListeners;

protected:
    void                                        ImplRegisterProperty( sal_uInt16 nPropType );
    void                                        ImplRegisterProperty( sal_uInt16 nPropId, const ::com::sun::star::uno::Any& rDefault );
    ::com::sun::star::uno::Sequence<sal_Int32>  ImplGetPropertyIds() const;
    virtual void                                ImplPropertyChanged( sal_uInt16 nPropId );
    virtual ::com::sun::star::uno::Any          ImplGetDefaultValue( sal_uInt16 nPropId ) const;
    sal_Bool                                    ImplHasProperty( sal_uInt16 nPropId ) const;

    /** called before setting multiple properties, allows to care for property dependencies

When multiple property values are set (e.g. XPropertySet::setPropertyValues), it may happen that some
        of them are dependent. For this, derivees which know such dependencies can affect the order in which
        the properties are internally really set.

    */
    virtual void ImplNormalizePropertySequence(
                    const sal_Int32                 _nCount,        /// the number of entries in the arrays
                    sal_Int32*                      _pHandles,      /// the handles of the properties to set
                    ::com::sun::star::uno::Any*     _pValues,       /// the values of the properties to set
                    sal_Int32*                      _pValidHandles  /// pointer to the valid handles, allowed to be adjusted
                )   const SAL_THROW(());

public:
                UnoControlModel();
                UnoControlModel( const UnoControlModel& rModel );
                ~UnoControlModel();

    virtual UnoControlModel*    Clone() const = 0;

    // ::com::sun::star::uno::XAggregation
    ::com::sun::star::uno::Any  SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException) { return OWeakAggObject::queryInterface(rType); }
    void                        SAL_CALL acquire() throw()  { OWeakAggObject::acquire(); }
    void                        SAL_CALL release() throw()  { OWeakAggObject::release(); }

    ::com::sun::star::uno::Any  SAL_CALL queryAggregation( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XUnoTunnel
    static const ::com::sun::star::uno::Sequence< sal_Int8 >&   GetUnoTunnelId() throw();
    static UnoControlModel*                                     GetImplementation( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rxIFace ) throw();
    sal_Int64                                                   SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& rIdentifier ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::util::XCloneable
    ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone() throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XTypeProvider
    ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type >  SAL_CALL getTypes() throw(::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< sal_Int8 >                     SAL_CALL getImplementationId() throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::awt::XControlModel

    // ::com::sun::star::lang::XComponent
    void SAL_CALL dispose(  ) throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::beans::XPropertyState
    ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState > SAL_CALL getPropertyStates( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::io::XPersistObject
    ::rtl::OUString SAL_CALL getServiceName() throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL write( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream >& OutStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL read( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream >& InStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XServiceInfo
    ::rtl::OUString SAL_CALL getImplementationName(  ) throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

    // ::cppu::OPropertySetHelper
    ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() = 0;
    sal_Bool SAL_CALL convertFastPropertyValue( ::com::sun::star::uno::Any & rConvertedValue, ::com::sun::star::uno::Any & rOldValue, sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::lang::IllegalArgumentException);
    void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::uno::Exception);
    void SAL_CALL getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;

    // setValue-Methoden ueberladen, um die Einzelproperties des FontDescriptors abzufangen
    // ::com::sun::star::beans::XPropertySet
    void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    // ::com::sun::star::beans::XFastPropertySet
    void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    // ::com::sun::star::beans::XMultiPropertySet
    ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException) = 0;
    void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& PropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Values ) throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
};

#endif // _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_

<commit_msg>INTEGRATION: CWS warnings01 (1.5.26); FILE MERGED 2005/11/14 10:36:06 pl 1.5.26.1: #i55991# removed warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unocontrolmodel.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 22:56:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_
#define _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_

#ifndef _COM_SUN_STAR_AWT_XCONTROLMODEL_HPP_
#include <com/sun/star/awt/XControlModel.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSTATE_HPP_
#include <com/sun/star/beans/XPropertyState.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XPERSISTOBJECT_HPP_
#include <com/sun/star/io/XPersistObject.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLONEABLE_HPP_
#include <com/sun/star/util/XCloneable.hpp>
#endif

#ifndef _CPPUHELPER_WEAKAGG_HXX_
#include <cppuhelper/weakagg.hxx>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#include <toolkit/helper/mutexandbroadcasthelper.hxx>
#include <toolkit/helper/listenermultiplexer.hxx>

#include <cppuhelper/propshlp.hxx>
#include <cppuhelper/interfacecontainer.hxx>

class ImplPropertyTable;

//  ----------------------------------------------------
//  class UnoControlModel
//  ----------------------------------------------------

class UnoControlModel : public ::com::sun::star::awt::XControlModel,
                        public ::com::sun::star::beans::XPropertyState,
                        public ::com::sun::star::io::XPersistObject,
                        public ::com::sun::star::lang::XComponent,
                        public ::com::sun::star::lang::XServiceInfo,
                        public ::com::sun::star::lang::XTypeProvider,
                        public ::com::sun::star::lang::XUnoTunnel,
                        public ::com::sun::star::util::XCloneable,
                        public MutexAndBroadcastHelper,
                        public ::cppu::OPropertySetHelper,
                        public ::cppu::OWeakAggObject
{
private:
    ImplPropertyTable*          mpData;
    EventListenerMultiplexer    maDisposeListeners;

protected:
    void                                        ImplRegisterProperty( sal_uInt16 nPropType );
    void                                        ImplRegisterProperty( sal_uInt16 nPropId, const ::com::sun::star::uno::Any& rDefault );
    ::com::sun::star::uno::Sequence<sal_Int32>  ImplGetPropertyIds() const;
    virtual void                                ImplPropertyChanged( sal_uInt16 nPropId );
    virtual ::com::sun::star::uno::Any          ImplGetDefaultValue( sal_uInt16 nPropId ) const;
    sal_Bool                                    ImplHasProperty( sal_uInt16 nPropId ) const;

    /** called before setting multiple properties, allows to care for property dependencies

When multiple property values are set (e.g. XPropertySet::setPropertyValues), it may happen that some
        of them are dependent. For this, derivees which know such dependencies can affect the order in which
        the properties are internally really set.

    */
    virtual void ImplNormalizePropertySequence(
                    const sal_Int32                 _nCount,        /// the number of entries in the arrays
                    sal_Int32*                      _pHandles,      /// the handles of the properties to set
                    ::com::sun::star::uno::Any*     _pValues,       /// the values of the properties to set
                    sal_Int32*                      _pValidHandles  /// pointer to the valid handles, allowed to be adjusted
                )   const SAL_THROW(());

public:
                UnoControlModel();
                UnoControlModel( const UnoControlModel& rModel );
                ~UnoControlModel();

    virtual UnoControlModel*    Clone() const = 0;

    // ::com::sun::star::uno::XAggregation
    ::com::sun::star::uno::Any  SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException) { return OWeakAggObject::queryInterface(rType); }
    void                        SAL_CALL acquire() throw()  { OWeakAggObject::acquire(); }
    void                        SAL_CALL release() throw()  { OWeakAggObject::release(); }

    ::com::sun::star::uno::Any  SAL_CALL queryAggregation( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XUnoTunnel
    static const ::com::sun::star::uno::Sequence< sal_Int8 >&   GetUnoTunnelId() throw();
    static UnoControlModel*                                     GetImplementation( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& rxIFace ) throw();
    sal_Int64                                                   SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& rIdentifier ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::util::XCloneable
    ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone() throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XTypeProvider
    ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type >  SAL_CALL getTypes() throw(::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< sal_Int8 >                     SAL_CALL getImplementationId() throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::awt::XControlModel

    // ::com::sun::star::lang::XComponent
    void SAL_CALL dispose(  ) throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw(::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::beans::XPropertyState
    ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState > SAL_CALL getPropertyStates( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::io::XPersistObject
    ::rtl::OUString SAL_CALL getServiceName() throw(::com::sun::star::uno::RuntimeException);
    void SAL_CALL write( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream >& OutStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    void SAL_CALL read( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream >& InStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // ::com::sun::star::lang::XServiceInfo
    ::rtl::OUString SAL_CALL getImplementationName(  ) throw(::com::sun::star::uno::RuntimeException);
    sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
    ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

    // ::cppu::OPropertySetHelper
    ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() = 0;
    sal_Bool SAL_CALL convertFastPropertyValue( ::com::sun::star::uno::Any & rConvertedValue, ::com::sun::star::uno::Any & rOldValue, sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::lang::IllegalArgumentException);
    void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const ::com::sun::star::uno::Any& rValue ) throw (::com::sun::star::uno::Exception);
    using cppu::OPropertySetHelper::getFastPropertyValue;
    void SAL_CALL getFastPropertyValue( ::com::sun::star::uno::Any& rValue, sal_Int32 nHandle ) const;

    // setValue-Methoden ueberladen, um die Einzelproperties des FontDescriptors abzufangen
    // ::com::sun::star::beans::XPropertySet
    void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    // ::com::sun::star::beans::XFastPropertySet
    void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    // ::com::sun::star::beans::XMultiPropertySet
    ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(::com::sun::star::uno::RuntimeException) = 0;
    void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& PropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Values ) throw(::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
};

#endif // _TOOLKIT_AWT_UNOCONTROLMODEL_HXX_

<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "PathOpsCubicIntersectionTestData.h"
#include "PathOpsQuadIntersectionTestData.h"
#include "PathOpsTestCommon.h"
#include "SkIntersections.h"
#include "SkPathOpsRect.h"
#include "SkReduceOrder.h"
#include "Test.h"

static bool controls_inside(const SkDCubic& cubic) {
    return between(cubic[0].fX, cubic[1].fX, cubic[3].fX)
            && between(cubic[0].fX, cubic[2].fX, cubic[3].fX)
            && between(cubic[0].fY, cubic[1].fY, cubic[3].fY)
            && between(cubic[0].fY, cubic[2].fY, cubic[3].fY);
}

static bool tiny(const SkDCubic& cubic) {
    int index, minX, maxX, minY, maxY;
    minX = maxX = minY = maxY = 0;
    for (index = 1; index < 4; ++index) {
        if (cubic[minX].fX > cubic[index].fX) {
            minX = index;
        }
        if (cubic[minY].fY > cubic[index].fY) {
            minY = index;
        }
        if (cubic[maxX].fX < cubic[index].fX) {
            maxX = index;
        }
        if (cubic[maxY].fY < cubic[index].fY) {
            maxY = index;
        }
    }
    return     approximately_equal(cubic[maxX].fX, cubic[minX].fX)
            && approximately_equal(cubic[maxY].fY, cubic[minY].fY);
}

#if 0 // disable test until stroke reduction is supported
static void find_tight_bounds(const SkDCubic& cubic, SkDRect& bounds) {
    SkDCubicPair cubicPair = cubic.chopAt(0.5);
    if (!tiny(cubicPair.first()) && !controls_inside(cubicPair.first())) {
        find_tight_bounds(cubicPair.first(), bounds);
    } else {
        bounds.add(cubicPair.first()[0]);
        bounds.add(cubicPair.first()[3]);
    }
    if (!tiny(cubicPair.second()) && !controls_inside(cubicPair.second())) {
        find_tight_bounds(cubicPair.second(), bounds);
    } else {
        bounds.add(cubicPair.second()[0]);
        bounds.add(cubicPair.second()[3]);
    }
}
#endif

static void PathOpsReduceOrderCubicTest(skiatest::Reporter* reporter) {
    size_t index;
    SkReduceOrder reducer;
    int order;
    enum {
        RunAll,
        RunPointDegenerates,
        RunNotPointDegenerates,
        RunLines,
        RunNotLines,
        RunModEpsilonLines,
        RunLessEpsilonLines,
        RunNegEpsilonLines,
        RunQuadraticLines,
        RunQuadraticPoints,
        RunQuadraticModLines,
        RunComputedLines,
        RunNone
    } run = RunAll;
    int firstTestIndex = 0;
#if 0
    run = RunComputedLines;
    firstTestIndex = 18;
#endif
    int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates
            ? firstTestIndex : SK_MaxS32;
    int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates
            ? firstTestIndex : SK_MaxS32;
    int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32;
    int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32;
    int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticPointTest = run == RunAll ? 0 : run == RunQuadraticPoints
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines
            ? firstTestIndex : SK_MaxS32;
#if 0
    int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines
            ? firstTestIndex : SK_MaxS32;
#endif
    for (index = firstPointDegeneratesTest; index < pointDegenerates_count; ++index) {
        const SkDCubic& cubic = pointDegenerates[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 1) {
            SkDebugf("[%d] pointDegenerates order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNotPointDegeneratesTest; index < notPointDegenerates_count; ++index) {
        const SkDCubic& cubic = notPointDegenerates[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 1) {
            SkDebugf("[%d] notPointDegenerates order=%d\n", static_cast<int>(index), order);
            order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstLinesTest; index < lines_count; ++index) {
        const SkDCubic& cubic = lines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] lines order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNotLinesTest; index < notLines_count; ++index) {
        const SkDCubic& cubic = notLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 2) {
            SkDebugf("[%d] notLines order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
       }
    }
    for (index = firstModEpsilonTest; index < modEpsilonLines_count; ++index) {
        const SkDCubic& cubic = modEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 2) {
            SkDebugf("[%d] line mod by epsilon order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstLessEpsilonTest; index < lessEpsilonLines_count; ++index) {
        const SkDCubic& cubic = lessEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line less by epsilon/2 order=%d\n", static_cast<int>(index), order);
            order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNegEpsilonTest; index < negEpsilonLines_count; ++index) {
        const SkDCubic& cubic = negEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line neg by epsilon/2 order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticPointTest; index < quadraticPoints_count; ++index) {
        const SkDQuad& quad = quadraticPoints[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 1) {
            SkDebugf("[%d] point quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
        const SkDQuad& quad = quadraticLines[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
        const SkDQuad& quad = quadraticModEpsilonLines[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 3) {
            SkDebugf("[%d] line mod quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }

#if 0 // disable test until stroke reduction is supported
// test if computed line end points are valid
    for (index = firstComputedLinesTest; index < lines_count; ++index) {
        const SkDCubic& cubic = lines[index];
        SkASSERT(ValidCubic(cubic));
        bool controlsInside = controls_inside(cubic);
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics,
                SkReduceOrder::kStroke_Style);
        if (order == 2 && reducer.fLine[0] == reducer.fLine[1]) {
            SkDebugf("[%d] line computed ends match order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
        if (controlsInside) {
            if (       (reducer.fLine[0].fX != cubic[0].fX && reducer.fLine[0].fX != cubic[3].fX)
                    || (reducer.fLine[0].fY != cubic[0].fY && reducer.fLine[0].fY != cubic[3].fY)
                    || (reducer.fLine[1].fX != cubic[0].fX && reducer.fLine[1].fX != cubic[3].fX)
                    || (reducer.fLine[1].fY != cubic[0].fY && reducer.fLine[1].fY != cubic[3].fY)) {
                SkDebugf("[%d] line computed ends order=%d\n", static_cast<int>(index), order);
                REPORTER_ASSERT(reporter, 0);
            }
        } else {
            // binary search for extrema, compare against actual results
                // while a control point is outside of bounding box formed by end points, split
            SkDRect bounds = {DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX};
            find_tight_bounds(cubic, bounds);
            if (      (!AlmostEqualUlps(reducer.fLine[0].fX, bounds.fLeft)
                    && !AlmostEqualUlps(reducer.fLine[0].fX, bounds.fRight))
                   || (!AlmostEqualUlps(reducer.fLine[0].fY, bounds.fTop)
                    && !AlmostEqualUlps(reducer.fLine[0].fY, bounds.fBottom))
                   || (!AlmostEqualUlps(reducer.fLine[1].fX, bounds.fLeft)
                    && !AlmostEqualUlps(reducer.fLine[1].fX, bounds.fRight))
                   || (!AlmostEqualUlps(reducer.fLine[1].fY, bounds.fTop)
                    && !AlmostEqualUlps(reducer.fLine[1].fY, bounds.fBottom))) {
                SkDebugf("[%d] line computed tight bounds order=%d\n", static_cast<int>(index), order);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
#endif
}

#include "TestClassDef.h"

DEFINE_TESTCLASS_SHORT(PathOpsReduceOrderCubicTest)
<commit_msg>remove more unused static functions<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "PathOpsCubicIntersectionTestData.h"
#include "PathOpsQuadIntersectionTestData.h"
#include "PathOpsTestCommon.h"
#include "SkIntersections.h"
#include "SkPathOpsRect.h"
#include "SkReduceOrder.h"
#include "Test.h"

#if 0 // disable test until stroke reduction is supported
static bool controls_inside(const SkDCubic& cubic) {
    return between(cubic[0].fX, cubic[1].fX, cubic[3].fX)
            && between(cubic[0].fX, cubic[2].fX, cubic[3].fX)
            && between(cubic[0].fY, cubic[1].fY, cubic[3].fY)
            && between(cubic[0].fY, cubic[2].fY, cubic[3].fY);
}

static bool tiny(const SkDCubic& cubic) {
    int index, minX, maxX, minY, maxY;
    minX = maxX = minY = maxY = 0;
    for (index = 1; index < 4; ++index) {
        if (cubic[minX].fX > cubic[index].fX) {
            minX = index;
        }
        if (cubic[minY].fY > cubic[index].fY) {
            minY = index;
        }
        if (cubic[maxX].fX < cubic[index].fX) {
            maxX = index;
        }
        if (cubic[maxY].fY < cubic[index].fY) {
            maxY = index;
        }
    }
    return     approximately_equal(cubic[maxX].fX, cubic[minX].fX)
            && approximately_equal(cubic[maxY].fY, cubic[minY].fY);
}

static void find_tight_bounds(const SkDCubic& cubic, SkDRect& bounds) {
    SkDCubicPair cubicPair = cubic.chopAt(0.5);
    if (!tiny(cubicPair.first()) && !controls_inside(cubicPair.first())) {
        find_tight_bounds(cubicPair.first(), bounds);
    } else {
        bounds.add(cubicPair.first()[0]);
        bounds.add(cubicPair.first()[3]);
    }
    if (!tiny(cubicPair.second()) && !controls_inside(cubicPair.second())) {
        find_tight_bounds(cubicPair.second(), bounds);
    } else {
        bounds.add(cubicPair.second()[0]);
        bounds.add(cubicPair.second()[3]);
    }
}
#endif

static void PathOpsReduceOrderCubicTest(skiatest::Reporter* reporter) {
    size_t index;
    SkReduceOrder reducer;
    int order;
    enum {
        RunAll,
        RunPointDegenerates,
        RunNotPointDegenerates,
        RunLines,
        RunNotLines,
        RunModEpsilonLines,
        RunLessEpsilonLines,
        RunNegEpsilonLines,
        RunQuadraticLines,
        RunQuadraticPoints,
        RunQuadraticModLines,
        RunComputedLines,
        RunNone
    } run = RunAll;
    int firstTestIndex = 0;
#if 0
    run = RunComputedLines;
    firstTestIndex = 18;
#endif
    int firstPointDegeneratesTest = run == RunAll ? 0 : run == RunPointDegenerates
            ? firstTestIndex : SK_MaxS32;
    int firstNotPointDegeneratesTest = run == RunAll ? 0 : run == RunNotPointDegenerates
            ? firstTestIndex : SK_MaxS32;
    int firstLinesTest = run == RunAll ? 0 : run == RunLines ? firstTestIndex : SK_MaxS32;
    int firstNotLinesTest = run == RunAll ? 0 : run == RunNotLines ? firstTestIndex : SK_MaxS32;
    int firstModEpsilonTest = run == RunAll ? 0 : run == RunModEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstLessEpsilonTest = run == RunAll ? 0 : run == RunLessEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstNegEpsilonTest = run == RunAll ? 0 : run == RunNegEpsilonLines
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticPointTest = run == RunAll ? 0 : run == RunQuadraticPoints
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticLineTest = run == RunAll ? 0 : run == RunQuadraticLines
            ? firstTestIndex : SK_MaxS32;
    int firstQuadraticModLineTest = run == RunAll ? 0 : run == RunQuadraticModLines
            ? firstTestIndex : SK_MaxS32;
#if 0
    int firstComputedLinesTest = run == RunAll ? 0 : run == RunComputedLines
            ? firstTestIndex : SK_MaxS32;
#endif
    for (index = firstPointDegeneratesTest; index < pointDegenerates_count; ++index) {
        const SkDCubic& cubic = pointDegenerates[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 1) {
            SkDebugf("[%d] pointDegenerates order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNotPointDegeneratesTest; index < notPointDegenerates_count; ++index) {
        const SkDCubic& cubic = notPointDegenerates[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 1) {
            SkDebugf("[%d] notPointDegenerates order=%d\n", static_cast<int>(index), order);
            order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstLinesTest; index < lines_count; ++index) {
        const SkDCubic& cubic = lines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] lines order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNotLinesTest; index < notLines_count; ++index) {
        const SkDCubic& cubic = notLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 2) {
            SkDebugf("[%d] notLines order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
       }
    }
    for (index = firstModEpsilonTest; index < modEpsilonLines_count; ++index) {
        const SkDCubic& cubic = modEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order == 2) {
            SkDebugf("[%d] line mod by epsilon order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstLessEpsilonTest; index < lessEpsilonLines_count; ++index) {
        const SkDCubic& cubic = lessEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line less by epsilon/2 order=%d\n", static_cast<int>(index), order);
            order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstNegEpsilonTest; index < negEpsilonLines_count; ++index) {
        const SkDCubic& cubic = negEpsilonLines[index];
        SkASSERT(ValidCubic(cubic));
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line neg by epsilon/2 order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticPointTest; index < quadraticPoints_count; ++index) {
        const SkDQuad& quad = quadraticPoints[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 1) {
            SkDebugf("[%d] point quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
        const SkDQuad& quad = quadraticLines[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 2) {
            SkDebugf("[%d] line quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }
    for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
        const SkDQuad& quad = quadraticModEpsilonLines[index];
        SkASSERT(ValidQuad(quad));
        SkDCubic cubic = quad.toCubic();
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
        if (order != 3) {
            SkDebugf("[%d] line mod quad order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
    }

#if 0 // disable test until stroke reduction is supported
// test if computed line end points are valid
    for (index = firstComputedLinesTest; index < lines_count; ++index) {
        const SkDCubic& cubic = lines[index];
        SkASSERT(ValidCubic(cubic));
        bool controlsInside = controls_inside(cubic);
        order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics,
                SkReduceOrder::kStroke_Style);
        if (order == 2 && reducer.fLine[0] == reducer.fLine[1]) {
            SkDebugf("[%d] line computed ends match order=%d\n", static_cast<int>(index), order);
            REPORTER_ASSERT(reporter, 0);
        }
        if (controlsInside) {
            if (       (reducer.fLine[0].fX != cubic[0].fX && reducer.fLine[0].fX != cubic[3].fX)
                    || (reducer.fLine[0].fY != cubic[0].fY && reducer.fLine[0].fY != cubic[3].fY)
                    || (reducer.fLine[1].fX != cubic[0].fX && reducer.fLine[1].fX != cubic[3].fX)
                    || (reducer.fLine[1].fY != cubic[0].fY && reducer.fLine[1].fY != cubic[3].fY)) {
                SkDebugf("[%d] line computed ends order=%d\n", static_cast<int>(index), order);
                REPORTER_ASSERT(reporter, 0);
            }
        } else {
            // binary search for extrema, compare against actual results
                // while a control point is outside of bounding box formed by end points, split
            SkDRect bounds = {DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX};
            find_tight_bounds(cubic, bounds);
            if (      (!AlmostEqualUlps(reducer.fLine[0].fX, bounds.fLeft)
                    && !AlmostEqualUlps(reducer.fLine[0].fX, bounds.fRight))
                   || (!AlmostEqualUlps(reducer.fLine[0].fY, bounds.fTop)
                    && !AlmostEqualUlps(reducer.fLine[0].fY, bounds.fBottom))
                   || (!AlmostEqualUlps(reducer.fLine[1].fX, bounds.fLeft)
                    && !AlmostEqualUlps(reducer.fLine[1].fX, bounds.fRight))
                   || (!AlmostEqualUlps(reducer.fLine[1].fY, bounds.fTop)
                    && !AlmostEqualUlps(reducer.fLine[1].fY, bounds.fBottom))) {
                SkDebugf("[%d] line computed tight bounds order=%d\n", static_cast<int>(index), order);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
#endif
}

#include "TestClassDef.h"

DEFINE_TESTCLASS_SHORT(PathOpsReduceOrderCubicTest)
<|endoftext|>


<commit_before>/* Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.

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

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

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

#include "paddle/fluid/operators/linspace_op.h"
#include <string>

namespace paddle {
namespace operators {

class LinspaceOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext *ctx) const override {
    OP_INOUT_CHECK(ctx->HasInput("Start"), "Input", "Start", "linspace");
    OP_INOUT_CHECK(ctx->HasInput("Stop"), "Input", "Stop", "linspace");
    OP_INOUT_CHECK(ctx->HasInput("Num"), "Input", "Num", "linspace");
    OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "linspace");

    auto s_dims = ctx->GetInputDim("Start");
    PADDLE_ENFORCE_EQ((s_dims.size() == 1) && (s_dims[0] == 1), true,
                      platform::errors::InvalidArgument(
                          "The shape of Input(Start) must be [1],"
                          "but received input shape is [%s].",
                          s_dims));
    auto e_dims = ctx->GetInputDim("Stop");
    PADDLE_ENFORCE_EQ((e_dims.size() == 1) && (e_dims[0] == 1), true,
                      platform::errors::InvalidArgument(
                          "The shape of Input(Stop) must be [1],"
                          "but received input shape is [%s].",
                          e_dims));
    auto step_dims = ctx->GetInputDim("Num");
    PADDLE_ENFORCE_EQ(
        (step_dims.size() == 1) && (step_dims[0] == 1), true,
        platform::errors::InvalidArgument("The shape of Input(Num) must be [1],"
                                          "but received input shape is [%s].",
                                          step_dims));
    ctx->SetOutputDim("Out", {-1});
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::proto::VarType::Type(ctx.Attr<int>("dtype")),
        ctx.GetPlace());
  }

  framework::OpKernelType GetKernelTypeForVar(
      const std::string &var_name, const framework::Tensor &tensor,
      const framework::OpKernelType &expected_kernel_type) const override {
    return expected_kernel_type;
  }
};

class LinspaceOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("Start",
             "First entry in the sequence. It is a tensor of shape [1], should "
             "be of type float32 or float64.");
    AddInput("Stop",
             "Last entry in the sequence. It is a tensor of shape [1], should "
             "be of type float32 or float64.");
    AddInput("Num",
             "Number of entry in the sequence. It is a tensor of shape [1], "
             "should be of type int32.");
    AddAttr<int>("dtype", "The output data type.");
    AddOutput("Out", "A sequence of numbers.");
    AddComment(R"DOC(
    Return fixed number of evenly spaced values within a given interval. First entry is start, and last entry is stop. In the case when Num is 1, only Start is returned. Like linspace function of numpy.
)DOC");
  }
};
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OP_WITHOUT_GRADIENT(linspace, ops::LinspaceOp, ops::LinspaceOpMaker);
REGISTER_OP_CPU_KERNEL(linspace, ops::CPULinspaceKernel<float>,
                       ops::CPULinspaceKernel<int32_t>,
                       ops::CPULinspaceKernel<int64_t>,
                       ops::CPULinspaceKernel<double>);
<commit_msg>Register op version for linspace,test=op_version (#30025)<commit_after>/* Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.

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

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

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

#include "paddle/fluid/operators/linspace_op.h"
#include <string>
#include "paddle/fluid/framework/op_version_registry.h"

namespace paddle {
namespace operators {

class LinspaceOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext *ctx) const override {
    OP_INOUT_CHECK(ctx->HasInput("Start"), "Input", "Start", "linspace");
    OP_INOUT_CHECK(ctx->HasInput("Stop"), "Input", "Stop", "linspace");
    OP_INOUT_CHECK(ctx->HasInput("Num"), "Input", "Num", "linspace");
    OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "linspace");

    auto s_dims = ctx->GetInputDim("Start");
    PADDLE_ENFORCE_EQ((s_dims.size() == 1) && (s_dims[0] == 1), true,
                      platform::errors::InvalidArgument(
                          "The shape of Input(Start) must be [1],"
                          "but received input shape is [%s].",
                          s_dims));
    auto e_dims = ctx->GetInputDim("Stop");
    PADDLE_ENFORCE_EQ((e_dims.size() == 1) && (e_dims[0] == 1), true,
                      platform::errors::InvalidArgument(
                          "The shape of Input(Stop) must be [1],"
                          "but received input shape is [%s].",
                          e_dims));
    auto step_dims = ctx->GetInputDim("Num");
    PADDLE_ENFORCE_EQ(
        (step_dims.size() == 1) && (step_dims[0] == 1), true,
        platform::errors::InvalidArgument("The shape of Input(Num) must be [1],"
                                          "but received input shape is [%s].",
                                          step_dims));
    ctx->SetOutputDim("Out", {-1});
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::proto::VarType::Type(ctx.Attr<int>("dtype")),
        ctx.GetPlace());
  }

  framework::OpKernelType GetKernelTypeForVar(
      const std::string &var_name, const framework::Tensor &tensor,
      const framework::OpKernelType &expected_kernel_type) const override {
    return expected_kernel_type;
  }
};

class LinspaceOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("Start",
             "First entry in the sequence. It is a tensor of shape [1], should "
             "be of type float32 or float64.");
    AddInput("Stop",
             "Last entry in the sequence. It is a tensor of shape [1], should "
             "be of type float32 or float64.");
    AddInput("Num",
             "Number of entry in the sequence. It is a tensor of shape [1], "
             "should be of type int32.");
    AddAttr<int>("dtype", "The output data type.");
    AddOutput("Out", "A sequence of numbers.");
    AddComment(R"DOC(
    Return fixed number of evenly spaced values within a given interval. First entry is start, and last entry is stop. In the case when Num is 1, only Start is returned. Like linspace function of numpy.
)DOC");
  }
};
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OP_WITHOUT_GRADIENT(linspace, ops::LinspaceOp, ops::LinspaceOpMaker);
REGISTER_OP_CPU_KERNEL(linspace, ops::CPULinspaceKernel<float>,
                       ops::CPULinspaceKernel<int32_t>,
                       ops::CPULinspaceKernel<int64_t>,
                       ops::CPULinspaceKernel<double>);

REGISTER_OP_VERSION(linspace)
    .AddCheckpoint(
        R"ROC(
      Upgrade linspace to add a new attribute [dtype].
    )ROC",
        paddle::framework::compatible::OpVersionDesc().NewAttr(
            "dtype", "In order to change output data type ", 5));
<|endoftext|>


<commit_before>/*
 * Tests for the scalar example solving the test equation
 */
#include <cmath>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using namespace ::testing;

#define PFASST_UNIT_TESTING
#include "../examples/scalar/scalar_sdc.cpp"
#undef PFASST_UNIT_TESTING

/*
 * parameterized test fixture with number of nodes as parameter
 */
class ConvergenceTest
  : public ::testing::TestWithParam<size_t>
{
  protected:
    size_t nnodes; // parameter

    const complex<double> lambda = complex<double>(-1.0, 1.0);
    const double Tend = 4.0;
    const vector<size_t> nsteps = { 2, 5, 10, 15, 20 };
    size_t nsteps_l;
    vector<double> err;
    vector<double> convrate;
    vector<double> convrate_legendre;
    double dt;
    size_t niters;
    pfasst::QuadratureType nodetype = pfasst::QuadratureType::GaussLobatto;

  public:
    virtual void SetUp()
    {
      this->nnodes = this->GetParam();
      this->nsteps_l = this->nsteps.size();
      this->err.resize(this->nsteps.size());
      this->convrate.resize(this->nsteps.size());

      // Run first for Lobatto nodes

      // Expect convergence rate of 2*nodes-2 from collocation formula,
      // doing an identical number of iteration should suffice to reach this as each
      // iteration should increase order by one
      this->niters = 2 * nnodes - 2;

      // run to compute errors
      for (size_t i = 0; i <= nsteps_l - 1; ++i) {
        dt = Tend / double(nsteps[i]);
        err[i] = run_scalar_sdc(nsteps[i], dt, nnodes, niters, lambda, nodetype);
      }

      // compute convergence rates
      for (size_t i = 0; i <= nsteps_l - 2; ++i) {
        convrate[i] = log10(err[i+1] / err[i]) / log10(double(nsteps[i]) / double(nsteps[i + 1]));
      }

      // Run for Legendre nodes
      nodetype = pfasst::QuadratureType::GaussLegendre;
      this->convrate_legendre.resize(this->nsteps.size());

      // NOTE: Setting M for Legendre nodes actually only results in M-2 "real" nodes,
      // because the first and the last are used for initial and final value.
      this->niters = 2*(nnodes-2);

    }

    virtual void TearDown()
    {}
};

/*
 * For Lobatto nodes, the resulting method should of order 2*M-2 with M=number of nodes
 * The test below verifies that the code approximately (up to a safety factor) reproduces
 * the theoretically expected rate of convergence
 */
TEST_P(ConvergenceTest, GaussLobattoNodes)
{
  for (size_t i = 0; i <= nsteps_l - 2; ++i) {

    EXPECT_THAT(convrate[i],
                testing::DoubleNear(double(2 * nnodes - 2), 0.99)) << "Convergence rate at node "
                                                                   << i
                                                                   << " not within expected range";
  }
}

INSTANTIATE_TEST_CASE_P(ScalarSDC, ConvergenceTest, Range<size_t>(2, 7));

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>test_scalar now also checks legendre nodes, but the test with DoubleNear fail, because we encounter better-than-expected convergence. Need a DoubleMore, but I did not get a corresponding matcher to run properly<commit_after>/*
 * Tests for the scalar example solving the test equation
 */
#include <cmath>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

using namespace ::testing;

#define PFASST_UNIT_TESTING
#include "../examples/scalar/scalar_sdc.cpp"
#undef PFASST_UNIT_TESTING

MATCHER(MyDoubleMore, "")
{
  return get<0>(arg) > get<1>(arg);
}

/*
 * parameterized test fixture with number of nodes as parameter
 */
class ConvergenceTest
  : public ::testing::TestWithParam<size_t>
{
  protected:
    size_t nnodes; // parameter

    complex<double> lambda = complex<double>(-1.0, 1.0);
    double Tend = 4.0;
    vector<size_t> nsteps = { 2, 5, 10, 15, 20 };
    size_t nsteps_l;
    vector<double> err;
    vector<double> convrate_lobatto;
    vector<double> convrate_legendre;
    double dt;
    size_t niters;
    pfasst::QuadratureType nodetype = pfasst::QuadratureType::GaussLobatto;

  public:
    virtual void SetUp()
    {
      this->nnodes = this->GetParam();
      this->nsteps_l = this->nsteps.size();
      this->err.resize(this->nsteps.size());
      this->convrate_lobatto.resize(this->nsteps.size());

      // Run first for Lobatto nodes which is the default nodetype

      // Expect convergence rate of 2*nodes-2 from collocation formula,
      // doing an identical number of iteration should suffice to reach this as each
      // iteration should increase order by one
      this->niters = 2 * nnodes - 2;

      // run to compute errors
      for (size_t i = 0; i <= nsteps_l - 1; ++i) {
        dt = Tend / double(nsteps[i]);
        err[i] = run_scalar_sdc(nsteps[i], dt, nnodes, niters, lambda, nodetype);
      }

      // compute convergence rates
      for (size_t i = 0; i <= nsteps_l - 2; ++i) {
        convrate_lobatto[i] = log10(err[i+1] / err[i]) / log10(double(nsteps[i]) / double(nsteps[i + 1]));
      }

      // Run for Legendre nodes
      nodetype = pfasst::QuadratureType::GaussLegendre;
      this->convrate_legendre.resize(this->nsteps.size());

      // refine parameter
      complex<double> lambda = complex<double>(-1.0, 4.0);
      this->Tend = 5.0;
      this->nsteps = { 5, 7, 9, 11, 13 };
      this->niters = 2*nnodes;

      // run to compute errors
      for (size_t i = 0; i <= nsteps_l - 1; ++i) {
        dt = Tend / double(nsteps[i]);

      // NOTE: Setting M for Legendre nodes actually only results in M-2 "real" nodes,
      // because the first and the last are used for initial and final value.
      // Hence us nnodes+2 as argument
        err[i] = run_scalar_sdc(nsteps[i], dt, nnodes+2, niters, lambda, nodetype);
      }

      for (size_t i = 0; i <= nsteps_l - 2; ++i) {
        convrate_legendre[i] = log10(err[i+1] / err[i]) / log10(double(nsteps[i]) / double(nsteps[i + 1]));
      }

    }

    virtual void TearDown()
    {}
};

/*
 * For Lobatto nodes, the resulting method should of order 2*M-2 with M=number of nodes
 * The test below verifies that the code approximately (up to a safety factor) reproduces
 * the theoretically expected rate of convergence
 */
TEST_P(ConvergenceTest, GaussNodes)
{
  for (size_t i = 0; i <= nsteps_l - 2; ++i) {

    EXPECT_THAT(convrate_lobatto[i],
                testing::DoubleNear(double(2 * nnodes - 2), 0.99)) << "Convergence rate at node "
                                                                   << i
                                                                   << " not within expected range";
    EXPECT_THAT(convrate_legendre[i],
                testing::DoubleNear(double(2 * nnodes ), 0.9)) << "Convergence rate at node "
                                                               << i
                                                               << " not within expected range";

  }
}

INSTANTIATE_TEST_CASE_P(ScalarSDC, ConvergenceTest, Range<size_t>(2, 7));

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/************************************************************************************
This source file is part of the Theora Video Playback Library
For latest info, see http://libtheoraplayer.googlecode.com
*************************************************************************************
Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
This program is free software; you can redistribute it and/or modify it under
the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
*************************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
#include "TheoraDataSource.h"
#include "TheoraException.h"
#include "TheoraVideoManager.h"
#include "TheoraUtil.h"

TheoraDataSource::~TheoraDataSource()
{

}

TheoraFileDataSource::TheoraFileDataSource(std::string filename)
{
	mFilename = filename;
	mFilePtr = NULL;
}

TheoraFileDataSource::~TheoraFileDataSource()
{
	if (mFilePtr)
	{
		fclose(mFilePtr);
		mFilePtr = NULL;
	}
}

void TheoraFileDataSource::openFile()
{
	if (mFilePtr == NULL)
	{
		mFilePtr = fopen(mFilename.c_str(), "rb");
		if (!mFilePtr)
        {
            std::string msg = "Can't open video file: " + mFilename;
            th_writelog(msg);
            throw TheoraGenericException(msg);
        }

#ifdef _WIN32
		struct _stat64 s;
		_fstati64(_fileno(mFilePtr), &s);
#else
		struct stat s;
		fstat(fileno(mFilePtr), &s);
#endif
		mSize = (uint64_t) s.st_size;
	}
}

int TheoraFileDataSource::read(void* output, int nBytes)
{
	if (mFilePtr == NULL) openFile();
	uint64_t n = fread(output, 1, nBytes, mFilePtr);
	return (int) n;
}

void TheoraFileDataSource::seek(uint64_t byte_index)
{
	if (mFilePtr == NULL) openFile();
	fpos_t fpos = byte_index;
	fsetpos(mFilePtr, &fpos);
}

uint64_t TheoraFileDataSource::size()
{
	if (mFilePtr == NULL) openFile();
	return mSize;
}

uint64_t TheoraFileDataSource::tell()
{
	if (mFilePtr == NULL) return 0;
	fpos_t pos;
	fgetpos(mFilePtr, &pos);
	return (uint64_t) pos;
}

TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(std::string filename) :
	mReadPointer(0),
	mData(0)
{
	mFilename=filename;
	FILE* f = fopen(filename.c_str(),"rb");
	if (!f) throw TheoraGenericException("Can't open video file: " + filename);

#ifdef _WIN32
	struct _stat64 s;
	_fstati64(_fileno(f), &s);
#else
	struct stat s;
	fstat(fileno(f), &s);
#endif
	mSize = (uint64_t) s.st_size;
	mData = new unsigned char[(unsigned int) mSize];
	if (mSize < UINT_MAX)
	{
		fread(mData, 1, (size_t) mSize, f);
	}
	else
	{
		throw TheoraGenericException("Unable to preload file to memory, file is too large.");
	}

	fclose(f);
}

TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(unsigned char* data, long size, const std::string& filename)
{
	mFilename = filename;
	mData = data;
	mSize = size;
	mReadPointer = 0;
}

TheoraMemoryFileDataSource::~TheoraMemoryFileDataSource()
{
	if (mData) delete [] mData;
}

int TheoraMemoryFileDataSource::read(void* output, int nBytes)
{
	int n = (int) ((mReadPointer+nBytes <= mSize) ? nBytes : mSize - mReadPointer);
	if (!n) return 0;
	memcpy(output, mData + mReadPointer, n);
	mReadPointer += n;
	return n;
}

void TheoraMemoryFileDataSource::seek(uint64_t byte_index)
{
	mReadPointer = byte_index;
}

uint64_t TheoraMemoryFileDataSource::size()
{
	return mSize;
}

uint64_t TheoraMemoryFileDataSource::tell()
{
	return mReadPointer;
}
<commit_msg>added an informative exception in memory data source indicating that memory preloaded files larger than 4GB are not supported.<commit_after>/************************************************************************************
This source file is part of the Theora Video Playback Library
For latest info, see http://libtheoraplayer.googlecode.com
*************************************************************************************
Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
This program is free software; you can redistribute it and/or modify it under
the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
*************************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
#include "TheoraDataSource.h"
#include "TheoraException.h"
#include "TheoraVideoManager.h"
#include "TheoraUtil.h"

TheoraDataSource::~TheoraDataSource()
{

}

TheoraFileDataSource::TheoraFileDataSource(std::string filename)
{
	mFilename = filename;
	mFilePtr = NULL;
}

TheoraFileDataSource::~TheoraFileDataSource()
{
	if (mFilePtr)
	{
		fclose(mFilePtr);
		mFilePtr = NULL;
	}
}

void TheoraFileDataSource::openFile()
{
	if (mFilePtr == NULL)
	{
		mFilePtr = fopen(mFilename.c_str(), "rb");
		if (!mFilePtr)
        {
            std::string msg = "Can't open video file: " + mFilename;
            th_writelog(msg);
            throw TheoraGenericException(msg);
        }

#ifdef _WIN32
		struct _stat64 s;
		_fstati64(_fileno(mFilePtr), &s);
#else
		struct stat s;
		fstat(fileno(mFilePtr), &s);
#endif
		mSize = (uint64_t) s.st_size;
	}
}

int TheoraFileDataSource::read(void* output, int nBytes)
{
	if (mFilePtr == NULL) openFile();
	uint64_t n = fread(output, 1, nBytes, mFilePtr);
	return (int) n;
}

void TheoraFileDataSource::seek(uint64_t byte_index)
{
	if (mFilePtr == NULL) openFile();
	fpos_t fpos = byte_index;
	fsetpos(mFilePtr, &fpos);
}

uint64_t TheoraFileDataSource::size()
{
	if (mFilePtr == NULL) openFile();
	return mSize;
}

uint64_t TheoraFileDataSource::tell()
{
	if (mFilePtr == NULL) return 0;
	fpos_t pos;
	fgetpos(mFilePtr, &pos);
	return (uint64_t) pos;
}

TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(std::string filename) :
	mReadPointer(0),
	mData(0)
{
	mFilename = filename;
	FILE* f = fopen(filename.c_str(),"rb");
	if (!f) throw TheoraGenericException("Can't open video file: " + filename);

#ifdef _WIN32
	struct _stat64 s;
	_fstati64(_fileno(f), &s);
#else
	struct stat s;
	fstat(fileno(f), &s);
#endif
	mSize = (uint64_t) s.st_size;
	if (mSize > 0xFFFFFFFF)
	{
		throw TheoraGenericException("TheoraMemoryFileDataSource doesn't support files larger than 4GB!");
	}
	mData = new unsigned char[(unsigned int) mSize];
	if (mSize < UINT_MAX)
	{
		fread(mData, 1, (size_t) mSize, f);
	}
	else
	{
		throw TheoraGenericException("Unable to preload file to memory, file is too large.");
	}

	fclose(f);
}

TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(unsigned char* data, long size, const std::string& filename)
{
	mFilename = filename;
	mData = data;
	mSize = size;
	mReadPointer = 0;
}

TheoraMemoryFileDataSource::~TheoraMemoryFileDataSource()
{
	if (mData) delete [] mData;
}

int TheoraMemoryFileDataSource::read(void* output, int nBytes)
{
	int n = (int) ((mReadPointer+nBytes <= mSize) ? nBytes : mSize - mReadPointer);
	if (!n) return 0;
	memcpy(output, mData + mReadPointer, n);
	mReadPointer += n;
	return n;
}

void TheoraMemoryFileDataSource::seek(uint64_t byte_index)
{
	mReadPointer = byte_index;
}

uint64_t TheoraMemoryFileDataSource::size()
{
	return mSize;
}

uint64_t TheoraMemoryFileDataSource::tell()
{
	return mReadPointer;
}
<|endoftext|>


<commit_before>#ifndef PERSISTENT_HPP
#define PERSISTENT_HPP

#include <sys/types.h>
#include <inttypes.h>
#include <string>
#include <iostream>
#include <memory>
#include <functional>
#include <pthread.h>
#include "HLC.hpp"
#include "PersistException.hpp"
#include "PersistLog.hpp"
#include "FilePersistLog.hpp"
#include "SerializationSupport.hpp"

using namespace mutils;

namespace ns_persistent {

  // #define DEFINE_PERSIST_VAR(_t,_n) DEFINE_PERSIST_VAR(_t,_n,ST_FILE)
  #define DEFINE_PERSIST_VAR(_t,_n,_s) \
    Persistent<_t, _s> _n(# _n)
  #define DECLARE_PERSIST_VAR(_t,_n,_s) \
    extern DEFINE_PERSIST_VAR(_t,_n,_s)

  /* deprecated
  // number of versions in the cache
  #define MAX_NUM_CACHED_VERSION        (1024)
  #define VERSION_HASH(v)               ( (int)((v) & (MAX_NUM_CACHED_VERSION-1)) )

  // invalid version:
  #define INVALID_VERSION (-1ll)

  // read from cache
  #define VERSION_IS_CACHED(v)  (this->m_aCache[VERSION_HASH(v)].ver == (v))
  #define GET_CACHED_OBJ_PTR(v) (this->m_aCache[VERSION_HASH(v)].obj)
  */

  // function types to be registered for create version
  // or persist version
  using VersionFunc = std::function<void(const __int128 &)>;
  using PersistFunc = std::function<void(void)>;
  using FuncRegisterCallback = std::function<void(VersionFunc,PersistFunc)>;

  // Persistent represents a variable backed up by persistent storage. The
  // backend is PersistLog class. PersistLog handles only raw bytes and this
  // class is repsonsible for converting it back and forth between raw bytes
  // and ObjectType. But, the serialization/deserialization functionality is
  // actually defined by ObjectType and provided by Persistent users.
  // - ObjectType: user-defined type of the variable it is required to support
  //   serialization and deserialization as follows:
  //   // serialize
  //   void * ObjectType::serialize(const ObjectType & obj, uint64_t *psize)
  //   - obj: obj is the reference to the object to be serialized
  //   - psize: psize is a uint64_t pointer to receive the size of the serialized
  //     data.
  //   - Return value is a pointer to a new malloced buffer with the serialized
  //     //TODO: this may not be efficient for large object...open to be changed.
  //   // deserialize
  //   ObjectType * ObjectType::deserialize(const void *pdata)
  //   - pdata: a buffer of the serialized data
  //   - Return value is a pointer to a new created ObjectType deserialized from
  //     'pdata' buffer.
  // - StorageType: storage type is defined in PersistLog. The value could be
  //   ST_FILE/ST_MEM/ST_3DXP ... I will start with ST_FILE and extend it to
  //   other persistent Storage.
  // TODO:comments
  template <typename ObjectType,
    StorageType storageType=ST_FILE>
  class Persistent{
  public:
      /** The constructor
       * @param func_register_cb Call this to register myself to Replicated<T>
       * @param object_name This name is used for persistent data in file.
       */
      Persistent(FuncRegisterCallback func_register_cb=nullptr,
        const char * object_name = (*Persistent::getNameMaker().make()).c_str())
        noexcept(false) {
         // Initialize log
        this->m_pLog = NULL;
        switch(storageType){
        // file system
        case ST_FILE:
          this->m_pLog = new FilePersistLog(object_name);
          if(this->m_pLog == NULL){
            throw PERSIST_EXP_NEW_FAILED_UNKNOWN;
          }
          break;
        // volatile
        case ST_MEM:
        {
          const string tmpfsPath = "/dev/shm/volatile_t";
          this->m_pLog = new FilePersistLog(object_name, tmpfsPath);
          if(this->m_pLog == NULL){
            throw PERSIST_EXP_NEW_FAILED_UNKNOWN;
          }
          break;
        }
        //default
        default:
          throw PERSIST_EXP_STORAGE_TYPE_UNKNOWN(storageType);
        }
        //register the version creator and persist callback
        if(func_register_cb != nullptr){
          func_register_cb(
            std::bind(&Persistent<ObjectType,storageType>::version,this,std::placeholders::_1),
            std::bind(&Persistent<ObjectType,storageType>::persist,this)
        );
        }
      }
      // destructor: release the resources
      virtual ~Persistent() noexcept(false){
        // destroy the in-memory log
        if(this->m_pLog != NULL){
          delete this->m_pLog;
        }
        //TODO:unregister the version creator and persist callback,
        // if the Persistent<T> is added to the pool dynamically.
      };

      /**
       * * operator to get the memory version
       * @return ObjectType&
       */
      ObjectType& operator * (){
        return this->wrapped_obj;
      }

      // get the latest Value of T. The user lambda will be fed with the latest object
      // zerocopy:this object will not live once it returns.
      // return value is decided by user lambda
      template <typename Func>
      auto get (
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return this->getByIndex(-1L,fun,dm);
      };

      // get the latest Value of T, returns a unique pointer to the object
      std::unique_ptr<ObjectType> get ( DeserializationManager *dm=nullptr)
        noexcept(false) {
        return this->getByIndex(-1L,dm);
      };

      // get a version of Value T. the user lambda will be fed with the given object
      // zerocopy:this object will not live once it returns.
      // return value is decided by user lambda
      template <typename Func>
      auto getByIndex (
        int64_t idx,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return deserialize_and_run<ObjectType>(dm,(char *)this->m_pLog->getEntryByIndex(idx),fun);
      };

      // get a version of value T. returns a unique pointer to the object
      std::unique_ptr<ObjectType> getByIndex(
        int64_t idx,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return from_bytes<ObjectType>(dm,(char const *)this->m_pLog->getEntryByIndex(idx));
      };

      // get a version of Value T, specified by version. the user lambda will be fed with
      // an object of T.
      // zerocopy: this object will not live once it returns.
      // return value is decided by the user lambda.
      template <typename Func>
      auto get (
        const __int128 & ver,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char * pdat = (char*)this->m_pLog->getEntry(ver);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_VERSION;
        }
        return deserialize_and_run<ObjectType>(dm,pdat,fun);
      };

      // get a version of value T. specified version.
      // return a deserialized copy for the variable.
      std::unique_ptr<ObjectType> get(
        const __int128 & ver,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char const * pdat = (char const *)this->m_pLog->getEntry(ver);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_VERSION;
        }

        return from_bytes<ObjectType>(dm,pdat);
      }

      template <typename TKey>
      void trim (const TKey &k) noexcept(false) {
        dbg_trace("trim.");
        this->m_pLog->trim(k);
        dbg_trace("trim...done");
      }

      // get a version of Value T, specified by HLC clock. the user lambda will be fed with
      // an object of T.
      // zerocopy: this object will not live once it returns.
      // return value is decided by the user lambda.
      template <typename Func>
      auto get (
        const HLC& hlc,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char * pdat = (char*)this->m_pLog->getEntry(hlc);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_HLC;
        }
        return deserialize_and_run<ObjectType>(dm,pdat,fun);
      };

      // get a version of value T. specified by HLC clock.
      std::unique_ptr<ObjectType> get(
        const HLC& hlc,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char const * pdat = (char const *)this->m_pLog->getEntry(hlc);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_HLC;
        }

        return from_bytes<ObjectType>(dm,pdat);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](int64_t idx)
        noexcept(false) {
        return this->getByIndex(idx);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](const __int128 ver)
        noexcept(false) {
        return this->get(ver);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](const HLC & hlc)
        noexcept(false) {
        return this->get(hlc);
      }

      // get number of the versions
      virtual int64_t getNumOfVersions() noexcept(false) {
        return this->m_pLog->getLength();
      };

      virtual int64_t getEarliestIndex() noexcept(false) {
        return this->m_pLog->getEarliestIndex();
      }

      // make a version with version and mhlc clock
      virtual void set(const ObjectType &v, const __int128 & ver, const HLC &mhlc)
        noexcept(false) {
        auto size = bytes_size(v);
        char buf[size];
        bzero(buf,size);
        to_bytes(v,buf);
        this->m_pLog->append((void*)buf,size,ver,mhlc);
      };

      // make a version with version
      virtual void set(const ObjectType &v, const __int128 & ver)
        noexcept(false) {
        HLC mhlc; // generate a default timestamp for it.
        this->set(v,ver,mhlc);
      }

      // make a version
      virtual void version(const __int128 & ver)
        noexcept(false) {
        this->set(this->wrapped_obj,ver);
      }

      /** persist till version
       * @param ver version number
       * @return the given version to be persisted.
       */
      virtual const __int128 persist()
        noexcept(false){
        return this->m_pLog->persist();
      }

      // internal _NameMaker class
      class _NameMaker{
      public:
        // Constructor
        _NameMaker() noexcept(false):
        m_sObjectTypeName(typeid(ObjectType).name()) {
          this->m_iCounter = 0;
          if (pthread_spin_init(&this->m_oLck,PTHREAD_PROCESS_SHARED) != 0) {
            throw PERSIST_EXP_SPIN_INIT(errno);
          }
        }

        // Destructor
        virtual ~_NameMaker() noexcept(true) {
          pthread_spin_destroy(&this->m_oLck);
        }

        // guess a name
        std::unique_ptr<std::string> make() noexcept(false) {
          int cnt;
          if (pthread_spin_lock(&this->m_oLck) != 0) {
            throw PERSIST_EXP_SPIN_LOCK(errno);
          }
          cnt = this->m_iCounter++;
          if (pthread_spin_unlock(&this->m_oLck) != 0) {
            throw PERSIST_EXP_SPIN_UNLOCK(errno);
          }
          std::unique_ptr<std::string> ret = std::make_unique<std::string>();
          //char * buf = (char *)malloc((strlen(this->m_sObjectTypeName)+13)/8*8);
          char buf[256];
          sprintf(buf,"%s-%d",this->m_sObjectTypeName,cnt);
         // return std::make_shared<const char *>((const char*)buf);
         *ret = buf;
         return ret;
        }

      private:
        int m_iCounter;
        const char *m_sObjectTypeName;
        pthread_spinlock_t m_oLck;
      };

  private:
      // wrapped objected
      ObjectType wrapped_obj;

      // PersistLog
      PersistLog * m_pLog;

      // get the static name maker.
      static _NameMaker & getNameMaker();
  };

  // How many times the constructor was called.
  template <typename ObjectType, StorageType storageType>
  typename Persistent<ObjectType,storageType>::_NameMaker &
    Persistent<ObjectType,storageType>::getNameMaker() noexcept(false) {
    static Persistent<ObjectType,storageType>::_NameMaker nameMaker;
    return nameMaker;
  }

  template <typename ObjectType>
  class Volatile: public Persistent<ObjectType,ST_MEM>{
  public:
    // constructor: this will guess the objectname form ObjectType
    Volatile<ObjectType>() noexcept(false):
      Persistent<ObjectType,ST_MEM>(){
    };
    // destructor:
    virtual ~Volatile() noexcept(false){
      // do nothing
    };
  };
}

#endif//PERSIST_VAR_H
<commit_msg>added registry definition to Persistent<T>, TODO: add registry to Replicate<T>.<commit_after>#ifndef PERSISTENT_HPP
#define PERSISTENT_HPP

#include <sys/types.h>
#include <inttypes.h>
#include <string>
#include <iostream>
#include <memory>
#include <functional>
#include <pthread.h>
#include "HLC.hpp"
#include "PersistException.hpp"
#include "PersistLog.hpp"
#include "FilePersistLog.hpp"
#include "SerializationSupport.hpp"

using namespace mutils;

namespace ns_persistent {

  // #define DEFINE_PERSIST_VAR(_t,_n) DEFINE_PERSIST_VAR(_t,_n,ST_FILE)
  #define DEFINE_PERSIST_VAR(_t,_n,_s) \
    Persistent<_t, _s> _n(# _n)
  #define DECLARE_PERSIST_VAR(_t,_n,_s) \
    extern DEFINE_PERSIST_VAR(_t,_n,_s)

  /* deprecated
  // number of versions in the cache
  #define MAX_NUM_CACHED_VERSION        (1024)
  #define VERSION_HASH(v)               ( (int)((v) & (MAX_NUM_CACHED_VERSION-1)) )

  // invalid version:
  #define INVALID_VERSION (-1ll)

  // read from cache
  #define VERSION_IS_CACHED(v)  (this->m_aCache[VERSION_HASH(v)].ver == (v))
  #define GET_CACHED_OBJ_PTR(v) (this->m_aCache[VERSION_HASH(v)].obj)
  */

  // function types to be registered for create version
  // , persist version, and trim a version
  using VersionFunc = std::function<void(const __int128 &)>;
  using PersistFunc = std::function<void(void)>;
  using TrimFunc = std::function<void(const __int128 &)>;
  using FuncRegisterCallback = std::function<void(VersionFunc,PersistFunc,TrimFunc)>;

  // Persistent represents a variable backed up by persistent storage. The
  // backend is PersistLog class. PersistLog handles only raw bytes and this
  // class is repsonsible for converting it back and forth between raw bytes
  // and ObjectType. But, the serialization/deserialization functionality is
  // actually defined by ObjectType and provided by Persistent users.
  // - ObjectType: user-defined type of the variable it is required to support
  //   serialization and deserialization as follows:
  //   // serialize
  //   void * ObjectType::serialize(const ObjectType & obj, uint64_t *psize)
  //   - obj: obj is the reference to the object to be serialized
  //   - psize: psize is a uint64_t pointer to receive the size of the serialized
  //     data.
  //   - Return value is a pointer to a new malloced buffer with the serialized
  //     //TODO: this may not be efficient for large object...open to be changed.
  //   // deserialize
  //   ObjectType * ObjectType::deserialize(const void *pdata)
  //   - pdata: a buffer of the serialized data
  //   - Return value is a pointer to a new created ObjectType deserialized from
  //     'pdata' buffer.
  // - StorageType: storage type is defined in PersistLog. The value could be
  //   ST_FILE/ST_MEM/ST_3DXP ... I will start with ST_FILE and extend it to
  //   other persistent Storage.
  // TODO:comments
  template <typename ObjectType,
    StorageType storageType=ST_FILE>
  class Persistent{
  public:
      /** The constructor
       * @param func_register_cb Call this to register myself to Replicated<T>
       * @param object_name This name is used for persistent data in file.
       */
      Persistent(FuncRegisterCallback func_register_cb=nullptr,
        const char * object_name = (*Persistent::getNameMaker().make()).c_str())
        noexcept(false) {
         // Initialize log
        this->m_pLog = NULL;
        switch(storageType){
        // file system
        case ST_FILE:
          this->m_pLog = new FilePersistLog(object_name);
          if(this->m_pLog == NULL){
            throw PERSIST_EXP_NEW_FAILED_UNKNOWN;
          }
          break;
        // volatile
        case ST_MEM:
        {
          const string tmpfsPath = "/dev/shm/volatile_t";
          this->m_pLog = new FilePersistLog(object_name, tmpfsPath);
          if(this->m_pLog == NULL){
            throw PERSIST_EXP_NEW_FAILED_UNKNOWN;
          }
          break;
        }
        //default
        default:
          throw PERSIST_EXP_STORAGE_TYPE_UNKNOWN(storageType);
        }
        //register the version creator and persist callback
        if(func_register_cb != nullptr){
          func_register_cb(
            std::bind(&Persistent<ObjectType,storageType>::version,this,std::placeholders::_1),
            std::bind(&Persistent<ObjectType,storageType>::persist,this),
            std::bind(&Persistent<ObjectType,storageType>::trim<const __int128>,this,std::placeholders::_1) //trim by version:(const __int128)
        );
        }
      }
      // destructor: release the resources
      virtual ~Persistent() noexcept(false){
        // destroy the in-memory log
        if(this->m_pLog != NULL){
          delete this->m_pLog;
        }
        //TODO:unregister the version creator and persist callback,
        // if the Persistent<T> is added to the pool dynamically.
      };

      /**
       * * operator to get the memory version
       * @return ObjectType&
       */
      ObjectType& operator * (){
        return this->wrapped_obj;
      }

      // get the latest Value of T. The user lambda will be fed with the latest object
      // zerocopy:this object will not live once it returns.
      // return value is decided by user lambda
      template <typename Func>
      auto get (
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return this->getByIndex(-1L,fun,dm);
      };

      // get the latest Value of T, returns a unique pointer to the object
      std::unique_ptr<ObjectType> get ( DeserializationManager *dm=nullptr)
        noexcept(false) {
        return this->getByIndex(-1L,dm);
      };

      // get a version of Value T. the user lambda will be fed with the given object
      // zerocopy:this object will not live once it returns.
      // return value is decided by user lambda
      template <typename Func>
      auto getByIndex (
        int64_t idx,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return deserialize_and_run<ObjectType>(dm,(char *)this->m_pLog->getEntryByIndex(idx),fun);
      };

      // get a version of value T. returns a unique pointer to the object
      std::unique_ptr<ObjectType> getByIndex(
        int64_t idx,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        return from_bytes<ObjectType>(dm,(char const *)this->m_pLog->getEntryByIndex(idx));
      };

      // get a version of Value T, specified by version. the user lambda will be fed with
      // an object of T.
      // zerocopy: this object will not live once it returns.
      // return value is decided by the user lambda.
      template <typename Func>
      auto get (
        const __int128 & ver,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char * pdat = (char*)this->m_pLog->getEntry(ver);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_VERSION;
        }
        return deserialize_and_run<ObjectType>(dm,pdat,fun);
      };

      // get a version of value T. specified version.
      // return a deserialized copy for the variable.
      std::unique_ptr<ObjectType> get(
        const __int128 & ver,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char const * pdat = (char const *)this->m_pLog->getEntry(ver);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_VERSION;
        }

        return from_bytes<ObjectType>(dm,pdat);
      }

      template <typename TKey>
      void trim (const TKey &k) noexcept(false) {
        dbg_trace("trim.");
        this->m_pLog->trim(k);
        dbg_trace("trim...done");
      }

      // get a version of Value T, specified by HLC clock. the user lambda will be fed with
      // an object of T.
      // zerocopy: this object will not live once it returns.
      // return value is decided by the user lambda.
      template <typename Func>
      auto get (
        const HLC& hlc,
        const Func& fun,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char * pdat = (char*)this->m_pLog->getEntry(hlc);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_HLC;
        }
        return deserialize_and_run<ObjectType>(dm,pdat,fun);
      };

      // get a version of value T. specified by HLC clock.
      std::unique_ptr<ObjectType> get(
        const HLC& hlc,
        DeserializationManager *dm=nullptr)
        noexcept(false) {
        char const * pdat = (char const *)this->m_pLog->getEntry(hlc);
        if (pdat == nullptr) {
          throw PERSIST_EXP_INV_HLC;
        }

        return from_bytes<ObjectType>(dm,pdat);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](int64_t idx)
        noexcept(false) {
        return this->getByIndex(idx);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](const __int128 ver)
        noexcept(false) {
        return this->get(ver);
      }

      // syntax sugar: get a specified version of T without DSM
      std::unique_ptr<ObjectType> operator [](const HLC & hlc)
        noexcept(false) {
        return this->get(hlc);
      }

      // get number of the versions
      virtual int64_t getNumOfVersions() noexcept(false) {
        return this->m_pLog->getLength();
      };

      virtual int64_t getEarliestIndex() noexcept(false) {
        return this->m_pLog->getEarliestIndex();
      }

      // make a version with version and mhlc clock
      virtual void set(const ObjectType &v, const __int128 & ver, const HLC &mhlc)
        noexcept(false) {
        auto size = bytes_size(v);
        char buf[size];
        bzero(buf,size);
        to_bytes(v,buf);
        this->m_pLog->append((void*)buf,size,ver,mhlc);
      };

      // make a version with version
      virtual void set(const ObjectType &v, const __int128 & ver)
        noexcept(false) {
        HLC mhlc; // generate a default timestamp for it.
        this->set(v,ver,mhlc);
      }

      // make a version
      virtual void version(const __int128 & ver)
        noexcept(false) {
        //TODO: compare if value has been changed?
        this->set(this->wrapped_obj,ver);
      }

      /** persist till version
       * @param ver version number
       * @return the given version to be persisted.
       */
      virtual const __int128 persist()
        noexcept(false){
        return this->m_pLog->persist();
      }

      // internal _NameMaker class
      class _NameMaker{
      public:
        // Constructor
        _NameMaker() noexcept(false):
        m_sObjectTypeName(typeid(ObjectType).name()) {
          this->m_iCounter = 0;
          if (pthread_spin_init(&this->m_oLck,PTHREAD_PROCESS_SHARED) != 0) {
            throw PERSIST_EXP_SPIN_INIT(errno);
          }
        }

        // Destructor
        virtual ~_NameMaker() noexcept(true) {
          pthread_spin_destroy(&this->m_oLck);
        }

        // guess a name
        std::unique_ptr<std::string> make() noexcept(false) {
          int cnt;
          if (pthread_spin_lock(&this->m_oLck) != 0) {
            throw PERSIST_EXP_SPIN_LOCK(errno);
          }
          cnt = this->m_iCounter++;
          if (pthread_spin_unlock(&this->m_oLck) != 0) {
            throw PERSIST_EXP_SPIN_UNLOCK(errno);
          }
          std::unique_ptr<std::string> ret = std::make_unique<std::string>();
          //char * buf = (char *)malloc((strlen(this->m_sObjectTypeName)+13)/8*8);
          char buf[256];
          sprintf(buf,"%s-%d",this->m_sObjectTypeName,cnt);
         // return std::make_shared<const char *>((const char*)buf);
         *ret = buf;
         return ret;
        }

      private:
        int m_iCounter;
        const char *m_sObjectTypeName;
        pthread_spinlock_t m_oLck;
      };

  protected:
      // wrapped objected
      ObjectType wrapped_obj;

      // PersistLog
      PersistLog * m_pLog;

      // get the static name maker.
      static _NameMaker & getNameMaker();
  };

  // How many times the constructor was called.
  template <typename ObjectType, StorageType storageType>
  typename Persistent<ObjectType,storageType>::_NameMaker &
    Persistent<ObjectType,storageType>::getNameMaker() noexcept(false) {
    static Persistent<ObjectType,storageType>::_NameMaker nameMaker;
    return nameMaker;
  }

  template <typename ObjectType>
  class Volatile: public Persistent<ObjectType,ST_MEM>{
  public:
    // constructor: this will guess the objectname form ObjectType
    Volatile (
      FuncRegisterCallback func_register_cb=nullptr,
      const char * object_name = (*Persistent<ObjectType,ST_MEM>::getNameMaker().make()).c_str())
      noexcept(false):
      Persistent<ObjectType,ST_MEM>(func_register_cb,object_name){
    };
    // destructor:
    virtual ~Volatile() noexcept(false){
      // do nothing
    };
  };

  /*
   * PersistentRegistry is a book for all the Persistent<T> or Volatile<T>
   * variables. Replicated<T> class should maintain such a registry to perform
   * the following operations:
   * - makeVersion(const __int128 & ver): create a version
   * - persist(): persist the existing versions
   * - trim(const __int128 & ver): trim all versions earlier than ver
   */
  class PersistentRegistry{
  public:
    PersistentRegistry() {
      //
    };
    virtual ~PersistentRegistry() {
      this->_registry.clear();
    };
    #define VERSION_FUNC_IDX (0)
    #define PERSIST_FUNC_IDX (1)
    #define TRIM_FUNC_IDX (2)
    void makeVersion(const __int128 & ver) noexcept(false) {
      callFunc<VERSION_FUNC_IDX>(ver);
    };
    void persist() noexcept(false) {
      callFunc<PERSIST_FUNC_IDX>();
    };
    void trim(const __int128 & ver) noexcept(false) {
      callFunc<TRIM_FUNC_IDX>(ver);
    };
    void registerPersist(const VersionFunc &vf,const PersistFunc &pf,const TrimFunc &tf) noexcept(false) {
      //this->_registry.push_back(std::make_tuple<VersionFunc,PersistFunc,TrimFunc>(
      this->_registry.push_back(std::make_tuple(vf,pf,tf));
    };
  protected:
    std::vector<std::tuple<VersionFunc,PersistFunc,TrimFunc>> _registry;
    template<int funcIdx,typename ... Args >
    void callFunc(Args ... args) {
      for (auto itr = this->_registry.begin();
        itr != this->_registry.end(); ++itr) {
        std::get<funcIdx>(*itr)(args ...);
      }
    };
  };
}

#endif//PERSIST_VAR_H
<|endoftext|>