<commit_before>/*************************************************************************
 *
 *  $RCSfile: saveopt.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: pb $ $Date: 2000-11-13 09:40:12 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#include "saveopt.hxx"

#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <osl/mutex.hxx>

using namespace utl;
using namespace rtl;
using namespace com::sun::star::uno;

static SvtSaveOptions_Impl* pOptions = NULL;
static sal_Int32           nRefCount = 0;

class SvtSaveOptions_Impl : public utl::ConfigItem
{
    sal_Int32                           nAutoSaveTime;
    SvtSaveOptions::SaveGraphicsMode    eSaveGraphics;
    sal_Bool                            bUseUserData,
                                        bBackup,
                                        bAutoSave,
                                        bAutoSavePrompt,
                                        bDocInfSave,
                                        bSaveWorkingSet,
                                        bSaveDocWins,
                                        bSaveDocView,
                                        bSaveRelINet,
                                        bSaveRelFSys;
public:
                            SvtSaveOptions_Impl();

    virtual void            Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
    virtual void            Commit();

    void                    SetAutoSaveTime( sal_Int32 n )      { nAutoSaveTime = n; SetModified();  }
    sal_Int32               GetAutoSaveTime() const             { return nAutoSaveTime; }
    void                    SetUseUserData( BOOL b )            { bUseUserData = b; SetModified();}
    BOOL                    IsUseUserData() const               { return bUseUserData; }
    void                    SetBackup( BOOL b )                 { bBackup = b; SetModified();}
    BOOL                    IsBackup() const                    { return bBackup; }
    void                    SetAutoSave( BOOL b )               { bAutoSave = b; SetModified();    }
    BOOL                    IsAutoSave() const                  { return bAutoSave; }
    void                    SetAutoSavePrompt( BOOL b )         { bAutoSavePrompt = b; SetModified();  }
    BOOL                    IsAutoSavePrompt() const            { return bAutoSavePrompt; }
    void                    SetDocInfoSave(BOOL b)              { bDocInfSave = b; SetModified(); }
    BOOL                    IsDocInfoSave() const               { return bDocInfSave; }
    void                    SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )   { eSaveGraphics = eMode; SetModified(); }
    SvtSaveOptions::SaveGraphicsMode        GetSaveGraphicsMode() const         { return eSaveGraphics; }
    void                    SetSaveWorkingSet( BOOL b )         { bSaveWorkingSet = b; SetModified();}
    BOOL                    IsSaveWorkingSet() const            { return bSaveWorkingSet;         }
    void                    SetSaveDocWins( BOOL b )            { bSaveDocWins = b; SetModified();}
    BOOL                    IsSaveDocWins() const               { return bSaveDocWins; }
    void                    SetSaveDocView( BOOL b )            { bSaveDocView = b; SetModified();}
    BOOL                    IsSaveDocView() const               { return bSaveDocView; }
    void                    SetSaveRelINet( BOOL b )            { bSaveRelINet = b; SetModified();}
    BOOL                    IsSaveRelINet() const               { return bSaveRelINet; }
    void                    SetSaveRelFSys( BOOL b )            { bSaveRelFSys = b; SetModified();}
    BOOL                    IsSaveRelFSys() const               { return bSaveRelFSys; }
};

#define FORMAT 0
#define TIMEINTERVALL 1
#define USEUSERDATA 2
#define CREATEBACKUP 3
#define AUTOSAVE 4
#define PROMPT 5
#define EDITPROPERTY 6
#define SAVEDOCWINS 7
#define SAVEVIEWINFO 8
#define FILESYSTEM 9
#define INTERNET 10
#define SAVEWORKINGSET 11

Sequence< OUString > GetPropertyNames()
{
    static const char* aPropNames[] =
    {
        "Graphic/Format",
        "Document/AutoSaveTimeIntervall",
        "Document/UseUserData",
        "Document/CreateBackup",
        "Document/AutoSave",
        "Document/AutoSavePrompt",
        "Document/EditProperty",
        "Document/DocumentWindows",
        "Document/ViewInfo",
        "URL/FileSystem",
        "URL/Internet",
        "WorkingSet"
    };

    const int nCount = sizeof( aPropNames ) / sizeof( const char* );
    Sequence< OUString > aNames( nCount );
    OUString* pNames = aNames.getArray();
    for ( int i = 0; i < nCount; i++ )
        pNames[i] = OUString::createFromAscii( aPropNames[i] );

    return aNames;
}

// -----------------------------------------------------------------------

SvtSaveOptions_Impl::SvtSaveOptions_Impl()
    : ConfigItem( OUString::createFromAscii("Office.Common/Save") )
    , nAutoSaveTime( 0 )
    , eSaveGraphics( SvtSaveOptions::SaveGraphicsNormal )
    , bUseUserData( sal_False )
    , bBackup( sal_False )
    , bAutoSave( sal_False )
    , bAutoSavePrompt( sal_False )
    , bDocInfSave( sal_False )
    , bSaveWorkingSet( sal_False )
    , bSaveDocWins( sal_False )
    , bSaveDocView( sal_False )
    , bSaveRelINet( sal_False )
    , bSaveRelFSys( sal_False )
{
    Sequence< OUString > aNames = GetPropertyNames();
    Sequence< Any > aValues = GetProperties( aNames );
    EnableNotification( aNames );
    const Any* pValues = aValues.getConstArray();
    DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
    if ( aValues.getLength() == aNames.getLength() )
    {
        for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
        {
            DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
            if ( pValues[nProp].hasValue() )
            {
                sal_Int32 nTemp;
                switch ( nProp )
                {
                    case TIMEINTERVALL :
                        if ( pValues[nProp] >>= nTemp )
                            nAutoSaveTime = nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    case FORMAT :
                        if ( pValues[nProp] >>= nTemp )
                            eSaveGraphics = (SvtSaveOptions::SaveGraphicsMode) nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    default:
                    {
                        sal_Bool bTemp;
                        if ( pValues[nProp] >>= bTemp )
                        {
                            switch ( nProp )
                            {
                                case USEUSERDATA :
                                    bUseUserData = bTemp;
                                    break;
                                case CREATEBACKUP :
                                    bBackup = bTemp;
                                    break;
                                case AUTOSAVE :
                                    bAutoSave = bTemp;
                                    break;
                                case PROMPT :
                                    bAutoSavePrompt = bTemp;
                                    break;
                                case EDITPROPERTY :
                                    bDocInfSave = bTemp;
                                    break;
                                case SAVEWORKINGSET :
                                    bSaveWorkingSet = bTemp;
                                    break;
                                case SAVEDOCWINS :
                                    bSaveDocWins = bTemp;
                                    break;
                                case SAVEVIEWINFO :
                                    bSaveDocView = bTemp;
                                    break;
                                case FILESYSTEM :
                                    bSaveRelFSys = bTemp;
                                    break;
                                case INTERNET :
                                    bSaveRelINet = bTemp;
                                    break;

                                default :
                                    DBG_ERRORFILE( "invalid index to load a path" );
                            }
                        }
                        else
                            DBG_ERROR( "Wrong Type!" );

                    }
                }
            }
        }
    }
}

void SvtSaveOptions_Impl::Commit()
{
    Sequence< OUString > aNames = GetPropertyNames();
    OUString* pNames = aNames.getArray();
    Sequence< Any > aValues( aNames.getLength() );
    Any* pValues = aValues.getArray();
    for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
    {
        switch ( nProp )
        {
            case TIMEINTERVALL :
                pValues[nProp] <<= nAutoSaveTime;
                break;
            case FORMAT :
                pValues[nProp] <<= (sal_Int16 ) eSaveGraphics;
                break;
            case USEUSERDATA :
                pValues[nProp] <<= bUseUserData;
                break;
            case CREATEBACKUP :
                pValues[nProp] <<= bBackup;
                break;
            case AUTOSAVE :
                pValues[nProp] <<= bAutoSave;
                break;
            case PROMPT :
                pValues[nProp] <<= bAutoSavePrompt;
                break;
            case EDITPROPERTY :
                pValues[nProp] <<= bDocInfSave;
                break;
            case SAVEWORKINGSET :
                pValues[nProp] <<= bSaveWorkingSet;
                break;
            case SAVEDOCWINS :
                pValues[nProp] <<= bSaveDocWins;
                break;
            case SAVEVIEWINFO :
                pValues[nProp] <<= bSaveDocView;
                break;
            case FILESYSTEM :
                pValues[nProp] <<= bSaveRelFSys;
                break;
            case INTERNET :
                pValues[nProp] <<= bSaveRelINet;
                break;
            default:
                DBG_ERRORFILE( "invalid index to save a path" );
        }
    }

    PutProperties( aNames, aValues );
}

// -----------------------------------------------------------------------

void SvtSaveOptions_Impl::Notify( const Sequence<rtl::OUString>& aPropertyNames )
{
    DBG_ERRORFILE( "properties have been changed" );
}

SvtSaveOptions::SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() );
    if ( !pOptions )
        pOptions = new SvtSaveOptions_Impl;
    ++nRefCount;
    pImp = pOptions;
}

// -----------------------------------------------------------------------

SvtSaveOptions::~SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if ( !--nRefCount )
    {
        if ( pOptions->IsModified() )
            pOptions->Commit();
        DELETEZ( pOptions );
    }
}

void SvtSaveOptions::SetAutoSaveTime( sal_Int32 n )
{
    pImp->SetAutoSaveTime( n );
}

sal_Int32 SvtSaveOptions::GetAutoSaveTime() const
{
    return pImp->GetAutoSaveTime();
}

void SvtSaveOptions::SetUseUserData( sal_Bool b )
{
    pImp->SetUseUserData( b );
}

sal_Bool SvtSaveOptions::IsUseUserData() const
{
    return pImp->IsUseUserData();
}

void SvtSaveOptions::SetBackup( sal_Bool b )
{
    pImp->SetBackup( b );
}

sal_Bool SvtSaveOptions::IsBackup() const
{
    return pImp->IsBackup();
}

void SvtSaveOptions::SetAutoSave( sal_Bool b )
{
    pImp->SetAutoSave( b );
}

sal_Bool SvtSaveOptions::IsAutoSave() const
{
    return pImp->IsAutoSave();
}

void SvtSaveOptions::SetAutoSavePrompt( sal_Bool b )
{
    pImp->SetAutoSavePrompt( b );
}

sal_Bool SvtSaveOptions::IsAutoSavePrompt() const
{
    return pImp->IsAutoSavePrompt();
}

void SvtSaveOptions::SetDocInfoSave(sal_Bool b)
{
    pImp->SetDocInfoSave( b );
}

sal_Bool SvtSaveOptions::IsDocInfoSave() const
{
    return pImp->IsDocInfoSave();
}

void SvtSaveOptions::SetSaveWorkingSet( sal_Bool b )
{
    pImp->SetSaveWorkingSet( b );
}

sal_Bool SvtSaveOptions::IsSaveWorkingSet() const
{
    return pImp->IsSaveWorkingSet();
}

void SvtSaveOptions::SetSaveDocWins( sal_Bool b )
{
    pImp->SetSaveDocWins( b );
}

sal_Bool SvtSaveOptions::IsSaveDocWins() const
{
    return pImp->IsSaveDocWins();
}

void SvtSaveOptions::SetSaveDocView( sal_Bool b )
{
    pImp->SetSaveDocView( b );
}

sal_Bool SvtSaveOptions::IsSaveDocView() const
{
    return pImp->IsSaveDocView();
}

void SvtSaveOptions::SetSaveRelINet( sal_Bool b )
{
    pImp->SetSaveRelINet( b );
}

sal_Bool SvtSaveOptions::IsSaveRelINet() const
{
    return pImp->IsSaveRelINet();
}

void SvtSaveOptions::SetSaveRelFSys( sal_Bool b )
{
    pImp->SetSaveRelFSys( b );
}

sal_Bool SvtSaveOptions::IsSaveRelFSys() const
{
    return pImp->IsSaveRelFSys();
}

SvtSaveOptions::SaveGraphicsMode SvtSaveOptions::GetSaveGraphicsMode() const
{
    return pImp->GetSaveGraphicsMode();
}

void SvtSaveOptions::SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )
{
    pImp->SetSaveGraphicsMode( eMode );
}

<commit_msg>#87097#: don't allow setting of graphics mode anymore<commit_after>/*************************************************************************
 *
 *  $RCSfile: saveopt.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: ka $ $Date: 2001-05-16 15:52:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#include "saveopt.hxx"

#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <osl/mutex.hxx>

using namespace utl;
using namespace rtl;
using namespace com::sun::star::uno;

static SvtSaveOptions_Impl* pOptions = NULL;
static sal_Int32           nRefCount = 0;

class SvtSaveOptions_Impl : public utl::ConfigItem
{
    sal_Int32                           nAutoSaveTime;
    SvtSaveOptions::SaveGraphicsMode    eSaveGraphics;
    sal_Bool                            bUseUserData,
                                        bBackup,
                                        bAutoSave,
                                        bAutoSavePrompt,
                                        bDocInfSave,
                                        bSaveWorkingSet,
                                        bSaveDocWins,
                                        bSaveDocView,
                                        bSaveRelINet,
                                        bSaveRelFSys;
public:
                            SvtSaveOptions_Impl();

    virtual void            Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
    virtual void            Commit();

    void                    SetAutoSaveTime( sal_Int32 n )      { nAutoSaveTime = n; SetModified();  }
    sal_Int32               GetAutoSaveTime() const             { return nAutoSaveTime; }
    void                    SetUseUserData( BOOL b )            { bUseUserData = b; SetModified();}
    BOOL                    IsUseUserData() const               { return bUseUserData; }
    void                    SetBackup( BOOL b )                 { bBackup = b; SetModified();}
    BOOL                    IsBackup() const                    { return bBackup; }
    void                    SetAutoSave( BOOL b )               { bAutoSave = b; SetModified();    }
    BOOL                    IsAutoSave() const                  { return bAutoSave; }
    void                    SetAutoSavePrompt( BOOL b )         { bAutoSavePrompt = b; SetModified();  }
    BOOL                    IsAutoSavePrompt() const            { return bAutoSavePrompt; }
    void                    SetDocInfoSave(BOOL b)              { bDocInfSave = b; SetModified(); }
    BOOL                    IsDocInfoSave() const               { return bDocInfSave; }
    void                    SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )   { eSaveGraphics = eMode; SetModified(); }
    SvtSaveOptions::SaveGraphicsMode        GetSaveGraphicsMode() const         { return eSaveGraphics; }
    void                    SetSaveWorkingSet( BOOL b )         { bSaveWorkingSet = b; SetModified();}
    BOOL                    IsSaveWorkingSet() const            { return bSaveWorkingSet;         }
    void                    SetSaveDocWins( BOOL b )            { bSaveDocWins = b; SetModified();}
    BOOL                    IsSaveDocWins() const               { return bSaveDocWins; }
    void                    SetSaveDocView( BOOL b )            { bSaveDocView = b; SetModified();}
    BOOL                    IsSaveDocView() const               { return bSaveDocView; }
    void                    SetSaveRelINet( BOOL b )            { bSaveRelINet = b; SetModified();}
    BOOL                    IsSaveRelINet() const               { return bSaveRelINet; }
    void                    SetSaveRelFSys( BOOL b )            { bSaveRelFSys = b; SetModified();}
    BOOL                    IsSaveRelFSys() const               { return bSaveRelFSys; }
};

#define FORMAT 0
#define TIMEINTERVALL 1
#define USEUSERDATA 2
#define CREATEBACKUP 3
#define AUTOSAVE 4
#define PROMPT 5
#define EDITPROPERTY 6
#define SAVEDOCWINS 7
#define SAVEVIEWINFO 8
#define FILESYSTEM 9
#define INTERNET 10
#define SAVEWORKINGSET 11

Sequence< OUString > GetPropertyNames()
{
    static const char* aPropNames[] =
    {
        "Graphic/Format",
        "Document/AutoSaveTimeIntervall",
        "Document/UseUserData",
        "Document/CreateBackup",
        "Document/AutoSave",
        "Document/AutoSavePrompt",
        "Document/EditProperty",
        "Document/DocumentWindows",
        "Document/ViewInfo",
        "URL/FileSystem",
        "URL/Internet",
        "WorkingSet"
    };

    const int nCount = sizeof( aPropNames ) / sizeof( const char* );
    Sequence< OUString > aNames( nCount );
    OUString* pNames = aNames.getArray();
    for ( int i = 0; i < nCount; i++ )
        pNames[i] = OUString::createFromAscii( aPropNames[i] );

    return aNames;
}

// -----------------------------------------------------------------------

SvtSaveOptions_Impl::SvtSaveOptions_Impl()
    : ConfigItem( OUString::createFromAscii("Office.Common/Save") )
    , nAutoSaveTime( 0 )
    , eSaveGraphics( SvtSaveOptions::SaveGraphicsNormal )
    , bUseUserData( sal_False )
    , bBackup( sal_False )
    , bAutoSave( sal_False )
    , bAutoSavePrompt( sal_False )
    , bDocInfSave( sal_False )
    , bSaveWorkingSet( sal_False )
    , bSaveDocWins( sal_False )
    , bSaveDocView( sal_False )
    , bSaveRelINet( sal_False )
    , bSaveRelFSys( sal_False )
{
    Sequence< OUString > aNames = GetPropertyNames();
    Sequence< Any > aValues = GetProperties( aNames );
    EnableNotification( aNames );
    const Any* pValues = aValues.getConstArray();
    DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
    if ( aValues.getLength() == aNames.getLength() )
    {
        for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
        {
            DBG_ASSERT( pValues[nProp].hasValue(), "property value missing" );
            if ( pValues[nProp].hasValue() )
            {
                sal_Int32 nTemp;
                switch ( nProp )
                {
                    case TIMEINTERVALL :
                        if ( pValues[nProp] >>= nTemp )
                            nAutoSaveTime = nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    case FORMAT :
                        if ( pValues[nProp] >>= nTemp )
                            eSaveGraphics = (SvtSaveOptions::SaveGraphicsMode) nTemp;
                        else
                            DBG_ERROR( "Wrong Type!" );
                        break;

                    default:
                    {
                        sal_Bool bTemp;
                        if ( pValues[nProp] >>= bTemp )
                        {
                            switch ( nProp )
                            {
                                case USEUSERDATA :
                                    bUseUserData = bTemp;
                                    break;
                                case CREATEBACKUP :
                                    bBackup = bTemp;
                                    break;
                                case AUTOSAVE :
                                    bAutoSave = bTemp;
                                    break;
                                case PROMPT :
                                    bAutoSavePrompt = bTemp;
                                    break;
                                case EDITPROPERTY :
                                    bDocInfSave = bTemp;
                                    break;
                                case SAVEWORKINGSET :
                                    bSaveWorkingSet = bTemp;
                                    break;
                                case SAVEDOCWINS :
                                    bSaveDocWins = bTemp;
                                    break;
                                case SAVEVIEWINFO :
                                    bSaveDocView = bTemp;
                                    break;
                                case FILESYSTEM :
                                    bSaveRelFSys = bTemp;
                                    break;
                                case INTERNET :
                                    bSaveRelINet = bTemp;
                                    break;

                                default :
                                    DBG_ERRORFILE( "invalid index to load a path" );
                            }
                        }
                        else
                            DBG_ERROR( "Wrong Type!" );

                    }
                }
            }
        }
    }
}

void SvtSaveOptions_Impl::Commit()
{
    Sequence< OUString > aNames = GetPropertyNames();
    OUString* pNames = aNames.getArray();
    Sequence< Any > aValues( aNames.getLength() );
    Any* pValues = aValues.getArray();
    for ( int nProp = 0; nProp < aNames.getLength(); nProp++ )
    {
        switch ( nProp )
        {
            case TIMEINTERVALL :
                pValues[nProp] <<= nAutoSaveTime;
                break;
            case FORMAT :
                pValues[nProp] <<= (sal_Int16 ) eSaveGraphics;
                break;
            case USEUSERDATA :
                pValues[nProp] <<= bUseUserData;
                break;
            case CREATEBACKUP :
                pValues[nProp] <<= bBackup;
                break;
            case AUTOSAVE :
                pValues[nProp] <<= bAutoSave;
                break;
            case PROMPT :
                pValues[nProp] <<= bAutoSavePrompt;
                break;
            case EDITPROPERTY :
                pValues[nProp] <<= bDocInfSave;
                break;
            case SAVEWORKINGSET :
                pValues[nProp] <<= bSaveWorkingSet;
                break;
            case SAVEDOCWINS :
                pValues[nProp] <<= bSaveDocWins;
                break;
            case SAVEVIEWINFO :
                pValues[nProp] <<= bSaveDocView;
                break;
            case FILESYSTEM :
                pValues[nProp] <<= bSaveRelFSys;
                break;
            case INTERNET :
                pValues[nProp] <<= bSaveRelINet;
                break;
            default:
                DBG_ERRORFILE( "invalid index to save a path" );
        }
    }

    PutProperties( aNames, aValues );
}

// -----------------------------------------------------------------------

void SvtSaveOptions_Impl::Notify( const Sequence<rtl::OUString>& aPropertyNames )
{
    DBG_ERRORFILE( "properties have been changed" );
}

SvtSaveOptions::SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() );
    if ( !pOptions )
        pOptions = new SvtSaveOptions_Impl;
    ++nRefCount;
    pImp = pOptions;
}

// -----------------------------------------------------------------------

SvtSaveOptions::~SvtSaveOptions()
{
    // Global access, must be guarded (multithreading)
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if ( !--nRefCount )
    {
        if ( pOptions->IsModified() )
            pOptions->Commit();
        DELETEZ( pOptions );
    }
}

void SvtSaveOptions::SetAutoSaveTime( sal_Int32 n )
{
    pImp->SetAutoSaveTime( n );
}

sal_Int32 SvtSaveOptions::GetAutoSaveTime() const
{
    return pImp->GetAutoSaveTime();
}

void SvtSaveOptions::SetUseUserData( sal_Bool b )
{
    pImp->SetUseUserData( b );
}

sal_Bool SvtSaveOptions::IsUseUserData() const
{
    return pImp->IsUseUserData();
}

void SvtSaveOptions::SetBackup( sal_Bool b )
{
    pImp->SetBackup( b );
}

sal_Bool SvtSaveOptions::IsBackup() const
{
    return pImp->IsBackup();
}

void SvtSaveOptions::SetAutoSave( sal_Bool b )
{
    pImp->SetAutoSave( b );
}

sal_Bool SvtSaveOptions::IsAutoSave() const
{
    return pImp->IsAutoSave();
}

void SvtSaveOptions::SetAutoSavePrompt( sal_Bool b )
{
    pImp->SetAutoSavePrompt( b );
}

sal_Bool SvtSaveOptions::IsAutoSavePrompt() const
{
    return pImp->IsAutoSavePrompt();
}

void SvtSaveOptions::SetDocInfoSave(sal_Bool b)
{
    pImp->SetDocInfoSave( b );
}

sal_Bool SvtSaveOptions::IsDocInfoSave() const
{
    return pImp->IsDocInfoSave();
}

void SvtSaveOptions::SetSaveWorkingSet( sal_Bool b )
{
    pImp->SetSaveWorkingSet( b );
}

sal_Bool SvtSaveOptions::IsSaveWorkingSet() const
{
    return pImp->IsSaveWorkingSet();
}

void SvtSaveOptions::SetSaveDocWins( sal_Bool b )
{
    pImp->SetSaveDocWins( b );
}

sal_Bool SvtSaveOptions::IsSaveDocWins() const
{
    return pImp->IsSaveDocWins();
}

void SvtSaveOptions::SetSaveDocView( sal_Bool b )
{
    pImp->SetSaveDocView( b );
}

sal_Bool SvtSaveOptions::IsSaveDocView() const
{
    return pImp->IsSaveDocView();
}

void SvtSaveOptions::SetSaveRelINet( sal_Bool b )
{
    pImp->SetSaveRelINet( b );
}

sal_Bool SvtSaveOptions::IsSaveRelINet() const
{
    return pImp->IsSaveRelINet();
}

void SvtSaveOptions::SetSaveRelFSys( sal_Bool b )
{
    pImp->SetSaveRelFSys( b );
}

sal_Bool SvtSaveOptions::IsSaveRelFSys() const
{
    return pImp->IsSaveRelFSys();
}

SvtSaveOptions::SaveGraphicsMode SvtSaveOptions::GetSaveGraphicsMode() const
{
    return pImp->GetSaveGraphicsMode();
}

void SvtSaveOptions::SetSaveGraphicsMode( SvtSaveOptions::SaveGraphicsMode eMode )
{
    // don't allow setting of this property
    // pImp->SetSaveGraphicsMode( eMode );
}

<|endoftext|>


<commit_before>#ifndef UTENSOR_MATRIX_OPS
#define UTENSOR_MATRIX_OPS

#include <cmath>
#include <cstdlib>
#include <limits>
#include "quantization_utils.hpp"
#include "tensor.hpp"

// tensorflow/tensorflow/core/kernels/reference_gemm.h

template <class T1, class T2, class T3>
void ReferenceGemmuImpl(bool transpose_a, bool transpose_b, bool transpose_c,
                        size_t m, size_t n, size_t k, const T1* a,
                        int32_t offset_a, size_t lda, const T2* b, int offset_b,
                        size_t ldb, T3* c, int shift_c, int offset_c,
                        int mult_c, size_t ldc) {
  int a_i_stride = lda;
  int a_l_stride = 1;
  if (transpose_a) {
    a_i_stride = 1;
    a_l_stride = lda;
  }

  int b_j_stride = 1;
  int b_l_stride = ldb;
  if (transpose_b) {
    b_j_stride = ldb;
    b_l_stride = 1;
  }

  int c_i_stride = ldc;
  int c_j_stride = 1;
  if (transpose_c) {
    c_i_stride = 1;
    c_j_stride = ldc;
  }

  const int32_t highest = static_cast<int32_t>(std::numeric_limits<T3>::max());
  const int32_t lowest = static_cast<int32_t>(std::numeric_limits<T3>::min());
  const int32_t rounding = (shift_c < 1) ? 0 : (1 << (shift_c - 1));

  size_t i, j, l;
  for (j = 0; j < n; j++) {
    for (i = 0; i < m; i++) {
      int32_t total = 0;
      for (l = 0; l < k; l++) {
        const size_t a_index = ((i * a_i_stride) + (l * a_l_stride));
        const int32_t a_value = static_cast<int32_t>(a[a_index]) - offset_a;
        const size_t b_index = ((j * b_j_stride) + (l * b_l_stride));
        const int32_t b_value = static_cast<int32_t>(b[b_index]) - offset_b;
        total += (a_value * b_value);
      }
      const size_t c_index = ((i * c_i_stride) + (j * c_j_stride));
      int32_t output = ((((total + offset_c) * mult_c) + rounding) >> shift_c);
      if (output > highest) {
        output = highest;
      }

      if (output < lowest) {
        output = lowest;
      }
      c[c_index] = static_cast<T3>(output);
    }
  }
}

template <class T>
float FloatForOneQuantizedLevel(
    float range_min,
    float
        range_max)  // NT: information loss if float_for_one_quantized_level < 1
{
  const int64_t highest = static_cast<int64_t>(std::numeric_limits<T>::max());
  const int64_t lowest = static_cast<int64_t>(std::numeric_limits<T>::lowest());
  const float float_for_one_quantized_level =
      (range_max - range_min) / (highest - lowest);
  return float_for_one_quantized_level;
}

template <class T1, class T2, class T3>
void QuantizationRangeForMultiplication(float min_a, float max_a, float min_b,
                                        float max_b, float* min_c,
                                        float* max_c) {
  const float a_float_for_one_quant_level =
      FloatForOneQuantizedLevel<T1>(min_a, max_a);
  const float b_float_for_one_quant_level =
      FloatForOneQuantizedLevel<T2>(min_b, max_b);

  const int64_t c_highest =
      static_cast<int64_t>(std::numeric_limits<T3>::max());
  const int64_t c_lowest =
      static_cast<int64_t>(std::numeric_limits<T3>::lowest());
  const float c_float_for_one_quant_level =
      a_float_for_one_quant_level * b_float_for_one_quant_level;

  *min_c = c_float_for_one_quant_level * c_lowest;  // NT: this resulting in
                                                    // taking only the necessary
                                                    // quantize range
  *max_c = c_float_for_one_quant_level * c_highest;
}

template <class T1, class T2, class Toutput>
void QuantizedMatMul(Tensor* A, Tensor* B, Tensor** C,
                     Tensor* mina, Tensor* minb, Tensor* maxa,
                     Tensor* maxb, Tensor* outmin,
                     Tensor* outmax, bool transpose_a = false,
                     bool transpose_b = false) {
  const float min_a = *(mina->read<float>(0, 0));
  const float max_a = *(maxa->read<float>(0, 0));
  const float min_b = *(minb->read<float>(0, 0));
  const float max_b = *(maxb->read<float>(0, 0));

  //auto tensor allocation
  Shape c_shape;
  c_shape.push_back((A->getShape())[0]);
  c_shape.push_back((B->getShape())[1]);
  tensorChkAlloc<Toutput>(C, c_shape);

  const int32_t offset_a = FloatToQuantizedUnclamped<T1>(
      0.0f, min_a, max_a);  // NT: what 0 quantized to; depends on
                            // Eigen::NumTraits<T>::lowest()
  const int32_t offset_b = FloatToQuantizedUnclamped<T2>(0.0f, min_b, max_b);
  const int32_t offset_c = 0;
  const int32_t mult_c = 1;
  const int32_t shift_c = 0;

  int first = transpose_a ? 0 : 1;
  int second = transpose_b ? 1 : 0;

  int a_dim_remaining = 1 - first;
  int b_dim_remaining = 1 - second;

  const T1* A_Data = A->read<T1>(0, 0);
  const T2* B_Data = B->read<T2>(0, 0);
  Toutput* C_Data = (*C)->write<Toutput>(0, 0);

  const bool transpose_c = false;
  const size_t m = A->getShape()[a_dim_remaining];
  const size_t n = B->getShape()[b_dim_remaining];
  const size_t k = A->getShape()[first];
  const size_t lda = A->getShape()[1];
  const size_t ldb = B->getShape()[1];
  const size_t ldc = n;

  ReferenceGemmuImpl<T1, T2, Toutput>(
      transpose_a, transpose_b, transpose_c, m, n, k, A_Data, offset_a, lda,
      B_Data, offset_b, ldb, C_Data, shift_c, offset_c, mult_c, ldc);
  float min_c_value;
  float max_c_value;

  QuantizationRangeForMultiplication<T1, T2, Toutput>(
      min_a, max_a, min_b, max_b, &min_c_value, &max_c_value);

  float* c_min = outmin->write<float>(0, 0);
  *c_min = min_c_value;
  float* c_max = outmax->write<float>(0, 0);
  *c_max = max_c_value;
}

//////////////////////////////////////////////////////
template <class T1, class T2, class Toutput>
void QuantizedMatMul2(S_TENSOR A, S_TENSOR B, S_TENSOR C,
                     S_TENSOR mina, S_TENSOR minb, S_TENSOR maxa,
                     S_TENSOR maxb, S_TENSOR outmin,
                     S_TENSOR outmax, bool transpose_a = false,
                     bool transpose_b = false) {
  const float min_a = *(mina->read<float>(0, 0));
  const float max_a = *(maxa->read<float>(0, 0));
  const float min_b = *(minb->read<float>(0, 0));
  const float max_b = *(maxb->read<float>(0, 0));

  //auto tensor allocation
  Shape c_shape;
  c_shape.push_back((A->getShape())[0]);
  c_shape.push_back((B->getShape())[1]);
  C->resize<Toutput>(c_shape);

  const int32_t offset_a = FloatToQuantizedUnclamped<T1>(
      0.0f, min_a, max_a);  // NT: what 0 quantized to; depends on
                            // Eigen::NumTraits<T>::lowest()
  const int32_t offset_b = FloatToQuantizedUnclamped<T2>(0.0f, min_b, max_b);
  const int32_t offset_c = 0;
  const int32_t mult_c = 1;
  const int32_t shift_c = 0;

  int first = transpose_a ? 0 : 1;
  int second = transpose_b ? 1 : 0;

  int a_dim_remaining = 1 - first;
  int b_dim_remaining = 1 - second;

  const T1* A_Data = A->read<T1>(0, 0);
  const T2* B_Data = B->read<T2>(0, 0);
  Toutput* C_Data = C->write<Toutput>(0, 0);

  const bool transpose_c = false;
  const size_t m = A->getShape()[a_dim_remaining];
  const size_t n = B->getShape()[b_dim_remaining];
  const size_t k = A->getShape()[first];
  const size_t lda = A->getShape()[1];
  const size_t ldb = B->getShape()[1];
  const size_t ldc = n;

  ReferenceGemmuImpl<T1, T2, Toutput>(
      transpose_a, transpose_b, transpose_c, m, n, k, A_Data, offset_a, lda,
      B_Data, offset_b, ldb, C_Data, shift_c, offset_c, mult_c, ldc);
  float min_c_value;
  float max_c_value;

  QuantizationRangeForMultiplication<T1, T2, Toutput>(
      min_a, max_a, min_b, max_b, &min_c_value, &max_c_value);

  float* c_min = outmin->write<float>(0, 0);
  *c_min = min_c_value;
  float* c_max = outmax->write<float>(0, 0);
  *c_max = max_c_value;
}

template <class T1, class T2, class TOut>
class QntMatMulOp : public Operator {
public:
  QntMatMulOp() {
    n_inputs = 6;
    n_outputs = 3;
  }
  virtual void compute() override {
    QuantizedMatMul2<T1, T2, TOut>(inputs[0], inputs[3],
     outputs[0], inputs[1], inputs[4], inputs[2], inputs[5],
      outputs[1], outputs[2]);
  }
};

#endif
<commit_msg>  1. convolution implementation draft<commit_after>#ifndef UTENSOR_MATRIX_OPS
#define UTENSOR_MATRIX_OPS

#include <cmath>
#include <cstdlib>
#include <limits>
#include "quantization_utils.hpp"
#include "tensor.hpp"

// tensorflow/tensorflow/core/kernels/reference_gemm.h

template <class T1, class T2, class T3>
void ReferenceGemmuImpl(bool transpose_a, bool transpose_b, bool transpose_c,
                        size_t m, size_t n, size_t k, const T1* a,
                        int32_t offset_a, size_t lda, const T2* b, int offset_b,
                        size_t ldb, T3* c, int shift_c, int offset_c,
                        int mult_c, size_t ldc) {
  int a_i_stride = lda;
  int a_l_stride = 1;
  if (transpose_a) {
    a_i_stride = 1;
    a_l_stride = lda;
  }

  int b_j_stride = 1;
  int b_l_stride = ldb;
  if (transpose_b) {
    b_j_stride = ldb;
    b_l_stride = 1;
  }

  int c_i_stride = ldc;
  int c_j_stride = 1;
  if (transpose_c) {
    c_i_stride = 1;
    c_j_stride = ldc;
  }

  const int32_t highest = static_cast<int32_t>(std::numeric_limits<T3>::max());
  const int32_t lowest = static_cast<int32_t>(std::numeric_limits<T3>::min());
  const int32_t rounding = (shift_c < 1) ? 0 : (1 << (shift_c - 1));

  size_t i, j, l;
  for (j = 0; j < n; j++) {
    for (i = 0; i < m; i++) {
      int32_t total = 0;
      for (l = 0; l < k; l++) {
        const size_t a_index = ((i * a_i_stride) + (l * a_l_stride));
        const int32_t a_value = static_cast<int32_t>(a[a_index]) - offset_a;
        const size_t b_index = ((j * b_j_stride) + (l * b_l_stride));
        const int32_t b_value = static_cast<int32_t>(b[b_index]) - offset_b;
        total += (a_value * b_value);
      }
      const size_t c_index = ((i * c_i_stride) + (j * c_j_stride));
      int32_t output = ((((total + offset_c) * mult_c) + rounding) >> shift_c);
      if (output > highest) {
        output = highest;
      }

      if (output < lowest) {
        output = lowest;
      }
      c[c_index] = static_cast<T3>(output);
    }
  }
}

template <class T>
float FloatForOneQuantizedLevel(
    float range_min,
    float
        range_max)  // NT: information loss if float_for_one_quantized_level < 1
{
  const int64_t highest = static_cast<int64_t>(std::numeric_limits<T>::max());
  const int64_t lowest = static_cast<int64_t>(std::numeric_limits<T>::lowest());
  const float float_for_one_quantized_level =
      (range_max - range_min) / (highest - lowest);
  return float_for_one_quantized_level;
}

template <class T1, class T2, class T3>
void QuantizationRangeForMultiplication(float min_a, float max_a, float min_b,
                                        float max_b, float* min_c,
                                        float* max_c) {
  const float a_float_for_one_quant_level =
      FloatForOneQuantizedLevel<T1>(min_a, max_a);
  const float b_float_for_one_quant_level =
      FloatForOneQuantizedLevel<T2>(min_b, max_b);

  const int64_t c_highest =
      static_cast<int64_t>(std::numeric_limits<T3>::max());
  const int64_t c_lowest =
      static_cast<int64_t>(std::numeric_limits<T3>::lowest());
  const float c_float_for_one_quant_level =
      a_float_for_one_quant_level * b_float_for_one_quant_level;

  *min_c = c_float_for_one_quant_level * c_lowest;  // NT: this resulting in
                                                    // taking only the necessary
                                                    // quantize range
  *max_c = c_float_for_one_quant_level * c_highest;
}

template <class T1, class T2, class Toutput>
void QuantizedMatMul(Tensor* A, Tensor* B, Tensor** C,
                     Tensor* mina, Tensor* minb, Tensor* maxa,
                     Tensor* maxb, Tensor* outmin,
                     Tensor* outmax, bool transpose_a = false,
                     bool transpose_b = false) {
  const float min_a = *(mina->read<float>(0, 0));
  const float max_a = *(maxa->read<float>(0, 0));
  const float min_b = *(minb->read<float>(0, 0));
  const float max_b = *(maxb->read<float>(0, 0));

  //auto tensor allocation
  Shape c_shape;
  c_shape.push_back((A->getShape())[0]);
  c_shape.push_back((B->getShape())[1]);
  tensorChkAlloc<Toutput>(C, c_shape);

  const int32_t offset_a = FloatToQuantizedUnclamped<T1>(
      0.0f, min_a, max_a);  // NT: what 0 quantized to; depends on
                            // Eigen::NumTraits<T>::lowest()
  const int32_t offset_b = FloatToQuantizedUnclamped<T2>(0.0f, min_b, max_b);
  const int32_t offset_c = 0;
  const int32_t mult_c = 1;
  const int32_t shift_c = 0;

  int first = transpose_a ? 0 : 1;
  int second = transpose_b ? 1 : 0;

  int a_dim_remaining = 1 - first;
  int b_dim_remaining = 1 - second;

  const T1* A_Data = A->read<T1>(0, 0);
  const T2* B_Data = B->read<T2>(0, 0);
  Toutput* C_Data = (*C)->write<Toutput>(0, 0);

  const bool transpose_c = false;
  const size_t m = A->getShape()[a_dim_remaining];
  const size_t n = B->getShape()[b_dim_remaining];
  const size_t k = A->getShape()[first];
  const size_t lda = A->getShape()[1];
  const size_t ldb = B->getShape()[1];
  const size_t ldc = n;

  ReferenceGemmuImpl<T1, T2, Toutput>(
      transpose_a, transpose_b, transpose_c, m, n, k, A_Data, offset_a, lda,
      B_Data, offset_b, ldb, C_Data, shift_c, offset_c, mult_c, ldc);
  float min_c_value;
  float max_c_value;

  QuantizationRangeForMultiplication<T1, T2, Toutput>(
      min_a, max_a, min_b, max_b, &min_c_value, &max_c_value);

  float* c_min = outmin->write<float>(0, 0);
  *c_min = min_c_value;
  float* c_max = outmax->write<float>(0, 0);
  *c_max = max_c_value;
}

//////////////////////////////////////////////////////
template <class T1, class T2, class Toutput>
void QuantizedMatMul2(S_TENSOR A, S_TENSOR B, S_TENSOR C,
                     S_TENSOR mina, S_TENSOR minb, S_TENSOR maxa,
                     S_TENSOR maxb, S_TENSOR outmin,
                     S_TENSOR outmax, bool transpose_a = false,
                     bool transpose_b = false) {
  const float min_a = *(mina->read<float>(0, 0));
  const float max_a = *(maxa->read<float>(0, 0));
  const float min_b = *(minb->read<float>(0, 0));
  const float max_b = *(maxb->read<float>(0, 0));

  //auto tensor allocation
  Shape c_shape;
  c_shape.push_back((A->getShape())[0]);
  c_shape.push_back((B->getShape())[1]);
  C->resize<Toutput>(c_shape);

  const int32_t offset_a = FloatToQuantizedUnclamped<T1>(
      0.0f, min_a, max_a);  // NT: what 0 quantized to; depends on
                            // Eigen::NumTraits<T>::lowest()
  const int32_t offset_b = FloatToQuantizedUnclamped<T2>(0.0f, min_b, max_b);
  const int32_t offset_c = 0;
  const int32_t mult_c = 1;
  const int32_t shift_c = 0;

  int first = transpose_a ? 0 : 1;
  int second = transpose_b ? 1 : 0;

  int a_dim_remaining = 1 - first;
  int b_dim_remaining = 1 - second;

  const T1* A_Data = A->read<T1>(0, 0);
  const T2* B_Data = B->read<T2>(0, 0);
  Toutput* C_Data = C->write<Toutput>(0, 0);

  const bool transpose_c = false;
  const size_t m = A->getShape()[a_dim_remaining];
  const size_t n = B->getShape()[b_dim_remaining];
  const size_t k = A->getShape()[first];
  const size_t lda = A->getShape()[1];
  const size_t ldb = B->getShape()[1];
  const size_t ldc = n;

  ReferenceGemmuImpl<T1, T2, Toutput>(
      transpose_a, transpose_b, transpose_c, m, n, k, A_Data, offset_a, lda,
      B_Data, offset_b, ldb, C_Data, shift_c, offset_c, mult_c, ldc);
  float min_c_value;
  float max_c_value;

  QuantizationRangeForMultiplication<T1, T2, Toutput>(
      min_a, max_a, min_b, max_b, &min_c_value, &max_c_value);

  float* c_min = outmin->write<float>(0, 0);
  *c_min = min_c_value;
  float* c_max = outmax->write<float>(0, 0);
  *c_max = max_c_value;
}

template<class T1, class T2, class T3>
void conv(S_TENSOR input_data, int input_batches, int input_height, int input_width,
        int input_depth, S_TENSOR filter_data, int filter_height, int filter_width,
        int filter_count, int stride_rows, int stride_cols, S_TENSOR output_data,
        int output_height, int output_width) {
    int filter_left_offset;
    int filter_top_offset;
    if (padding == VALID) {
      filter_left_offset =
          ((output_width - 1) * stride_cols + filter_width - input_width + 1) /
          2;
      filter_top_offset = ((output_height - 1) * stride_rows + filter_height -
                           input_height + 1) /
                          2;
    } else {
      filter_left_offset =
          ((output_width - 1) * stride_cols + filter_width - input_width) / 2;
      filter_top_offset =
          ((output_height - 1) * stride_rows + filter_height - input_height) /
          2;
    }

    // If we've got multiple images in our input, work through each of them.
    for (int batch = 0; batch < input_batches; ++batch) {
      // Walk through all the output image values, sliding the filter to
      // different positions in the input.
      for (int out_y = 0; out_y < output_height; ++out_y) {
        for (int out_x = 0; out_x < output_width; ++out_x) {
          // Each filter kernel produces one output channel.
          for (int out_channel = 0; out_channel < filter_count; ++out_channel) {
            const int in_x_origin = (out_x * stride_cols) - filter_left_offset;
            const int in_y_origin = (out_y * stride_rows) - filter_top_offset;
            T3 total(0);
            for (int filter_y = 0; filter_y < filter_height; ++filter_y) {
              for (int filter_x = 0; filter_x < filter_width; ++filter_x) {
                for (int in_channel = 0; in_channel < input_depth;
                     ++in_channel) {
                  const int in_x = in_x_origin + filter_x;
                  const int in_y = in_y_origin + filter_y;
                  const T1 *input_value;
                  if ((in_x >= 0) && (in_x < input_width) && (in_y >= 0) &&
                      (in_y < input_height)) {
                    *input_value =
                        input_data->read<T1>(((batch * input_height * input_width *
                                    input_depth) +
                                   (in_y * input_width * input_depth) +
                                   (in_x * input_depth) + in_channel), 0);
                  } else {
                    *input_value = T1(0);
                  }
                  const T2 *filter_value =
                      filter_data->read<T2>((filter_y * filter_width * input_depth *
                                   filter_count) +
                                  (filter_x * input_depth * filter_count) +
                                  (in_channel * filter_count) + out_channel, 0);
                  total += (input_value * filter_value);
                }
              }
            }
            T3 *output =
            output_data->write<T3>((batch * output_height * output_width * filter_count) +
                        (out_y * output_width * filter_count) +
                        (out_x * filter_count) + out_channel, 0);
            *output = total;
          }
        }
      }
    }
}

template <class T1, class T2, class TOut>
class QntMatMulOp : public Operator {
    public:
  QntMatMulOp() {
    n_inputs = 6;
    n_outputs = 3;
  }
  virtual void compute() override {
    QuantizedMatMul2<T1, T2, TOut>(inputs[0], inputs[3],
     outputs[0], inputs[1], inputs[4], inputs[2], inputs[5],
      outputs[1], outputs[2]);
  }
};

#endif
<|endoftext|>


<commit_before>/* Copyright (c) 2018 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 <sys/time.h>
#include <time.h>
#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "paddle/fluid/inference/tests/test_helper.h"

DEFINE_string(dirname, "", "Directory of the inference model.");

TEST(inference, understand_sentiment) {
  if (FLAGS_dirname.empty()) {
    LOG(FATAL) << "Usage: ./example --dirname=path/to/your/model";
  }

  LOG(INFO) << "FLAGS_dirname: " << FLAGS_dirname << std::endl;
  std::string dirname = FLAGS_dirname;

  // 0. Call `paddle::framework::InitDevices()` initialize all the devices
  // In unittests, this is done in paddle/testing/paddle_gtest_main.cc
  paddle::framework::LoDTensor words;
  /*
    paddle::framework::LoD lod{{0, 83}};
    int64_t word_dict_len = 198392;
    SetupLoDTensor(&words, lod, static_cast<int64_t>(0),
                   static_cast<int64_t>(word_dict_len - 1));
   */
  std::vector<int64_t> srcdata{
      784,    784,   1550,   6463,   56,     75693, 6189,  784,    784,  1550,
      198391, 6463,  42468,  4376,   10251,  10760, 6189,  297,    396,  6463,
      6463,   1550,  198391, 6463,   22564,  1612,  291,   68,     164,  784,
      784,    1550,  198391, 6463,   13659,  3362,  42468, 6189,   2209, 198391,
      6463,   2209,  2209,   198391, 6463,   2209,  1062,  3029,   1831, 3029,
      1065,   2281,  100,    11216,  1110,   56,    10869, 9811,   100,  198391,
      6463,   100,   9280,   100,    288,    40031, 1680,  1335,   100,  1550,
      9280,   7265,  244,    1550,   198391, 6463,  1550,  198391, 6463, 42468,
      4376,   10251, 10760};
  paddle::framework::LoD lod{{0, srcdata.size()}};
  words.set_lod(lod);
  int64_t* pdata = words.mutable_data<int64_t>(
      {static_cast<int64_t>(srcdata.size()), 1}, paddle::platform::CPUPlace());
  memcpy(pdata, srcdata.data(), words.numel() * sizeof(int64_t));

  LOG(INFO) << "number of input size:" << words.numel();
  std::vector<paddle::framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&words);

  paddle::framework::LoDTensor output1;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  int repeat = 100;
  // Run inference on CPU
  TestInference<paddle::platform::CPUPlace, true, true>(dirname, cpu_feeds,
                                                        cpu_fetchs1, repeat);
  LOG(INFO) << output1.lod();
  LOG(INFO) << output1.dims();

