<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: myucp_datasupplier.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 06:40:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

/**************************************************************************
                                TODO
 **************************************************************************

 *************************************************************************/

#include <vector>

#ifndef _UCBHELPER_CONTENTIDENTIFIER_HXX
#include <ucbhelper/contentidentifier.hxx>
#endif
#ifndef _UCBHELPER_PROVIDERHELPER_HXX
#include <ucbhelper/providerhelper.hxx>
#endif

#ifndef DBA_DATASUPPLIER_HXX
#include "myucp_datasupplier.hxx"
#endif
#ifndef DBA_CONTENTHELPER_HXX
#include "ContentHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XHIERARCHICALNAMEACCESS_HPP_
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::container;

// @@@ Adjust namespace name.
using namespace dbaccess;

// @@@ Adjust namespace name.
namespace dbaccess
{

//=========================================================================
//
// struct ResultListEntry.
//
//=========================================================================

struct ResultListEntry
{
    rtl::OUString                       aId;
    Reference< XContentIdentifier >     xId;
    ::rtl::Reference< OContentHelper >  xContent;
    Reference< XRow >                   xRow;
    const ContentProperties&            rData;

    ResultListEntry( const ContentProperties& rEntry ) : rData( rEntry ) {}
};

//=========================================================================
//
// ResultList.
//
//=========================================================================

typedef std::vector< ResultListEntry* > ResultList;

//=========================================================================
//
// struct DataSupplier_Impl.
//
//=========================================================================

struct DataSupplier_Impl
{
    osl::Mutex                                   m_aMutex;
    ResultList                                   m_aResults;
    rtl::Reference< ODocumentContainer >             m_xContent;
    Reference< XMultiServiceFactory >            m_xSMgr;
      sal_Int32                                  m_nOpenMode;
      sal_Bool                                   m_bCountFinal;

    DataSupplier_Impl( const Reference< XMultiServiceFactory >& rxSMgr,
                        const rtl::Reference< ODocumentContainer >& rContent,
                       sal_Int32 nOpenMode )
    : m_xContent(rContent)
    , m_xSMgr( rxSMgr )
    , m_nOpenMode( nOpenMode )
    , m_bCountFinal( sal_False ) {}
    ~DataSupplier_Impl();
};

//=========================================================================
DataSupplier_Impl::~DataSupplier_Impl()
{
    ResultList::const_iterator it  = m_aResults.begin();
    ResultList::const_iterator end = m_aResults.end();

    while ( it != end )
    {
        delete (*it);
        it++;
    }
}

}

//=========================================================================
//=========================================================================
//
// DataSupplier Implementation.
//
//=========================================================================
//=========================================================================
DBG_NAME(DataSupplier)

DataSupplier::DataSupplier( const Reference< XMultiServiceFactory >& rxSMgr,
                           const rtl::Reference< ODocumentContainer >& rContent,
                            sal_Int32 nOpenMode )
: m_pImpl( new DataSupplier_Impl( rxSMgr, rContent,nOpenMode ) )
{
    DBG_CTOR(DataSupplier,NULL);

}

//=========================================================================
// virtual
DataSupplier::~DataSupplier()
{

    DBG_DTOR(DataSupplier,NULL);
}

//=========================================================================
// virtual
rtl::OUString DataSupplier::queryContentIdentifierString( sal_Int32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
        if ( aId.getLength() )
        {
            // Already cached.
            return aId;
        }
    }

    if ( getResult( nIndex ) )
    {
        rtl::OUString aId
            = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier();

        if ( aId.getLength() )
            aId += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));

        aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle;

        m_pImpl->m_aResults[ nIndex ]->aId = aId;
        return aId;
    }
    return rtl::OUString();
}

//=========================================================================
// virtual
Reference< XContentIdentifier >
DataSupplier::queryContentIdentifier( sal_Int32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId;
        if ( xId.is() )
        {
            // Already cached.
            return xId;
        }
    }

    rtl::OUString aId = queryContentIdentifierString( nIndex );
    if ( aId.getLength() )
    {
        Reference< XContentIdentifier > xId = new ::ucb::ContentIdentifier( aId );
        m_pImpl->m_aResults[ nIndex ]->xId = xId;
        return xId;
    }
    return Reference< XContentIdentifier >();
}

//=========================================================================
// virtual
Reference< XContent >
DataSupplier::queryContent( sal_Int32 _nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)_nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
        if ( xContent.is() )
        {
            // Already cached.
            return xContent;
        }
    }

    Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex );
    if ( xId.is() )
    {
        try
        {
            Reference< XContent > xContent;
            ::rtl::OUString sName = xId->getContentIdentifier();
            sal_Int32 nIndex = sName.lastIndexOf('/') + 1;
            sName = sName.getToken(0,'/',nIndex);

            m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName);

            xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
            return xContent;

        }
        catch ( IllegalIdentifierException& )
        {
        }
    }
    return Reference< XContent >();
}

//=========================================================================
// virtual
sal_Bool DataSupplier::getResult( sal_Int32 nIndex )
{
    osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        // Result already present.
        return sal_True;
    }

    // Result not (yet) present.

    if ( m_pImpl->m_bCountFinal )
        return sal_False;

    // Try to obtain result...

    sal_Int32 nOldCount = m_pImpl->m_aResults.size();
    sal_Bool bFound = sal_False;
    sal_Int32 nPos = nOldCount;

    // @@@ Obtain data and put it into result list...
    Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames();
    if ( nIndex < aSeq.getLength() )
    {
        const ::rtl::OUString* pIter = aSeq.getConstArray();
        const ::rtl::OUString* pEnd   = pIter + aSeq.getLength();
        for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos)
        {
            m_pImpl->m_aResults.push_back(
                            new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );

            if ( nPos == nIndex )
            {
                // Result obtained.
                bFound = sal_True;
                break;
            }
        }
    }

    if ( !bFound )
        m_pImpl->m_bCountFinal = sal_True;

    rtl::Reference< ::ucb::ResultSet > xResultSet = getResultSet().getBodyPtr();
    if ( xResultSet.is() )
    {
        // Callbacks follow!
        aGuard.clear();

        if ( (size_t)nOldCount < m_pImpl->m_aResults.size() )
            xResultSet->rowCountChanged(
                                    nOldCount, m_pImpl->m_aResults.size() );

        if ( m_pImpl->m_bCountFinal )
            xResultSet->rowCountFinal();
    }

    return bFound;
}

//=========================================================================
// virtual
sal_Int32 DataSupplier::totalCount()
{
    osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( m_pImpl->m_bCountFinal )
        return m_pImpl->m_aResults.size();

    sal_Int32 nOldCount = m_pImpl->m_aResults.size();

    // @@@ Obtain data and put it into result list...
    Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames();
    const ::rtl::OUString* pIter = aSeq.getConstArray();
    const ::rtl::OUString* pEnd   = pIter + aSeq.getLength();
    for(;pIter != pEnd;++pIter)
        m_pImpl->m_aResults.push_back(
                        new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );

    m_pImpl->m_bCountFinal = sal_True;

    rtl::Reference< ::ucb::ResultSet > xResultSet = getResultSet().getBodyPtr();
    if ( xResultSet.is() )
    {
        // Callbacks follow!
        aGuard.clear();

        if ( (size_t)nOldCount < m_pImpl->m_aResults.size() )
            xResultSet->rowCountChanged(
                                    nOldCount, m_pImpl->m_aResults.size() );

        xResultSet->rowCountFinal();
    }

    return m_pImpl->m_aResults.size();
}

//=========================================================================
// virtual
sal_Int32 DataSupplier::currentCount()
{
    return m_pImpl->m_aResults.size();
}

//=========================================================================
// virtual
sal_Bool DataSupplier::isCountFinal()
{
    return m_pImpl->m_bCountFinal;
}

//=========================================================================
// virtual
Reference< XRow >
DataSupplier::queryPropertyValues( sal_Int32 nIndex  )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
        if ( xRow.is() )
        {
            // Already cached.
            return xRow;
        }
    }

    if ( getResult( nIndex ) )
    {
        if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() )
            queryContent(nIndex);

        Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties());
        m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
        return xRow;
    }

    return Reference< XRow >();
}

//=========================================================================
// virtual
void DataSupplier::releasePropertyValues( sal_Int32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
        m_pImpl->m_aResults[ nIndex ]->xRow = Reference< XRow >();
}

//=========================================================================
// virtual
void DataSupplier::close()
{
}

//=========================================================================
// virtual
void DataSupplier::validate()
    throw( ResultSetException )
{
}

<commit_msg>INTEGRATION: CWS bgdlremove (1.6.98); FILE MERGED 2007/05/18 09:03:13 kso 1.6.98.2: #i77419# - cleanup of ucbhelper namespaces. 2007/05/11 07:45:35 kso 1.6.98.1: #i76911# - ucbhelper lib no longer uses VOS. (vos::ORef => rtl::Reference, vos::OMutex => osl::Mutex, ...)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: myucp_datasupplier.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: ihi $ $Date: 2007-06-05 14:39:34 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"

/**************************************************************************
                                TODO
 **************************************************************************

 *************************************************************************/

#include <vector>

#ifndef _UCBHELPER_CONTENTIDENTIFIER_HXX
#include <ucbhelper/contentidentifier.hxx>
#endif
#ifndef _UCBHELPER_PROVIDERHELPER_HXX
#include <ucbhelper/providerhelper.hxx>
#endif

#ifndef DBA_DATASUPPLIER_HXX
#include "myucp_datasupplier.hxx"
#endif
#ifndef DBA_CONTENTHELPER_HXX
#include "ContentHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XHIERARCHICALNAMEACCESS_HPP_
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::container;

// @@@ Adjust namespace name.
using namespace dbaccess;

// @@@ Adjust namespace name.
namespace dbaccess
{

//=========================================================================
//
// struct ResultListEntry.
//
//=========================================================================

struct ResultListEntry
{
    rtl::OUString                       aId;
    Reference< XContentIdentifier >     xId;
    ::rtl::Reference< OContentHelper >  xContent;
    Reference< XRow >                   xRow;
    const ContentProperties&            rData;

