<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <sal/config.h>

#include <com/sun/star/ucb/UniversalContentBroker.hpp>
#include <comphelper/processfactory.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <ucbhelper/fileidentifierconverter.hxx>
#include <rtl/ustring.hxx>
#include <rtl/instance.hxx>
#include <osl/file.hxx>
#include <tools/time.hxx>
#include <tools/debug.hxx>
#include <stdio.h>

#ifdef UNX
#include <sys/stat.h>
#endif

using namespace osl;

namespace
{
    struct TempNameBase_Impl
        : public rtl::Static< OUString, TempNameBase_Impl > {};
}

namespace utl
{

struct TempFile_Impl
{
    OUString    aName;
    OUString    aURL;
    SvStream*   pStream;
    bool        bIsDirectory;

    TempFile_Impl()
        : pStream(0)
        , bIsDirectory(false)
    {
    }
};

OUString getParentName( const OUString& aFileName )
{
    sal_Int32 lastIndex = aFileName.lastIndexOf( '/' );
    OUString aParent = aFileName.copy( 0, lastIndex );

    if( aParent.endsWith(":") && aParent.getLength() == 6 )
        aParent += "/";

    if( aParent.equalsAscii( "file://" ) )
        aParent = "file:///";

    return aParent;
}

bool ensuredir( const OUString& rUnqPath )
{
    OUString aPath;
    if ( rUnqPath.isEmpty() )
        return false;

    // remove trailing slash
    if ( rUnqPath.endsWith("/") )
        aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aPath = rUnqPath;

    // HACK: create directory on a mount point with nobrowse option
    // returns ENOSYS in any case !!
    osl::Directory aDirectory( aPath );
    osl::FileBase::RC nError = aDirectory.open();
    aDirectory.close();
    if( nError == osl::File::E_None )
        return true;

    // try to create the directory
    nError = osl::Directory::create( aPath );
    bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
    if( !bSuccess )
    {
        // perhaps parent(s) don't exist
        OUString aParentDir = getParentName( aPath );
        if ( aParentDir != aPath )
        {
            bSuccess = ensuredir( getParentName( aPath ) );

            // After parent directory structure exists try it one's more
            if ( bSuccess )
            {
                // Parent directory exists, retry creation of directory
                nError = osl::Directory::create( aPath );
                bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
            }
        }
    }

    return bSuccess;
}

OUString ConstructTempDir_Impl( const OUString* pParent )
{
    OUString aName;
    if ( pParent && !pParent->isEmpty() )
    {
        com::sun::star::uno::Reference<
            com::sun::star::ucb::XUniversalContentBroker > pBroker(
                com::sun::star::ucb::UniversalContentBroker::create(
                    comphelper::getProcessComponentContext() ) );

        // if parent given try to use it
        OUString aTmp( *pParent );

        // test for valid filename
        OUString aRet;
        ::osl::FileBase::getFileURLFromSystemPath(
            ::ucbhelper::getSystemPathFromFileURL( pBroker, aTmp ),
            aRet );
        if ( !aRet.isEmpty() )
        {
            ::osl::DirectoryItem aItem;
            sal_Int32 i = aRet.getLength();
            if ( aRet[i-1] == '/' )
                i--;

            if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
                aName = aRet;
        }
    }

    if ( aName.isEmpty() )
    {
        OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        if (rTempNameBase_Impl.isEmpty())
        {
            OUString ustrTempDirURL;
            ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
                ustrTempDirURL );
            if (rc == ::osl::FileBase::E_None)
                rTempNameBase_Impl = ustrTempDirURL;
        }
        // if no parent or invalid parent : use default directory
        DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
        aName = rTempNameBase_Impl;
        ensuredir( aName );
    }

    // Make sure that directory ends with a separator
    if( !aName.isEmpty() && !aName.endsWith("/") )
        aName += "/";

    return aName;
}

void CreateTempName_Impl( OUString& rName, bool bKeep, bool bDir = true )
{
    // add a suitable tempname
    // 36 ** 6 == 2176782336
    unsigned const nRadix = 36;
    unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
    OUString aName;
    OUString aEyeCatcher = "lu";
#ifdef DBG_UTIL
#ifdef UNX
    const char* eye = getenv("LO_TESTNAME");
    if(eye)
    {
        aEyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US);
    }
#endif
#endif
    aName = rName + aEyeCatcher;
    rName = "";
    static unsigned long u = Time::GetSystemTicks() % nMax;
    for ( unsigned long nSeed = u; ++u != nSeed; )
    {
        u %= nMax;
        OUString aTmp( aName );
        aTmp += OUString::number(u, nRadix);
        aTmp += ".tmp";

        if ( bDir )
        {
#ifdef UNX /* RW permission for the user only! */
            mode_t old_mode = umask(077);
#endif
            FileBase::RC err = Directory::create( aTmp );
#ifdef UNX
            umask(old_mode);
#endif
            if ( err == FileBase::E_None )
            {
                // !bKeep: only for creating a name, not a file or directory
                if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
                    rName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
            }
        }
        else
        {
            DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
            File aFile( aTmp );
#ifdef UNX /* RW permission for the user only! */
            mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
#ifdef UNX
            umask(old_mode);
#endif
            if (  err == FileBase::E_None )
            {
                rName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                 // if f.e. name contains invalid chars stop trying to create files
                 // but if there is a folder with such name proceed further

                 DirectoryItem aTmpItem;
                 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
                 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                   || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                   || aTmpStatus.getFileType() != FileStatus::Directory )
                     break;
            }
        }
    }
}

void lcl_createName(TempFile_Impl& _rImpl,const OUString& rLeadingChars, bool _bStartWithZero,
                    const OUString* pExtension, const OUString* pParent, bool bDirectory)
{
    _rImpl.bIsDirectory = bDirectory;

    // get correct directory
    OUString aName = ConstructTempDir_Impl( pParent );

    bool bUseNumber = _bStartWithZero;
    // now use special naming scheme ( name takes leading chars and an index counting up from zero
    aName += rLeadingChars;
    for ( sal_Int32 i=0;; i++ )
    {
        OUString aTmp( aName );
        if ( bUseNumber )
            aTmp += OUString::number( i );
        bUseNumber = true;
        if ( pExtension )
            aTmp += *pExtension;
        else
            aTmp += ".tmp";
        if ( bDirectory )
        {
            FileBase::RC err = Directory::create( aTmp );
            if ( err == FileBase::E_None )
            {
                _rImpl.aName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
        }
        else
        {
            File aFile( aTmp );
#ifdef UNX
            /* RW permission for the user only! */
            mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
            umask(old_mode);
#endif
            if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
            {
                _rImpl.aName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                // but if there is a folder with such name proceed further

                DirectoryItem aTmpItem;
                FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
                if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                  || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                  || aTmpStatus.getFileType() != FileStatus::Directory )
                    break;
            }
        }
        if ( !_bStartWithZero )
            aTmp += OUString::number( i );
    }
}

OUString TempFile::CreateTempName( const OUString* pParent )
{
    // get correct directory
    OUString aName = ConstructTempDir_Impl( pParent );

    // get TempFile name with default naming scheme
    CreateTempName_Impl( aName, false );

    // convert to file URL
    OUString aTmp;
    if ( !aName.isEmpty() )
        FileBase::getSystemPathFromFileURL( aName, aTmp );
    return aTmp;
}

TempFile::TempFile( const OUString* pParent, bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    pImp->aName = ConstructTempDir_Impl( pParent );

    // get TempFile with default naming scheme
    CreateTempName_Impl( pImp->aName, true, bDirectory );
}

TempFile::TempFile( const OUString& rLeadingChars, const OUString* pExtension, const OUString* pParent, bool bDirectory)
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    lcl_createName(*pImp, rLeadingChars, true, pExtension, pParent, bDirectory);
}
TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero, const OUString* pExtension, const OUString* pParent, bool bDirectory)
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    lcl_createName(*pImp, rLeadingChars, _bStartWithZero, pExtension, pParent, bDirectory);
}

TempFile::~TempFile()
{
    delete pImp->pStream;
    if ( bKillingFileEnabled )
    {
        if ( pImp->bIsDirectory )
        {
            // at the moment no recursiv algorithm present
            Directory::remove( pImp->aName );
        }
        else
        {
            File::remove( pImp->aName );
        }
    }

    delete pImp;
}

bool TempFile::IsValid() const
{
    return !(pImp->aName.isEmpty());
}

OUString TempFile::GetFileName() const
{
    OUString aTmp;
    FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
    return aTmp;
}

OUString TempFile::GetURL() const
{
    if ( pImp->aURL.isEmpty() )
    {
        OUString aTmp;
        LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
        pImp->aURL = aTmp;
    }

    return pImp->aURL;
}