#ifdef PADDLE_WITH_CUDA
  paddle::framework::LoDTensor output2;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs2;
  cpu_fetchs2.push_back(&output2);

  // Run inference on CUDA GPU
  TestInference<paddle::platform::CUDAPlace>(dirname, cpu_feeds, cpu_fetchs2);
  LOG(INFO) << output2.lod();
  LOG(INFO) << output2.dims();

  CheckError<float>(output1, output2);
#endif
}
<commit_msg>enable more choices<commit_after>/* Copyright (c) 2018 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 <sys/time.h>
#include <time.h>
#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "paddle/fluid/inference/tests/test_helper.h"

DEFINE_string(dirname, "", "Directory of the inference model.");
DEFINE_int32(repeat, 100, "Running the inference program repeat times");
DEFINE_bool(use_mkldnn, false, "Use MKLDNN to run inference");
DEFINE_bool(prepare_vars, true, "Prepare variables before executor");
DEFINE_bool(prepare_context, true, "Prepare Context before executor");

TEST(inference, understand_sentiment) {
  if (FLAGS_dirname.empty()) {
    LOG(FATAL) << "Usage: ./example --dirname=path/to/your/model";
  }

  LOG(INFO) << "FLAGS_dirname: " << FLAGS_dirname << std::endl;
  std::string dirname = FLAGS_dirname;

  // 0. Call `paddle::framework::InitDevices()` initialize all the devices
  // In unittests, this is done in paddle/testing/paddle_gtest_main.cc
  paddle::framework::LoDTensor words;
  /*
    paddle::framework::LoD lod{{0, 83}};
    int64_t word_dict_len = 198392;
    SetupLoDTensor(&words, lod, static_cast<int64_t>(0),
                   static_cast<int64_t>(word_dict_len - 1));
   */
  std::vector<int64_t> srcdata{
      784,    784,   1550,   6463,   56,     75693, 6189,  784,    784,  1550,
      198391, 6463,  42468,  4376,   10251,  10760, 6189,  297,    396,  6463,
      6463,   1550,  198391, 6463,   22564,  1612,  291,   68,     164,  784,
      784,    1550,  198391, 6463,   13659,  3362,  42468, 6189,   2209, 198391,
      6463,   2209,  2209,   198391, 6463,   2209,  1062,  3029,   1831, 3029,
      1065,   2281,  100,    11216,  1110,   56,    10869, 9811,   100,  198391,
      6463,   100,   9280,   100,    288,    40031, 1680,  1335,   100,  1550,
      9280,   7265,  244,    1550,   198391, 6463,  1550,  198391, 6463, 42468,
      4376,   10251, 10760};
  paddle::framework::LoD lod{{0, srcdata.size()}};
  words.set_lod(lod);
  int64_t* pdata = words.mutable_data<int64_t>(
      {static_cast<int64_t>(srcdata.size()), 1}, paddle::platform::CPUPlace());
  memcpy(pdata, srcdata.data(), words.numel() * sizeof(int64_t));

  LOG(INFO) << "number of input size:" << words.numel();
  std::vector<paddle::framework::LoDTensor*> cpu_feeds;
  cpu_feeds.push_back(&words);

  paddle::framework::LoDTensor output1;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs1;
  cpu_fetchs1.push_back(&output1);

  // Run inference on CPU
  const bool model_combined = false;
  if (FLAGS_prepare_vars) {
    if (FLAGS_prepare_context) {
      TestInference<paddle::platform::CPUPlace, false, true>(
          dirname, cpu_feeds, cpu_fetchs1, FLAGS_repeat, model_combined,
          FLAGS_use_mkldnn);
    } else {
      TestInference<paddle::platform::CPUPlace, false, false>(
          dirname, cpu_feeds, cpu_fetchs1, FLAGS_repeat, model_combined,
          FLAGS_use_mkldnn);
    }
  } else {
    if (FLAGS_prepare_context) {
      TestInference<paddle::platform::CPUPlace, true, true>(
          dirname, cpu_feeds, cpu_fetchs1, FLAGS_repeat, model_combined,
          FLAGS_use_mkldnn);
    } else {
      TestInference<paddle::platform::CPUPlace, true, false>(
          dirname, cpu_feeds, cpu_fetchs1, FLAGS_repeat, model_combined,
          FLAGS_use_mkldnn);
    }
  }
  LOG(INFO) << output1.lod();
  LOG(INFO) << output1.dims();