    ResultListEntry( const ContentProperties& rEntry ) : rData( rEntry ) {}
};

//=========================================================================
//
// ResultList.
//
//=========================================================================

typedef std::vector< ResultListEntry* > ResultList;

//=========================================================================
//
// struct DataSupplier_Impl.
//
//=========================================================================

struct DataSupplier_Impl
{
    osl::Mutex                                   m_aMutex;
    ResultList                                   m_aResults;
    rtl::Reference< ODocumentContainer >             m_xContent;
    Reference< XMultiServiceFactory >            m_xSMgr;
      sal_Int32                                  m_nOpenMode;
      sal_Bool                                   m_bCountFinal;

    DataSupplier_Impl( const Reference< XMultiServiceFactory >& rxSMgr,
                        const rtl::Reference< ODocumentContainer >& rContent,
                       sal_Int32 nOpenMode )
    : m_xContent(rContent)
    , m_xSMgr( rxSMgr )
    , m_nOpenMode( nOpenMode )
    , m_bCountFinal( sal_False ) {}
    ~DataSupplier_Impl();
};

//=========================================================================
DataSupplier_Impl::~DataSupplier_Impl()
{
    ResultList::const_iterator it  = m_aResults.begin();
    ResultList::const_iterator end = m_aResults.end();

    while ( it != end )
    {
        delete (*it);
        it++;
    }
}

}

//=========================================================================
//=========================================================================
//
// DataSupplier Implementation.
//
//=========================================================================
//=========================================================================
DBG_NAME(DataSupplier)

DataSupplier::DataSupplier( const Reference< XMultiServiceFactory >& rxSMgr,
                           const rtl::Reference< ODocumentContainer >& rContent,
                            sal_Int32 nOpenMode )
: m_pImpl( new DataSupplier_Impl( rxSMgr, rContent,nOpenMode ) )
{
    DBG_CTOR(DataSupplier,NULL);

}

//=========================================================================
// virtual
DataSupplier::~DataSupplier()
{

    DBG_DTOR(DataSupplier,NULL);
}

//=========================================================================
// virtual
rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
        if ( aId.getLength() )
        {
            // Already cached.
            return aId;
        }
    }

    if ( getResult( nIndex ) )
    {
        rtl::OUString aId
            = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier();

        if ( aId.getLength() )
            aId += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));

        aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle;

        m_pImpl->m_aResults[ nIndex ]->aId = aId;
        return aId;
    }
    return rtl::OUString();
}

//=========================================================================
// virtual
Reference< XContentIdentifier >
DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId;
        if ( xId.is() )
        {
            // Already cached.
            return xId;
        }
    }

    rtl::OUString aId = queryContentIdentifierString( nIndex );
    if ( aId.getLength() )
    {
        Reference< XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aId );
        m_pImpl->m_aResults[ nIndex ]->xId = xId;
        return xId;
    }
    return Reference< XContentIdentifier >();
}

//=========================================================================
// virtual
Reference< XContent >
DataSupplier::queryContent( sal_uInt32 _nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)_nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
        if ( xContent.is() )
        {
            // Already cached.
            return xContent;
        }
    }

    Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex );
    if ( xId.is() )
    {
        try
        {
            Reference< XContent > xContent;
            ::rtl::OUString sName = xId->getContentIdentifier();
            sal_Int32 nIndex = sName.lastIndexOf('/') + 1;
            sName = sName.getToken(0,'/',nIndex);

            m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName);

            xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
            return xContent;

        }
        catch ( IllegalIdentifierException& )
        {
        }
    }
    return Reference< XContent >();
}

//=========================================================================
// virtual
sal_Bool DataSupplier::getResult( sal_uInt32 nIndex )
{
    osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        // Result already present.
        return sal_True;
    }

    // Result not (yet) present.

    if ( m_pImpl->m_bCountFinal )
        return sal_False;

    // Try to obtain result...

    sal_uInt32 nOldCount = m_pImpl->m_aResults.size();
    sal_Bool bFound = sal_False;
    sal_uInt32 nPos = nOldCount;

    // @@@ Obtain data and put it into result list...
    Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames();
    if ( nIndex < sal::static_int_cast< sal_uInt32 >( aSeq.getLength() ) )
    {
        const ::rtl::OUString* pIter = aSeq.getConstArray();
        const ::rtl::OUString* pEnd   = pIter + aSeq.getLength();
        for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos)
        {
            m_pImpl->m_aResults.push_back(
                            new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );

            if ( nPos == nIndex )
            {
                // Result obtained.
                bFound = sal_True;
                break;
            }
        }
    }

    if ( !bFound )
        m_pImpl->m_bCountFinal = sal_True;

    rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get();
    if ( xResultSet.is() )
    {
        // Callbacks follow!
        aGuard.clear();

        if ( (size_t)nOldCount < m_pImpl->m_aResults.size() )
            xResultSet->rowCountChanged(
                                    nOldCount, m_pImpl->m_aResults.size() );

        if ( m_pImpl->m_bCountFinal )
            xResultSet->rowCountFinal();
    }

    return bFound;
}

//=========================================================================
// virtual
sal_uInt32 DataSupplier::totalCount()
{
    osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( m_pImpl->m_bCountFinal )
        return m_pImpl->m_aResults.size();

    sal_uInt32 nOldCount = m_pImpl->m_aResults.size();

    // @@@ Obtain data and put it into result list...
    Sequence< ::rtl::OUString> aSeq = m_pImpl->m_xContent->getElementNames();
    const ::rtl::OUString* pIter = aSeq.getConstArray();
    const ::rtl::OUString* pEnd   = pIter + aSeq.getLength();
    for(;pIter != pEnd;++pIter)
        m_pImpl->m_aResults.push_back(
                        new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );

    m_pImpl->m_bCountFinal = sal_True;

    rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get();
    if ( xResultSet.is() )
    {
        // Callbacks follow!
        aGuard.clear();

        if ( (size_t)nOldCount < m_pImpl->m_aResults.size() )
            xResultSet->rowCountChanged(
                                    nOldCount, m_pImpl->m_aResults.size() );

        xResultSet->rowCountFinal();
    }

    return m_pImpl->m_aResults.size();
}

//=========================================================================
// virtual
sal_uInt32 DataSupplier::currentCount()
{
    return m_pImpl->m_aResults.size();
}

//=========================================================================
// virtual
sal_Bool DataSupplier::isCountFinal()
{
    return m_pImpl->m_bCountFinal;
}

//=========================================================================
// virtual
Reference< XRow >
DataSupplier::queryPropertyValues( sal_uInt32 nIndex  )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
    {
        Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
        if ( xRow.is() )
        {
            // Already cached.
            return xRow;
        }
    }

    if ( getResult( nIndex ) )
    {
        if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() )
            queryContent(nIndex);

        Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties());
        m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
        return xRow;
    }

    return Reference< XRow >();
}

//=========================================================================
// virtual
void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
{
    osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );

    if ( (size_t)nIndex < m_pImpl->m_aResults.size() )
        m_pImpl->m_aResults[ nIndex ]->xRow = Reference< XRow >();
}

//=========================================================================
// virtual
void DataSupplier::close()
{
}

//=========================================================================
// virtual
void DataSupplier::validate()
    throw( ResultSetException )
{
}

<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_PROXY_ISTREAM_POINTER_HXX
#define BENG_PROXY_ISTREAM_POINTER_HXX

#include "istream.hxx"

#include <cstddef>
#include <cassert>

class IstreamPointer {
    Istream *stream;

public:
    IstreamPointer() = default;
    explicit IstreamPointer(std::nullptr_t):stream(nullptr) {}

    IstreamPointer(Istream &_stream,
                   IstreamHandler &handler,
                   FdTypeMask direct=0)
        :stream(&_stream) {
        stream->SetHandler(handler, direct);
    }

    explicit IstreamPointer(Istream *_stream,
                            IstreamHandler &handler,
                            FdTypeMask direct=0)
        :stream(_stream) {
        if (stream != nullptr)
            stream->SetHandler(handler, direct);
    }

    IstreamPointer(IstreamPointer &&other)
        :stream(other.stream) {
        other.stream = nullptr;
    }

    IstreamPointer(const IstreamPointer &) = delete;
    IstreamPointer &operator=(const IstreamPointer &) = delete;

    bool IsDefined() const {
        return stream != nullptr;
    }

    void Clear() noexcept {
        stream = nullptr;
    }

    void Close() noexcept {
        assert(IsDefined());

        stream->Close();
    }

    void ClearAndClose() noexcept {
        assert(IsDefined());

        auto *old = stream;
        Clear();
        old->Close();
    }

    Istream *Steal() noexcept {
        Istream *result = stream;
        stream = nullptr;
        return result;
    }

    void Set(Istream &_stream,
             IstreamHandler &handler,
             FdTypeMask direct=0) {
        assert(!IsDefined());

        stream = &_stream;
        stream->SetHandler(handler, direct);
    }

    void Replace(Istream &_stream,
                 IstreamHandler &handler,
                 FdTypeMask direct=0) {
        Close();

        stream = &_stream;
        stream->SetHandler(handler, direct);
    }

    void SetDirect(FdTypeMask direct) {
        assert(IsDefined());

        stream->SetDirect(direct);
    }

    void SetDirect(const Istream &src) {
        SetDirect(src.GetHandlerDirect());
    }

    void Read() {
        assert(IsDefined());

        stream->Read();
    }

    void FillBucketList(IstreamBucketList &list) {
        assert(IsDefined());

        stream->FillBucketList(list);
    }

    size_t ConsumeBucketList(size_t nbytes) {
        assert(IsDefined());

        return stream->ConsumeBucketList(nbytes);
    }

    gcc_pure
    off_t GetAvailable(bool partial) const {
        assert(IsDefined());

        return stream->GetAvailable(partial);
    }

    off_t Skip(off_t length) {
        assert(IsDefined());

        return stream->Skip(length);
    }

    int AsFd() {
        assert(IsDefined());

        return stream->AsFd();
    }
};

#endif
<commit_msg>istream/Pointer: use std::exchange()<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_PROXY_ISTREAM_POINTER_HXX
#define BENG_PROXY_ISTREAM_POINTER_HXX

#include "istream.hxx"

#include <utility>
#include <cstddef>
#include <cassert>