SvStream* TempFile::GetStream( StreamMode eMode )
{
    if ( !pImp->pStream )
    {
        if ( !GetURL().isEmpty() )
            pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, true /* bFileExists */ );
        else
            pImp->pStream = new SvMemoryStream( eMode );
    }

    return pImp->pStream;
}

void TempFile::CloseStream()
{
    if ( pImp->pStream )
    {
        delete pImp->pStream;
        pImp->pStream = NULL;
    }
}

OUString TempFile::SetTempNameBaseDirectory( const OUString &rBaseName )
{
    if( rBaseName.isEmpty() )
        return OUString();

    OUString aUnqPath( rBaseName );

    // remove trailing slash
    if ( rBaseName.endsWith("/") )
        aUnqPath = rBaseName.copy( 0, rBaseName.getLength() - 1 );

    // try to create the directory
    bool bRet = false;
    osl::FileBase::RC err = osl::Directory::create( aUnqPath );
    if ( err != FileBase::E_None && err != FileBase::E_EXIST )
        // perhaps parent(s) don't exist
        bRet = ensuredir( aUnqPath );
    else
        bRet = true;

    // failure to create base directory means returning an empty string
    OUString aTmp;
    if ( bRet )
    {
        // append own internal directory
        bRet = true;
        OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        rTempNameBase_Impl = rBaseName;
        rTempNameBase_Impl += OUString('/');

        TempFile aBase( NULL, true );
        if ( aBase.IsValid() )
            // use it in case of success
            rTempNameBase_Impl = aBase.pImp->aName;

        // return system path of used directory
        FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    }

    return aTmp;
}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Related fdo#60338: Create missing temp file dir with user's original umask<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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 http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <sal/config.h>

#include <com/sun/star/ucb/UniversalContentBroker.hpp>
#include <comphelper/processfactory.hxx>
#include <unotools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <ucbhelper/fileidentifierconverter.hxx>
#include <rtl/ustring.hxx>
#include <rtl/instance.hxx>
#include <osl/file.hxx>
#include <tools/time.hxx>
#include <tools/debug.hxx>
#include <stdio.h>

#ifdef UNX
#include <sys/stat.h>
#endif

using namespace osl;

namespace
{
    struct TempNameBase_Impl
        : public rtl::Static< OUString, TempNameBase_Impl > {};
}

namespace utl
{

struct TempFile_Impl
{
    OUString    aName;
    OUString    aURL;
    SvStream*   pStream;
    bool        bIsDirectory;

    TempFile_Impl()
        : pStream(0)
        , bIsDirectory(false)
    {
    }
};

OUString getParentName( const OUString& aFileName )
{
    sal_Int32 lastIndex = aFileName.lastIndexOf( '/' );
    OUString aParent = aFileName.copy( 0, lastIndex );

    if( aParent.endsWith(":") && aParent.getLength() == 6 )
        aParent += "/";

    if( aParent.equalsAscii( "file://" ) )
        aParent = "file:///";

    return aParent;
}

bool ensuredir( const OUString& rUnqPath )
{
    OUString aPath;
    if ( rUnqPath.isEmpty() )
        return false;

    // remove trailing slash
    if ( rUnqPath.endsWith("/") )
        aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aPath = rUnqPath;

    // HACK: create directory on a mount point with nobrowse option
    // returns ENOSYS in any case !!
    osl::Directory aDirectory( aPath );
    osl::FileBase::RC nError = aDirectory.open();
    aDirectory.close();
    if( nError == osl::File::E_None )
        return true;

    // try to create the directory
    nError = osl::Directory::create( aPath );
    bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
    if( !bSuccess )
    {
        // perhaps parent(s) don't exist
        OUString aParentDir = getParentName( aPath );
        if ( aParentDir != aPath )
        {
            bSuccess = ensuredir( getParentName( aPath ) );

            // After parent directory structure exists try it one's more
            if ( bSuccess )
            {
                // Parent directory exists, retry creation of directory
                nError = osl::Directory::create( aPath );
                bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
            }
        }
    }

    return bSuccess;
}

OUString ConstructTempDir_Impl( const OUString* pParent )
{
    OUString aName;
    if ( pParent && !pParent->isEmpty() )
    {
        com::sun::star::uno::Reference<
            com::sun::star::ucb::XUniversalContentBroker > pBroker(
                com::sun::star::ucb::UniversalContentBroker::create(
                    comphelper::getProcessComponentContext() ) );

        // if parent given try to use it
        OUString aTmp( *pParent );

        // test for valid filename
        OUString aRet;
        ::osl::FileBase::getFileURLFromSystemPath(
            ::ucbhelper::getSystemPathFromFileURL( pBroker, aTmp ),
            aRet );
        if ( !aRet.isEmpty() )
        {
            ::osl::DirectoryItem aItem;
            sal_Int32 i = aRet.getLength();
            if ( aRet[i-1] == '/' )
                i--;

            if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
                aName = aRet;
        }
    }

    if ( aName.isEmpty() )
    {
        OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        if (rTempNameBase_Impl.isEmpty())
        {
            OUString ustrTempDirURL;
            ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
                ustrTempDirURL );
            if (rc == ::osl::FileBase::E_None)
                rTempNameBase_Impl = ustrTempDirURL;
        }
        // if no parent or invalid parent : use default directory
        DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
        aName = rTempNameBase_Impl;
        ensuredir( aName );
    }

    // Make sure that directory ends with a separator
    if( !aName.isEmpty() && !aName.endsWith("/") )
        aName += "/";

    return aName;
}

void CreateTempName_Impl( OUString& rName, bool bKeep, bool bDir = true )
{
    // add a suitable tempname
    // 36 ** 6 == 2176782336
    unsigned const nRadix = 36;
    unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
    OUString aName;
    OUString aEyeCatcher = "lu";
#ifdef DBG_UTIL
#ifdef UNX
    const char* eye = getenv("LO_TESTNAME");
    if(eye)
    {
        aEyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US);
    }
#endif
#endif
    aName = rName + aEyeCatcher;
    rName = "";
    static unsigned long u = Time::GetSystemTicks() % nMax;
    for ( unsigned long nSeed = u; ++u != nSeed; )
    {
        u %= nMax;
        OUString aTmp( aName );
        aTmp += OUString::number(u, nRadix);
        aTmp += ".tmp";

        if ( bDir )
        {
            FileBase::RC err = Directory::create( aTmp );
            if ( err == FileBase::E_None )
            {
                // !bKeep: only for creating a name, not a file or directory
                if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
                    rName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
            }
        }
        else
        {
            DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
            File aFile( aTmp );
#ifdef UNX /* RW permission for the user only! */
            mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
#ifdef UNX
            umask(old_mode);
#endif
            if (  err == FileBase::E_None )
            {
                rName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                 // if f.e. name contains invalid chars stop trying to create files
                 // but if there is a folder with such name proceed further

                 DirectoryItem aTmpItem;
                 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
                 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                   || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                   || aTmpStatus.getFileType() != FileStatus::Directory )
                     break;
            }
        }
    }
}

void lcl_createName(TempFile_Impl& _rImpl,const OUString& rLeadingChars, bool _bStartWithZero,
                    const OUString* pExtension, const OUString* pParent, bool bDirectory)
{
    _rImpl.bIsDirectory = bDirectory;

    // get correct directory
    OUString aName = ConstructTempDir_Impl( pParent );

    bool bUseNumber = _bStartWithZero;
    // now use special naming scheme ( name takes leading chars and an index counting up from zero
    aName += rLeadingChars;
    for ( sal_Int32 i=0;; i++ )
    {
        OUString aTmp( aName );
        if ( bUseNumber )
            aTmp += OUString::number( i );
        bUseNumber = true;
        if ( pExtension )
            aTmp += *pExtension;
        else
            aTmp += ".tmp";
        if ( bDirectory )
        {
            FileBase::RC err = Directory::create( aTmp );
            if ( err == FileBase::E_None )
            {
                _rImpl.aName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
        }
        else
        {
            File aFile( aTmp );
#ifdef UNX
            /* RW permission for the user only! */
            mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
            umask(old_mode);
#endif
            if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
            {
                _rImpl.aName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                // but if there is a folder with such name proceed further

                DirectoryItem aTmpItem;
                FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
                if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                  || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                  || aTmpStatus.getFileType() != FileStatus::Directory )
                    break;
            }
        }
        if ( !_bStartWithZero )
            aTmp += OUString::number( i );
    }
}