#ifdef PADDLE_WITH_CUDA
  paddle::framework::LoDTensor output2;
  std::vector<paddle::framework::LoDTensor*> cpu_fetchs2;
  cpu_fetchs2.push_back(&output2);

  // Run inference on CUDA GPU
  TestInference<paddle::platform::CUDAPlace>(dirname, cpu_feeds, cpu_fetchs2);
  LOG(INFO) << output2.lod();
  LOG(INFO) << output2.dims();

  CheckError<float>(output1, output2);
#endif
}
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <string>

#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <cstdlib>
#include <cstring>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"
#include "terminate_message.h"

#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *>, ps_compare> procLocDict;
static list<server_function_info *> roundRobinList;
static list<server_info *> serverList;

bool onSwitch = true;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void mapPrint(){
  cout << "procLocDict size: "<<procLocDict.size() << endl;
  cout << "Map Print: ";
  for(map<procedure_signature, list<server_info *>, ps_compare> ::const_iterator it = procLocDict.begin();
   it != procLocDict.end(); it++){

    cout << it->first.name << ", " ;
  }

  cout << endl;
}

void roundRobinPrint(){
  cout << "roundRobin Print: ";
  for(list<server_function_info *> ::const_iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    cout << (*it)->ps->name << endl;
  }
}