class IstreamPointer {
    Istream *stream;

public:
    IstreamPointer() = default;
    explicit IstreamPointer(std::nullptr_t):stream(nullptr) {}

    IstreamPointer(Istream &_stream,
                   IstreamHandler &handler,
                   FdTypeMask direct=0)
        :stream(&_stream) {
        stream->SetHandler(handler, direct);
    }

    explicit IstreamPointer(Istream *_stream,
                            IstreamHandler &handler,
                            FdTypeMask direct=0)
        :stream(_stream) {
        if (stream != nullptr)
            stream->SetHandler(handler, direct);
    }

    IstreamPointer(IstreamPointer &&other)
        :stream(std::exchange(other.stream, nullptr)) {}

    IstreamPointer(const IstreamPointer &) = delete;
    IstreamPointer &operator=(const IstreamPointer &) = delete;

    bool IsDefined() const {
        return stream != nullptr;
    }

    void Clear() noexcept {
        stream = nullptr;
    }

    void Close() noexcept {
        assert(IsDefined());

        stream->Close();
    }

    void ClearAndClose() noexcept {
        assert(IsDefined());

        auto *old = stream;
        Clear();
        old->Close();
    }

    Istream *Steal() noexcept {
        Istream *result = stream;
        stream = nullptr;
        return result;
    }

    void Set(Istream &_stream,
             IstreamHandler &handler,
             FdTypeMask direct=0) {
        assert(!IsDefined());

        stream = &_stream;
        stream->SetHandler(handler, direct);
    }

    void Replace(Istream &_stream,
                 IstreamHandler &handler,
                 FdTypeMask direct=0) {
        Close();

        stream = &_stream;
        stream->SetHandler(handler, direct);
    }

    void SetDirect(FdTypeMask direct) {
        assert(IsDefined());

        stream->SetDirect(direct);
    }

    void SetDirect(const Istream &src) {
        SetDirect(src.GetHandlerDirect());
    }

    void Read() {
        assert(IsDefined());

        stream->Read();
    }

    void FillBucketList(IstreamBucketList &list) {
        assert(IsDefined());

        stream->FillBucketList(list);
    }

    size_t ConsumeBucketList(size_t nbytes) {
        assert(IsDefined());

        return stream->ConsumeBucketList(nbytes);
    }

    gcc_pure
    off_t GetAvailable(bool partial) const {
        assert(IsDefined());

        return stream->GetAvailable(partial);
    }

    off_t Skip(off_t length) {
        assert(IsDefined());

        return stream->Skip(length);
    }

    int AsFd() {
        assert(IsDefined());

        return stream->AsFd();
    }
};

#endif
<|endoftext|>


<commit_before>
#pragma once

#include <togo/core/error/assert.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/io/types.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/io/proto.hpp>

#include <cstring>

using namespace togo;

namespace {

union FloatInt {
	float f;
	u32 i;
};

bool float_exact(float const x, float const y) {
	FloatInt const xu{x};
	FloatInt const yu{y};
	return xu.i == yu.i;
}

static u8 const partial_out[5]{0, 8, 16, 32, 64};

struct TestStreamState {
	u8  v8 {8};
	u16 v16{16};
	u32 v32{32};
	u64 v64{64};
	float vfloat{-32.0f};
	u32 array[10]{0};
};

enum : signed {
	SIZE_VALUES
		= sizeof(TestStreamState::v8)
		+ sizeof(TestStreamState::v16)
		+ sizeof(TestStreamState::v32)
		+ sizeof(TestStreamState::v64)
		+ sizeof(TestStreamState::vfloat)
	,
	SIZE_ARRAY = sizeof(TestStreamState::array),
	SIZE_BOTH = SIZE_VALUES + SIZE_ARRAY
};

} // anonymous namespace

void test_reader(IReader& stream, bool const seekable) {
	TestStreamState s{};
	std::memset(&s, 0, sizeof(TestStreamState));
	TOGO_ASSERTE(io::read_value(stream, s.v8 ) && s.v8  ==  8);
	TOGO_ASSERTE(io::read_value(stream, s.v16) && s.v16 == 16);
	TOGO_ASSERTE(io::read_value(stream, s.v32) && s.v32 == 32);
	TOGO_ASSERTE(io::read_value(stream, s.v64) && s.v64 == 64);
	TOGO_ASSERTE(io::read_value(stream, s.vfloat) && float_exact(s.vfloat, -32.0f));

	if (seekable) {
		TOGO_ASSERTE(io::position(dynamic_cast<IStreamSeekable&>(stream)) == SIZE_VALUES);
	}

	TOGO_ASSERTE(io::read_array(stream, s.array, array_extent(&TestStreamState::array)));
	u32 bit = 128;
	for (u32& v : s.array) {
		TOGO_ASSERTE(v == bit);
		bit <<= 1;
	}

	if (seekable) {
		IStreamSeekable& stream_seekable = dynamic_cast<IStreamSeekable&>(stream);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
		TOGO_ASSERTE(!io::status(stream_seekable).eof());

		TOGO_ASSERTE(io::seek_relative(stream_seekable, -SIZE_ARRAY) == SIZE_VALUES);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_VALUES);
		TOGO_ASSERTE(io::seek_to(stream_seekable, 0) == 0);
		TOGO_ASSERTE(io::position(stream_seekable) == 0);

		TOGO_ASSERTE(io::seek_to(stream_seekable, SIZE_BOTH) == SIZE_BOTH);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
	}

	u8 partial_in[10]{};
	unsigned read_size = 0;
	io::read(stream, partial_in, array_extent(partial_in), &read_size);
	TOGO_ASSERTE(!io::status(stream).fail() && io::status(stream).eof());
	TOGO_ASSERTE(read_size == array_extent(partial_out));
	TOGO_ASSERTE(std::memcmp(partial_in, partial_out, read_size) == 0);
}

void test_writer(IWriter& stream, bool const seekable) {
	TestStreamState s{};
	TOGO_ASSERTE(io::write_value(stream, s.v8 ));
	TOGO_ASSERTE(io::write_value(stream, s.v16));
	TOGO_ASSERTE(io::write_value(stream, s.v32));
	TOGO_ASSERTE(io::write_value(stream, s.v64));
	TOGO_ASSERTE(io::write_value(stream, s.vfloat));

	if (seekable) {
		TOGO_ASSERTE(io::position(dynamic_cast<IStreamSeekable&>(stream)) == SIZE_VALUES);
	}

	u32 bit = 128;
	for (u32& v : s.array) {
		v = bit;
		bit <<= 1;
	}
	TOGO_ASSERTE(io::write_array(stream, s.array, array_extent(&TestStreamState::array)));

	if (seekable) {
		IStreamSeekable& stream_seekable = dynamic_cast<IStreamSeekable&>(stream);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
		TOGO_ASSERTE(!io::status(stream_seekable).eof());

		TOGO_ASSERTE(io::seek_relative(stream_seekable, -SIZE_ARRAY) == SIZE_VALUES);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_VALUES);
		TOGO_ASSERTE(io::seek_to(stream_seekable, 0) == 0);
		TOGO_ASSERTE(io::position(stream_seekable) == 0);

		TOGO_ASSERTE(io::seek_to(stream_seekable, SIZE_BOTH) == SIZE_BOTH);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
	}

	TOGO_ASSERTE(io::write(stream, partial_out, array_extent(partial_out)));
}
<commit_msg>lib/core/test/io/common: test f64 as well; tidy.<commit_after>
#pragma once

#include <togo/core/error/assert.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/io/types.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/io/proto.hpp>

#include <cstring>

using namespace togo;

namespace {

union FloatInt32 {
	f32 f;
	u32 i;
};

union FloatInt64 {
	f64 f;
	u64 i;
};

bool float_exact_32(f32 const x, f32 const y) {
	FloatInt32 const xu{x};
	FloatInt32 const yu{y};
	return xu.i == yu.i;
}

bool float_exact_64(f64 const x, f64 const y) {
	FloatInt64 const xu{x};
	FloatInt64 const yu{y};
	return xu.i == yu.i;
}

static u8 const partial_out[5]{0, 8, 16, 32, 64};

struct TestStreamState {
	u8  i8 {8};
	u16 i16{16};
	u32 i32{32};
	u64 i64{64};
	f32 f32{-32.0f};
	f64 f64{-64.0f};
	u32 array[10]{0};
};

enum : signed {
	SIZE_VALUES
		= sizeof(TestStreamState::i8)
		+ sizeof(TestStreamState::i16)
		+ sizeof(TestStreamState::i32)
		+ sizeof(TestStreamState::i64)
		+ sizeof(TestStreamState::f32)
		+ sizeof(TestStreamState::f64)
	,
	SIZE_ARRAY = sizeof(TestStreamState::array),
	SIZE_BOTH = SIZE_VALUES + SIZE_ARRAY
};

} // anonymous namespace

void test_reader(IReader& stream, bool const seekable) {
	TestStreamState s{};
	std::memset(&s, 0, sizeof(TestStreamState));
	TOGO_ASSERTE(io::read_value(stream, s.i8 ) && s.i8  ==  8);
	TOGO_ASSERTE(io::read_value(stream, s.i16) && s.i16 == 16);
	TOGO_ASSERTE(io::read_value(stream, s.i32) && s.i32 == 32);
	TOGO_ASSERTE(io::read_value(stream, s.i64) && s.i64 == 64);
	TOGO_ASSERTE(io::read_value(stream, s.f32) && float_exact_32(s.f32, -32.0f));
	TOGO_ASSERTE(io::read_value(stream, s.f64) && float_exact_64(s.f64, -64.0f));

	if (seekable) {
		TOGO_ASSERTE(io::position(dynamic_cast<IStreamSeekable&>(stream)) == SIZE_VALUES);
	}

	TOGO_ASSERTE(io::read_array(stream, s.array, array_extent(&TestStreamState::array)));
	u32 bit = 128;
	for (u32& v : s.array) {
		TOGO_ASSERTE(v == bit);
		bit <<= 1;
	}

	if (seekable) {
		IStreamSeekable& stream_seekable = dynamic_cast<IStreamSeekable&>(stream);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
		TOGO_ASSERTE(!io::status(stream_seekable).eof());

		TOGO_ASSERTE(io::seek_relative(stream_seekable, -SIZE_ARRAY) == SIZE_VALUES);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_VALUES);
		TOGO_ASSERTE(io::seek_to(stream_seekable, 0) == 0);
		TOGO_ASSERTE(io::position(stream_seekable) == 0);

		TOGO_ASSERTE(io::seek_to(stream_seekable, SIZE_BOTH) == SIZE_BOTH);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
	}

	u8 partial_in[10]{};
	unsigned read_size = 0;
	io::read(stream, partial_in, array_extent(partial_in), &read_size);
	TOGO_ASSERTE(!io::status(stream).fail() && io::status(stream).eof());
	TOGO_ASSERTE(read_size == array_extent(partial_out));
	TOGO_ASSERTE(std::memcmp(partial_in, partial_out, read_size) == 0);
}