OUString TempFile::CreateTempName( const OUString* pParent )
{
    // get correct directory
    OUString aName = ConstructTempDir_Impl( pParent );

    // get TempFile name with default naming scheme
    CreateTempName_Impl( aName, false );

    // convert to file URL
    OUString aTmp;
    if ( !aName.isEmpty() )
        FileBase::getSystemPathFromFileURL( aName, aTmp );
    return aTmp;
}

TempFile::TempFile( const OUString* pParent, bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    pImp->aName = ConstructTempDir_Impl( pParent );

    // get TempFile with default naming scheme
    CreateTempName_Impl( pImp->aName, true, bDirectory );
}

TempFile::TempFile( const OUString& rLeadingChars, const OUString* pExtension, const OUString* pParent, bool bDirectory)
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    lcl_createName(*pImp, rLeadingChars, true, pExtension, pParent, bDirectory);
}
TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero, const OUString* pExtension, const OUString* pParent, bool bDirectory)
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( false )
{
    lcl_createName(*pImp, rLeadingChars, _bStartWithZero, pExtension, pParent, bDirectory);
}

TempFile::~TempFile()
{
    delete pImp->pStream;
    if ( bKillingFileEnabled )
    {
        if ( pImp->bIsDirectory )
        {
            // at the moment no recursiv algorithm present
            Directory::remove( pImp->aName );
        }
        else
        {
            File::remove( pImp->aName );
        }
    }

    delete pImp;
}

bool TempFile::IsValid() const
{
    return !(pImp->aName.isEmpty());
}

OUString TempFile::GetFileName() const
{
    OUString aTmp;
    FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
    return aTmp;
}

OUString TempFile::GetURL() const
{
    if ( pImp->aURL.isEmpty() )
    {
        OUString aTmp;
        LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
        pImp->aURL = aTmp;
    }

    return pImp->aURL;
}

SvStream* TempFile::GetStream( StreamMode eMode )
{
    if ( !pImp->pStream )
    {
        if ( !GetURL().isEmpty() )
            pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, true /* bFileExists */ );
        else
            pImp->pStream = new SvMemoryStream( eMode );
    }

    return pImp->pStream;
}

void TempFile::CloseStream()
{
    if ( pImp->pStream )
    {
        delete pImp->pStream;
        pImp->pStream = NULL;
    }
}

OUString TempFile::SetTempNameBaseDirectory( const OUString &rBaseName )
{
    if( rBaseName.isEmpty() )
        return OUString();

    OUString aUnqPath( rBaseName );

    // remove trailing slash
    if ( rBaseName.endsWith("/") )
        aUnqPath = rBaseName.copy( 0, rBaseName.getLength() - 1 );

    // try to create the directory
    bool bRet = false;
    osl::FileBase::RC err = osl::Directory::create( aUnqPath );
    if ( err != FileBase::E_None && err != FileBase::E_EXIST )
        // perhaps parent(s) don't exist
        bRet = ensuredir( aUnqPath );
    else
        bRet = true;

    // failure to create base directory means returning an empty string
    OUString aTmp;
    if ( bRet )
    {
        // append own internal directory
        bRet = true;
        OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        rTempNameBase_Impl = rBaseName;
        rTempNameBase_Impl += OUString('/');

        TempFile aBase( NULL, true );
        if ( aBase.IsValid() )
            // use it in case of success
            rTempNameBase_Impl = aBase.pImp->aName;

        // return system path of used directory
        FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    }

    return aTmp;
}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/***************************************************************************
 *  algo/test_random_shuffle.cpp
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2007 Manuel Krings
 *  Copyright (C) 2007 Markus Westphal
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

//! \example algo/test_random_shuffle.cpp
//! Test \c stxxl::random_shuffle()

#include <stxxl/bits/algo/random_shuffle.h>

template <typename type>
struct counter
{
    type value;
    counter(type v = type(0)) : value(v) { }
    type operator () ()
    {
        type old_val = value;
        value++;
        return old_val;
    }
};

int main()
{
    typedef stxxl::vector<int> ext_vec_type;
    ext_vec_type STXXLVector(1024 * 1024 * 256 / sizeof(int));

    STXXL_MSG("Filling vector with increasing values...");
    stxxl::generate(STXXLVector.begin(), STXXLVector.end(),
                    counter<stxxl::uint64>(), 4);

    stxxl::uint64 i;

    STXXL_MSG("Begin: ");
    for (i = 0; i < 10; i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("End: ");
    for (i = STXXLVector.size() - 10; i < STXXLVector.size(); i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("Permute randomly...");
    stxxl::random_shuffle(STXXLVector.begin(), STXXLVector.end(), 1024 * 1024 * 128);

    STXXL_MSG("Begin: ");
    for (i = 0; i < 10; i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("End: ");
    for (i = STXXLVector.size() - 10; i < STXXLVector.size(); i++)
        STXXL_MSG(STXXLVector[i]);
}
<commit_msg>use stxxl/random_shuffle instead of .../bits/...<commit_after>/***************************************************************************
 *  algo/test_random_shuffle.cpp
 *
 *  Part of the STXXL. See http://stxxl.sourceforge.net
 *
 *  Copyright (C) 2007 Manuel Krings
 *  Copyright (C) 2007 Markus Westphal
 *
 *  Distributed under the Boost Software License, Version 1.0.
 *  (See accompanying file LICENSE_1_0.txt or copy at
 *  http://www.boost.org/LICENSE_1_0.txt)
 **************************************************************************/

//! \example algo/test_random_shuffle.cpp
//! Test \c stxxl::random_shuffle()

#include <stxxl/random_shuffle>

template <typename type>
struct counter
{
    type value;
    counter(type v = type(0)) : value(v) { }
    type operator () ()
    {
        type old_val = value;
        value++;
        return old_val;
    }
};