void serverListPrint(){
  cout << "serverList Print: " << endl;
  for(list<server_info *> ::const_iterator it = serverList.begin(); it != serverList.end(); it++){
    cout << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
  }
}

void registration_request_handler(RegisterRequestMessage * message, int sock){
  const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  cout << "We are trying to register: " << name  << ", " << server_identifier << ", " << port << endl;

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (procLocDict.find(key) == procLocDict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    procLocDict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);
    server_function_info * info = new server_function_info(entry, newKey);

    //Adding to roundRobinList if server is not found
    roundRobinList.push_back(info);

    //Adding to serverList if server is not found
    bool serverExist = false;
    for (list<server_info *>::iterator it = serverList.begin(); it != serverList.end(); it++) {

      if( (*it)->server_identifier == entry->server_identifier && (*it)->port == entry->port &&  (*it)->socket == entry->socket){
          serverExist = true;
          break;
        }
    }

    cout << "entry->server_identifier: " <<entry->server_identifier << endl;
    cout << "entry->port: " <<entry->port << endl;
    cout << " entry->socket: " << entry->socket << endl;

    if(!serverExist){
      serverList.push_back(entry);
    }

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = procLocDict[key];

    for (list<server_info *>::iterator it = hostList.begin(); it != hostList.end(); it++) {
      if((*it)->socket == sock){
        //If they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList.push_back(new_msg_loc);
    }
  }

  //mapPrint();
  //roundRobinPrint();
  serverListPrint();

  RegisterSuccessMessage regSuccessMsg = RegisterSuccessMessage(status);
  Segment regSuccessSeg = Segment(regSuccessMsg.getLength(), MSG_TYPE_REGISTER_SUCCESS, &regSuccessMsg);
  regSuccessSeg.send(sock);

}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
void location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
  string serverIdToPushBack;
  int portToPushBack;
  int socketToPushBack;

  //cout << "Hunted name names: " << message->getName() << endl;

	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    //If the name are the same and argTypes
    //cout << "Iterator names: " << (*it)->ps->name << endl;

    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;

      //cout << "Attempt to send locSuccessMsg" << endl;
      //cout << "server_identifier: "<< (*it)->si->server_identifier << endl;
      //cout << "port: " << (*it)->si->port<< endl;

      serverIdToPushBack = (*it)->si->server_identifier;
      portToPushBack = (*it)->si->port;
      socketToPushBack = (*it)->si->socket;

      LocSuccessMessage locSuccessMsg = LocSuccessMessage((*it)->si->server_identifier.c_str(), (*it)->si->port);
      Segment locSuccessSeg = Segment(locSuccessMsg.getLength(), MSG_TYPE_LOC_SUCCESS, &locSuccessMsg);
      locSuccessSeg.send(sock);

      //When we have identified the correct procedure_signature use splice and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      break;
 		}
	}

  if(exist){
    for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

       if((*it)->si->server_identifier == serverIdToPushBack && (*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }
    }
  }else {
    int reasoncode = -5; // Need actual reasoncode
    LocFailureMessage locFailMsg = LocFailureMessage(reasoncode);
    Segment locFailSeg = Segment(locFailMsg.getLength(), MSG_TYPE_LOC_FAILURE, &locFailMsg);
    locFailSeg.send(sock);
  }
}