void test_writer(IWriter& stream, bool const seekable) {
	TestStreamState s{};
	TOGO_ASSERTE(io::write_value(stream, s.i8 ));
	TOGO_ASSERTE(io::write_value(stream, s.i16));
	TOGO_ASSERTE(io::write_value(stream, s.i32));
	TOGO_ASSERTE(io::write_value(stream, s.i64));
	TOGO_ASSERTE(io::write_value(stream, s.f32));
	TOGO_ASSERTE(io::write_value(stream, s.f64));

	if (seekable) {
		TOGO_ASSERTE(io::position(dynamic_cast<IStreamSeekable&>(stream)) == SIZE_VALUES);
	}

	u32 bit = 128;
	for (u32& v : s.array) {
		v = bit;
		bit <<= 1;
	}
	TOGO_ASSERTE(io::write_array(stream, s.array, array_extent(&TestStreamState::array)));

	if (seekable) {
		IStreamSeekable& stream_seekable = dynamic_cast<IStreamSeekable&>(stream);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
		TOGO_ASSERTE(!io::status(stream_seekable).eof());

		TOGO_ASSERTE(io::seek_relative(stream_seekable, -SIZE_ARRAY) == SIZE_VALUES);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_VALUES);
		TOGO_ASSERTE(io::seek_to(stream_seekable, 0) == 0);
		TOGO_ASSERTE(io::position(stream_seekable) == 0);

		TOGO_ASSERTE(io::seek_to(stream_seekable, SIZE_BOTH) == SIZE_BOTH);
		TOGO_ASSERTE(io::position(stream_seekable) == SIZE_BOTH);
	}

	TOGO_ASSERTE(io::write(stream, partial_out, array_extent(partial_out)));
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_tree_grafting.cpp
 *
 * Takes assignments to variables that are dereferenced only once and
 * pastes the RHS expression into where the variable is dereferenced.
 *
 * In the process of various operations like function inlining and
 * tertiary op handling, we'll end up with our expression trees having
 * been chopped up into a series of assignments of short expressions
 * to temps.  Other passes like ir_algebraic.cpp would prefer to see
 * the deepest expression trees they can to try to optimize them.
 *
 * This is a lot like copy propagaton.  In comparison, copy
 * propagation only acts on plain copies, not arbitrary expressions on
 * the RHS.  Generally, we wouldn't want to go pasting some
 * complicated expression everywhere it got used, though, so we don't
 * handle expressions in that pass.
 *
 * The hard part is making sure we don't move an expression across
 * some other assignments that would change the value of the
 * expression.  So we split this into two passes: First, find the
 * variables in our scope which are written to once and read once, and
 * then go through basic blocks seeing if we find an opportunity to
 * move those expressions safely.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_variable_refcount.h"
#include "ir_basic_block.h"
#include "ir_optimization.h"
#include "glsl_types.h"

static bool debug = false;

class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
public:
   ir_tree_grafting_visitor(ir_assignment *graft_assign,
			    ir_variable *graft_var)
   {
      this->progress = false;
      this->graft_assign = graft_assign;
      this->graft_var = graft_var;
   }

   virtual ir_visitor_status visit_leave(class ir_assignment *);
   virtual ir_visitor_status visit_enter(class ir_call *);
   virtual ir_visitor_status visit_enter(class ir_expression *);
   virtual ir_visitor_status visit_enter(class ir_function *);
   virtual ir_visitor_status visit_enter(class ir_function_signature *);
   virtual ir_visitor_status visit_enter(class ir_if *);
   virtual ir_visitor_status visit_enter(class ir_loop *);
   virtual ir_visitor_status visit_enter(class ir_swizzle *);
   virtual ir_visitor_status visit_enter(class ir_texture *);

   bool do_graft(ir_rvalue **rvalue);

   bool progress;
   ir_variable *graft_var;
   ir_assignment *graft_assign;
};

struct find_deref_info {
   ir_variable *var;
   bool found;
};

void
dereferences_variable_callback(ir_instruction *ir, void *data)
{
   struct find_deref_info *info = (struct find_deref_info *)data;

   if (ir == info->var)
      info->found = true;
}

static bool
dereferences_variable(ir_instruction *ir, ir_variable *var)
{
   struct find_deref_info info;

   info.var = var;
   info.found = false;

   visit_tree(ir, dereferences_variable_callback, &info);

   return info.found;
}