int main()
{
    typedef stxxl::vector<int> ext_vec_type;
    ext_vec_type STXXLVector(1024 * 1024 * 256 / sizeof(int));

    STXXL_MSG("Filling vector with increasing values...");
    stxxl::generate(STXXLVector.begin(), STXXLVector.end(),
                    counter<stxxl::uint64>(), 4);

    stxxl::uint64 i;

    STXXL_MSG("Begin: ");
    for (i = 0; i < 10; i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("End: ");
    for (i = STXXLVector.size() - 10; i < STXXLVector.size(); i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("Permute randomly...");
    stxxl::random_shuffle(STXXLVector.begin(), STXXLVector.end(), 1024 * 1024 * 128);

    STXXL_MSG("Begin: ");
    for (i = 0; i < 10; i++)
        STXXL_MSG(STXXLVector[i]);

    STXXL_MSG("End: ");
    for (i = STXXLVector.size() - 10; i < STXXLVector.size(); i++)
        STXXL_MSG(STXXLVector[i]);
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include <vespa/searchlib/attribute/multienumattribute.h>
#include <vespa/searchlib/attribute/multivalueattribute.hpp>
#include "multienumattributesaver.h"
#include "load_utils.h"

#include <stdexcept>

namespace search {

template <typename B, typename M>
bool
MultiValueEnumAttribute<B, M>::extractChangeData(const Change & c, EnumIndex & idx)
{
    if (c._enumScratchPad == Change::UNSET_ENUM) {
        return this->_enumStore.findIndex(c._data.raw(), idx);
    }
    idx = EnumIndex(c._enumScratchPad);
    return true;
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::considerAttributeChange(const Change & c, UniqueSet & newUniques)
{
    if (c._type == ChangeBase::APPEND ||
        (this->getInternalCollectionType().createIfNonExistant() &&
         (c._type >= ChangeBase::INCREASEWEIGHT && c._type <= ChangeBase::DIVWEIGHT)))
    {
        EnumIndex idx;
        if (!this->_enumStore.findIndex(c._data.raw(), idx)) {
            newUniques.insert(c._data);
        } else {
            c._enumScratchPad = idx.ref();
        }
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::reEnumerate()
{
    // update MultiValueMapping with new EnumIndex values.
    EnumModifier enumGuard(this->getEnumModifier());
    for (DocId doc = 0; doc < this->getNumDocs(); ++doc) {
        uint32_t valueCount = this->_mvMapping.getValueCount(doc);
        WeightedIndexVector indices(valueCount);
        this->_mvMapping.get(doc, &indices[0], valueCount);

        for (uint32_t i = 0; i < indices.size(); ++i) {
            EnumIndex oldIndex = indices[i].value();
            EnumIndex newIndex;
            this->_enumStore.getCurrentIndex(oldIndex, newIndex);
            std::atomic_thread_fence(std::memory_order_release);
            indices[i] = WeightedIndex(newIndex, indices[i].weight());
        }

        std::atomic_thread_fence(std::memory_order_release);
        this->_mvMapping.replace(doc, indices);
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::applyValueChanges(const DocIndices & docIndices, EnumStoreBase::IndexVector & unused)
{
    // set new set of indices for documents with changes
    ValueModifier valueGuard(this->getValueModifier());
    for (typename DocIndices::const_iterator iter = docIndices.begin(); iter != docIndices.end(); ++iter) {
        const WeightedIndex * oldIndices = NULL;
        uint32_t valueCount(this->_mvMapping.get(iter->first, oldIndices));
        this->_mvMapping.set(iter->first, iter->second);
        for (uint32_t i = 0; i < iter->second.size(); ++i) {
            incRefCount(iter->second[i]);
        }
        for (uint32_t i = 0; i < valueCount; ++i) {
            decRefCount(oldIndices[i]);
            if (this->_enumStore.getRefCount(oldIndices[i]) == 0) {
                unused.push_back(oldIndices[i].value());
            }
        }
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillValues(LoadedVector & loaded)
{
    Histogram capacityNeeded = this->_mvMapping.getEmptyHistogram();
    uint32_t numDocs(this->getNumDocs());
    size_t numValues = loaded.size();
    size_t count = 0;
    for (DocId doc = 0; doc < numDocs; ++doc) {
        uint32_t valueCount(0);
        for(;(count < numValues) && (loaded.read()._docId == doc); count++, loaded.next()) {
            valueCount++;
        }
        if (valueCount < this->_mvMapping.maxValues()) {
            capacityNeeded[valueCount] += 1;
        } else {
            capacityNeeded[this->_mvMapping.maxValues()] += 1;
        }
    }

    this->_mvMapping.reset(numDocs, capacityNeeded);

    loaded.rewind();
    count = 0;
    WeightedIndexVector indices;
    for (DocId doc = 0; doc < numDocs; ++doc) {
        for(const typename LoadedVector::Type * v = & loaded.read();(count < numValues) && (v->_docId == doc); count++, loaded.next(), v = & loaded.read()) {
            indices.push_back(WeightedIndex(v->getEidx(), v->getWeight()));
        }
        this->checkSetMaxValueCount(indices.size());
        this->_mvMapping.set(doc, indices);
        indices.clear();
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillEnumIdx(ReaderBase &attrReader,
                                           const EnumIndexVector &eidxs,
                                           LoadedEnumAttributeVector &loaded)
{
    uint32_t maxvc = attribute::loadFromEnumeratedMultiValue(this->_mvMapping, attrReader, vespalib::ConstArrayRef<EnumIndex>(eidxs), attribute::SaveLoadedEnum(loaded));
    this->checkSetMaxValueCount(maxvc);
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillEnumIdx(ReaderBase &attrReader,
                                           const EnumIndexVector &eidxs,
                                           EnumVector &enumHist)
{
    uint32_t maxvc = attribute::loadFromEnumeratedMultiValue(this->_mvMapping, attrReader, vespalib::ConstArrayRef<EnumIndex>(eidxs), attribute::SaveEnumHist(enumHist));
    this->checkSetMaxValueCount(maxvc);
}

template <typename B, typename M>
MultiValueEnumAttribute<B, M>::
MultiValueEnumAttribute(const vespalib::string &baseFileName,
                        const AttributeVector::Config & cfg)
    : MultiValueAttribute<B, M>(baseFileName, cfg)
{
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onCommit()
{
    // update enum store
    EnumStoreBase::IndexVector possiblyUnused;
    this->insertNewUniqueValues(possiblyUnused);
    DocIndices docIndices;
    this->applyAttributeChanges(docIndices);
    applyValueChanges(docIndices, possiblyUnused);
    this->_changes.clear();
    this->_enumStore.freeUnusedEnums(possiblyUnused);
    this->freezeEnumDictionary();
    this->setEnumMax(this->_enumStore.getLastEnum());
    std::atomic_thread_fence(std::memory_order_release);
    this->removeAllOldGenerations();
}
template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onUpdateStat()
{
    // update statistics
    MemoryUsage total;
    total.merge(this->_enumStore.getMemoryUsage());
    total.merge(this->_enumStore.getTreeMemoryUsage());
    total.merge(this->_mvMapping.getMemoryUsage());
    mergeMemoryStats(total);
    this->updateStatistics(this->_mvMapping.getTotalValueCnt(), this->_enumStore.getNumUniques(), total.allocatedBytes(),
                     total.usedBytes(), total.deadBytes(), total.allocatedBytesOnHold());
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::removeOldGenerations(generation_t firstUsed)
{
    this->_enumStore.trimHoldLists(firstUsed);
    this->_mvMapping.trimHoldLists(firstUsed);
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onGenerationChange(generation_t generation)
{
    /*
     * Freeze tree before generation is increased in attribute vector
     * but after generation is increased in tree. This ensures that
     * unlocked readers accessing a frozen tree will access a
     * sufficiently new frozen tree.
     */
    freezeEnumDictionary();
    this->_mvMapping.transferHoldLists(generation - 1);
    this->_enumStore.transferHoldLists(generation - 1);
}

template <typename B, typename M>
std::unique_ptr<AttributeSaver>
MultiValueEnumAttribute<B, M>::onInitSave()
{
    {
        EnumModifier enumGuard(this->getEnumModifier());
        this->_enumStore.reEnumerate();
    }
    vespalib::GenerationHandler::Guard guard(this->getGenerationHandler().
                                             takeGuard());
    return std::make_unique<MultiValueEnumAttributeSaver<WeightedIndex,
        typename M::Index>>
        (std::move(guard), this->createSaveTargetConfig(), this->_mvMapping,
         this->_enumStore);
}

} // namespace search

<commit_msg>Use new API to get values from multivalue mapping. Remove unneeded thread fence (memory barrier).<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include <vespa/searchlib/attribute/multienumattribute.h>
#include <vespa/searchlib/attribute/multivalueattribute.hpp>
#include "multienumattributesaver.h"
#include "load_utils.h"

#include <stdexcept>

namespace search {

template <typename B, typename M>
bool
MultiValueEnumAttribute<B, M>::extractChangeData(const Change & c, EnumIndex & idx)
{
    if (c._enumScratchPad == Change::UNSET_ENUM) {
        return this->_enumStore.findIndex(c._data.raw(), idx);
    }
    idx = EnumIndex(c._enumScratchPad);
    return true;
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::considerAttributeChange(const Change & c, UniqueSet & newUniques)
{
    if (c._type == ChangeBase::APPEND ||
        (this->getInternalCollectionType().createIfNonExistant() &&
         (c._type >= ChangeBase::INCREASEWEIGHT && c._type <= ChangeBase::DIVWEIGHT)))
    {
        EnumIndex idx;
        if (!this->_enumStore.findIndex(c._data.raw(), idx)) {
            newUniques.insert(c._data);
        } else {
            c._enumScratchPad = idx.ref();
        }
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::reEnumerate()
{
    // update MultiValueMapping with new EnumIndex values.
    EnumModifier enumGuard(this->getEnumModifier());
    for (DocId doc = 0; doc < this->getNumDocs(); ++doc) {
        vespalib::ConstArrayRef<WeightedIndex> indicesRef(this->_mvMapping.get(doc));
        WeightedIndexVector indices(indicesRef.cbegin(), indicesRef.cend());

        for (uint32_t i = 0; i < indices.size(); ++i) {
            EnumIndex oldIndex = indices[i].value();
            EnumIndex newIndex;
            this->_enumStore.getCurrentIndex(oldIndex, newIndex);
            indices[i] = WeightedIndex(newIndex, indices[i].weight());
        }

        std::atomic_thread_fence(std::memory_order_release);
        this->_mvMapping.replace(doc, indices);
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::applyValueChanges(const DocIndices & docIndices, EnumStoreBase::IndexVector & unused)
{
    // set new set of indices for documents with changes
    ValueModifier valueGuard(this->getValueModifier());
    for (typename DocIndices::const_iterator iter = docIndices.begin(); iter != docIndices.end(); ++iter) {
        vespalib::ConstArrayRef<WeightedIndex> oldIndices(this->_mvMapping.get(iter->first));
        uint32_t valueCount = oldIndices.size();
        this->_mvMapping.set(iter->first, iter->second);
        for (uint32_t i = 0; i < iter->second.size(); ++i) {
            incRefCount(iter->second[i]);
        }
        for (uint32_t i = 0; i < valueCount; ++i) {
            decRefCount(oldIndices[i]);
            if (this->_enumStore.getRefCount(oldIndices[i]) == 0) {
                unused.push_back(oldIndices[i].value());
            }
        }
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillValues(LoadedVector & loaded)
{
    Histogram capacityNeeded = this->_mvMapping.getEmptyHistogram();
    uint32_t numDocs(this->getNumDocs());
    size_t numValues = loaded.size();
    size_t count = 0;
    for (DocId doc = 0; doc < numDocs; ++doc) {
        uint32_t valueCount(0);
        for(;(count < numValues) && (loaded.read()._docId == doc); count++, loaded.next()) {
            valueCount++;
        }
        if (valueCount < this->_mvMapping.maxValues()) {
            capacityNeeded[valueCount] += 1;
        } else {
            capacityNeeded[this->_mvMapping.maxValues()] += 1;
        }
    }

    this->_mvMapping.reset(numDocs, capacityNeeded);

    loaded.rewind();
    count = 0;
    WeightedIndexVector indices;
    for (DocId doc = 0; doc < numDocs; ++doc) {
        for(const typename LoadedVector::Type * v = & loaded.read();(count < numValues) && (v->_docId == doc); count++, loaded.next(), v = & loaded.read()) {
            indices.push_back(WeightedIndex(v->getEidx(), v->getWeight()));
        }
        this->checkSetMaxValueCount(indices.size());
        this->_mvMapping.set(doc, indices);
        indices.clear();
    }
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillEnumIdx(ReaderBase &attrReader,
                                           const EnumIndexVector &eidxs,
                                           LoadedEnumAttributeVector &loaded)
{
    uint32_t maxvc = attribute::loadFromEnumeratedMultiValue(this->_mvMapping, attrReader, vespalib::ConstArrayRef<EnumIndex>(eidxs), attribute::SaveLoadedEnum(loaded));
    this->checkSetMaxValueCount(maxvc);
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::fillEnumIdx(ReaderBase &attrReader,
                                           const EnumIndexVector &eidxs,
                                           EnumVector &enumHist)
{
    uint32_t maxvc = attribute::loadFromEnumeratedMultiValue(this->_mvMapping, attrReader, vespalib::ConstArrayRef<EnumIndex>(eidxs), attribute::SaveEnumHist(enumHist));
    this->checkSetMaxValueCount(maxvc);
}

template <typename B, typename M>
MultiValueEnumAttribute<B, M>::
MultiValueEnumAttribute(const vespalib::string &baseFileName,
                        const AttributeVector::Config & cfg)
    : MultiValueAttribute<B, M>(baseFileName, cfg)
{
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onCommit()
{
    // update enum store
    EnumStoreBase::IndexVector possiblyUnused;
    this->insertNewUniqueValues(possiblyUnused);
    DocIndices docIndices;
    this->applyAttributeChanges(docIndices);
    applyValueChanges(docIndices, possiblyUnused);
    this->_changes.clear();
    this->_enumStore.freeUnusedEnums(possiblyUnused);
    this->freezeEnumDictionary();
    this->setEnumMax(this->_enumStore.getLastEnum());
    std::atomic_thread_fence(std::memory_order_release);
    this->removeAllOldGenerations();
}
template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onUpdateStat()
{
    // update statistics
    MemoryUsage total;
    total.merge(this->_enumStore.getMemoryUsage());
    total.merge(this->_enumStore.getTreeMemoryUsage());
    total.merge(this->_mvMapping.getMemoryUsage());
    mergeMemoryStats(total);
    this->updateStatistics(this->_mvMapping.getTotalValueCnt(), this->_enumStore.getNumUniques(), total.allocatedBytes(),
                     total.usedBytes(), total.deadBytes(), total.allocatedBytesOnHold());
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::removeOldGenerations(generation_t firstUsed)
{
    this->_enumStore.trimHoldLists(firstUsed);
    this->_mvMapping.trimHoldLists(firstUsed);
}

template <typename B, typename M>
void
MultiValueEnumAttribute<B, M>::onGenerationChange(generation_t generation)
{
    /*
     * Freeze tree before generation is increased in attribute vector
     * but after generation is increased in tree. This ensures that
     * unlocked readers accessing a frozen tree will access a
     * sufficiently new frozen tree.
     */
    freezeEnumDictionary();
    this->_mvMapping.transferHoldLists(generation - 1);
    this->_enumStore.transferHoldLists(generation - 1);
}

template <typename B, typename M>
std::unique_ptr<AttributeSaver>
MultiValueEnumAttribute<B, M>::onInitSave()
{
    {
        EnumModifier enumGuard(this->getEnumModifier());
        this->_enumStore.reEnumerate();
    }
    vespalib::GenerationHandler::Guard guard(this->getGenerationHandler().
                                             takeGuard());
    return std::make_unique<MultiValueEnumAttributeSaver<WeightedIndex,
        typename M::Index>>
        (std::move(guard), this->createSaveTargetConfig(), this->_mvMapping,
         this->_enumStore);
}

} // namespace search

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016
// Mehdi Goli    Codeplay Software Ltd.
// Ralph Potter  Codeplay Software Ltd.
// Luke Iwanski  Codeplay Software Ltd.
// Contact: <eigen@codeplay.com>
// Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// 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 http://mozilla.org/MPL/2.0/.

#define EIGEN_TEST_NO_LONGDOUBLE
#define EIGEN_TEST_NO_COMPLEX
#define EIGEN_TEST_FUNC cxx11_tensor_sycl
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
#define EIGEN_USE_SYCL

#include "main.h"
#include <unsupported/Eigen/CXX11/Tensor>

using Eigen::array;
using Eigen::SyclDevice;
using Eigen::Tensor;
using Eigen::TensorMap;
template <typename DataType, int DataLayout>
void test_sycl_mem_transfers(const Eigen::SyclDevice &sycl_device) {
  int sizeDim1 = 100;
  int sizeDim2 = 10;
  int sizeDim3 = 20;
  array<int, 3> tensorRange = {{sizeDim1, sizeDim2, sizeDim3}};
  Tensor<DataType, 3, DataLayout> in1(tensorRange);
  Tensor<DataType, 3, DataLayout> out1(tensorRange);
  Tensor<DataType, 3, DataLayout> out2(tensorRange);
  Tensor<DataType, 3, DataLayout> out3(tensorRange);

  in1 = in1.random();

  DataType* gpu_data1  = static_cast<DataType*>(sycl_device.allocate(in1.size()*sizeof(DataType)));
  DataType* gpu_data2  = static_cast<DataType*>(sycl_device.allocate(out1.size()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout>> gpu1(gpu_data1, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu2(gpu_data2, tensorRange);

  sycl_device.memcpyHostToDevice(gpu_data1, in1.data(),(in1.size())*sizeof(DataType));
  sycl_device.memcpyHostToDevice(gpu_data2, in1.data(),(in1.size())*sizeof(DataType));
  gpu1.device(sycl_device) = gpu1 * 3.14f;
  gpu2.device(sycl_device) = gpu2 * 2.7f;
  sycl_device.memcpyDeviceToHost(out1.data(), gpu_data1,(out1.size())*sizeof(DataType));
  sycl_device.memcpyDeviceToHost(out2.data(), gpu_data1,(out2.size())*sizeof(DataType));
  sycl_device.memcpyDeviceToHost(out3.data(), gpu_data2,(out3.size())*sizeof(DataType));

  for (int i = 0; i < in1.size(); ++i) {
    VERIFY_IS_APPROX(out1(i), in1(i) * 3.14f);
    VERIFY_IS_APPROX(out2(i), in1(i) * 3.14f);
    VERIFY_IS_APPROX(out3(i), in1(i) * 2.7f);
  }

  sycl_device.deallocate(gpu_data1);
  sycl_device.deallocate(gpu_data2);
}
template <typename DataType, int DataLayout>
void test_sycl_computations(const Eigen::SyclDevice &sycl_device) {

  int sizeDim1 = 100;
  int sizeDim2 = 10;
  int sizeDim3 = 20;
  array<int, 3> tensorRange = {{sizeDim1, sizeDim2, sizeDim3}};
  Tensor<DataType, 3,DataLayout> in1(tensorRange);
  Tensor<DataType, 3,DataLayout> in2(tensorRange);
  Tensor<DataType, 3,DataLayout> in3(tensorRange);
  Tensor<DataType, 3,DataLayout> out(tensorRange);

  in2 = in2.random();
  in3 = in3.random();

  DataType * gpu_in1_data  = static_cast<DataType*>(sycl_device.allocate(in1.size()*sizeof(DataType)));
  DataType * gpu_in2_data  = static_cast<DataType*>(sycl_device.allocate(in2.size()*sizeof(DataType)));
  DataType * gpu_in3_data  = static_cast<DataType*>(sycl_device.allocate(in3.size()*sizeof(DataType)));
  DataType * gpu_out_data =  static_cast<DataType*>(sycl_device.allocate(out.size()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in1(gpu_in1_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in2(gpu_in2_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in3(gpu_in3_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_out(gpu_out_data, tensorRange);

  /// a=1.2f
  gpu_in1.device(sycl_device) = gpu_in1.constant(1.2f);
  sycl_device.memcpyDeviceToHost(in1.data(), gpu_in1_data ,(in1.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(in1(i,j,k), 1.2f);
      }
    }
  }
  printf("a=1.2f Test passed\n");

  /// a=b*1.2f
  gpu_out.device(sycl_device) = gpu_in1 * 1.2f;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data ,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) * 1.2f);
      }
    }
  }
  printf("a=b*1.2f Test Passed\n");

  /// c=a*b
  sycl_device.memcpyHostToDevice(gpu_in2_data, in2.data(),(in2.size())*sizeof(DataType));
  gpu_out.device(sycl_device) = gpu_in1 * gpu_in2;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) *
                             in2(i,j,k));
      }
    }
  }
  printf("c=a*b Test Passed\n");

  /// c=a+b
  gpu_out.device(sycl_device) = gpu_in1 + gpu_in2;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) +
                             in2(i,j,k));
      }
    }
  }
  printf("c=a+b Test Passed\n");

  /// c=a*a
  gpu_out.device(sycl_device) = gpu_in1 * gpu_in1;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) *
                             in1(i,j,k));
      }
    }
  }
  printf("c= a*a Test Passed\n");

  //a*3.14f + b*2.7f
  gpu_out.device(sycl_device) =  gpu_in1 * gpu_in1.constant(3.14f) + gpu_in2 * gpu_in2.constant(2.7f);
  sycl_device.memcpyDeviceToHost(out.data(),gpu_out_data,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) * 3.14f
                       + in2(i,j,k) * 2.7f);
      }
    }
  }
  printf("a*3.14f + b*2.7f Test Passed\n");

  ///d= (a>0.5? b:c)
  sycl_device.memcpyHostToDevice(gpu_in3_data, in3.data(),(in3.size())*sizeof(DataType));
  gpu_out.device(sycl_device) =(gpu_in1 > gpu_in1.constant(0.5f)).select(gpu_in2, gpu_in3);
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i, j, k), (in1(i, j, k) > 0.5f)
                                                ? in2(i, j, k)
                                                : in3(i, j, k));
      }
    }
  }
  printf("d= (a>0.5? b:c) Test Passed\n");
  sycl_device.deallocate(gpu_in1_data);
  sycl_device.deallocate(gpu_in2_data);
  sycl_device.deallocate(gpu_in3_data);
  sycl_device.deallocate(gpu_out_data);
}
template<typename DataType, typename dev_Selector> void sycl_computing_test_per_device(dev_Selector s){
  QueueInterface queueInterface(s);
  auto sycl_device = Eigen::SyclDevice(&queueInterface);
  test_sycl_mem_transfers<DataType, RowMajor>(sycl_device);
  test_sycl_computations<DataType, RowMajor>(sycl_device);
  test_sycl_mem_transfers<DataType, ColMajor>(sycl_device);
  test_sycl_computations<DataType, ColMajor>(sycl_device);
}
void test_cxx11_tensor_sycl() {
  for (const auto& device :Eigen::get_sycl_supported_devices()) {
    CALL_SUBTEST(sycl_computing_test_per_device<float>(device));
  }
}
<commit_msg>Added an OpenCL regression test<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016
// Mehdi Goli    Codeplay Software Ltd.
// Ralph Potter  Codeplay Software Ltd.
// Luke Iwanski  Codeplay Software Ltd.
// Contact: <eigen@codeplay.com>
// Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// 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 http://mozilla.org/MPL/2.0/.

#define EIGEN_TEST_NO_LONGDOUBLE
#define EIGEN_TEST_NO_COMPLEX
#define EIGEN_TEST_FUNC cxx11_tensor_sycl
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
#define EIGEN_USE_SYCL

#include "main.h"
#include <unsupported/Eigen/CXX11/Tensor>

using Eigen::array;
using Eigen::SyclDevice;
using Eigen::Tensor;
using Eigen::TensorMap;

template <typename DataType, int DataLayout>
void test_sycl_mem_transfers(const Eigen::SyclDevice &sycl_device) {
  int sizeDim1 = 100;
  int sizeDim2 = 10;
  int sizeDim3 = 20;
  array<int, 3> tensorRange = {{sizeDim1, sizeDim2, sizeDim3}};
  Tensor<DataType, 3, DataLayout> in1(tensorRange);
  Tensor<DataType, 3, DataLayout> out1(tensorRange);
  Tensor<DataType, 3, DataLayout> out2(tensorRange);
  Tensor<DataType, 3, DataLayout> out3(tensorRange);

  in1 = in1.random();

  DataType* gpu_data1  = static_cast<DataType*>(sycl_device.allocate(in1.size()*sizeof(DataType)));
  DataType* gpu_data2  = static_cast<DataType*>(sycl_device.allocate(out1.size()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout>> gpu1(gpu_data1, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu2(gpu_data2, tensorRange);

  sycl_device.memcpyHostToDevice(gpu_data1, in1.data(),(in1.size())*sizeof(DataType));
  sycl_device.memcpyHostToDevice(gpu_data2, in1.data(),(in1.size())*sizeof(DataType));
  gpu1.device(sycl_device) = gpu1 * 3.14f;
  gpu2.device(sycl_device) = gpu2 * 2.7f;
  sycl_device.memcpyDeviceToHost(out1.data(), gpu_data1,(out1.size())*sizeof(DataType));
  sycl_device.memcpyDeviceToHost(out2.data(), gpu_data1,(out2.size())*sizeof(DataType));
  sycl_device.memcpyDeviceToHost(out3.data(), gpu_data2,(out3.size())*sizeof(DataType));
  sycl_device.synchronize();

  for (int i = 0; i < in1.size(); ++i) {
    VERIFY_IS_APPROX(out1(i), in1(i) * 3.14f);
    VERIFY_IS_APPROX(out2(i), in1(i) * 3.14f);
    VERIFY_IS_APPROX(out3(i), in1(i) * 2.7f);
  }

  sycl_device.deallocate(gpu_data1);
  sycl_device.deallocate(gpu_data2);
}

template <typename DataType, int DataLayout>
void test_sycl_mem_sync(const Eigen::SyclDevice &sycl_device) {
  int size = 20;
  array<int, 1> tensorRange = {{size}};
  Tensor<DataType, 1, DataLayout> in1(tensorRange);
  Tensor<DataType, 1, DataLayout> in2(tensorRange);
  Tensor<DataType, 1, DataLayout> out(tensorRange);

  in1 = in1.random();
  in2 = in1;

  DataType* gpu_data  = static_cast<DataType*>(sycl_device.allocate(in1.size()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 1, DataLayout>> gpu1(gpu_data, tensorRange);
  sycl_device.memcpyHostToDevice(gpu_data, in1.data(),(in1.size())*sizeof(DataType));
  sycl_device.synchronize();
  in1.setZero();

  sycl_device.memcpyDeviceToHost(out.data(), gpu_data, out.size()*sizeof(DataType));
  sycl_device.synchronize();

  for (int i = 0; i < in1.size(); ++i) {
    VERIFY_IS_APPROX(out(i), in2(i));
  }

  sycl_device.deallocate(gpu_data);
}

template <typename DataType, int DataLayout>
void test_sycl_computations(const Eigen::SyclDevice &sycl_device) {

  int sizeDim1 = 100;
  int sizeDim2 = 10;
  int sizeDim3 = 20;
  array<int, 3> tensorRange = {{sizeDim1, sizeDim2, sizeDim3}};
  Tensor<DataType, 3,DataLayout> in1(tensorRange);
  Tensor<DataType, 3,DataLayout> in2(tensorRange);
  Tensor<DataType, 3,DataLayout> in3(tensorRange);
  Tensor<DataType, 3,DataLayout> out(tensorRange);

  in2 = in2.random();
  in3 = in3.random();

  DataType * gpu_in1_data  = static_cast<DataType*>(sycl_device.allocate(in1.size()*sizeof(DataType)));
  DataType * gpu_in2_data  = static_cast<DataType*>(sycl_device.allocate(in2.size()*sizeof(DataType)));
  DataType * gpu_in3_data  = static_cast<DataType*>(sycl_device.allocate(in3.size()*sizeof(DataType)));
  DataType * gpu_out_data =  static_cast<DataType*>(sycl_device.allocate(out.size()*sizeof(DataType)));

  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in1(gpu_in1_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in2(gpu_in2_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_in3(gpu_in3_data, tensorRange);
  TensorMap<Tensor<DataType, 3, DataLayout>> gpu_out(gpu_out_data, tensorRange);

  /// a=1.2f
  gpu_in1.device(sycl_device) = gpu_in1.constant(1.2f);
  sycl_device.memcpyDeviceToHost(in1.data(), gpu_in1_data ,(in1.size())*sizeof(DataType));
  sycl_device.synchronize();

  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(in1(i,j,k), 1.2f);
      }
    }
  }
  printf("a=1.2f Test passed\n");

  /// a=b*1.2f
  gpu_out.device(sycl_device) = gpu_in1 * 1.2f;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data ,(out.size())*sizeof(DataType));
  sycl_device.synchronize();

  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) * 1.2f);
      }
    }
  }
  printf("a=b*1.2f Test Passed\n");

  /// c=a*b
  sycl_device.memcpyHostToDevice(gpu_in2_data, in2.data(),(in2.size())*sizeof(DataType));
  gpu_out.device(sycl_device) = gpu_in1 * gpu_in2;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  sycl_device.synchronize();

  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) *
                             in2(i,j,k));
      }
    }
  }
  printf("c=a*b Test Passed\n");

  /// c=a+b
  gpu_out.device(sycl_device) = gpu_in1 + gpu_in2;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  sycl_device.synchronize();
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) +
                             in2(i,j,k));
      }
    }
  }
  printf("c=a+b Test Passed\n");

  /// c=a*a
  gpu_out.device(sycl_device) = gpu_in1 * gpu_in1;
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  sycl_device.synchronize();
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) *
                             in1(i,j,k));
      }
    }
  }
  printf("c= a*a Test Passed\n");

  //a*3.14f + b*2.7f
  gpu_out.device(sycl_device) =  gpu_in1 * gpu_in1.constant(3.14f) + gpu_in2 * gpu_in2.constant(2.7f);
  sycl_device.memcpyDeviceToHost(out.data(),gpu_out_data,(out.size())*sizeof(DataType));
  sycl_device.synchronize();
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i,j,k),
                         in1(i,j,k) * 3.14f
                       + in2(i,j,k) * 2.7f);
      }
    }
  }
  printf("a*3.14f + b*2.7f Test Passed\n");

  ///d= (a>0.5? b:c)
  sycl_device.memcpyHostToDevice(gpu_in3_data, in3.data(),(in3.size())*sizeof(DataType));
  gpu_out.device(sycl_device) =(gpu_in1 > gpu_in1.constant(0.5f)).select(gpu_in2, gpu_in3);
  sycl_device.memcpyDeviceToHost(out.data(), gpu_out_data,(out.size())*sizeof(DataType));
  sycl_device.synchronize();
  for (int i = 0; i < sizeDim1; ++i) {
    for (int j = 0; j < sizeDim2; ++j) {
      for (int k = 0; k < sizeDim3; ++k) {
        VERIFY_IS_APPROX(out(i, j, k), (in1(i, j, k) > 0.5f)
                                                ? in2(i, j, k)
                                                : in3(i, j, k));
      }
    }
  }
  printf("d= (a>0.5? b:c) Test Passed\n");
  sycl_device.deallocate(gpu_in1_data);
  sycl_device.deallocate(gpu_in2_data);
  sycl_device.deallocate(gpu_in3_data);
  sycl_device.deallocate(gpu_out_data);
}
template<typename DataType, typename dev_Selector> void sycl_computing_test_per_device(dev_Selector s){
  QueueInterface queueInterface(s);
  auto sycl_device = Eigen::SyclDevice(&queueInterface);
  test_sycl_mem_transfers<DataType, RowMajor>(sycl_device);
  test_sycl_computations<DataType, RowMajor>(sycl_device);
  test_sycl_mem_sync<DataType, RowMajor>(sycl_device);
  test_sycl_mem_transfers<DataType, ColMajor>(sycl_device);
  test_sycl_computations<DataType, ColMajor>(sycl_device);
  test_sycl_mem_sync<DataType, ColMajor>(sycl_device);
}