void binder_terminate_handler() {
  cout << "Binder set to execute" << endl;

  for (list<server_info *>::const_iterator it = serverList.begin(); it != serverList.end(); it++) {
    cout << "Terminating server: " << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
    TerminateMessage termMsg = TerminateMessage();
    Segment termSeg = Segment(termMsg.getLength(), MSG_TYPE_TERMINATE, &termMsg);
    termSeg.send((*it)->socket);

  }

  onSwitch = false;

}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);

    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){

    cout << "Loc Request" << endl;

    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);

    location_request_handler(lqm, sock);

  }else if (segment->getType() == MSG_TYPE_TERMINATE){

    cout << "Terminate Request" <<endl;

    binder_terminate_handler();
  }

	return retval;
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main() {
// Code refactoring
/*
  fd_set allSockets;
  fd_set readSockets;

  // Clears all entries from the all sockets set and the read
  // sockets set
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  // Creates the welcome socket, adds it to the all sockets set and
  // sets it as the maximum socket so far
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  // Prints the binder address and the binder port on the binder's
  // standard output
  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        // Creates the connection socket when a connection is made
        // to the welcome socket
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        // Sets the connection socket as the maximum socket so far
        // if necessary
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        // Creates a segment to receive data from the client/server and
        // reads into it from the connection socket
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result <= 0) {
          // Closes the connection socket and removes it from the
          // all sockets set
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        request_handler(segment, i);
      }
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
*/
  vector<int> myConnections;
  vector<int> myToRemove;

  // Creates the welcome socket
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);

  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  fd_set readfds;
  int n;

  while(onSwitch){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(welcomeSocket, &readfds);

    n = welcomeSocket;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(welcomeSocket, &readfds)) {
        int connectionSocket = acceptConnection(welcomeSocket);

        if (connectionSocket < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          continue;
        }

        myConnections.push_back(connectionSocket);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {
            Segment * segment = 0;
            status = Segment::receive(tempConnection, segment);

            if (segment != 0){
              cout << "To be handled: "<< tempConnection << endl;
              if (segment->getType() == 0){
                cout << "getType() is null" << endl;
              }else{
                cout << segment->getType() << endl;
              }
            }

            request_handler(segment, tempConnection);

          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        destroySocket(*it);
      }
      myToRemove.clear();
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
}
<commit_msg>changes<commit_after>#include <iostream>
#include <sstream>
#include <string>