bool
ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return false;

   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();

   if (!deref || deref->var != this->graft_var)
      return false;

   if (debug) {
      printf("GRAFTING:\n");
      this->graft_assign->rhs->print();
      printf("\n");
      printf("TO:\n");
      (*rvalue)->print();
      printf("\n");
   }

   this->graft_assign->remove();
   *rvalue = this->graft_assign->rhs;

   this->progress = true;
   return true;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
{
   (void)ir;
   /* Do not traverse into the body of the loop since that is a
    * different basic block.
    */
   return visit_stop;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
{
   if (do_graft(&ir->rhs) ||
       do_graft(&ir->condition))
      return visit_stop;

   /* If this assignment updates a variable used in the assignment
    * we're trying to graft, then we're done.
    */
   if (dereferences_variable(this->graft_assign->rhs,
			     ir->lhs->variable_referenced())) {
      if (debug) {
	 printf("graft killed by: ");
	 ir->print();
	 printf("\n");
      }
      return visit_stop;
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_function *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
{
   (void)ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_call *ir)
{
   /* Reminder: iterating ir_call iterates its parameters. */
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *ir = (ir_rvalue *)iter.get();
      ir_rvalue *new_ir = ir;

      if (do_graft(&new_ir)) {
	 ir->replace_with(new_ir);
	 return visit_stop;
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
{
   for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
      if (do_graft(&ir->operands[i]))
	 return visit_stop;
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_if *ir)
{
   if (do_graft(&ir->condition))
      return visit_stop;

   /* Do not traverse into the body of the if-statement since that is a
    * different basic block.
    */
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
{
   if (do_graft(&ir->val))
      return visit_stop;

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
{
   if (do_graft(&ir->coordinate) ||
       do_graft(&ir->projector) ||
       do_graft(&ir->shadow_comparitor))
	 return visit_stop;

   switch (ir->op) {
   case ir_tex:
      break;
   case ir_txb:
      if (do_graft(&ir->lod_info.bias))
	 return visit_stop;
      break;
   case ir_txf:
   case ir_txl:
      if (do_graft(&ir->lod_info.lod))
	 return visit_stop;
      break;
   case ir_txd:
      if (do_graft(&ir->lod_info.grad.dPdx) ||
	  do_graft(&ir->lod_info.grad.dPdy))
	 return visit_stop;
      break;
   }

   return visit_continue;
}

struct tree_grafting_info {
   ir_variable_refcount_visitor *refs;
   bool progress;
};

static bool
try_tree_grafting(ir_assignment *start,
		  ir_variable *lhs_var,
		  ir_instruction *bb_last)
{
   ir_tree_grafting_visitor v(start, lhs_var);

   if (debug) {
      printf("trying to graft: ");
      lhs_var->print();
      printf("\n");
   }

   for (ir_instruction *ir = (ir_instruction *)start->next;
	ir != bb_last->next;
	ir = (ir_instruction *)ir->next) {

      if (debug) {
	 printf("- ");
	 ir->print();
	 printf("\n");
      }

      ir_visitor_status s = ir->accept(&v);
      if (s == visit_stop)
	 return v.progress;
   }

   return false;
}

static void
tree_grafting_basic_block(ir_instruction *bb_first,
			  ir_instruction *bb_last,
			  void *data)
{
   struct tree_grafting_info *info = (struct tree_grafting_info *)data;
   ir_instruction *ir, *next;

   for (ir = bb_first, next = (ir_instruction *)ir->next;
	ir != bb_last->next;
	ir = next, next = (ir_instruction *)ir->next) {
      ir_assignment *assign = ir->as_assignment();

      if (!assign)
	 continue;

      ir_variable *lhs_var = assign->whole_variable_written();
      if (!lhs_var)
	 continue;

      if (lhs_var->mode == ir_var_out ||
	  lhs_var->mode == ir_var_inout)
	 continue;

      struct variable_entry *entry = info->refs->get_variable_entry(lhs_var);

      if (!entry->declaration ||
	  entry->assigned_count != 1 ||
	  entry->referenced_count != 2)
	 continue;

      assert(assign == entry->assign);

      /* Found a possibly graftable assignment.  Now, walk through the
       * rest of the BB seeing if the deref is here, and if nothing interfered with
       * pasting its expression's values in between.
       */
      info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
   }
}

/**
 * Does a copy propagation pass on the code present in the instruction stream.
 */
bool
do_tree_grafting(exec_list *instructions)
{
   ir_variable_refcount_visitor refs;
   struct tree_grafting_info info;

   info.progress = false;
   info.refs = &refs;

   visit_list_elements(info.refs, instructions);

   call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);

   return info.progress;
}
<commit_msg>glsl2: Fix the dereferences_variable check in ir_tree_grafting.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_tree_grafting.cpp
 *
 * Takes assignments to variables that are dereferenced only once and
 * pastes the RHS expression into where the variable is dereferenced.
 *
 * In the process of various operations like function inlining and
 * tertiary op handling, we'll end up with our expression trees having
 * been chopped up into a series of assignments of short expressions
 * to temps.  Other passes like ir_algebraic.cpp would prefer to see
 * the deepest expression trees they can to try to optimize them.
 *
 * This is a lot like copy propagaton.  In comparison, copy
 * propagation only acts on plain copies, not arbitrary expressions on
 * the RHS.  Generally, we wouldn't want to go pasting some
 * complicated expression everywhere it got used, though, so we don't
 * handle expressions in that pass.
 *
 * The hard part is making sure we don't move an expression across
 * some other assignments that would change the value of the
 * expression.  So we split this into two passes: First, find the
 * variables in our scope which are written to once and read once, and
 * then go through basic blocks seeing if we find an opportunity to
 * move those expressions safely.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_variable_refcount.h"
#include "ir_basic_block.h"
#include "ir_optimization.h"
#include "glsl_types.h"

static bool debug = false;

class ir_tree_grafting_visitor : public ir_hierarchical_visitor {
public:
   ir_tree_grafting_visitor(ir_assignment *graft_assign,
			    ir_variable *graft_var)
   {
      this->progress = false;
      this->graft_assign = graft_assign;
      this->graft_var = graft_var;
   }

   virtual ir_visitor_status visit_leave(class ir_assignment *);
   virtual ir_visitor_status visit_enter(class ir_call *);
   virtual ir_visitor_status visit_enter(class ir_expression *);
   virtual ir_visitor_status visit_enter(class ir_function *);
   virtual ir_visitor_status visit_enter(class ir_function_signature *);
   virtual ir_visitor_status visit_enter(class ir_if *);
   virtual ir_visitor_status visit_enter(class ir_loop *);
   virtual ir_visitor_status visit_enter(class ir_swizzle *);
   virtual ir_visitor_status visit_enter(class ir_texture *);

   bool do_graft(ir_rvalue **rvalue);

   bool progress;
   ir_variable *graft_var;
   ir_assignment *graft_assign;
};

struct find_deref_info {
   ir_variable *var;
   bool found;
};

void
dereferences_variable_callback(ir_instruction *ir, void *data)
{
   struct find_deref_info *info = (struct find_deref_info *)data;
   ir_dereference_variable *deref = ir->as_dereference_variable();

   if (deref && deref->var == info->var)
      info->found = true;
}

static bool
dereferences_variable(ir_instruction *ir, ir_variable *var)
{
   struct find_deref_info info;

   info.var = var;
   info.found = false;

   visit_tree(ir, dereferences_variable_callback, &info);

   return info.found;
}

bool
ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return false;

   ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();

   if (!deref || deref->var != this->graft_var)
      return false;

   if (debug) {
      printf("GRAFTING:\n");
      this->graft_assign->print();
      printf("\n");
      printf("TO:\n");
      (*rvalue)->print();
      printf("\n");
   }

   this->graft_assign->remove();
   *rvalue = this->graft_assign->rhs;

   this->progress = true;
   return true;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_loop *ir)
{
   (void)ir;
   /* Do not traverse into the body of the loop since that is a
    * different basic block.
    */
   return visit_stop;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_leave(ir_assignment *ir)
{
   if (do_graft(&ir->rhs) ||
       do_graft(&ir->condition))
      return visit_stop;

   /* If this assignment updates a variable used in the assignment
    * we're trying to graft, then we're done.
    */
   if (dereferences_variable(this->graft_assign->rhs,
			     ir->lhs->variable_referenced())) {
      if (debug) {
	 printf("graft killed by: ");
	 ir->print();
	 printf("\n");
      }
      return visit_stop;
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_function *ir)
{
   (void) ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir)
{
   (void)ir;
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_call *ir)
{
   /* Reminder: iterating ir_call iterates its parameters. */
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_rvalue *ir = (ir_rvalue *)iter.get();
      ir_rvalue *new_ir = ir;

      if (do_graft(&new_ir)) {
	 ir->replace_with(new_ir);
	 return visit_stop;
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_expression *ir)
{
   for (unsigned int i = 0; i < ir->get_num_operands(); i++) {
      if (do_graft(&ir->operands[i]))
	 return visit_stop;
   }

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_if *ir)
{
   if (do_graft(&ir->condition))
      return visit_stop;

   /* Do not traverse into the body of the if-statement since that is a
    * different basic block.
    */
   return visit_continue_with_parent;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir)
{
   if (do_graft(&ir->val))
      return visit_stop;

   return visit_continue;
}

ir_visitor_status
ir_tree_grafting_visitor::visit_enter(ir_texture *ir)
{
   if (do_graft(&ir->coordinate) ||
       do_graft(&ir->projector) ||
       do_graft(&ir->shadow_comparitor))
	 return visit_stop;

   switch (ir->op) {
   case ir_tex:
      break;
   case ir_txb:
      if (do_graft(&ir->lod_info.bias))
	 return visit_stop;
      break;
   case ir_txf:
   case ir_txl:
      if (do_graft(&ir->lod_info.lod))
	 return visit_stop;
      break;
   case ir_txd:
      if (do_graft(&ir->lod_info.grad.dPdx) ||
	  do_graft(&ir->lod_info.grad.dPdy))
	 return visit_stop;
      break;
   }

   return visit_continue;
}

struct tree_grafting_info {
   ir_variable_refcount_visitor *refs;
   bool progress;
};

static bool
try_tree_grafting(ir_assignment *start,
		  ir_variable *lhs_var,
		  ir_instruction *bb_last)
{
   ir_tree_grafting_visitor v(start, lhs_var);

   if (debug) {
      printf("trying to graft: ");
      lhs_var->print();
      printf("\n");
   }

   for (ir_instruction *ir = (ir_instruction *)start->next;
	ir != bb_last->next;
	ir = (ir_instruction *)ir->next) {

      if (debug) {
	 printf("- ");
	 ir->print();
	 printf("\n");
      }

      ir_visitor_status s = ir->accept(&v);
      if (s == visit_stop)
	 return v.progress;
   }

   return false;
}

static void
tree_grafting_basic_block(ir_instruction *bb_first,
			  ir_instruction *bb_last,
			  void *data)
{
   struct tree_grafting_info *info = (struct tree_grafting_info *)data;
   ir_instruction *ir, *next;

   for (ir = bb_first, next = (ir_instruction *)ir->next;
	ir != bb_last->next;
	ir = next, next = (ir_instruction *)ir->next) {
      ir_assignment *assign = ir->as_assignment();

      if (!assign)
	 continue;

      ir_variable *lhs_var = assign->whole_variable_written();
      if (!lhs_var)
	 continue;

      if (lhs_var->mode == ir_var_out ||
	  lhs_var->mode == ir_var_inout)
	 continue;

      struct variable_entry *entry = info->refs->get_variable_entry(lhs_var);

      if (!entry->declaration ||
	  entry->assigned_count != 1 ||
	  entry->referenced_count != 2)
	 continue;

      assert(assign == entry->assign);

      /* Found a possibly graftable assignment.  Now, walk through the
       * rest of the BB seeing if the deref is here, and if nothing interfered with
       * pasting its expression's values in between.
       */
      info->progress |= try_tree_grafting(assign, lhs_var, bb_last);
   }
}

/**
 * Does a copy propagation pass on the code present in the instruction stream.
 */
bool
do_tree_grafting(exec_list *instructions)
{
   ir_variable_refcount_visitor refs;
   struct tree_grafting_info info;

   info.progress = false;
   info.refs = &refs;

   visit_list_elements(info.refs, instructions);

   call_for_basic_blocks(instructions, tree_grafting_basic_block, &info);

   return info.progress;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <boost/lexical_cast.hpp>
#include <gtest/gtest.h>
#include "dxjson/dxjson.h"
#include "dxcpp.h"

using namespace std;
using namespace dx;

// TODO: Finish writing tests for other classes.

//////////////
// DXRecord //
//////////////

class DXRecordTest : public testing::Test {
public:
  static const JSON example_JSON;
  static const JSON another_example_JSON;
  DXRecord dxrecord;
};

const JSON DXRecordTest::example_JSON =
  JSON::parse("{\"foo\": \"bar\", \"alpha\": [1, 2, 3]}");
const JSON DXRecordTest::another_example_JSON =
  JSON::parse("[\"foo\", \"bar\", {\"alpha\": [1, 2.340, -10]}]");

TEST_F(DXRecordTest, CreateDestroyJSONTest) {
  DXRecord first_record = DXRecord::newDXRecord(DXRecordTest::example_JSON);
  ASSERT_EQ(DXRecordTest::example_JSON,
	    first_record.get());
  string firstID = first_record.getID();

  DXRecord second_record = DXRecord(first_record.getID());
  ASSERT_EQ(first_record.getID(), second_record.getID());
  ASSERT_EQ(first_record.get(), second_record.get());

  second_record.create(DXRecordTest::example_JSON);
  ASSERT_NE(first_record.getID(), second_record.getID());
  ASSERT_EQ(first_record.get(), second_record.get());

  ASSERT_NO_THROW(first_record.describe());

  first_record.destroy();
  ASSERT_NO_THROW(first_record.getID());
  ASSERT_THROW(first_record.describe(), DXAPIError);
  second_record.destroy();
  ASSERT_THROW(second_record.describe(), DXAPIError);
}

TEST_F(DXRecordTest, GetSetJSONTest) {
  DXRecord dxrecord = DXRecord::newDXRecord(DXRecordTest::example_JSON);
  ASSERT_EQ(DXRecordTest::example_JSON, dxrecord.get());

  dxrecord.set(DXRecordTest::another_example_JSON);
  ASSERT_NE(DXRecordTest::example_JSON, dxrecord.get());
  ASSERT_EQ(DXRecordTest::another_example_JSON, dxrecord.get());
  dxrecord.destroy();
}

////////////
// DXFile //
////////////

string getBaseName(const string& filename) {
  size_t lastslash = filename.find_last_of("/\\");
  return filename.substr(lastslash+1);
}

string foofilename = "";

class DXFileTest : public testing::Test {
public:
  static const string foostr;
  string tempfilename;

  DXFile dxfile;

protected:
  virtual void SetUp() {
    char name [L_tmpnam];
    tmpnam(name);
    tempfilename = string(name);

    if (foofilename == "") {
      char fooname [L_tmpnam];
      tmpnam(fooname);
      foofilename = string(fooname);
      ofstream foofile(fooname);
      foofile << foostr;
      foofile.close();
    }
  }

  virtual void TearDown() {
    remove(tempfilename.c_str());

    try {
      dxfile.destroy();
    } catch (...) {
    }
  }
};

const string DXFileTest::foostr = "foo\n";

TEST_F(DXFileTest, UploadDownloadFiles) {
  dxfile = DXFile::uploadLocalFile(foofilename);
  dxfile.waitOnClose();
  ASSERT_FALSE(dxfile.is_open());

  EXPECT_EQ(getBaseName(foofilename),
  	    dxfile.getProperties()["name"].get<string>());

  DXFile::downloadDXFile(dxfile.getID(), tempfilename);

  string stored;
  ifstream downloadedfile(tempfilename.c_str());
  downloadedfile >> stored;
  ASSERT_EQ(foostr, stored);
}

TEST_F(DXFileTest, WriteReadFile) {
  // TODO

  dxfile = DXFile::newDXFile();
  dxfile.write(DXFileTest::foostr.data(), DXFileTest::foostr.length());

  DXFile same_dxfile = DXFile::openDXFile(dxfile.getID());
  same_dxfile.waitOnClose();

  char buf[10];
  same_dxfile.read(buf, foostr.length()+1);
  ASSERT_EQ(buf, DXFileTest::foostr.c_str());
  EXPECT_TRUE(same_dxfile.eof());

  same_dxfile.seek(1);
  EXPECT_FALSE(same_dxfile.eof());
  same_dxfile.read(buf, foostr.length());
  ASSERT_EQ(buf, DXFileTest::foostr.substr(1).c_str());
}

TEST_F(DXFileTest, StreamingOperators) {
  dxfile = DXFile::newDXFile();
  stringstream samestr;
  dxfile  << "foo" << 1 << " " << 2.5 << endl;
  samestr << "foo" << 1 << " " << 2.5 << endl;
  dxfile  << "bar" << endl;
  samestr << "bar" << endl;
  dxfile.close(true);

  string stored;
  DXFile::downloadDXFile(dxfile.getID(), tempfilename);
  ifstream downloadedfile(tempfilename.c_str());
  downloadedfile >> stored;
  ASSERT_EQ(samestr.str(), stored);

  // TODO: Test >> if/when implemented
}

/////////////
// DXTable //
/////////////

class DXTableTest : public testing::Test {
public:
  DXTable dxtable;
  static const JSON columns;

protected:
  virtual void TearDown() {
    try {
      dxtable.destroy();
    } catch (...) {
    }
  }
};

const JSON DXTableTest::columns = JSON::parse("[\"a:string\", \"b:int32\"]");

TEST_F(DXTableTest, ColumnDescTest) {
  JSON columns(JSON_ARRAY);
  columns.push_back(DXTable::columnDesc("a", "string"));
  columns.push_back(DXTable::columnDesc("b", "int32"));
  ASSERT_EQ(DXTableTest::columns, columns);
}

TEST_F(DXTableTest, CreateDXTableTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);
  JSON desc = dxtable.describe();
  ASSERT_EQ(DXTableTest::columns, desc["columns"]);
}

TEST_F(DXTableTest, ExtendDXTableTest) {
  DXTable table_to_extend = DXTable::newDXTable(DXTableTest::columns);
  try {
    table_to_extend.addRows(JSON::parse("[[\"Row 1\", 1], [\"Row 2\", 2]]"));
    table_to_extend.close(true);
    EXPECT_EQ("closed", table_to_extend.describe()["state"].get<string>());

    JSON more_cols = JSON::parse("[\"c:int32\", \"d:string\"]");
    dxtable = DXTable::extendDXTable(table_to_extend.getID(),
				  more_cols);

    ASSERT_EQ(JSON::parse("[\"a:string\", \"b:int32\", \"c:int32\", \"d:string\"]"),
	      dxtable.describe()["columns"]);

    dxtable.addRows(JSON::parse("[[10, \"End row 1\"], [20, \"End row 2\"]]"));

    dxtable.close(true);
  } catch (int e) {
    try {
      table_to_extend.destroy();
    } catch (...) {
    }
    throw e;
  }
}

TEST_F(DXTableTest, AddRowsTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);
  dxtable.addRows(JSON(JSON_ARRAY), 9999);

  JSON empty_row = JSON(JSON_ARRAY);
  empty_row.push_back(JSON(JSON_ARRAY));
  ASSERT_THROW(dxtable.addRows(empty_row, 9997), DXAPIError);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i) + "]]";
    dxtable.addRows(JSON::parse(rowstr), i+1);
  }

  dxtable.close();

  ASSERT_THROW(dxtable.close(), DXAPIError);
}

TEST_F(DXTableTest, AddRowsNoIndexTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i+1) + "]]";
    dxtable.addRows(JSON::parse(rowstr));
  }
  dxtable.flush();
  JSON desc = dxtable.describe();
  EXPECT_EQ(1, desc["parts"].size());

  dxtable.close(true);

  desc = dxtable.describe();
  EXPECT_EQ(64, desc["size"].get<int>());
}

TEST_F(DXTableTest, InvalidSpecTest) {
  ASSERT_THROW(DXTable::newDXTable(JSON::parse("[\"a:string\", \"b:muffins\"]")),
	       DXAPIError);
}

TEST_F(DXTableTest, GetRowsTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i+1) + "]]";
    dxtable.addRows(JSON::parse(rowstr), i+1);
  }
  dxtable.close(true);

  JSON rows = dxtable.getRows();
  EXPECT_EQ(64, rows["size"].get<int>());
  EXPECT_EQ(JSON_NULL, rows["next"].type());
  EXPECT_EQ(64, rows["data"].size());
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  loadFromEnvironment();
  int result = RUN_ALL_TESTS();
  remove(foofilename.c_str());
  return result;
}
<commit_msg>disabling dxfile tests (not fully implemented yet)<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <boost/lexical_cast.hpp>
#include <gtest/gtest.h>
#include "dxjson/dxjson.h"
#include "dxcpp.h"

using namespace std;
using namespace dx;

// TODO: Finish writing tests for other classes.

//////////////
// DXRecord //
//////////////

class DXRecordTest : public testing::Test {
public:
  static const JSON example_JSON;
  static const JSON another_example_JSON;
  DXRecord dxrecord;
};

const JSON DXRecordTest::example_JSON =
  JSON::parse("{\"foo\": \"bar\", \"alpha\": [1, 2, 3]}");
const JSON DXRecordTest::another_example_JSON =
  JSON::parse("[\"foo\", \"bar\", {\"alpha\": [1, 2.340, -10]}]");

TEST_F(DXRecordTest, CreateDestroyJSONTest) {
  DXRecord first_record = DXRecord::newDXRecord(DXRecordTest::example_JSON);
  ASSERT_EQ(DXRecordTest::example_JSON,
	    first_record.get());
  string firstID = first_record.getID();

  DXRecord second_record = DXRecord(first_record.getID());
  ASSERT_EQ(first_record.getID(), second_record.getID());
  ASSERT_EQ(first_record.get(), second_record.get());

  second_record.create(DXRecordTest::example_JSON);
  ASSERT_NE(first_record.getID(), second_record.getID());
  ASSERT_EQ(first_record.get(), second_record.get());

  ASSERT_NO_THROW(first_record.describe());

  first_record.destroy();
  ASSERT_NO_THROW(first_record.getID());
  ASSERT_THROW(first_record.describe(), DXAPIError);
  second_record.destroy();
  ASSERT_THROW(second_record.describe(), DXAPIError);
}

TEST_F(DXRecordTest, GetSetJSONTest) {
  DXRecord dxrecord = DXRecord::newDXRecord(DXRecordTest::example_JSON);
  ASSERT_EQ(DXRecordTest::example_JSON, dxrecord.get());

  dxrecord.set(DXRecordTest::another_example_JSON);
  ASSERT_NE(DXRecordTest::example_JSON, dxrecord.get());
  ASSERT_EQ(DXRecordTest::another_example_JSON, dxrecord.get());
  dxrecord.destroy();
}

////////////
// DXFile //
////////////

string getBaseName(const string& filename) {
  size_t lastslash = filename.find_last_of("/\\");
  return filename.substr(lastslash+1);
}

string foofilename = "";

class DISABLED_DXFileTest : public testing::Test {
public:
  static const string foostr;
  string tempfilename;

  DXFile dxfile;

protected:
  virtual void SetUp() {
    char name [L_tmpnam];
    tmpnam(name);
    tempfilename = string(name);

    if (foofilename == "") {
      char fooname [L_tmpnam];
      tmpnam(fooname);
      foofilename = string(fooname);
      ofstream foofile(fooname);
      foofile << foostr;
      foofile.close();
    }
  }

  virtual void TearDown() {
    remove(tempfilename.c_str());

    try {
      dxfile.destroy();
    } catch (...) {
    }
  }
};

const string DISABLED_DXFileTest::foostr = "foo\n";

TEST_F(DISABLED_DXFileTest, UploadDownloadFiles) {
  dxfile = DXFile::uploadLocalFile(foofilename);
  dxfile.waitOnClose();
  ASSERT_FALSE(dxfile.is_open());

  EXPECT_EQ(getBaseName(foofilename),
  	    dxfile.getProperties()["name"].get<string>());

  DXFile::downloadDXFile(dxfile.getID(), tempfilename);

  string stored;
  ifstream downloadedfile(tempfilename.c_str());
  downloadedfile >> stored;
  ASSERT_EQ(foostr, stored);
}

TEST_F(DISABLED_DXFileTest, WriteReadFile) {
  // TODO

  dxfile = DXFile::newDXFile();
  dxfile.write(DISABLED_DXFileTest::foostr.data(), DISABLED_DXFileTest::foostr.length());

  DXFile same_dxfile = DXFile::openDXFile(dxfile.getID());
  same_dxfile.waitOnClose();

  char buf[10];
  same_dxfile.read(buf, foostr.length()+1);
  ASSERT_EQ(buf, DISABLED_DXFileTest::foostr.c_str());
  EXPECT_TRUE(same_dxfile.eof());

  same_dxfile.seek(1);
  EXPECT_FALSE(same_dxfile.eof());
  same_dxfile.read(buf, foostr.length());
  ASSERT_EQ(buf, DISABLED_DXFileTest::foostr.substr(1).c_str());
}

TEST_F(DISABLED_DXFileTest, StreamingOperators) {
  dxfile = DXFile::newDXFile();
  stringstream samestr;
  dxfile  << "foo" << 1 << " " << 2.5 << endl;
  samestr << "foo" << 1 << " " << 2.5 << endl;
  dxfile  << "bar" << endl;
  samestr << "bar" << endl;
  dxfile.close(true);

  string stored;
  DXFile::downloadDXFile(dxfile.getID(), tempfilename);
  ifstream downloadedfile(tempfilename.c_str());
  downloadedfile >> stored;
  ASSERT_EQ(samestr.str(), stored);

  // TODO: Test >> if/when implemented
}

/////////////
// DXTable //
/////////////

class DXTableTest : public testing::Test {
public:
  DXTable dxtable;
  static const JSON columns;

protected:
  virtual void TearDown() {
    try {
      dxtable.destroy();
    } catch (...) {
    }
  }
};

const JSON DXTableTest::columns = JSON::parse("[\"a:string\", \"b:int32\"]");

TEST_F(DXTableTest, ColumnDescTest) {
  JSON columns(JSON_ARRAY);
  columns.push_back(DXTable::columnDesc("a", "string"));
  columns.push_back(DXTable::columnDesc("b", "int32"));
  ASSERT_EQ(DXTableTest::columns, columns);
}

TEST_F(DXTableTest, CreateDXTableTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);
  JSON desc = dxtable.describe();
  ASSERT_EQ(DXTableTest::columns, desc["columns"]);
}