void test_cxx11_tensor_sycl() {
  for (const auto& device :Eigen::get_sycl_supported_devices()) {
    CALL_SUBTEST(sycl_computing_test_per_device<float>(device));
  }
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2006 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/memory_consumption.h>
#include <grid/tria_objects.h>

#include <algorithm>
#include <functional>

namespace internal
{
  namespace Triangulation
  {

    template<>
    void
    TriaObjects<Line>::reserve_space (const unsigned int new_lines)
    {
      const unsigned int new_size = new_lines +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // only allocate space if necessary
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Line());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);
        };
    }

    template<>
    void
    TriaObjects<Quad>::reserve_space (const unsigned int new_quads)
    {
      const unsigned int new_size = new_quads +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // see above...
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Quad());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);
        };
    }

    void
    TriaObjectsHex::reserve_space (const unsigned int new_hexes)
    {
      const unsigned int new_size = new_hexes +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // see above...
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Hexahedron());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);

          face_orientations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
          face_orientations.insert (face_orientations.end(),
				    new_size * GeometryInfo<3>::faces_per_cell
				    - face_orientations.size(),
				    true);
        };
    }

    template<>
    void
    TriaObjects<Line>::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("lines",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
    }

    template<>
    void
    TriaObjects<Quad>::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("quads",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
    }

    void
    TriaObjectsHex::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("hexes",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
      Assert (cells.size() * GeometryInfo<3>::faces_per_cell
              == face_orientations.size(),
              ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
                                face_orientations.size()));
    }

    template <typename G>
    void
    TriaObjects<G>::clear()
    {
      cells.clear();
      children.clear();
      used.clear();
      user_flags.clear();
      material_id.clear();
      user_pointers.clear();
    }

    void
    TriaObjectsHex::clear()
    {
      TriaObjects<Hexahedron>::clear();
      face_orientations.clear();
    }

    template<typename G>
    unsigned int
    TriaObjects<G>::memory_consumption () const
    {
      return (MemoryConsumption::memory_consumption (cells) +
              MemoryConsumption::memory_consumption (children) +
              MemoryConsumption::memory_consumption (used) +
              MemoryConsumption::memory_consumption (user_flags) +
              MemoryConsumption::memory_consumption (material_id) +
              MemoryConsumption::memory_consumption (user_pointers));
    }

    unsigned int
    TriaObjectsHex::memory_consumption () const
    {
      return (MemoryConsumption::memory_consumption (face_orientations) +
	      this->TriaObjects<Hexahedron>::memory_consumption() );
    }

				     // explicit instantiations

    template class TriaObjects<Line>;