#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <cstdlib>
#include <cstring>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"
#include "terminate_message.h"

#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *>, ps_compare> procLocDict;
static list<server_function_info *> roundRobinList;
static list<server_info *> serverList;

bool onSwitch = true;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void mapPrint(){
  cout << "procLocDict size: "<<procLocDict.size() << endl;
  cout << "Map Print: ";
  for(map<procedure_signature, list<server_info *>, ps_compare> ::const_iterator it = procLocDict.begin();
   it != procLocDict.end(); it++){

    cout << it->first.name << ", " ;
  }

  cout << endl;
}

void roundRobinPrint(){
  cout << "roundRobin Print: ";
  for(list<server_function_info *> ::const_iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    cout << (*it)->ps->name << endl;
  }
}

void serverListPrint(){
  cout << "serverList Print: " << endl;
  for(list<server_info *> ::const_iterator it = serverList.begin(); it != serverList.end(); it++){
    cout << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
  }
}

void registration_request_handler(RegisterRequestMessage * message, int sock){
  const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  cout << "We are trying to register: " << name  << ", " << server_identifier << ", " << port << endl;

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (procLocDict.find(key) == procLocDict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    procLocDict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);
    server_function_info * info = new server_function_info(entry, newKey);

    //Adding to roundRobinList if server is not found
    roundRobinList.push_back(info);

    //Adding to serverList if server is not found
    bool serverExist = false;
    for (list<server_info *>::iterator it = serverList.begin(); it != serverList.end(); it++) {

      if( (*it)->server_identifier == entry->server_identifier && (*it)->port == entry->port &&  (*it)->socket == entry->socket){
          serverExist = true;
          break;
        }
    }

    cout << "entry->server_identifier: " <<entry->server_identifier << endl;
    cout << "entry->port: " <<entry->port << endl;
    cout << " entry->socket: " << entry->socket << endl;

    if(!serverExist){
      serverList.push_back(entry);
    }

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = procLocDict[key];

    for (list<server_info *>::iterator it = hostList.begin(); it != hostList.end(); it++) {
      if((*it)->socket == sock){
        //If they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList.push_back(new_msg_loc);
    }
  }

  //mapPrint();
  //roundRobinPrint();
  serverListPrint();

  RegisterSuccessMessage regSuccessMsg = RegisterSuccessMessage(status);
  Segment regSuccessSeg = Segment(regSuccessMsg.getLength(), MSG_TYPE_REGISTER_SUCCESS, &regSuccessMsg);
  regSuccessSeg.send(sock);

}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
void location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
  string serverIdToPushBack;
  int portToPushBack;
  int socketToPushBack;

  //cout << "Hunted name names: " << message->getName() << endl;

	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    //If the name are the same and argTypes
    //cout << "Iterator names: " << (*it)->ps->name << endl;

    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;

      //cout << "Attempt to send locSuccessMsg" << endl;
      //cout << "server_identifier: "<< (*it)->si->server_identifier << endl;
      //cout << "port: " << (*it)->si->port<< endl;

      serverIdToPushBack = (*it)->si->server_identifier;
      portToPushBack = (*it)->si->port;
      socketToPushBack = (*it)->si->socket;

      LocSuccessMessage locSuccessMsg = LocSuccessMessage((*it)->si->server_identifier.c_str(), (*it)->si->port);
      Segment locSuccessSeg = Segment(locSuccessMsg.getLength(), MSG_TYPE_LOC_SUCCESS, &locSuccessMsg);
      locSuccessSeg.send(sock);

      //When we have identified the correct procedure_signature use splice and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      break;
 		}
	}

  if(exist){
    for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

       if((*it)->si->server_identifier == serverIdToPushBack && (*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }
    }
  }else {
    int reasoncode = -5; // Need actual reasoncode
    LocFailureMessage locFailMsg = LocFailureMessage(reasoncode);
    Segment locFailSeg = Segment(locFailMsg.getLength(), MSG_TYPE_LOC_FAILURE, &locFailMsg);
    locFailSeg.send(sock);
  }
}