TEST_F(DXTableTest, ExtendDXTableTest) {
  DXTable table_to_extend = DXTable::newDXTable(DXTableTest::columns);
  try {
    table_to_extend.addRows(JSON::parse("[[\"Row 1\", 1], [\"Row 2\", 2]]"));
    table_to_extend.close(true);
    EXPECT_EQ("closed", table_to_extend.describe()["state"].get<string>());

    JSON more_cols = JSON::parse("[\"c:int32\", \"d:string\"]");
    dxtable = DXTable::extendDXTable(table_to_extend.getID(),
				  more_cols);

    ASSERT_EQ(JSON::parse("[\"a:string\", \"b:int32\", \"c:int32\", \"d:string\"]"),
	      dxtable.describe()["columns"]);

    dxtable.addRows(JSON::parse("[[10, \"End row 1\"], [20, \"End row 2\"]]"));

    dxtable.close(true);
  } catch (int e) {
    try {
      table_to_extend.destroy();
    } catch (...) {
    }
    throw e;
  }
}

TEST_F(DXTableTest, AddRowsTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);
  dxtable.addRows(JSON(JSON_ARRAY), 9999);

  JSON empty_row = JSON(JSON_ARRAY);
  empty_row.push_back(JSON(JSON_ARRAY));
  ASSERT_THROW(dxtable.addRows(empty_row, 9997), DXAPIError);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i) + "]]";
    dxtable.addRows(JSON::parse(rowstr), i+1);
  }

  dxtable.close();

  ASSERT_THROW(dxtable.close(), DXAPIError);
}