#if deal_II_dimension >=2
    template class TriaObjects<Quad>;
#endif

  }
}
<commit_msg>Fix for static linking.<commit_after>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2006 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/memory_consumption.h>
#include <grid/tria_objects.h>

#include <algorithm>
#include <functional>

namespace internal
{
  namespace Triangulation
  {

    template<>
    void
    TriaObjects<Line>::reserve_space (const unsigned int new_lines)
    {
      const unsigned int new_size = new_lines +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // only allocate space if necessary
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Line());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);
        };
    }

    template<>
    void
    TriaObjects<Quad>::reserve_space (const unsigned int new_quads)
    {
      const unsigned int new_size = new_quads +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // see above...
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Quad());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);
        };
    }

    void
    TriaObjectsHex::reserve_space (const unsigned int new_hexes)
    {
      const unsigned int new_size = new_hexes +
                                    std::count_if (used.begin(),
                                                   used.end(),
                                                   std::bind2nd (std::equal_to<bool>(), true));

                                       // see above...
      if (new_size>cells.size())
        {
          cells.reserve (new_size);
          cells.insert (cells.end(),
			new_size-cells.size(),
			Hexahedron());

          used.reserve (new_size);
          used.insert (used.end(),
		       new_size-used.size(),
		       false);

          user_flags.reserve (new_size);
          user_flags.insert (user_flags.end(),
			     new_size-user_flags.size(),
			     false);

          children.reserve (new_size);
          children.insert (children.end(),
			   new_size-children.size(),
			   -1);

          material_id.reserve (new_size);
          material_id.insert (material_id.end(),
			      new_size-material_id.size(),
			      255);

          user_pointers.reserve (new_size);
          user_pointers.insert (user_pointers.end(),
				new_size-user_pointers.size(),
				0);

          face_orientations.reserve (new_size * GeometryInfo<3>::faces_per_cell);
          face_orientations.insert (face_orientations.end(),
				    new_size * GeometryInfo<3>::faces_per_cell
				    - face_orientations.size(),
				    true);
        };
    }

    template<>
    void
    TriaObjects<Line>::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("lines",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
    }

    template<>
    void
    TriaObjects<Quad>::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("quads",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
    }

    void
    TriaObjectsHex::monitor_memory (const unsigned int) const
    {
                                       // check that we have not allocated
                                       // too much memory. note that bool
                                       // vectors allocate their memory in
                                       // chunks of whole integers, so
                                       // they may over-allocate by up to
                                       // as many elements as an integer
                                       // has bits
      Assert (cells.size() == cells.capacity() ||
              cells.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("hexes",
                               cells.size(), cells.capacity()));
      Assert (children.size() == children.capacity() ||
              children.size()<DEAL_II_MIN_VECTOR_CAPACITY,
              ExcMemoryWasted ("children",
                               children.size(), children.capacity()));
      Assert (used.size() <= used.capacity() + sizeof(int)*8 ||
              used.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("used",
                               used.size(), used.capacity()));
      Assert (user_flags.size() <= user_flags.capacity() + sizeof(int)*8 ||
              user_flags.size()<DEAL_II_MIN_BOOL_VECTOR_CAPACITY,
              ExcMemoryWasted ("user_flags",
                               user_flags.size(), user_flags.capacity()));
      Assert (cells.size() == used.size(),
              ExcMemoryInexact (cells.size(), used.size()));
      Assert (cells.size() == user_flags.size(),
              ExcMemoryInexact (cells.size(), user_flags.size()));
      Assert (cells.size() == children.size(),
              ExcMemoryInexact (cells.size(), children.size()));
      Assert (cells.size() == material_id.size(),
              ExcMemoryInexact (cells.size(), material_id.size()));
      Assert (cells.size() == user_pointers.size(),
              ExcMemoryInexact (cells.size(), user_pointers.size()));
      Assert (cells.size() * GeometryInfo<3>::faces_per_cell
              == face_orientations.size(),
              ExcMemoryInexact (cells.size() * GeometryInfo<3>::faces_per_cell,
                                face_orientations.size()));
    }

    template <typename G>
    void
    TriaObjects<G>::clear()
    {
      cells.clear();
      children.clear();
      used.clear();
      user_flags.clear();
      material_id.clear();
      user_pointers.clear();
    }

    void
    TriaObjectsHex::clear()
    {
      TriaObjects<Hexahedron>::clear();
      face_orientations.clear();
    }

    template<typename G>
    unsigned int
    TriaObjects<G>::memory_consumption () const
    {
      return (MemoryConsumption::memory_consumption (cells) +
              MemoryConsumption::memory_consumption (children) +
              MemoryConsumption::memory_consumption (used) +
              MemoryConsumption::memory_consumption (user_flags) +
              MemoryConsumption::memory_consumption (material_id) +
              MemoryConsumption::memory_consumption (user_pointers));
    }

    unsigned int
    TriaObjectsHex::memory_consumption () const
    {
      return (MemoryConsumption::memory_consumption (face_orientations) +
	      this->TriaObjects<Hexahedron>::memory_consumption() );
    }

				     // explicit instantiations

    template class TriaObjects<Line>;
    template class TriaObjects<Quad>;
  }
}
<|endoftext|>