void binder_terminate_handler() {
  cout << "Binder set to execute" << endl;

  for (list<server_info *>::const_iterator it = serverList.begin(); it != serverList.end(); it++) {
    cout << "Terminating server: " << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
    TerminateMessage termMsg = TerminateMessage();
    Segment termSeg = Segment(termMsg.getLength(), MSG_TYPE_TERMINATE, &termMsg);
    termSeg.send((*it)->socket);

    sleep(1);
  }

  onSwitch = false;

}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);

    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){

    cout << "Loc Request" << endl;

    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);

    location_request_handler(lqm, sock);

  }else if (segment->getType() == MSG_TYPE_TERMINATE){

    cout << "Terminate Request" <<endl;

    binder_terminate_handler();
  }

	return retval;
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main() {
// Code refactoring
/*
  fd_set allSockets;
  fd_set readSockets;

  // Clears all entries from the all sockets set and the read
  // sockets set
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  // Creates the welcome socket, adds it to the all sockets set and
  // sets it as the maximum socket so far
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  // Prints the binder address and the binder port on the binder's
  // standard output
  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        // Creates the connection socket when a connection is made
        // to the welcome socket
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        // Sets the connection socket as the maximum socket so far
        // if necessary
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        // Creates a segment to receive data from the client/server and
        // reads into it from the connection socket
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result <= 0) {
          // Closes the connection socket and removes it from the
          // all sockets set
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        request_handler(segment, i);
      }
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
*/
  vector<int> myConnections;
  vector<int> myToRemove;

  // Creates the welcome socket
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);

  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  fd_set readfds;
  int n;

  while(onSwitch){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(welcomeSocket, &readfds);

    n = welcomeSocket;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(welcomeSocket, &readfds)) {
        int connectionSocket = acceptConnection(welcomeSocket);

        if (connectionSocket < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          continue;
        }

        myConnections.push_back(connectionSocket);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {
            Segment * segment = 0;
            status = Segment::receive(tempConnection, segment);

            if (segment != 0){
              cout << "To be handled: "<< tempConnection << endl;
              if (segment->getType() == 0){
                cout << "getType() is null" << endl;
              }else{
                cout << segment->getType() << endl;
              }
            }

            request_handler(segment, tempConnection);

          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        destroySocket(*it);
      }
      myToRemove.clear();
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
}
<|endoftext|>