TEST_F(DXTableTest, AddRowsNoIndexTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i+1) + "]]";
    dxtable.addRows(JSON::parse(rowstr));
  }
  dxtable.flush();
  JSON desc = dxtable.describe();
  EXPECT_EQ(1, desc["parts"].size());

  dxtable.close(true);

  desc = dxtable.describe();
  EXPECT_EQ(64, desc["size"].get<int>());
}

TEST_F(DXTableTest, InvalidSpecTest) {
  ASSERT_THROW(DXTable::newDXTable(JSON::parse("[\"a:string\", \"b:muffins\"]")),
	       DXAPIError);
}

TEST_F(DXTableTest, GetRowsTest) {
  dxtable = DXTable::newDXTable(DXTableTest::columns);

  for (int i = 0; i < 64; i++) {
    string rowstr = "[[\"Row " + boost::lexical_cast<string>(i) +
      "\", " + boost::lexical_cast<string>(i+1) + "]]";
    dxtable.addRows(JSON::parse(rowstr), i+1);
  }
  dxtable.close(true);

  JSON rows = dxtable.getRows();
  EXPECT_EQ(64, rows["size"].get<int>());
  EXPECT_EQ(JSON_NULL, rows["next"].type());
  EXPECT_EQ(64, rows["data"].size());
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  loadFromEnvironment();
  int result = RUN_ALL_TESTS();
  remove(foofilename.c_str());
  return result;
}
<|endoftext|>


<commit_before>#include "JsDebugger.h"
#include "v8-debug.h"
#include <assert.h>
#include <android/log.h>

using namespace std;
using namespace tns;

JsDebugger::JsDebugger()
{
}

void JsDebugger::Init(const string& packageName, int port)
{
	s_packageName = packageName;
	s_port = port;

	JEnv env;
	s_JsDebuggerClass = env.FindClass("com/tns/JsDebugger");
	assert(s_JsDebuggerClass != nullptr);
	s_DispatchMessagesDebugAgentCallback = env.GetStaticMethodID(s_JsDebuggerClass, "dispatchMessagesDebugAgentCallback", "()Z");
	assert(s_DispatchMessagesDebugAgentCallback != nullptr);

	v8::Debug::SetDebugMessageDispatchHandler(DispatchMessagesDebugAgentCallback);
}

int JsDebugger::GetDebuggerPort()
{
	return s_port;
}

int JsDebugger::GetCurrentDebuggerPort()
{
	return s_currentPort;
}

string JsDebugger::GetPackageName()
{
	return s_packageName;
}

void JsDebugger::DispatchMessagesDebugAgentCallback()
{
	JEnv env;
	jboolean success = env.CallStaticBooleanMethod(s_JsDebuggerClass, s_DispatchMessagesDebugAgentCallback);
	assert(JNI_TRUE == success);
}

void JsDebugger::ProcessDebugMessages()
{
	v8::Debug::ProcessDebugMessages();
}

bool JsDebugger::EnableAgent(const std::string& name, int port, bool waitForConnection)
{
	bool success = v8::Debug::EnableAgent(name.c_str(), port, waitForConnection);
	__android_log_print(ANDROID_LOG_DEBUG, "TNS.Native", "Enable V8 debugger (app=%s, port=%d, waitForConnection=%d, success=%d)", name.c_str(), port, waitForConnection, success);
	s_currentPort = success ? port : INVALID_PORT;
	return success;
}

void JsDebugger::DisableAgent()
{
	v8::Debug::DisableAgent();
	s_currentPort = INVALID_PORT;
}

int JsDebugger::s_port = JsDebugger::INVALID_PORT;
int JsDebugger::s_currentPort = JsDebugger::INVALID_PORT;
string JsDebugger::s_packageName = "";
jclass JsDebugger::s_JsDebuggerClass = nullptr;
jmethodID JsDebugger::s_DispatchMessagesDebugAgentCallback = nullptr;

<commit_msg>Add more logging.<commit_after>#include "JsDebugger.h"
#include "v8-debug.h"
#include <assert.h>
#include <android/log.h>

using namespace std;
using namespace tns;

JsDebugger::JsDebugger()
{
}

void JsDebugger::Init(const string& packageName, int port)
{
	s_packageName = packageName;
	s_port = port;

	JEnv env;
	s_JsDebuggerClass = env.FindClass("com/tns/JsDebugger");
	assert(s_JsDebuggerClass != nullptr);
	s_DispatchMessagesDebugAgentCallback = env.GetStaticMethodID(s_JsDebuggerClass, "dispatchMessagesDebugAgentCallback", "()Z");
	assert(s_DispatchMessagesDebugAgentCallback != nullptr);

	v8::Debug::SetDebugMessageDispatchHandler(DispatchMessagesDebugAgentCallback);
}

int JsDebugger::GetDebuggerPort()
{
	return s_port;
}

int JsDebugger::GetCurrentDebuggerPort()
{
	return s_currentPort;
}

string JsDebugger::GetPackageName()
{
	return s_packageName;
}

void JsDebugger::DispatchMessagesDebugAgentCallback()
{
	JEnv env;
	jboolean success = env.CallStaticBooleanMethod(s_JsDebuggerClass, s_DispatchMessagesDebugAgentCallback);
	assert(JNI_TRUE == success);
}

void JsDebugger::ProcessDebugMessages()
{
	v8::Debug::ProcessDebugMessages();
}

bool JsDebugger::EnableAgent(const std::string& name, int port, bool waitForConnection)
{
	bool success = v8::Debug::EnableAgent(name.c_str(), port, waitForConnection);
	__android_log_print(ANDROID_LOG_DEBUG, "TNS.Native", "Enable V8 debugger (app=%s, port=%d, waitForConnection=%d, success=%d)", name.c_str(), port, waitForConnection, success);
	s_currentPort = success ? port : INVALID_PORT;
	return success;
}

void JsDebugger::DisableAgent()
{
	v8::Debug::DisableAgent();
	s_currentPort = INVALID_PORT;
	__android_log_print(ANDROID_LOG_DEBUG, "TNS.Native", "Disable V8 debugger");
}

int JsDebugger::s_port = JsDebugger::INVALID_PORT;
int JsDebugger::s_currentPort = JsDebugger::INVALID_PORT;
string JsDebugger::s_packageName = "";
jclass JsDebugger::s_JsDebuggerClass = nullptr;
jmethodID JsDebugger::s_DispatchMessagesDebugAgentCallback = nullptr;

<|endoftext|>


<commit_before>#include "../tlang.h"
#include <taichi/system/timer.h>
#include <openvdb/openvdb.h>
#include <openvdb/io/Stream.h>
#include <openvdb/tools/Filter.h>

TLANG_NAMESPACE_BEGIN

TC_TEST("hashed_3d") {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog;

  Global(x, i32);
  Global(sum, i32);

  int n = 256;

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);
    root.hashed({i, j, k}, n).place(x);
    root.place(sum);
  });

  x.val<int>(2, 5, 9) = 10;
  x.val<int>(12, 5, 9) = 30;
  x.val<int>(2, 115, 9) = 11;

  auto reduce = kernel([&] {
    Declare(i);
    For(i, x, [&]() { sum[Expr(0)] += x[i]; });
  });

  reduce();

  TC_ASSERT(sum.val<int>() == 51);
};