<commit_before>/*
* kaccelmenuwatch.cpp -- Implementation of class KAccelMenuWatch.
* Author:	Sirtaj Singh Kang
* Version:	$Id$
* Generated:	Thu Jan  7 15:05:26 EST 1999
*/

#include <assert.h>
#include "kaccelmenuwatch.h"

KAccelMenuWatch::KAccelMenuWatch( KAccel *accel, QObject *parent )
	: QObject( parent ),
	_accel( accel ),
	_menu ( 0 )
{
	_accList.setAutoDelete( true );
	_menuList.setAutoDelete( false );
}

void KAccelMenuWatch::setMenu( QPopupMenu *menu )
{
	assert( menu );

	// we use  _menuList to ensure that the signal is
	// connected only once per menu.

	if ( !_menuList.findRef( menu ) ) {
		_menuList.append( menu );
		connect( menu, SIGNAL(destroyed()),
			this, SLOT(removeDeadMenu()) );
	}

	_menu = menu;
}

void KAccelMenuWatch::connectAccel( int itemId, const char *action )
{
	AccelItem *item = newAccelItem( _menu, itemId, StringAccel ) ;
	item->action	= action;
}

void KAccelMenuWatch::connectAccel( int itemId, KStdAccel::StdAccel accel )
{
	AccelItem *item = newAccelItem( _menu, itemId, StdAccel ) ;
	item->stdAction	= accel;
}