<commit_before>/*
** Copyright (c) 2014-2016, Eren Okka
**
** This Source Code Form is subject to the terms of the Mozilla Public
** License, v. 2.0. If a copy of the MPL was not distributed with this
** file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#include <algorithm>

#include "keyword.h"
#include "token.h"

namespace anitomy {

KeywordManager keyword_manager;

KeywordOptions::KeywordOptions(bool identifiable, bool searchable, bool valid)
    : identifiable(identifiable), searchable(searchable), valid(valid) {
}

Keyword::Keyword(ElementCategory category, const KeywordOptions& options)
    : category(category), options(options) {
}

////////////////////////////////////////////////////////////////////////////////

KeywordManager::KeywordManager() {
  const KeywordOptions options_default;
  const KeywordOptions options_invalid(true, true, false);
  const KeywordOptions options_unidentifiable(false, true, true);
  const KeywordOptions options_unidentifiable_invalid(false, true, false);
  const KeywordOptions options_unidentifiable_unsearchable(false, false, true);

  Add(kElementAnimeSeasonPrefix, options_unidentifiable, {
      L"SAISON", L"SEASON"});

  Add(kElementAnimeType, options_unidentifiable, {
      L"GEKIJOUBAN", L"MOVIE",
      L"OAD", L"OAV", L"ONA", L"OVA",
      L"SPECIAL", L"SPECIALS",
      L"TV"});
  Add(kElementAnimeType, options_unidentifiable_unsearchable, {
      L"SP"});  // e.g. "Yumeiro Patissiere SP Professional"
  Add(kElementAnimeType, options_unidentifiable_invalid, {
      L"ED", L"ENDING", L"NCED",
      L"NCOP", L"OP", L"OPENING",
      L"PREVIEW", L"PV"});

  Add(kElementAudioTerm, options_default, {
      // Audio channels
      L"2.0CH", L"2CH", L"5.1", L"5.1CH", L"DTS", L"DTS-ES", L"DTS5.1",
      L"TRUEHD5.1",
      // Audio codec
      L"AAC", L"AACX2", L"AACX3", L"AACX4", L"AC3", L"FLAC", L"FLACX2",
      L"FLACX3", L"FLACX4", L"LOSSLESS", L"MP3", L"OGG", L"VORBIS",
      // Audio language
      L"DUALAUDIO", L"DUAL AUDIO"});

  Add(kElementDeviceCompatibility, options_default, {
      L"IPAD3", L"IPHONE5", L"IPOD", L"PS3", L"XBOX", L"XBOX360"});
  Add(kElementDeviceCompatibility, options_unidentifiable, {
      L"ANDROID"});

  Add(kElementEpisodePrefix, options_default, {
      L"EP", L"EP.", L"EPS", L"EPS.", L"EPISODE", L"EPISODE.", L"EPISODES",
      L"CAPITULO", L"EPISODIO", L"FOLGE"});
  Add(kElementEpisodePrefix, options_invalid, {
      L"E", L"\x7B2C"});  // single-letter episode keywords are not valid tokens

  Add(kElementFileExtension, options_default, {
      L"3GP", L"AVI", L"DIVX", L"FLV", L"M2TS", L"MKV", L"MOV", L"MP4", L"MPG",
      L"OGM", L"RM", L"RMVB", L"WEBM", L"WMV"});
  Add(kElementFileExtension, options_invalid, {
      L"AAC", L"AIFF", L"FLAC", L"M4A", L"MP3", L"MKA", L"OGG", L"WAV", L"WMA",
      L"7Z", L"RAR", L"ZIP",
      L"ASS", L"SRT"});

  Add(kElementLanguage, options_default, {
      L"ENG", L"ENGLISH", L"ESPANOL", L"JAP", L"PT-BR", L"SPANISH", L"VOSTFR"});
  Add(kElementLanguage, options_unidentifiable, {
      L"ESP", L"ITA"});  // e.g. "Tokyo ESP", "Bokura ga Ita"

  Add(kElementOther, options_default, {
      L"REMASTER", L"REMASTERED", L"UNCENSORED", L"UNCUT",
      L"TS", L"VFR", L"WIDESCREEN", L"WS"});

  Add(kElementReleaseGroup, options_default, {
      L"THORA"});

  Add(kElementReleaseInformation, options_default, {
      L"BATCH", L"COMPLETE", L"PATCH", L"REMUX"});
  Add(kElementReleaseInformation, options_unidentifiable, {
      L"END", L"FINAL"});  // e.g. "The End of Evangelion", "Final Approach"

  Add(kElementReleaseVersion, options_default, {
      L"V0", L"V1", L"V2", L"V3", L"V4"});

  Add(kElementSource, options_default, {
      L"BD", L"BDRIP", L"BLURAY", L"BLU-RAY",
      L"DVD", L"DVD5", L"DVD9", L"DVD-R2J", L"DVDRIP", L"DVD-RIP",
      L"R2DVD", L"R2J", L"R2JDVD", L"R2JDVDRIP",
      L"HDTV", L"HDTVRIP", L"TVRIP", L"TV-RIP",
      L"WEBCAST", L"WEBRIP"});

  Add(kElementSubtitles, options_default, {
      L"ASS", L"BIG5", L"DUB", L"DUBBED", L"HARDSUB", L"RAW", L"SOFTSUB",
      L"SOFTSUBS", L"SUB", L"SUBBED", L"SUBTITLED"});

  Add(kElementVideoTerm, options_default, {
      // Frame rate
      L"23.976FPS", L"24FPS", L"29.97FPS", L"30FPS", L"60FPS", L"120FPS",
      // Video codec
      L"8BIT", L"8-BIT", L"10BIT", L"10BITS", L"10-BIT", L"10-BITS", L"HI10P",
      L"H264", L"H265", L"H.264", L"H.265", L"X264", L"X265", L"X.264",
      L"AVC", L"HEVC", L"DIVX", L"DIVX5", L"DIVX6", L"XVID",
      // Video format
      L"AVI", L"RMVB", L"WMV", L"WMV3", L"WMV9",
      // Video quality
      L"HQ", L"LQ",
      // Video resolution
      L"HD", L"SD"});

  Add(kElementVolumePrefix, options_default, {
      L"VOL", L"VOL.", L"VOLUME"});
}

void KeywordManager::Add(ElementCategory category,
                         const KeywordOptions& options,
                         const std::initializer_list<string_t>& keywords) {
  auto& keys = GetKeywordContainer(category);
  for (const auto& keyword : keywords) {
    if (keyword.empty())
      continue;
    if (keys.find(keyword) != keys.end())
      continue;
    keys.insert(std::make_pair(keyword, Keyword(category, options)));
  }
}

bool KeywordManager::Find(ElementCategory category, const string_t& str) const {
  const auto& keys = GetKeywordContainer(category);
  auto it = keys.find(str);
  if (it != keys.end() && it->second.category == category)
    return true;

  return false;
}

bool KeywordManager::Find(const string_t& str, ElementCategory& category,
                          KeywordOptions& options) const {
  const auto& keys = GetKeywordContainer(category);
  auto it = keys.find(str);
  if (it != keys.end()) {
    if (category == kElementUnknown) {
      category = it->second.category;
    } else if (it->second.category != category) {
      return false;
    }
    options = it->second.options;
    return true;
  }

  return false;
}

string_t KeywordManager::Normalize(const string_t& str) const {
  return StringToUpperCopy(str);
}

KeywordManager::keyword_container_t& KeywordManager::GetKeywordContainer(
    ElementCategory category) const {
  return category == kElementFileExtension ?
      const_cast<keyword_container_t&>(file_extensions_) :
      const_cast<keyword_container_t&>(keys_);
}

////////////////////////////////////////////////////////////////////////////////

void KeywordManager::Peek(const string_t& filename,
                          const TokenRange& range,
                          Elements& elements,
                          std::vector<TokenRange>& preidentified_tokens) const {
  typedef std::pair<ElementCategory, std::vector<string_t>> entry_t;
  static const std::vector<entry_t> entries{
    {kElementAudioTerm, {L"Dual Audio"}},
    {kElementVideoTerm, {L"H264", L"H.264", L"h264", L"h.264"}},
    {kElementVideoResolution, {L"480p", L"720p", L"1080p"}},
    {kElementSource, {L"Blu-Ray"}}
  };

  auto it_begin = filename.begin() + range.offset;
  auto it_end = it_begin + range.size;

  for (const auto& entry : entries) {
    for (const auto& keyword : entry.second) {
      auto it = std::search(it_begin, it_end, keyword.begin(), keyword.end());
      if (it != it_end) {
        auto offset = it - filename.begin();
        elements.insert(entry.first, keyword);
        preidentified_tokens.push_back(TokenRange(offset, keyword.size()));
      }
    }
  }
}

}  // namespace anitomy<commit_msg>Add keyword: Hi10<commit_after>/*
** Copyright (c) 2014-2016, Eren Okka
**
** This Source Code Form is subject to the terms of the Mozilla Public
** License, v. 2.0. If a copy of the MPL was not distributed with this
** file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#include <algorithm>

#include "keyword.h"
#include "token.h"

namespace anitomy {

KeywordManager keyword_manager;

KeywordOptions::KeywordOptions(bool identifiable, bool searchable, bool valid)
    : identifiable(identifiable), searchable(searchable), valid(valid) {
}

Keyword::Keyword(ElementCategory category, const KeywordOptions& options)
    : category(category), options(options) {
}

////////////////////////////////////////////////////////////////////////////////

KeywordManager::KeywordManager() {
  const KeywordOptions options_default;
  const KeywordOptions options_invalid(true, true, false);
  const KeywordOptions options_unidentifiable(false, true, true);
  const KeywordOptions options_unidentifiable_invalid(false, true, false);
  const KeywordOptions options_unidentifiable_unsearchable(false, false, true);

  Add(kElementAnimeSeasonPrefix, options_unidentifiable, {
      L"SAISON", L"SEASON"});

  Add(kElementAnimeType, options_unidentifiable, {
      L"GEKIJOUBAN", L"MOVIE",
      L"OAD", L"OAV", L"ONA", L"OVA",
      L"SPECIAL", L"SPECIALS",
      L"TV"});
  Add(kElementAnimeType, options_unidentifiable_unsearchable, {
      L"SP"});  // e.g. "Yumeiro Patissiere SP Professional"
  Add(kElementAnimeType, options_unidentifiable_invalid, {
      L"ED", L"ENDING", L"NCED",
      L"NCOP", L"OP", L"OPENING",
      L"PREVIEW", L"PV"});

  Add(kElementAudioTerm, options_default, {
      // Audio channels
      L"2.0CH", L"2CH", L"5.1", L"5.1CH", L"DTS", L"DTS-ES", L"DTS5.1",
      L"TRUEHD5.1",
      // Audio codec
      L"AAC", L"AACX2", L"AACX3", L"AACX4", L"AC3", L"FLAC", L"FLACX2",
      L"FLACX3", L"FLACX4", L"LOSSLESS", L"MP3", L"OGG", L"VORBIS",
      // Audio language
      L"DUALAUDIO", L"DUAL AUDIO"});

  Add(kElementDeviceCompatibility, options_default, {
      L"IPAD3", L"IPHONE5", L"IPOD", L"PS3", L"XBOX", L"XBOX360"});
  Add(kElementDeviceCompatibility, options_unidentifiable, {
      L"ANDROID"});

  Add(kElementEpisodePrefix, options_default, {
      L"EP", L"EP.", L"EPS", L"EPS.", L"EPISODE", L"EPISODE.", L"EPISODES",
      L"CAPITULO", L"EPISODIO", L"FOLGE"});
  Add(kElementEpisodePrefix, options_invalid, {
      L"E", L"\x7B2C"});  // single-letter episode keywords are not valid tokens

  Add(kElementFileExtension, options_default, {
      L"3GP", L"AVI", L"DIVX", L"FLV", L"M2TS", L"MKV", L"MOV", L"MP4", L"MPG",
      L"OGM", L"RM", L"RMVB", L"WEBM", L"WMV"});
  Add(kElementFileExtension, options_invalid, {
      L"AAC", L"AIFF", L"FLAC", L"M4A", L"MP3", L"MKA", L"OGG", L"WAV", L"WMA",
      L"7Z", L"RAR", L"ZIP",
      L"ASS", L"SRT"});

  Add(kElementLanguage, options_default, {
      L"ENG", L"ENGLISH", L"ESPANOL", L"JAP", L"PT-BR", L"SPANISH", L"VOSTFR"});
  Add(kElementLanguage, options_unidentifiable, {
      L"ESP", L"ITA"});  // e.g. "Tokyo ESP", "Bokura ga Ita"

  Add(kElementOther, options_default, {
      L"REMASTER", L"REMASTERED", L"UNCENSORED", L"UNCUT",
      L"TS", L"VFR", L"WIDESCREEN", L"WS"});

  Add(kElementReleaseGroup, options_default, {
      L"THORA"});

  Add(kElementReleaseInformation, options_default, {
      L"BATCH", L"COMPLETE", L"PATCH", L"REMUX"});
  Add(kElementReleaseInformation, options_unidentifiable, {
      L"END", L"FINAL"});  // e.g. "The End of Evangelion", "Final Approach"

  Add(kElementReleaseVersion, options_default, {
      L"V0", L"V1", L"V2", L"V3", L"V4"});

  Add(kElementSource, options_default, {
      L"BD", L"BDRIP", L"BLURAY", L"BLU-RAY",
      L"DVD", L"DVD5", L"DVD9", L"DVD-R2J", L"DVDRIP", L"DVD-RIP",
      L"R2DVD", L"R2J", L"R2JDVD", L"R2JDVDRIP",
      L"HDTV", L"HDTVRIP", L"TVRIP", L"TV-RIP",
      L"WEBCAST", L"WEBRIP"});

  Add(kElementSubtitles, options_default, {
      L"ASS", L"BIG5", L"DUB", L"DUBBED", L"HARDSUB", L"RAW", L"SOFTSUB",
      L"SOFTSUBS", L"SUB", L"SUBBED", L"SUBTITLED"});

  Add(kElementVideoTerm, options_default, {
      // Frame rate
      L"23.976FPS", L"24FPS", L"29.97FPS", L"30FPS", L"60FPS", L"120FPS",
      // Video codec
      L"8BIT", L"8-BIT", L"10BIT", L"10BITS", L"10-BIT", L"10-BITS", L"HI10", L"HI10P",
      L"H264", L"H265", L"H.264", L"H.265", L"X264", L"X265", L"X.264",
      L"AVC", L"HEVC", L"DIVX", L"DIVX5", L"DIVX6", L"XVID",
      // Video format
      L"AVI", L"RMVB", L"WMV", L"WMV3", L"WMV9",
      // Video quality
      L"HQ", L"LQ",
      // Video resolution
      L"HD", L"SD"});

  Add(kElementVolumePrefix, options_default, {
      L"VOL", L"VOL.", L"VOLUME"});
}

void KeywordManager::Add(ElementCategory category,
                         const KeywordOptions& options,
                         const std::initializer_list<string_t>& keywords) {
  auto& keys = GetKeywordContainer(category);
  for (const auto& keyword : keywords) {
    if (keyword.empty())
      continue;
    if (keys.find(keyword) != keys.end())
      continue;
    keys.insert(std::make_pair(keyword, Keyword(category, options)));
  }
}

bool KeywordManager::Find(ElementCategory category, const string_t& str) const {
  const auto& keys = GetKeywordContainer(category);
  auto it = keys.find(str);
  if (it != keys.end() && it->second.category == category)
    return true;

  return false;
}

bool KeywordManager::Find(const string_t& str, ElementCategory& category,
                          KeywordOptions& options) const {
  const auto& keys = GetKeywordContainer(category);
  auto it = keys.find(str);
  if (it != keys.end()) {
    if (category == kElementUnknown) {
      category = it->second.category;
    } else if (it->second.category != category) {
      return false;
    }
    options = it->second.options;
    return true;
  }

  return false;
}

string_t KeywordManager::Normalize(const string_t& str) const {
  return StringToUpperCopy(str);
}

KeywordManager::keyword_container_t& KeywordManager::GetKeywordContainer(
    ElementCategory category) const {
  return category == kElementFileExtension ?
      const_cast<keyword_container_t&>(file_extensions_) :
      const_cast<keyword_container_t&>(keys_);
}

////////////////////////////////////////////////////////////////////////////////

void KeywordManager::Peek(const string_t& filename,
                          const TokenRange& range,
                          Elements& elements,
                          std::vector<TokenRange>& preidentified_tokens) const {
  typedef std::pair<ElementCategory, std::vector<string_t>> entry_t;
  static const std::vector<entry_t> entries{
    {kElementAudioTerm, {L"Dual Audio"}},
    {kElementVideoTerm, {L"H264", L"H.264", L"h264", L"h.264"}},
    {kElementVideoResolution, {L"480p", L"720p", L"1080p"}},
    {kElementSource, {L"Blu-Ray"}}
  };

  auto it_begin = filename.begin() + range.offset;
  auto it_end = it_begin + range.size;

  for (const auto& entry : entries) {
    for (const auto& keyword : entry.second) {
      auto it = std::search(it_begin, it_end, keyword.begin(), keyword.end());
      if (it != it_end) {
        auto offset = it - filename.begin();
        elements.insert(entry.first, keyword);
        preidentified_tokens.push_back(TokenRange(offset, keyword.size()));
      }
    }
  }
}

}  // namespace anitomy<|endoftext|>