auto benchmark_vdb = [](std::vector<std::string> param) {
  TC_ASSERT(param.size() == 1);
  auto fn = param[0];

  CoreState::set_trigger_gdb_when_crash(true);
  Program prog;

  AmbientGlobal(x, f32, 0.0f);
  Global(y, f32);
  Global(sum, i32);

  int tree_config[] = {5, 4, 3};

  for (int i = 0; i < 3; i++) {
    tree_config[i] = 1 << tree_config[i];
  }

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);

    int int1_size = tree_config[0];
    int int2_size = tree_config[1];
    int leaf_size = tree_config[2];

    root.hashed({i, j, k}, 1024)
        .fixed({i, j, k}, int1_size)
        .pointer()
        .fixed({i, j, k}, int2_size)
        .pointer()
        .fixed({i, j, k}, leaf_size)
        .place(x, y);

    root.place(sum);
  });

  int num_leaves = 0;

  using GridType = openvdb::FloatGrid;
  using TreeType = GridType::TreeType;
  using RootType = TreeType::RootNodeType;  // level 3 RootNode
  TC_ASSERT(RootType::LEVEL == 3);
  using Int1Type = RootType::ChildNodeType;  // level 2 InternalNode
  using Int2Type = Int1Type::ChildNodeType;  // level 1 InternalNode
  using LeafType = TreeType::LeafNodeType;   // level 0 LeafNode

  // Initialize the OpenVDB library.  This must be called at least
  // once per program and may safely be called multiple times.
  openvdb::initialize();
  // Create an empty floating-point grid with background value 0.

  std::ifstream ifile(fn, std::ios_base::binary);
  auto grids = openvdb::io::Stream(ifile).getGrids();

  auto grid = static_cast<GridType *>((*grids)[0].get());

  auto dsl_value = [&](Expr var, openvdb::Coord coord) -> float32 & {
    int offset = 512;
    int i = coord.x() + offset, j = coord.y() + offset, k = coord.z() + offset;

    TC_ASSERT(i >= 0);
    TC_ASSERT(j >= 0);
    TC_ASSERT(k >= 0);

    return var.val<float32>(i, j, k);
  };

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      real value;
      if (!leaf.probeValue(t, value)) {
        leaf.setValueOn(t, 1.0f);
      }
      leaf.setValueOn(t, 1.0f);
      auto coord = leaf.offsetToGlobalCoord(t);
      dsl_value(x, coord) = leaf.getValue(t);
    }
    num_leaves += 1;
  }

  int counter[4] = {0};
  for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) {
    switch (iter.getDepth()) {
      case 0: {
        RootType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[0]++;
        break;
      }
      case 1: {
        Int1Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[1]++;
        break;
      }
      case 2: {
        Int2Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[2]++;
        break;
      }
      case 3: {
        LeafType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[3]++;
        auto coord = node->offsetToGlobalCoord(0);
        break;
      }
    }
  }
  TC_P(grid->activeVoxelCount());
  for (int i = 0; i < 4; i++) {
    TC_INFO("Depth {}: nodes {}", i, counter[i]);
  }

  openvdb::tools::Filter<GridType> filter(*grid);

  tbb::task_arena limited(1);

  limited.execute([&] {
    for (int i = 0; i < 1; i++)
      TC_TIME(filter.mean(1));
  });

  auto count = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { sum[Expr(0)] += 1; });
  });

  count();

  TC_P(num_leaves);
  TC_ASSERT(num_leaves * pow<3>(8) == sum.val<int>());

  auto mean_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i - 1, j, k] + x[i, j, k] + x[i + 1, j, k]);
    });
  });

  auto mean_y = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j - 1, k] + x[i, j, k] + x[i, j + 1, k]);
    });
  });

  auto mean_z = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j, k - 1] + x[i, j, k] + x[i, j, k + 1]);
    });
  });

  auto copy_y_to_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { x[i, j, k] = y[i, j, k]; });
  });

  auto mean = [&]() {
    mean_x();
    copy_y_to_x();
    mean_y();
    copy_y_to_x();
    mean_z();
    copy_y_to_x();
  };

  for (int i = 0; i < 1; i++)
    TC_TIME(mean());

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      auto coord = leaf.offsetToGlobalCoord(t);
      TC_P(t);
      TC_P(dsl_value(x, coord));
      TC_P(leaf.getValue(t));
      TC_ASSERT(dsl_value(x, coord) == leaf.getValue(t));
    }
    num_leaves += 1;
  }
};

TC_REGISTER_TASK(benchmark_vdb);

TLANG_NAMESPACE_END
<commit_msg>change vdb background<commit_after>#include "../tlang.h"
#include <taichi/system/timer.h>
#include <openvdb/openvdb.h>
#include <openvdb/io/Stream.h>
#include <openvdb/tools/Filter.h>
#include <openvdb/tools/ChangeBackground.h>

TLANG_NAMESPACE_BEGIN

TC_TEST("hashed_3d") {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog;

  Global(x, i32);
  Global(sum, i32);

  int n = 256;

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);
    root.hashed({i, j, k}, n).place(x);
    root.place(sum);
  });

  x.val<int>(2, 5, 9) = 10;
  x.val<int>(12, 5, 9) = 30;
  x.val<int>(2, 115, 9) = 11;

  auto reduce = kernel([&] {
    Declare(i);
    For(i, x, [&]() { sum[Expr(0)] += x[i]; });
  });

  reduce();

  TC_ASSERT(sum.val<int>() == 51);
};

auto benchmark_vdb = [](std::vector<std::string> param) {
  TC_ASSERT(param.size() == 1);
  auto fn = param[0];

  CoreState::set_trigger_gdb_when_crash(true);
  Program prog;

  AmbientGlobal(x, f32, 0.0f);
  Global(y, f32);
  Global(sum, i32);

  int tree_config[] = {5, 4, 3};

  for (int i = 0; i < 3; i++) {
    tree_config[i] = 1 << tree_config[i];
  }

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);

    int int1_size = tree_config[0];
    int int2_size = tree_config[1];
    int leaf_size = tree_config[2];

    root.hashed({i, j, k}, 1024)
        .fixed({i, j, k}, int1_size)
        .pointer()
        .fixed({i, j, k}, int2_size)
        .pointer()
        .fixed({i, j, k}, leaf_size)
        .place(x, y);

    root.place(sum);
  });

  int num_leaves = 0;

  using GridType = openvdb::FloatGrid;
  using TreeType = GridType::TreeType;
  using RootType = TreeType::RootNodeType;  // level 3 RootNode
  TC_ASSERT(RootType::LEVEL == 3);
  using Int1Type = RootType::ChildNodeType;  // level 2 InternalNode
  using Int2Type = Int1Type::ChildNodeType;  // level 1 InternalNode
  using LeafType = TreeType::LeafNodeType;   // level 0 LeafNode

  // Initialize the OpenVDB library.  This must be called at least
  // once per program and may safely be called multiple times.
  openvdb::initialize();
  // Create an empty floating-point grid with background value 0.

  std::ifstream ifile(fn, std::ios_base::binary);
  auto grids = openvdb::io::Stream(ifile).getGrids();

  auto grid = static_cast<GridType *>((*grids)[0].get());
  openvdb::tools::changeBackground(grid->tree(), 0.0f);

  auto dsl_value = [&](Expr var, openvdb::Coord coord) -> float32 & {
    int offset = 512;
    int i = coord.x() + offset, j = coord.y() + offset, k = coord.z() + offset;

    TC_ASSERT(i >= 0);
    TC_ASSERT(j >= 0);
    TC_ASSERT(k >= 0);

    return var.val<float32>(i, j, k);
  };

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      real value;
      if (!leaf.probeValue(t, value)) {
        leaf.setValueOn(t, 1.0f);
      }
      auto coord = leaf.offsetToGlobalCoord(t);
      dsl_value(x, coord) = leaf.getValue(t);
    }
    num_leaves += 1;
  }

  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int i = -1; i < 2; i++) {
      for (int j = -1; j < 2; j++) {
        for (int k = -1; k < 2; k++) {
          auto coord = leaf.offsetToGlobalCoord(0);
          coord.x() += i;
          coord.y() += j;
          coord.z() += k;
        }
      }
    }
    break;
  }

  int counter[4] = {0};
  for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) {
    switch (iter.getDepth()) {
      case 0: {
        RootType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[0]++;
        break;
      }
      case 1: {
        Int1Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[1]++;
        break;
      }
      case 2: {
        Int2Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[2]++;
        break;
      }
      case 3: {
        LeafType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[3]++;
        break;
      }
    }
  }
  TC_P(grid->activeVoxelCount());
  for (int i = 0; i < 4; i++) {
    TC_INFO("Depth {}: nodes {}", i, counter[i]);
  }

  openvdb::tools::Filter<GridType> filter(*grid);

  tbb::task_arena limited(1);

  limited.execute([&] {
    for (int i = 0; i < 1; i++)
      TC_TIME(filter.mean(1));
  });

  auto count = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { sum[Expr(0)] += 1; });
  });

  count();

  TC_P(num_leaves);
  TC_ASSERT(num_leaves * pow<3>(8) == sum.val<int>());

  auto mean_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i - 1, j, k] + x[i, j, k] + x[i + 1, j, k]);
    });
  });

  auto mean_y = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j - 1, k] + x[i, j, k] + x[i, j + 1, k]);
    });
  });

  auto mean_z = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j, k - 1] + x[i, j, k] + x[i, j, k + 1]);
    });
  });

  auto copy_y_to_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { x[i, j, k] = y[i, j, k]; });
  });

  auto mean = [&]() {
    mean_x();
    copy_y_to_x();
    mean_y();
    copy_y_to_x();
    mean_z();
    copy_y_to_x();
  };

  for (int i = 0; i < 1; i++)
    TC_TIME(mean());

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      TC_P(t);
      auto coord = leaf.offsetToGlobalCoord(t);
      auto dsl = dsl_value(x, coord), vdb = leaf.getValue(t);
      TC_ASSERT_EQUAL(dsl, vdb, 1e-5_f);
    }
    num_leaves += 1;
  }
};

TC_REGISTER_TASK(benchmark_vdb);

TLANG_NAMESPACE_END
<|endoftext|>