void KAccelMenuWatch::updateMenus()
{
	assert( _accel != 0 );

	QPtrListIterator<AccelItem> iter( _accList );
	AccelItem *item;

	for( ; (item = iter.current()) ; ++iter ) {
		switch( item->type ) {
			case StringAccel:
				_accel->changeMenuAccel( item->menu,
					item->itemId,
					item->action );
				break;
			case StdAccel:
				_accel->changeMenuAccel( item->menu,
					item->itemId,
					item->stdAction );
				break;
			default:
				break;
		}
	}

}

void KAccelMenuWatch::removeDeadMenu()
{
	QPopupMenu *sdr = (QPopupMenu *) sender();
	assert( sdr );

	if ( !_menuList.findRef( sdr ) ) {
		return;
	}

	// remove all accels

	AccelItem *accel;
	for ( accel = _accList.first(); accel; accel = _accList.next() ) {

loop:
		if( accel && accel->menu == sdr ) {
			_accList.remove();
			accel = _accList.current();
			goto loop;
		}
	}

	// remove from menu list
	_menuList.remove( sdr );

	return;
}

KAccelMenuWatch::AccelItem *KAccelMenuWatch::newAccelItem( QPopupMenu *,
		int itemId, AccelType type )
{
	AccelItem *item = new AccelItem;

	item->menu	= _menu;
	item->itemId	= itemId;
	item->type	= type;

	_accList.append( item );

	return item;
}

#include "kaccelmenuwatch.moc"
<commit_msg>port to latest qt-copy<commit_after>/*
* kaccelmenuwatch.cpp -- Implementation of class KAccelMenuWatch.
* Author:	Sirtaj Singh Kang
* Version:	$Id$
* Generated:	Thu Jan  7 15:05:26 EST 1999
*/

#include <assert.h>
#include "kaccelmenuwatch.h"

KAccelMenuWatch::KAccelMenuWatch( KAccel *accel, QObject *parent )
	: QObject( parent ),
	_accel( accel ),
	_menu ( 0 )
{
	_accList.setAutoDelete( true );
	_menuList.setAutoDelete( false );
}

void KAccelMenuWatch::setMenu( QPopupMenu *menu )
{
	assert( menu );

	// we use  _menuList to ensure that the signal is
	// connected only once per menu.

	if ( !_menuList.findRef( menu ) ) {
		_menuList.append( menu );
		connect( menu, SIGNAL(destroyed()),
			this, SLOT(removeDeadMenu()) );
	}

	_menu = menu;
}

void KAccelMenuWatch::connectAccel( int itemId, const char *action )
{
	AccelItem *item = newAccelItem( _menu, itemId, StringAccel ) ;
	item->action	= QString::fromLocal8Bit( action );
}

void KAccelMenuWatch::connectAccel( int itemId, KStdAccel::StdAccel accel )
{
	AccelItem *item = newAccelItem( _menu, itemId, StdAccel ) ;
	item->stdAction	= accel;
}

void KAccelMenuWatch::updateMenus()
{
	assert( _accel != 0 );

	QPtrListIterator<AccelItem> iter( _accList );
	AccelItem *item;

	for( ; (item = iter.current()) ; ++iter ) {
		switch( item->type ) {
			case StringAccel:
				_accel->changeMenuAccel( item->menu,
					item->itemId,
					item->action );
				break;
			case StdAccel:
				_accel->changeMenuAccel( item->menu,
					item->itemId,
					item->stdAction );
				break;
			default:
				break;
		}
	}

}

void KAccelMenuWatch::removeDeadMenu()
{
	QPopupMenu *sdr = (QPopupMenu *) sender();
	assert( sdr );

	if ( !_menuList.findRef( sdr ) ) {
		return;
	}

	// remove all accels

	AccelItem *accel;
	for ( accel = _accList.first(); accel; accel = _accList.next() ) {

loop:
		if( accel && accel->menu == sdr ) {
			_accList.remove();
			accel = _accList.current();
			goto loop;
		}
	}

	// remove from menu list
	_menuList.remove( sdr );

	return;
}

KAccelMenuWatch::AccelItem *KAccelMenuWatch::newAccelItem( QPopupMenu *,
		int itemId, AccelType type )
{
	AccelItem *item = new AccelItem;

	item->menu	= _menu;
	item->itemId	= itemId;
	item->type	= type;

	_accList.append( item );

	return item;
}

#include "kaccelmenuwatch.moc"
<|endoftext|>