<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    ImagePlaneWidget.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkVolume16Reader.h"
#include "vtkOutlineFilter.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkImagePlaneWidget.h"
#include "vtkImageReader.h"
#include "vtkCellPicker.h"

#include "vtkRegressionTestImage.h"
#include "vtkDebugLeaks.h"

int main( int argc, char *argv[] )
{
  const char *temp=getenv("VTK_DATA_ROOT");
  char filename[2048];

  if ( ! temp )
    {
    cerr << "ERROR: Please define environment variable VTK_DATA_ROOT\n";
    return 1;
    }
  strcpy(filename,temp);
  strcat(filename,"/Data/headsq/quarter");

  vtkVolume16Reader* v16 =  vtkVolume16Reader::New();
    v16->SetDataDimensions( 64, 64);
    v16->SetDataByteOrderToLittleEndian();
    v16->SetFilePrefix( filename );
    v16->SetImageRange( 1, 93);
    v16->SetDataSpacing( 3.2, 3.2, 1.5);
    v16->Update();

  vtkOutlineFilter* outline = vtkOutlineFilter::New();
    outline->SetInput(v16->GetOutput());

  vtkPolyDataMapper* outlineMapper = vtkPolyDataMapper::New();
    outlineMapper->SetInput(outline->GetOutput());

  vtkActor* outlineActor =  vtkActor::New();
    outlineActor->SetMapper( outlineMapper);

  vtkRenderer*       ren1 = vtkRenderer::New();

  vtkRenderWindow* renWin = vtkRenderWindow::New();
    renWin->AddRenderer( ren1);

  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
    iren->SetRenderWindow( renWin);

  vtkCellPicker* picker = vtkCellPicker::New();
    picker->SetTolerance(0.005);
    picker->PickFromListOn();

  vtkImagePlaneWidget* planeWidgetX = vtkImagePlaneWidget::New();
  planeWidgetX->SetInput(v16->GetOutput());
  planeWidgetX->SetInteractor( iren);
  planeWidgetX->SetPlaneOrientationToXAxes();
  planeWidgetX->SetSliceIndex(32);
  planeWidgetX->SetPicker(picker);
  planeWidgetX->On();

  vtkImagePlaneWidget* planeWidgetY = vtkImagePlaneWidget::New();
  planeWidgetY->SetInput(v16->GetOutput());
  planeWidgetY->SetInteractor( iren);
  planeWidgetY->SetPlaneOrientationToYAxes();
  planeWidgetY->SetSliceIndex(32);
  planeWidgetY->SetPicker(picker);
  planeWidgetY->On();

  vtkImagePlaneWidget* planeWidgetZ = vtkImagePlaneWidget::New();
  planeWidgetZ->SetInput(v16->GetOutput());
  planeWidgetZ->SetInteractor( iren);
  planeWidgetZ->SetPlaneOrientationToZAxes();
  planeWidgetZ->SetSliceIndex(46);
  planeWidgetZ->SetPicker(picker);
  planeWidgetZ->On();

  ren1->AddActor( outlineActor);

  ren1->SetBackground( 0.1, 0.1, 0.2);
  renWin->SetSize( 300, 300);

  renWin->Render();
  iren->SetKeyCode('r');
  iren->InvokeEvent(vtkCommand::CharEvent,NULL);
  renWin->Render();

  ren1->GetActiveCamera()->Elevation(110);
  ren1->GetActiveCamera()->SetViewUp(0, 0, -1);
  ren1->GetActiveCamera()->Azimuth(45);
  ren1->ResetCameraClippingRange();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  planeWidgetX->Delete();
  planeWidgetY->Delete();
  planeWidgetZ->Delete();
  picker->Delete();
  outlineActor->Delete();
  outlineMapper->Delete();
  outline->Delete();
  iren->Delete();
  renWin->Delete();
  ren1->Delete();
  v16->Delete();

  return 0;
}
<commit_msg>ENH: init different colors for X,Y,Z slices<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    ImagePlaneWidget.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkVolume16Reader.h"
#include "vtkOutlineFilter.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkImagePlaneWidget.h"
#include "vtkImageReader.h"
#include "vtkCellPicker.h"

#include "vtkRegressionTestImage.h"
#include "vtkDebugLeaks.h"

int main( int argc, char *argv[] )
{
  const char *temp=getenv("VTK_DATA_ROOT");
  char filename[2048];

  if ( ! temp )
    {
    cerr << "ERROR: Please define environment variable VTK_DATA_ROOT\n";
    return 1;
    }
  strcpy(filename,temp);
  strcat(filename,"/Data/headsq/quarter");

  vtkVolume16Reader* v16 =  vtkVolume16Reader::New();
    v16->SetDataDimensions( 64, 64);
    v16->SetDataByteOrderToLittleEndian();
    v16->SetFilePrefix( filename );
    v16->SetImageRange( 1, 93);
    v16->SetDataSpacing( 3.2, 3.2, 1.5);
    v16->Update();

  vtkOutlineFilter* outline = vtkOutlineFilter::New();
    outline->SetInput(v16->GetOutput());

  vtkPolyDataMapper* outlineMapper = vtkPolyDataMapper::New();
    outlineMapper->SetInput(outline->GetOutput());

  vtkActor* outlineActor =  vtkActor::New();
    outlineActor->SetMapper( outlineMapper);

  vtkRenderer*       ren1 = vtkRenderer::New();

  vtkRenderWindow* renWin = vtkRenderWindow::New();
    renWin->AddRenderer( ren1);

  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
    iren->SetRenderWindow( renWin);

  vtkCellPicker* picker = vtkCellPicker::New();
    picker->SetTolerance(0.005);
    picker->PickFromListOn();

  vtkImagePlaneWidget* planeWidgetX = vtkImagePlaneWidget::New();
  planeWidgetX->SetInput(v16->GetOutput());
  planeWidgetX->SetInteractor( iren);
  planeWidgetX->SetPlaneOrientationToXAxes();
  planeWidgetX->SetSliceIndex(32);
  planeWidgetX->SetPicker(picker);
  planeWidgetX->GetPlaneProperty()->SetColor(1,0,0);
  planeWidgetX->On();

  vtkImagePlaneWidget* planeWidgetY = vtkImagePlaneWidget::New();
  planeWidgetY->SetInput(v16->GetOutput());
  planeWidgetY->SetInteractor( iren);
  planeWidgetY->SetPlaneOrientationToYAxes();
  planeWidgetY->SetSliceIndex(32);
  planeWidgetY->SetPicker(picker);
  planeWidgetY->GetPlaneProperty()->SetColor(1,1,0);
  planeWidgetY->On();

  vtkImagePlaneWidget* planeWidgetZ = vtkImagePlaneWidget::New();
  planeWidgetZ->SetInput(v16->GetOutput());
  planeWidgetZ->SetInteractor( iren);
  planeWidgetZ->SetPlaneOrientationToZAxes();
  planeWidgetZ->SetSliceIndex(46);
  planeWidgetZ->SetPicker(picker);
  planeWidgetZ->GetPlaneProperty()->SetColor(0,0,1);
  planeWidgetZ->On();

  ren1->AddActor( outlineActor);

  ren1->SetBackground( 0.1, 0.1, 0.2);
  renWin->SetSize( 300, 300);

  renWin->Render();
  iren->SetKeyCode('r');
  iren->InvokeEvent(vtkCommand::CharEvent,NULL);
  renWin->Render();

  ren1->GetActiveCamera()->Elevation(110);
  ren1->GetActiveCamera()->SetViewUp(0, 0, -1);
  ren1->GetActiveCamera()->Azimuth(45);
  ren1->ResetCameraClippingRange();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  planeWidgetX->Delete();
  planeWidgetY->Delete();
  planeWidgetZ->Delete();
  picker->Delete();
  outlineActor->Delete();
  outlineMapper->Delete();
  outline->Delete();
  iren->Delete();
  renWin->Delete();
  ren1->Delete();
  v16->Delete();

  return 0;
}
<|endoftext|>


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

#ifndef _FORMS_DATE_HXX_
#include "Date.hxx"
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _DATE_HXX
#include <tools/date.hxx>
#endif
#ifndef _DBHELPER_DBCONVERSION_HXX_
#include <connectivity/dbconversion.hxx>
#endif

#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif

using namespace dbtools;

//.........................................................................
namespace frm
{
//.........................................................................

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;

//------------------------------------------------------------------
ODateControl::ODateControl(const Reference<XMultiServiceFactory>& _rxFactory)
               :OBoundControl(_rxFactory, VCL_CONTROL_DATEFIELD)
{
}

//------------------------------------------------------------------
InterfaceRef SAL_CALL ODateControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
{
    return *(new ODateControl(_rxFactory));
}

//------------------------------------------------------------------------------
Sequence<Type> ODateControl::_getTypes()
{
    return OBoundControl::_getTypes();
}

//------------------------------------------------------------------------------
StringSequence SAL_CALL ODateControl::getSupportedServiceNames() throw()
{
    StringSequence aSupported = OBoundControl::getSupportedServiceNames();
    aSupported.realloc(aSupported.getLength() + 1);

    ::rtl::OUString*pArray = aSupported.getArray();
    pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_DATEFIELD;
    return aSupported;
}

/*************************************************************************/
//------------------------------------------------------------------
InterfaceRef SAL_CALL ODateModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
{
    return *(new ODateModel(_rxFactory));
}

//------------------------------------------------------------------------------
Sequence<Type> ODateModel::_getTypes()
{
    return OEditBaseModel::_getTypes();
}

//------------------------------------------------------------------
DBG_NAME( ODateModel )
//------------------------------------------------------------------
ODateModel::ODateModel(const Reference<XMultiServiceFactory>& _rxFactory)
            :OEditBaseModel( _rxFactory, VCL_CONTROLMODEL_DATEFIELD, FRM_SUN_CONTROL_DATEFIELD, sal_True, sal_True )
                        // use the old control name for compytibility reasons
            ,OLimitedFormats( _rxFactory, FormComponentType::DATEFIELD )
{
    DBG_CTOR( ODateModel, NULL );

    m_nClassId = FormComponentType::DATEFIELD;
    initValueProperty( PROPERTY_DATE, PROPERTY_ID_DATE );

    setAggregateSet(m_xAggregateFastSet, getOriginalHandle(PROPERTY_ID_DATEFORMAT));

    osl_incrementInterlockedCount( &m_refCount );
    try
    {
        if ( m_xAggregateSet.is() )
            m_xAggregateSet->setPropertyValue( PROPERTY_DATEMIN, makeAny( (sal_Int32)( ::Date( 1, 1, 1800 ).GetDate() ) ) );
    }
    catch( const Exception& )
    {
        OSL_ENSURE( sal_False, "ODateModel::ODateModel: caught an exception!" );
    }
    osl_decrementInterlockedCount( &m_refCount );
}

//------------------------------------------------------------------------------
ODateModel::ODateModel( const ODateModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory )
    :OEditBaseModel( _pOriginal, _rxFactory )
    ,OLimitedFormats( _rxFactory, FormComponentType::DATEFIELD )
{
    DBG_CTOR( ODateModel, NULL );

    setAggregateSet( m_xAggregateFastSet, getOriginalHandle( PROPERTY_ID_DATEFORMAT ) );
}

//------------------------------------------------------------------------------
ODateModel::~ODateModel( )
{
    setAggregateSet(Reference< XFastPropertySet >(), -1);
    DBG_DTOR( ODateModel, NULL );
}

// XCloneable
//------------------------------------------------------------------------------
IMPLEMENT_DEFAULT_CLONING( ODateModel )

// XServiceInfo
//------------------------------------------------------------------------------
StringSequence SAL_CALL ODateModel::getSupportedServiceNames() throw()
{
    StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();

    sal_Int32 nOldLen = aSupported.getLength();
    aSupported.realloc( nOldLen + 8 );
    ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen;

    *pStoreTo++ = BINDABLE_CONTROL_MODEL;
    *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
    *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;

    *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
    *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;

    *pStoreTo++ = FRM_SUN_COMPONENT_DATEFIELD;
    *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_DATEFIELD;
    *pStoreTo++ = BINDABLE_DATABASE_DATE_FIELD;

    return aSupported;
}

//------------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODateModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException)
{
    return FRM_COMPONENT_DATEFIELD; // old (non-sun) name for compatibility !
}

// XPropertySet
//------------------------------------------------------------------------------
Reference<XPropertySetInfo> SAL_CALL ODateModel::getPropertySetInfo() throw( RuntimeException )
{
    Reference<XPropertySetInfo>  xInfo( createPropertySetInfo( getInfoHelper() ) );
    return xInfo;
}

//------------------------------------------------------------------------------
void ODateModel::fillProperties(
        Sequence< Property >& _rProps,
        Sequence< Property >& _rAggregateProps ) const
{
    BEGIN_DESCRIBE_PROPERTIES( 4, OEditBaseModel )
        DECL_PROP3(DEFAULT_DATE,            sal_Int32,              BOUND, MAYBEDEFAULT, MAYBEVOID);
        DECL_PROP1(TABINDEX,                sal_Int16,              BOUND);
        DECL_PROP1(FORMATKEY,               sal_Int32,              TRANSIENT);
        DECL_IFACE_PROP2(FORMATSSUPPLIER,   XNumberFormatsSupplier, READONLY, TRANSIENT);
    END_DESCRIBE_PROPERTIES();
}

//------------------------------------------------------------------------------
::cppu::IPropertyArrayHelper& ODateModel::getInfoHelper()
{
    return *const_cast<ODateModel*>(this)->getArrayHelper();
}

//------------------------------------------------------------------------------
void SAL_CALL ODateModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle ) const
{
    switch (_nHandle)
    {
        case PROPERTY_ID_FORMATKEY:
            getFormatKeyPropertyValue(_rValue);
            break;
        case PROPERTY_ID_FORMATSSUPPLIER:
            _rValue <<= getFormatsSupplier();
            break;
        default:
            OEditBaseModel::getFastPropertyValue(_rValue, _nHandle);
            break;
    }
}

//------------------------------------------------------------------------------
sal_Bool SAL_CALL ODateModel::convertFastPropertyValue(Any& _rConvertedValue, Any& _rOldValue,
        sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
{
    if (PROPERTY_ID_FORMATKEY == _nHandle)
        return convertFormatKeyPropertyValue(_rConvertedValue, _rOldValue, _rValue);
    else
        return OEditBaseModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue );
}

//------------------------------------------------------------------------------
void SAL_CALL ODateModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw ( ::com::sun::star::uno::Exception)
{
    if (PROPERTY_ID_FORMATKEY == _nHandle)
        setFormatKeyPropertyValue(_rValue);
    else
        OEditBaseModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
}

// XLoadListener
//------------------------------------------------------------------------------
void ODateModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
{
    OBoundControlModel::onConnectedDbColumn( _rxForm );
    Reference<XPropertySet> xField = getField();
    if (xField.is())
    {
        m_bDateTimeField = sal_False;
        try
        {
            sal_Int32 nFieldType;
            xField->getPropertyValue(PROPERTY_FIELDTYPE) >>= nFieldType;
            m_bDateTimeField = (nFieldType == DataType::TIMESTAMP);
        }
        catch(Exception&)
        {
        }
    }
}

//------------------------------------------------------------------------------
sal_Bool ODateModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
{
    Any aControlValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) );
    if ( !compare( aControlValue, m_aSaveValue ) )
    {
        if ( !aControlValue.hasValue() )
            m_xColumnUpdate->updateNull();
        else
        {
            try
            {
                util::Date aDate;
                if ( !( aControlValue >>= aDate ) )
                {
                    sal_Int32 nAsInt(0);
                    aControlValue >>= nAsInt;
                    aDate = DBTypeConversion::toDate(nAsInt);
                }

                if ( !m_bDateTimeField )
                    m_xColumnUpdate->updateDate( aDate );
                else
                {
                    util::DateTime aDateTime = m_xColumn->getTimestamp();
                    aDateTime.Day = aDate.Day;
                    aDateTime.Month = aDate.Month;
                    aDateTime.Year = aDate.Year;
                    m_xColumnUpdate->updateTimestamp( aDateTime );
                }
            }
            catch(Exception&)
            {
                return sal_False;
            }
        }
        m_aSaveValue = aControlValue;
    }
    return sal_True;
}

//------------------------------------------------------------------------------
void ODateModel::impl_translateControlValueToUNODate( Any& _rUNOValue ) const
{
    _rUNOValue = getControlValue();
    if ( _rUNOValue.hasValue() )
    {
        sal_Int32 nDate = 0;
        OSL_VERIFY( _rUNOValue >>= nDate );
        _rUNOValue <<= DBTypeConversion::toDate( nDate );
    }
}

//------------------------------------------------------------------------------
Any ODateModel::translateControlValueToExternalValue( ) const
{
    Any aExternalValue;
    impl_translateControlValueToUNODate( aExternalValue );
    return aExternalValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateExternalValueToControlValue( ) const
{
    OSL_PRECOND( hasExternalValueBinding(),
        "ODateModel::translateExternalValueToControlValue: precondition not met!" );

    Any aControlValue;
    if ( hasExternalValueBinding() )
    {
        Any aExternalValue = getExternalValueBinding()->getValue( ::getCppuType( static_cast< util::Date* >( NULL ) ) );
        if ( aExternalValue.hasValue() )
        {
            util::Date aDate;
            OSL_VERIFY( aExternalValue >>= aDate );
            aControlValue <<= DBTypeConversion::toINT32( aDate );
        }
    }
    return aControlValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateControlValueToValidatableValue( ) const
{
    Any aValidatableValue;
    impl_translateControlValueToUNODate( aValidatableValue );
    return aValidatableValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateDbColumnToControlValue()
{
    util::Date aDate = m_xColumn->getDate();
    if (m_xColumn->wasNull())
        m_aSaveValue.clear();
    else
        // the aggregated set expects an Int32 as value ...
        m_aSaveValue <<= DBTypeConversion::toINT32(aDate);

    return m_aSaveValue;
}

//------------------------------------------------------------------------------
Any ODateModel::getDefaultForReset() const
{
    return m_aDefault;
}

//------------------------------------------------------------------------------
sal_Bool ODateModel::approveValueBinding( const Reference< binding::XValueBinding >& _rxBinding )
{
    OSL_PRECOND( _rxBinding.is(), "ODateModel::approveValueBinding: invalid binding!" );

    return  _rxBinding.is()
        &&  _rxBinding->supportsType( ::getCppuType( static_cast< util::Date* >( NULL ) ) );
}

//.........................................................................
}   // namespace frm
//.........................................................................

<commit_msg>INTEGRATION: CWS pchfix02 (1.22.18); FILE MERGED 2006/09/01 17:27:34 kaib 1.22.18.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Date.cxx,v $
 *
 *  $Revision: 1.23 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 23:48:14 $
 *
 *  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_forms.hxx"

#ifndef _FORMS_DATE_HXX_
#include "Date.hxx"
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _DATE_HXX
#include <tools/date.hxx>
#endif
#ifndef _DBHELPER_DBCONVERSION_HXX_
#include <connectivity/dbconversion.hxx>
#endif

#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif

using namespace dbtools;

//.........................................................................
namespace frm
{
//.........................................................................

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::sdb;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;

//------------------------------------------------------------------
ODateControl::ODateControl(const Reference<XMultiServiceFactory>& _rxFactory)
               :OBoundControl(_rxFactory, VCL_CONTROL_DATEFIELD)
{
}

//------------------------------------------------------------------
InterfaceRef SAL_CALL ODateControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
{
    return *(new ODateControl(_rxFactory));
}

//------------------------------------------------------------------------------
Sequence<Type> ODateControl::_getTypes()
{
    return OBoundControl::_getTypes();
}

//------------------------------------------------------------------------------
StringSequence SAL_CALL ODateControl::getSupportedServiceNames() throw()
{
    StringSequence aSupported = OBoundControl::getSupportedServiceNames();
    aSupported.realloc(aSupported.getLength() + 1);

    ::rtl::OUString*pArray = aSupported.getArray();
    pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_DATEFIELD;
    return aSupported;
}

/*************************************************************************/
//------------------------------------------------------------------
InterfaceRef SAL_CALL ODateModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
{
    return *(new ODateModel(_rxFactory));
}

//------------------------------------------------------------------------------
Sequence<Type> ODateModel::_getTypes()
{
    return OEditBaseModel::_getTypes();
}

//------------------------------------------------------------------
DBG_NAME( ODateModel )
//------------------------------------------------------------------
ODateModel::ODateModel(const Reference<XMultiServiceFactory>& _rxFactory)
            :OEditBaseModel( _rxFactory, VCL_CONTROLMODEL_DATEFIELD, FRM_SUN_CONTROL_DATEFIELD, sal_True, sal_True )
                        // use the old control name for compytibility reasons
            ,OLimitedFormats( _rxFactory, FormComponentType::DATEFIELD )
{
    DBG_CTOR( ODateModel, NULL );

    m_nClassId = FormComponentType::DATEFIELD;
    initValueProperty( PROPERTY_DATE, PROPERTY_ID_DATE );

    setAggregateSet(m_xAggregateFastSet, getOriginalHandle(PROPERTY_ID_DATEFORMAT));

    osl_incrementInterlockedCount( &m_refCount );
    try
    {
        if ( m_xAggregateSet.is() )
            m_xAggregateSet->setPropertyValue( PROPERTY_DATEMIN, makeAny( (sal_Int32)( ::Date( 1, 1, 1800 ).GetDate() ) ) );
    }
    catch( const Exception& )
    {
        OSL_ENSURE( sal_False, "ODateModel::ODateModel: caught an exception!" );
    }
    osl_decrementInterlockedCount( &m_refCount );
}

//------------------------------------------------------------------------------
ODateModel::ODateModel( const ODateModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory )
    :OEditBaseModel( _pOriginal, _rxFactory )
    ,OLimitedFormats( _rxFactory, FormComponentType::DATEFIELD )
{
    DBG_CTOR( ODateModel, NULL );

    setAggregateSet( m_xAggregateFastSet, getOriginalHandle( PROPERTY_ID_DATEFORMAT ) );
}

//------------------------------------------------------------------------------
ODateModel::~ODateModel( )
{
    setAggregateSet(Reference< XFastPropertySet >(), -1);
    DBG_DTOR( ODateModel, NULL );
}

// XCloneable
//------------------------------------------------------------------------------
IMPLEMENT_DEFAULT_CLONING( ODateModel )

// XServiceInfo
//------------------------------------------------------------------------------
StringSequence SAL_CALL ODateModel::getSupportedServiceNames() throw()
{
    StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();

    sal_Int32 nOldLen = aSupported.getLength();
    aSupported.realloc( nOldLen + 8 );
    ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen;

    *pStoreTo++ = BINDABLE_CONTROL_MODEL;
    *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
    *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;

    *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
    *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;

    *pStoreTo++ = FRM_SUN_COMPONENT_DATEFIELD;
    *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_DATEFIELD;
    *pStoreTo++ = BINDABLE_DATABASE_DATE_FIELD;

    return aSupported;
}

//------------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODateModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException)
{
    return FRM_COMPONENT_DATEFIELD; // old (non-sun) name for compatibility !
}

// XPropertySet
//------------------------------------------------------------------------------
Reference<XPropertySetInfo> SAL_CALL ODateModel::getPropertySetInfo() throw( RuntimeException )
{
    Reference<XPropertySetInfo>  xInfo( createPropertySetInfo( getInfoHelper() ) );
    return xInfo;
}

//------------------------------------------------------------------------------
void ODateModel::fillProperties(
        Sequence< Property >& _rProps,
        Sequence< Property >& _rAggregateProps ) const
{
    BEGIN_DESCRIBE_PROPERTIES( 4, OEditBaseModel )
        DECL_PROP3(DEFAULT_DATE,            sal_Int32,              BOUND, MAYBEDEFAULT, MAYBEVOID);
        DECL_PROP1(TABINDEX,                sal_Int16,              BOUND);
        DECL_PROP1(FORMATKEY,               sal_Int32,              TRANSIENT);
        DECL_IFACE_PROP2(FORMATSSUPPLIER,   XNumberFormatsSupplier, READONLY, TRANSIENT);
    END_DESCRIBE_PROPERTIES();
}

//------------------------------------------------------------------------------
::cppu::IPropertyArrayHelper& ODateModel::getInfoHelper()
{
    return *const_cast<ODateModel*>(this)->getArrayHelper();
}

//------------------------------------------------------------------------------
void SAL_CALL ODateModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle ) const
{
    switch (_nHandle)
    {
        case PROPERTY_ID_FORMATKEY:
            getFormatKeyPropertyValue(_rValue);
            break;
        case PROPERTY_ID_FORMATSSUPPLIER:
            _rValue <<= getFormatsSupplier();
            break;
        default:
            OEditBaseModel::getFastPropertyValue(_rValue, _nHandle);
            break;
    }
}

//------------------------------------------------------------------------------
sal_Bool SAL_CALL ODateModel::convertFastPropertyValue(Any& _rConvertedValue, Any& _rOldValue,
        sal_Int32 _nHandle, const Any& _rValue ) throw(IllegalArgumentException)
{
    if (PROPERTY_ID_FORMATKEY == _nHandle)
        return convertFormatKeyPropertyValue(_rConvertedValue, _rOldValue, _rValue);
    else
        return OEditBaseModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue );
}

//------------------------------------------------------------------------------
void SAL_CALL ODateModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw ( ::com::sun::star::uno::Exception)
{
    if (PROPERTY_ID_FORMATKEY == _nHandle)
        setFormatKeyPropertyValue(_rValue);
    else
        OEditBaseModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
}

// XLoadListener
//------------------------------------------------------------------------------
void ODateModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
{
    OBoundControlModel::onConnectedDbColumn( _rxForm );
    Reference<XPropertySet> xField = getField();
    if (xField.is())
    {
        m_bDateTimeField = sal_False;
        try
        {
            sal_Int32 nFieldType;
            xField->getPropertyValue(PROPERTY_FIELDTYPE) >>= nFieldType;
            m_bDateTimeField = (nFieldType == DataType::TIMESTAMP);
        }
        catch(Exception&)
        {
        }
    }
}

//------------------------------------------------------------------------------
sal_Bool ODateModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
{
    Any aControlValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) );
    if ( !compare( aControlValue, m_aSaveValue ) )
    {
        if ( !aControlValue.hasValue() )
            m_xColumnUpdate->updateNull();
        else
        {
            try
            {
                util::Date aDate;
                if ( !( aControlValue >>= aDate ) )
                {
                    sal_Int32 nAsInt(0);
                    aControlValue >>= nAsInt;
                    aDate = DBTypeConversion::toDate(nAsInt);
                }

                if ( !m_bDateTimeField )
                    m_xColumnUpdate->updateDate( aDate );
                else
                {
                    util::DateTime aDateTime = m_xColumn->getTimestamp();
                    aDateTime.Day = aDate.Day;
                    aDateTime.Month = aDate.Month;
                    aDateTime.Year = aDate.Year;
                    m_xColumnUpdate->updateTimestamp( aDateTime );
                }
            }
            catch(Exception&)
            {
                return sal_False;
            }
        }
        m_aSaveValue = aControlValue;
    }
    return sal_True;
}

//------------------------------------------------------------------------------
void ODateModel::impl_translateControlValueToUNODate( Any& _rUNOValue ) const
{
    _rUNOValue = getControlValue();
    if ( _rUNOValue.hasValue() )
    {
        sal_Int32 nDate = 0;
        OSL_VERIFY( _rUNOValue >>= nDate );
        _rUNOValue <<= DBTypeConversion::toDate( nDate );
    }
}

//------------------------------------------------------------------------------
Any ODateModel::translateControlValueToExternalValue( ) const
{
    Any aExternalValue;
    impl_translateControlValueToUNODate( aExternalValue );
    return aExternalValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateExternalValueToControlValue( ) const
{
    OSL_PRECOND( hasExternalValueBinding(),
        "ODateModel::translateExternalValueToControlValue: precondition not met!" );

    Any aControlValue;
    if ( hasExternalValueBinding() )
    {
        Any aExternalValue = getExternalValueBinding()->getValue( ::getCppuType( static_cast< util::Date* >( NULL ) ) );
        if ( aExternalValue.hasValue() )
        {
            util::Date aDate;
            OSL_VERIFY( aExternalValue >>= aDate );
            aControlValue <<= DBTypeConversion::toINT32( aDate );
        }
    }
    return aControlValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateControlValueToValidatableValue( ) const
{
    Any aValidatableValue;
    impl_translateControlValueToUNODate( aValidatableValue );
    return aValidatableValue;
}

//------------------------------------------------------------------------------
Any ODateModel::translateDbColumnToControlValue()
{
    util::Date aDate = m_xColumn->getDate();
    if (m_xColumn->wasNull())
        m_aSaveValue.clear();
    else
        // the aggregated set expects an Int32 as value ...
        m_aSaveValue <<= DBTypeConversion::toINT32(aDate);

    return m_aSaveValue;
}

//------------------------------------------------------------------------------
Any ODateModel::getDefaultForReset() const
{
    return m_aDefault;
}

//------------------------------------------------------------------------------
sal_Bool ODateModel::approveValueBinding( const Reference< binding::XValueBinding >& _rxBinding )
{
    OSL_PRECOND( _rxBinding.is(), "ODateModel::approveValueBinding: invalid binding!" );

    return  _rxBinding.is()
        &&  _rxBinding->supportsType( ::getCppuType( static_cast< util::Date* >( NULL ) ) );
}

//.........................................................................
}   // namespace frm
//.........................................................................

<|endoftext|>


<commit_before>#include "thin-stack.h"
using namespace std;
namespace k = kernels;

ThinStack::ThinStack(ModelSpec spec, ThinStackParameters params,
    cublasHandle_t handle)
  : spec(spec), params(params), stack_size(spec.seq_length), handle(handle) {

  stack_total_size = (stack_size * spec.batch_size) * spec.model_dim;
  buffer_total_size = spec.batch_size * spec.seq_length * spec.model_dim;
  queue_total_size = spec.batch_size * spec.seq_length;
  cursors_total_size = spec.batch_size;

  // Pre-allocate inputs.
  cudaMalloc(&X, spec.batch_size * spec.seq_length * spec.model_dim * sizeof(float));
  cudaMalloc(&transitions, spec.batch_size * spec.seq_length * sizeof(float));

  // Pre-allocate auxiliary data structures.
  cudaMalloc(&stack, stack_total_size * sizeof(float));
  cudaMalloc(&queue, queue_total_size * sizeof(float));
  cudaMalloc(&cursors, cursors_total_size * sizeof(float));
  cudaMalloc(&buffer, buffer_total_size * sizeof(float));

  // Pre-allocate temporary containers.
  cudaMalloc(&buffer_top_idxs_t, spec.batch_size * sizeof(float));
  cudaMalloc(&buffer_top_t, spec.batch_size * spec.model_dim * sizeof(float));
  cudaMalloc(&stack_1_ptrs, spec.batch_size * sizeof(float));
  cudaMalloc(&stack_1_t, spec.model_dim * spec.batch_size * sizeof(float));
  cudaMalloc(&stack_2_ptrs, spec.batch_size * sizeof(float));
  cudaMalloc(&stack_2_t, spec.model_dim * spec.batch_size * sizeof(float));
  cudaMalloc(&push_output, spec.batch_size * spec.model_dim * sizeof(float));
  cudaMalloc(&merge_output, spec.batch_size * spec.model_dim * sizeof(float));

  // Pre-allocate accumulators.
  cudaMalloc(&buffer_cur_t, spec.batch_size * sizeof(float));

  init_helpers();

}

void ThinStack::init_helpers() {
  cudaMalloc(&batch_range, spec.batch_size * sizeof(float));
  cudaMalloc(&batch_ones, spec.batch_size * sizeof(float));

  float h_batch_ones[spec.batch_size];
  float h_batch_range[spec.batch_size];
  for (int i = 0; i < spec.batch_size; i++) {
    h_batch_ones[i] = 1.0f;
    h_batch_range[i] = (float) i;
  }

  cudaMemcpy(batch_range, h_batch_range, spec.batch_size * sizeof(float),
      cudaMemcpyHostToDevice);
  cudaMemcpy(batch_ones, h_batch_ones, spec.batch_size * sizeof(float),
      cudaMemcpyHostToDevice);
  cudaDeviceSynchronize();
}

void ThinStack::free_helpers() {
  cudaFree(batch_ones);
  cudaFree(batch_range);
}

ThinStack::~ThinStack() {

  free_helpers();

  cudaFree(X);
  cudaFree(transitions);

  cudaFree(stack);
  cudaFree(queue);
  cudaFree(cursors);
  cudaFree(buffer);

  cudaFree(buffer_top_idxs_t);
  cudaFree(buffer_top_t);
  cudaFree(stack_1_ptrs);
  cudaFree(stack_2_ptrs);
  cudaFree(push_output);
  cudaFree(merge_output);

  cudaFree(buffer_cur_t);

}

void ThinStack::forward() {

  // TODO embedding projection
  buffer = X;
  reset();

  for (int t = 0; t < spec.seq_length; t++) {
    step(t);
    cudaDeviceSynchronize();
#if DEBUG
    cout << endl << "======================" << endl << endl;
#endif
  }

  // TODO: Don't need to sync here. Could have the client establish a lock on
  // results and simultaneously begin the next batch + copy out results
  cudaDeviceSynchronize();

}

void ThinStack::step(int t) {

  // TODO sync after kernel calls.
  float *transitions_t = &transitions[t * spec.batch_size];

  // buffer_top = buffer[buffer_cur_t * batch_size + batch_range]
  k::subtensor1(buffer_top_t, buffer, buffer_cur_t,
          spec.batch_size * spec.model_dim, spec.batch_size,
          spec.model_dim, 0.0f, spec.batch_size, 1.0f, batch_range);
#if DEBUG
  cout << "buffer_top after:" << endl;
  print_device_matrix(buffer_top_t, spec.model_dim, spec.batch_size);
#endif

  // stack_2_ptrs = (cursors - 1) + batch_range * seq_length
  k::subtensor1(stack_2_ptrs, queue, cursors, spec.batch_size,
          spec.batch_size, spec.seq_length, -1.0f, 1.0f, spec.seq_length,
          batch_range);
#if DEBUG
  cout << "stack_2_ptrs #1" << endl;
  print_device_matrix(stack_2_ptrs, 1, spec.batch_size);
#endif

  // stack_2_ptrs = stack_2_ptrs * batch_size + batch_range * 1
  k::addi_vv(handle, stack_2_ptrs, batch_range, spec.batch_size, 1,
          spec.batch_size);
#if DEBUG
  cout << "stack_2_ptrs" << endl;
  print_device_matrix(stack_2_ptrs, 1, spec.batch_size);
#endif

  // stack_1, stack_2
  // stack_1_t = stack[batch_range + (t - 1) * spec.batch_size]
  k::subtensor1(stack_1_t, stack, batch_range,
          spec.batch_size * spec.seq_length, spec.batch_size,
          spec.model_dim, (float) (t - 1) * spec.batch_size, 1.0f, 0.0f,
          NULL);

  k::subtensor1(stack_2_t, stack, stack_2_ptrs,
          spec.batch_size * spec.seq_length, spec.batch_size,
          spec.model_dim, 0.0f, 1.0f, 0.0f, NULL);

  // Run recurrence, which writes into `push_output`, `merge_output`.
  recurrence(stack_1_t, stack_2_t, buffer_top_t);

  // Write in the next stack top.
  mask_and_update_stack(buffer_top_t, merge_output, transitions_t, t);

  mask_and_update_cursors(cursors, transitions_t, t);
#if DEBUG
  cout << "cursors after" << endl;
  print_device_matrix(cursors, 1, spec.batch_size);
#endif

  // queue[cursors + 0 + batch_range * spec.seq_length] = t
  k::set_subtensor1i_s(queue, t, cursors, spec.batch_size, 0, spec.seq_length,
          batch_range);
#if DEBUG
  cout << "queue after" << endl;
  print_device_matrix(queue, spec.seq_length, spec.batch_size);
#endif

  // buffer_cur += (1 - transitions)
  update_buffer_cur(buffer_cur_t, transitions_t, t);
#if DEBUG
  cout << "buffer cur after" << endl;
  print_device_matrix(buffer_cur_t, 1, spec.batch_size);
#endif

}

void ThinStack::recurrence(const float *stack_1_t, const float *stack_2_t,
    const float *buffer_top_t) {

  // merge_out = W_l l
  float alpha = 1.0f;
  float beta = 0.0f;
  cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, spec.model_dim, spec.batch_size,
      spec.model_dim, &alpha, params.compose_W_l, spec.model_dim, stack_2_t,
      spec.model_dim, &beta, merge_output, spec.model_dim);
  // merge_out += W_r r
  float beta2 = 1.0f;
  cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, spec.model_dim, spec.batch_size,
      spec.model_dim, &alpha, params.compose_W_r, spec.model_dim, stack_1_t,
      spec.model_dim, &beta2, merge_output, spec.model_dim);

  // TODO bias (broadcast-add)
  // TODO relu

}

void ThinStack::mask_and_update_stack(const float *push_value,
    const float *merge_value, const float *transitions, int t) {

  // Find start position of write destination (next-top corresponding to
  // timestep `t`).
  int stack_offset = t * spec.batch_size * spec.model_dim;

#if DEBUG
  cout << "merge value:" << endl;
  print_device_matrix(merge_value, spec.model_dim, spec.batch_size);
  cout << "push value:" << endl;
  print_device_matrix(push_value, spec.model_dim, spec.batch_size);
#endif

  k::switch_m(&stack[stack_offset], transitions, merge_value, push_value,
              spec.batch_size, spec.model_dim);

#if DEBUG
  cout << "stack top t:" << endl;
  print_device_matrix(&stack[stack_offset], spec.model_dim, spec.batch_size);
#endif

}

void ThinStack::mask_and_update_cursors(float *cursors, const float *transitions,
    int t) {

  // cursors += 1
  float alpha1 = 1.0f;
  cublasSaxpy(handle, spec.batch_size, &alpha1, batch_ones, 1, cursors, 1);

  // cursors -= 2*transitions
  float alpha2 = -2.0f;
  cublasSaxpy(handle, spec.batch_size, &alpha2, transitions, 1, cursors, 1);

}

void ThinStack::update_buffer_cur(float *buffer_cur_t, float *transitions, int t) {

  // buffer_cur += 1
  float alpha1 = 1.0;
  cublasSaxpy(handle, spec.batch_size, &alpha1, batch_ones, 1, buffer_cur_t, 1);

  // buffer_cur -= transitions
  float alpha2 = -1.0;
  cublasSaxpy(handle, spec.batch_size, &alpha2, transitions, 1, buffer_cur_t, 1);

}

void ThinStack::reset() {
  cudaMemset(stack, 0, stack_total_size * sizeof(float));
  cudaMemset(queue, 0, queue_total_size * sizeof(float));

  float alpha = -1.0f;
  cudaMemset(cursors, 0, cursors_total_size * sizeof(float));
  cublasSaxpy(handle, spec.batch_size, &alpha, batch_ones, 1, cursors, 1);

  cudaMemset(buffer_cur_t, 0, spec.batch_size * sizeof(float));
}
<commit_msg>Fix stack_2_ptrs indexing issue<commit_after>#include "thin-stack.h"
using namespace std;
namespace k = kernels;

ThinStack::ThinStack(ModelSpec spec, ThinStackParameters params,
    cublasHandle_t handle)
  : spec(spec), params(params), stack_size(spec.seq_length), handle(handle) {

  stack_total_size = (stack_size * spec.batch_size) * spec.model_dim;
  buffer_total_size = spec.batch_size * spec.seq_length * spec.model_dim;
  queue_total_size = spec.batch_size * spec.seq_length;
  cursors_total_size = spec.batch_size;

  // Pre-allocate inputs.
  cudaMalloc(&X, spec.batch_size * spec.seq_length * spec.model_dim * sizeof(float));
  cudaMalloc(&transitions, spec.batch_size * spec.seq_length * sizeof(float));

  // Pre-allocate auxiliary data structures.
  cudaMalloc(&stack, stack_total_size * sizeof(float));
  cudaMalloc(&queue, queue_total_size * sizeof(float));
  cudaMalloc(&cursors, cursors_total_size * sizeof(float));
  cudaMalloc(&buffer, buffer_total_size * sizeof(float));

  // Pre-allocate temporary containers.
  cudaMalloc(&buffer_top_idxs_t, spec.batch_size * sizeof(float));
  cudaMalloc(&buffer_top_t, spec.batch_size * spec.model_dim * sizeof(float));
  cudaMalloc(&stack_1_ptrs, spec.batch_size * sizeof(float));
  cudaMalloc(&stack_1_t, spec.model_dim * spec.batch_size * sizeof(float));
  cudaMalloc(&stack_2_ptrs, spec.batch_size * sizeof(float));
  cudaMalloc(&stack_2_t, spec.model_dim * spec.batch_size * sizeof(float));
  cudaMalloc(&push_output, spec.batch_size * spec.model_dim * sizeof(float));
  cudaMalloc(&merge_output, spec.batch_size * spec.model_dim * sizeof(float));

  // Pre-allocate accumulators.
  cudaMalloc(&buffer_cur_t, spec.batch_size * sizeof(float));

  init_helpers();

}

void ThinStack::init_helpers() {
  cudaMalloc(&batch_range, spec.batch_size * sizeof(float));
  cudaMalloc(&batch_ones, spec.batch_size * sizeof(float));

  float h_batch_ones[spec.batch_size];
  float h_batch_range[spec.batch_size];
  for (int i = 0; i < spec.batch_size; i++) {
    h_batch_ones[i] = 1.0f;
    h_batch_range[i] = (float) i;
  }

  cudaMemcpy(batch_range, h_batch_range, spec.batch_size * sizeof(float),
      cudaMemcpyHostToDevice);
  cudaMemcpy(batch_ones, h_batch_ones, spec.batch_size * sizeof(float),
      cudaMemcpyHostToDevice);
  cudaDeviceSynchronize();
}

void ThinStack::free_helpers() {
  cudaFree(batch_ones);
  cudaFree(batch_range);
}

ThinStack::~ThinStack() {

  free_helpers();

  cudaFree(X);
  cudaFree(transitions);

  cudaFree(stack);
  cudaFree(queue);
  cudaFree(cursors);
  cudaFree(buffer);

  cudaFree(buffer_top_idxs_t);
  cudaFree(buffer_top_t);
  cudaFree(stack_1_ptrs);
  cudaFree(stack_2_ptrs);
  cudaFree(push_output);
  cudaFree(merge_output);

  cudaFree(buffer_cur_t);

}

void ThinStack::forward() {

  // TODO embedding projection
  buffer = X;
  reset();

  for (int t = 0; t < spec.seq_length; t++) {
    step(t);
    cudaDeviceSynchronize();
#if DEBUG
    cout << endl << "======================" << endl << endl;
#endif
  }

  // TODO: Don't need to sync here. Could have the client establish a lock on
  // results and simultaneously begin the next batch + copy out results
  cudaDeviceSynchronize();

  cout << "final" << endl;
  print_device_matrix(stack, spec.model_dim, spec.batch_size * spec.seq_length);

}

void ThinStack::step(int t) {

  // TODO sync after kernel calls.
  float *transitions_t = &transitions[t * spec.batch_size];

  // buffer_top = buffer[buffer_cur_t * batch_size + batch_range]
  k::subtensor1(buffer_top_t, buffer, buffer_cur_t,
          spec.batch_size * spec.model_dim, spec.batch_size,
          spec.model_dim, 0.0f, spec.batch_size, 1.0f, batch_range);
#if DEBUG
  cout << "buffer_top after:" << endl;
  print_device_matrix(buffer_top_t, spec.model_dim, spec.batch_size);
#endif

  // stack_2_ptrs = (cursors - 1) + batch_range * seq_length
  k::subtensor1(stack_2_ptrs, queue, cursors, spec.batch_size,
          spec.batch_size, 1, -1.0f, 1.0f, spec.seq_length,
          batch_range);
#if DEBUG
  cout << "stack_2_ptrs #1" << endl;
  print_device_matrix(stack_2_ptrs, 1, spec.batch_size);
#endif

  // stack_2_ptrs = stack_2_ptrs * batch_size + batch_range * 1
  k::addi_vv(handle, stack_2_ptrs, batch_range, spec.batch_size, 1,
          spec.batch_size);
#if DEBUG
  cout << "stack_2_ptrs" << endl;
  print_device_matrix(stack_2_ptrs, 1, spec.batch_size);
#endif

  // stack_1, stack_2
  // stack_1_t = stack[batch_range + (t - 1) * spec.batch_size]
  k::subtensor1(stack_1_t, stack, batch_range,
          spec.batch_size * spec.seq_length, spec.batch_size,
          spec.model_dim, (float) (t - 1) * spec.batch_size, 1.0f, 0.0f,
          NULL);

  k::subtensor1(stack_2_t, stack, stack_2_ptrs,
          spec.batch_size * spec.seq_length, spec.batch_size,
          spec.model_dim, 0.0f, 1.0f, 0.0f, NULL);

  // Run recurrence, which writes into `push_output`, `merge_output`.
  recurrence(stack_1_t, stack_2_t, buffer_top_t);

  // Write in the next stack top.
  mask_and_update_stack(buffer_top_t, merge_output, transitions_t, t);

  mask_and_update_cursors(cursors, transitions_t, t);
#if DEBUG
  cout << "cursors after" << endl;
  print_device_matrix(cursors, 1, spec.batch_size);
#endif

  // queue[cursors + 0 + batch_range * spec.seq_length] = t
  k::set_subtensor1i_s(queue, t, cursors, spec.batch_size, 0, spec.seq_length,
          batch_range);
#if DEBUG
  cout << "queue after" << endl;
  print_device_matrix(queue, 1, spec.seq_length * spec.batch_size);
#endif

  // buffer_cur += (1 - transitions)
  update_buffer_cur(buffer_cur_t, transitions_t, t);
#if DEBUG
  cout << "buffer cur after" << endl;
  print_device_matrix(buffer_cur_t, 1, spec.batch_size);
#endif

}

void ThinStack::recurrence(const float *stack_1_t, const float *stack_2_t,
    const float *buffer_top_t) {

  // merge_out = W_l l
  float alpha = 1.0f;
  float beta = 0.0f;
  cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, spec.model_dim, spec.batch_size,
      spec.model_dim, &alpha, params.compose_W_l, spec.model_dim, stack_2_t,
      spec.model_dim, &beta, merge_output, spec.model_dim);
  // merge_out += W_r r
  float beta2 = 1.0f;
  cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, spec.model_dim, spec.batch_size,
      spec.model_dim, &alpha, params.compose_W_r, spec.model_dim, stack_1_t,
      spec.model_dim, &beta2, merge_output, spec.model_dim);

  // TODO bias (broadcast-add)
  // TODO relu

}

void ThinStack::mask_and_update_stack(const float *push_value,
    const float *merge_value, const float *transitions, int t) {

  // Find start position of write destination (next-top corresponding to
  // timestep `t`).
  int stack_offset = t * spec.batch_size * spec.model_dim;

#if DEBUG
  cout << "merge value:" << endl;
  print_device_matrix(merge_value, spec.model_dim, spec.batch_size);
  cout << "push value:" << endl;
  print_device_matrix(push_value, spec.model_dim, spec.batch_size);
#endif

  k::switch_m(&stack[stack_offset], transitions, merge_value, push_value,
              spec.batch_size, spec.model_dim);

#if DEBUG
  cout << "stack top t (offset " << stack_offset << "):" << endl;
  print_device_matrix(&stack[stack_offset], spec.model_dim, spec.batch_size);
#endif

}

void ThinStack::mask_and_update_cursors(float *cursors, const float *transitions,
    int t) {

  // cursors += 1
  float alpha1 = 1.0f;
  cublasSaxpy(handle, spec.batch_size, &alpha1, batch_ones, 1, cursors, 1);

  // cursors -= 2*transitions
  float alpha2 = -2.0f;
  cublasSaxpy(handle, spec.batch_size, &alpha2, transitions, 1, cursors, 1);

}

void ThinStack::update_buffer_cur(float *buffer_cur_t, float *transitions, int t) {

  // buffer_cur += 1
  float alpha1 = 1.0;
  cublasSaxpy(handle, spec.batch_size, &alpha1, batch_ones, 1, buffer_cur_t, 1);

  // buffer_cur -= transitions
  float alpha2 = -1.0;
  cublasSaxpy(handle, spec.batch_size, &alpha2, transitions, 1, buffer_cur_t, 1);

}

void ThinStack::reset() {
  cudaMemset(stack, 0, stack_total_size * sizeof(float));
  cudaMemset(queue, 0, queue_total_size * sizeof(float));

  float alpha = -1.0f;
  cudaMemset(cursors, 0, cursors_total_size * sizeof(float));
  cublasSaxpy(handle, spec.batch_size, &alpha, batch_ones, 1, cursors, 1);

  cudaMemset(buffer_cur_t, 0, spec.batch_size * sizeof(float));
}
<|endoftext|>


<commit_before>/** @file

  Calculate some derivative metrics (for convenience).

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

#include "DerivativeMetrics.h"

// ToDo: It's a little bizarre that we include this here, but it's the only way to get to RecSetRecord(). We should
// move that elsewhere... But other places in our core does the same thing.
#include "P_RecCore.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This currently only supports one type of derivative metrics: Sums() of other, existing metrics. It's ok to add
// additional metrics here, and we prefer to call them proxy.process (since, hopefully in the future, traffic_manager dies).
//
static const std::vector<DerivativeSum> sum_metrics = {
  // Total bytes of client request body + headers
  {"proxy.process.http.user_agent_total_request_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_request_document_total_size", "proxy.process.http.user_agent_request_header_total_size"}},
  // Total bytes of client response body + headers
  {"proxy.process.http.user_agent_total_response_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_response_document_total_size", "proxy.process.http.user_agent_response_header_total_size"}},
  // Total bytes of origin server request body + headers
  {"proxy.process.http.origin_server_total_request_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_request_document_total_size", "proxy.process.http.origin_server_request_header_total_size"}},
  // Total bytes of origin server response body + headers
  {"proxy.process.http.origin_server_total_response_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_response_document_total_size",
    "proxy.process.http.origin_server_response_header_total_size"}},
  // Total byates of client request and response (total traffic to and from clients)
  {"proxy.process.user_agent_total_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_total_request_bytes", "proxy.process.http.user_agent_total_response_bytes"}},
  // Total bytes of origin/parent request and response
  {"proxy.process.origin_server_total_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_total_request_bytes", "proxy.process.http.origin_server_total_response_bytes",
    "proxy.process.http.parent_proxy_request_total_bytes", "proxy.process.http.parent_proxy_response_total_bytes"}},
  // Total requests which are cache hits
  {"proxy.process.cache_total_hits",
   RECD_COUNTER,
   {"proxy.process.http.cache_hit_fresh", "proxy.process.http.cache_hit_mem_fresh", "proxy.process.http.cache_hit_revalidated",
    "proxy.process.http.cache_hit_ims", "proxy.process.http.cache_hit_stale_served"}},
  // Total requests which are cache misses
  {"proxy.process.cache_total_misses",
   RECD_COUNTER,
   {"proxy.process.http.cache_miss_cold", "proxy.process.http.cache_miss_changed", "proxy.process.http.cache_miss_client_no_cache",
    "proxy.process.http.cache_miss_ims", "proxy.process.http.cache_miss_client_not_cacheable"}},
  // Total requests, both hits and misses (this is slightly superflous, but assures correct percentage calculations)
  {"proxy.process.cache_total_requests", RECD_COUNTER, {"proxy.process.cache_total_hits", "proxy.process.cache_total_misses"}},
  // Total cache requests bytes which are cache hits
  {"proxy.process.cache_total_hits_bytes",
   RECD_INT,
   {"proxy.process.http.tcp_hit_user_agent_bytes_stat", "proxy.process.http.tcp_refresh_hit_user_agent_bytes_stat",
    "proxy.process.http.tcp_ims_hit_user_agent_bytes_stat"}},
  // Total cache requests bytes which are cache misses
  {"proxy.process.cache_total_misses_bytes",
   RECD_INT,
   {"proxy.process.http.tcp_miss_user_agent_bytes_stat", "proxy.process.http.tcp_expired_miss_user_agent_bytes_stat",
    "proxy.process.http.tcp_refresh_miss_user_agent_bytes_stat", "proxy.process.http.tcp_ims_miss_user_agent_bytes_stat"}},
  // Total request bytes, both hits and misses
  {"proxy.process.cache_total_bytes", RECD_INT, {"proxy.process.cache_total_hits_bytes", "proxy.process.cache_total_misses_bytes"}},
  // Total of all server connections (sum of origins and parent connections)
  {"proxy.process.current_server_connections",
   RECD_INT,
   {"proxy.process.http.current_server_connections", "proxy.process.http.current_parent_proxy_connections"}}};

// The constructor is responsible for registering the new metrics. ToDo: At some point we could
// in theory expand this to support some sort of configuration, and then replace the hardcoded metrics
// here with parameters to an Add() method.
DerivativeMetrics::DerivativeMetrics()
{
  // Add all the sum derived metrics to LibRecords
  for (auto &&[derived_metric, type, metric_parts] : sum_metrics) {
    (void)metric_parts;

    switch (type) {
    case RECD_INT:
      RecRegisterStatInt(RECT_PROCESS, derived_metric, static_cast<RecInt>(0), RECP_NON_PERSISTENT);
      break;
    case RECD_COUNTER:
      RecRegisterStatCounter(RECT_PROCESS, derived_metric, static_cast<RecCounter>(0), RECP_NON_PERSISTENT);
      break;
    default:
      ink_release_assert(!"Unsupported metric type");
      break;
    }
  }
}

// Updates all the derived metrics
void
DerivativeMetrics::Update()
{
  int error = REC_ERR_FAIL;
  RecData sum;
  RecInt int_val;
  RecCounter counter_val;

  for (auto &&[derived_metric, type, metric_parts] : sum_metrics) {
    ink_zero(sum);
    for (auto &&metric : metric_parts) {
      switch (type) {
      case RECD_INT:
        error = RecGetRecordInt(metric, &int_val);
        sum.rec_int += int_val;
        break;
      case RECD_COUNTER:
        error = RecGetRecordCounter(metric, &counter_val);
        sum.rec_counter += counter_val;
        break;
      default:
        ink_release_assert(!"Unsupported metric type");
        break;
      }
      if (error) { // No point in continuing here, since the metric is failing for odd reasons
        break;
      }
    }

    if (!error) {
      RecSetRecord(RECT_NULL, derived_metric, type, &sum, nullptr, REC_SOURCE_EXPLICIT);
    }
  }
}
<commit_msg>Fixes the cache_total_hits to be correct<commit_after>/** @file

  Calculate some derivative metrics (for convenience).

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

#include "DerivativeMetrics.h"

// ToDo: It's a little bizarre that we include this here, but it's the only way to get to RecSetRecord(). We should
// move that elsewhere... But other places in our core does the same thing.
#include "P_RecCore.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This currently only supports one type of derivative metrics: Sums() of other, existing metrics. It's ok to add
// additional metrics here, and we prefer to call them proxy.process (since, hopefully in the future, traffic_manager dies).
//
static const std::vector<DerivativeSum> sum_metrics = {
  // Total bytes of client request body + headers
  {"proxy.process.http.user_agent_total_request_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_request_document_total_size", "proxy.process.http.user_agent_request_header_total_size"}},
  // Total bytes of client response body + headers
  {"proxy.process.http.user_agent_total_response_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_response_document_total_size", "proxy.process.http.user_agent_response_header_total_size"}},
  // Total bytes of origin server request body + headers
  {"proxy.process.http.origin_server_total_request_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_request_document_total_size", "proxy.process.http.origin_server_request_header_total_size"}},
  // Total bytes of origin server response body + headers
  {"proxy.process.http.origin_server_total_response_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_response_document_total_size",
    "proxy.process.http.origin_server_response_header_total_size"}},
  // Total byates of client request and response (total traffic to and from clients)
  {"proxy.process.user_agent_total_bytes",
   RECD_INT,
   {"proxy.process.http.user_agent_total_request_bytes", "proxy.process.http.user_agent_total_response_bytes"}},
  // Total bytes of origin/parent request and response
  {"proxy.process.origin_server_total_bytes",
   RECD_INT,
   {"proxy.process.http.origin_server_total_request_bytes", "proxy.process.http.origin_server_total_response_bytes",
    "proxy.process.http.parent_proxy_request_total_bytes", "proxy.process.http.parent_proxy_response_total_bytes"}},
  // Total requests which are cache hits
  {"proxy.process.cache_total_hits",
   RECD_COUNTER,
   {"proxy.process.http.cache_hit_fresh", "proxy.process.http.cache_hit_revalidated", "proxy.process.http.cache_hit_ims",
    "proxy.process.http.cache_hit_stale_served"}},
  // Total requests which are cache misses
  {"proxy.process.cache_total_misses",
   RECD_COUNTER,
   {"proxy.process.http.cache_miss_cold", "proxy.process.http.cache_miss_changed", "proxy.process.http.cache_miss_client_no_cache",
    "proxy.process.http.cache_miss_ims", "proxy.process.http.cache_miss_client_not_cacheable"}},
  // Total requests, both hits and misses (this is slightly superflous, but assures correct percentage calculations)
  {"proxy.process.cache_total_requests", RECD_COUNTER, {"proxy.process.cache_total_hits", "proxy.process.cache_total_misses"}},
  // Total cache requests bytes which are cache hits
  {"proxy.process.cache_total_hits_bytes",
   RECD_INT,
   {"proxy.process.http.tcp_hit_user_agent_bytes_stat", "proxy.process.http.tcp_refresh_hit_user_agent_bytes_stat",
    "proxy.process.http.tcp_ims_hit_user_agent_bytes_stat"}},
  // Total cache requests bytes which are cache misses
  {"proxy.process.cache_total_misses_bytes",
   RECD_INT,
   {"proxy.process.http.tcp_miss_user_agent_bytes_stat", "proxy.process.http.tcp_expired_miss_user_agent_bytes_stat",
    "proxy.process.http.tcp_refresh_miss_user_agent_bytes_stat", "proxy.process.http.tcp_ims_miss_user_agent_bytes_stat"}},
  // Total request bytes, both hits and misses
  {"proxy.process.cache_total_bytes", RECD_INT, {"proxy.process.cache_total_hits_bytes", "proxy.process.cache_total_misses_bytes"}},
  // Total of all server connections (sum of origins and parent connections)
  {"proxy.process.current_server_connections",
   RECD_INT,
   {"proxy.process.http.current_server_connections", "proxy.process.http.current_parent_proxy_connections"}}};

// The constructor is responsible for registering the new metrics. ToDo: At some point we could
// in theory expand this to support some sort of configuration, and then replace the hardcoded metrics
// here with parameters to an Add() method.
DerivativeMetrics::DerivativeMetrics()
{
  // Add all the sum derived metrics to LibRecords
  for (auto &&[derived_metric, type, metric_parts] : sum_metrics) {
    (void)metric_parts;

    switch (type) {
    case RECD_INT:
      RecRegisterStatInt(RECT_PROCESS, derived_metric, static_cast<RecInt>(0), RECP_NON_PERSISTENT);
      break;
    case RECD_COUNTER:
      RecRegisterStatCounter(RECT_PROCESS, derived_metric, static_cast<RecCounter>(0), RECP_NON_PERSISTENT);
      break;
    default:
      ink_release_assert(!"Unsupported metric type");
      break;
    }
  }
}

// Updates all the derived metrics
void
DerivativeMetrics::Update()
{
  int error = REC_ERR_FAIL;
  RecData sum;
  RecInt int_val;
  RecCounter counter_val;

  for (auto &&[derived_metric, type, metric_parts] : sum_metrics) {
    ink_zero(sum);
    for (auto &&metric : metric_parts) {
      switch (type) {
      case RECD_INT:
        error = RecGetRecordInt(metric, &int_val);
        sum.rec_int += int_val;
        break;
      case RECD_COUNTER:
        error = RecGetRecordCounter(metric, &counter_val);
        sum.rec_counter += counter_val;
        break;
      default:
        ink_release_assert(!"Unsupported metric type");
        break;
      }
      if (error) { // No point in continuing here, since the metric is failing for odd reasons
        break;
      }
    }

    if (!error) {
      RecSetRecord(RECT_NULL, derived_metric, type, &sum, nullptr, REC_SOURCE_EXPLICIT);
    }
  }
}
<|endoftext|>


<commit_before><commit_msg>[Smart Lock] Fix wrong condition for the branding in password generation.<commit_after><|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/xattr.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include <sstream>
#include <algorithm>

#include "../fs/rm.hh"
#include "../json/encoder.hh"
#include "../stream/buffered-stream.hh"
#include "../stream/copy.hh"
#include "../stream/direct-fd-stream.hh"
#include "../string-ref.hh"
#include "../uri/normalize-path.hh"
#include "error-handler.hh"
#include "fs-handler.hh"
#include "log.hh"
#include "mime-db.hh"

namespace mimosa
{
  namespace http
  {
    FsHandler::FsHandler(const std::string & root, int nskip)
      : root_(root),
        nskip_(nskip),
        can_readdir_(false),
        can_head_(true),
        can_get_(true),
        can_put_(false),
        can_delete_(false),
        can_mkcol_(false),
        use_xattr_(false),
        can_symlink_(false),
        can_move_(false)
    {
    }

    std::string
    FsHandler::checkPath(RequestReader & request) const
    {
      return checkPath(request.location());
    }

    std::string
    FsHandler::checkPath(const std::string & location) const
    {
      StringRef path(location);
      for (auto nskip = nskip_; nskip > 0; --nskip)
      {
        auto pos = path.find('/', 1);
        if (pos == StringRef::npos)
        {
          if (nskip == 1 && path.size() > 1) // our location is root and is not terminated by '/'
          {
            path = StringRef("/");
            break;
          }
          else
            return "";
        }
        path = path.substr(pos);
      }

      // TODO: check every component for symlinks going out of root.

      std::string real_path(root_);
      real_path.append(path.data(), path.size());
      return real_path;
    }

    bool
    FsHandler::head(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_head_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      struct stat st;
      if (::stat(real_path.c_str(), &st))
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);
      response.setContentLength(st.st_size);
      response.setContentType(MimeDb::instance().mimeType(real_path));
      return true;
    }

    bool
    FsHandler::get(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_get_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      struct stat st;
      if (::stat(real_path.c_str(), &st))
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      if (S_ISREG(st.st_mode)) {
        if (use_xattr_) {
          char xattr_buffer[128];
          getxattr(real_path.c_str(), "user.Content-Type", xattr_buffer, sizeof (xattr_buffer));
          xattr_buffer[sizeof (xattr_buffer) - 1] = '\0';
          response.setContentType(xattr_buffer);
        }
        return streamFile(request, response, real_path, st);
      } else if (S_ISDIR(st.st_mode) && can_readdir_)
        return readDir(request, response, real_path);
      return ErrorHandler::basicResponse(request, response, kStatusForbidden);
    }

    bool
    FsHandler::put(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_put_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      stream::DirectFdStream out;
      if (!out.open(real_path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666))
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

      if (stream::copy(request, out) < 0)
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

      if (use_xattr_)
        setxattr(real_path.c_str(), "user.Content-Type", request.contentType().c_str(),
                 request.contentType().size() + 1, 0);
      return true;
    }

    bool
    FsHandler::del(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_delete_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      if (!fs::rm(real_path, false, false)) {
        if (errno == ENOENT)
          return ErrorHandler::basicResponse(request, response, kStatusNotFound);
        if (errno == EISDIR)
          return ErrorHandler::basicResponse(request, response, kStatusBadRequest);
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::mkcol(RequestReader & request,
                     ResponseWriter & response) const
    {
      if (!can_mkcol_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      if (mkdir(real_path.c_str(), 0777)) {
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        if (errno == EEXIST)
          return ErrorHandler::basicResponse(request, response, kStatusConflict);
        if (errno == ENOSPC)
          return ErrorHandler::basicResponse(request, response, kStatusInsufficientStorage);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::move(RequestReader & request,
                    ResponseWriter & response) const
    {
      if (!can_move_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string source_real_path = checkPath(request);
      std::string destination;
      uri::normalizePath(request.destination().c_str(), request.destination().size(),
                         &destination);
      std::string destination_real_path = checkPath(destination);
      if (source_real_path.empty() || destination_real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusBadRequest);
      }

      if (::rename(source_real_path.c_str(), destination_real_path.c_str())) {
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        if (errno == EEXIST)
          return ErrorHandler::basicResponse(request, response, kStatusConflict);
        if (errno == ENOSPC)
          return ErrorHandler::basicResponse(request, response, kStatusInsufficientStorage);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::streamFile(RequestReader &     request,
                          ResponseWriter &    response,
                          const std::string & real_path)
    {
      struct stat st;

      if (stat(real_path.c_str(), &st))
        return false;
      return streamFile(request, response, real_path, st);
    }

    bool
    FsHandler::streamFile(RequestReader &     request,
                          ResponseWriter &    response,
                          const std::string & real_path,
                          struct stat &       st)
    {
      if (request.hasIfModifiedSince() && request.ifModifiedSince() >= st.st_mtime)
      {
        response.setContentLength(0);
        response.setStatus(kStatusNotModified);
        response.sendHeader();
        return true;
      }

      int fd = ::open(real_path.c_str(), O_RDONLY, 0644);
      if (fd < 0)
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

      int64_t length = st.st_size;

      // to use sendfile and support content-range, we need identity
      response.setContentEncoding(kCodingIdentity);
      response.setContentLength(st.st_size);

      // content-range support
      if (request.hasRange()) {
        ByteRange range = request.range().front();

        switch (range.type_) {
        case ByteRange::kStart:
          range.end_ = st.st_size;
          break;
        case ByteRange::kRange:
          range.end_++;
          break;
        case ByteRange::kSuffix:
          range.start_ = st.st_size - range.end_;
          range.end_   = st.st_size;
          break;
        }

        if (range.end_ <= range.start_ ||
            range.end_ > st.st_size ||
            range.start_ < 0) {
          ::close(fd);
          return ErrorHandler::basicResponse(request, response, kStatusRequestedRangeNotSatisfiable);
        }

        if (range.start_ > 0)
          if (::lseek(fd, request.contentRangeStart(), SEEK_SET) != range.start_) {
            ::close(fd);
            return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
          }

        length = range.end_ - range.start_;
        response.setStatus(kStatusPartialContent);
        response.setContentRange(range.start_, range.end_, st.st_size);
      }

      // guess content-type
      if (response.contentType().empty())
        response.setContentType(MimeDb::instance().mimeType(real_path));
      response.setLastModified(st.st_mtime);
      response.sendHeader();

      stream::DirectFdStream file(fd);
      stream::DirectFdStream *sock = response.directFdStream();

      int64_t ret;
      if (sock)
        ret = stream::copy(file, *sock, length);
      else
        ret = stream::copy(file, response, length);
      return ret == st.st_size;
    }

    bool
    FsHandler::readDir(RequestReader &     request,
                       ResponseWriter &    response,
                       const std::string & real_path) const
    {
      auto & format = request.queryGet("format");

      if (format == "json")
        return readDirJson(request, response, real_path);
      return readDirHtml(request, response, real_path);
    }

    bool
    FsHandler::readDirHtml(RequestReader &     request,
                           ResponseWriter &    response,
                           const std::string & real_path) const
    {
      DIR * dir = ::opendir(real_path.c_str());
      if (!dir)
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      response.setContentType("text/html");
      response.sendHeader();
      assert(response.transferEncoding() == kCodingChunked);

      std::ostringstream os;

      os << "<!DOCTYPE html>"
        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>"
        "<title>" << request.location() << "</title>"
        "
Directory listing: " << request.location() << "

";

      std::vector<std::string> directories;
      std::vector<std::string> files;

      struct dirent * entry;
      while ((entry = ::readdir(dir)))
      {
        std::ostringstream tmp;
        tmp << real_path << '/' << entry->d_name;

        std::string file_path(tmp.str());

        struct ::stat st;
        if (::stat(file_path.c_str(), &st))
          continue;

        if (S_ISDIR(st.st_mode))
          directories.push_back(entry->d_name);
        else
          files.push_back(entry->d_name);
      }

      std::sort(directories.begin(), directories.end());
      std::sort(files.begin(), files.end());

      for (auto it = directories.begin(); it != directories.end(); ++it)
        os << "<a href=\"" << *it << "/\">" << *it << "/
";

      for (auto it = files.begin(); it != files.end(); ++it)
        os << "<a href=\"" << *it << "\">" << *it << "
";

      os << "";

      ::closedir(dir);
      std::string data(os.str());
      response.write(data.data(), data.size());
      return true;
    }

    bool
    FsHandler::readDirJson(RequestReader &     request,
                           ResponseWriter &    response,
                           const std::string & real_path) const
    {
      DIR * dir = ::opendir(real_path.c_str());
      if (!dir)
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      response.setContentType("application/json");
      response.sendHeader();

      stream::Stream::Ptr buf(new stream::BufferedStream(&response));
      json::Encoder enc(buf);

      enc.startArray();
      struct dirent * entry;
      while ((entry = ::readdir(dir)))
      {
        std::ostringstream tmp;
        tmp << real_path << '/' << entry->d_name;

        std::string file_path(tmp.str());
        struct ::stat st;
        if (::stat(file_path.c_str(), &st))
          continue;

        enc.startObject();

        enc.pushString("name");
        enc.pushString(entry->d_name);

        enc.pushString("size");
        enc.pushNumber(st.st_size);

        enc.pushString("type");
        if (S_ISDIR(st.st_mode))
          enc.pushString("dir");
        else if (S_ISREG(st.st_mode))
          enc.pushString("reg");
        else if (S_ISLNK(st.st_mode))
          enc.pushString("lnk");
        else if (S_ISSOCK(st.st_mode))
          enc.pushString("sock");
        else if (S_ISFIFO(st.st_mode))
          enc.pushString("fifo");
        else if (S_ISCHR(st.st_mode))
          enc.pushString("chr");
        else if (S_ISBLK(st.st_mode))
          enc.pushString("blk");
        else
          enc.pushString("???");

        enc.endObject();
      }
      enc.endArray();
      ::closedir(dir);
      return true;
    }
  }
}
<commit_msg>MacOSX port<commit_after>#include <sys/types.h>
#include <sys/xattr.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include <sstream>
#include <algorithm>

#include "../fs/rm.hh"
#include "../json/encoder.hh"
#include "../stream/buffered-stream.hh"
#include "../stream/copy.hh"
#include "../stream/direct-fd-stream.hh"
#include "../string-ref.hh"
#include "../uri/normalize-path.hh"
#include "error-handler.hh"
#include "fs-handler.hh"
#include "log.hh"
#include "mime-db.hh"

namespace mimosa
{
  namespace http
  {
    FsHandler::FsHandler(const std::string & root, int nskip)
      : root_(root),
        nskip_(nskip),
        can_readdir_(false),
        can_head_(true),
        can_get_(true),
        can_put_(false),
        can_delete_(false),
        can_mkcol_(false),
        use_xattr_(false),
        can_symlink_(false),
        can_move_(false)
    {
    }

    std::string
    FsHandler::checkPath(RequestReader & request) const
    {
      return checkPath(request.location());
    }

    std::string
    FsHandler::checkPath(const std::string & location) const
    {
      StringRef path(location);
      for (auto nskip = nskip_; nskip > 0; --nskip)
      {
        auto pos = path.find('/', 1);
        if (pos == StringRef::npos)
        {
          if (nskip == 1 && path.size() > 1) // our location is root and is not terminated by '/'
          {
            path = StringRef("/");
            break;
          }
          else
            return "";
        }
        path = path.substr(pos);
      }

      // TODO: check every component for symlinks going out of root.

      std::string real_path(root_);
      real_path.append(path.data(), path.size());
      return real_path;
    }

    bool
    FsHandler::head(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_head_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      struct stat st;
      if (::stat(real_path.c_str(), &st))
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);
      response.setContentLength(st.st_size);
      response.setContentType(MimeDb::instance().mimeType(real_path));
      return true;
    }

    bool
    FsHandler::get(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_get_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      struct stat st;
      if (::stat(real_path.c_str(), &st))
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      if (S_ISREG(st.st_mode)) {
#ifndef __MACH__
        if (use_xattr_) {
          char xattr_buffer[128];
          getxattr(real_path.c_str(), "user.Content-Type", xattr_buffer, sizeof (xattr_buffer));
          xattr_buffer[sizeof (xattr_buffer) - 1] = '\0';
          response.setContentType(xattr_buffer);
        }
#endif
        return streamFile(request, response, real_path, st);
      } else if (S_ISDIR(st.st_mode) && can_readdir_)
        return readDir(request, response, real_path);
      return ErrorHandler::basicResponse(request, response, kStatusForbidden);
    }

    bool
    FsHandler::put(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_put_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      stream::DirectFdStream out;
      if (!out.open(real_path.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666))
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

      if (stream::copy(request, out) < 0)
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

#ifndef __MACH__
      if (use_xattr_)
        setxattr(real_path.c_str(), "user.Content-Type", request.contentType().c_str(),
                 request.contentType().size() + 1, 0);
#endif
      return true;
    }

    bool
    FsHandler::del(RequestReader & request, ResponseWriter & response) const
    {
      if (!can_delete_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      if (!fs::rm(real_path, false, false)) {
        if (errno == ENOENT)
          return ErrorHandler::basicResponse(request, response, kStatusNotFound);
        if (errno == EISDIR)
          return ErrorHandler::basicResponse(request, response, kStatusBadRequest);
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::mkcol(RequestReader & request,
                     ResponseWriter & response) const
    {
      if (!can_mkcol_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string real_path = checkPath(request);
      if (real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }

      if (mkdir(real_path.c_str(), 0777)) {
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        if (errno == EEXIST)
          return ErrorHandler::basicResponse(request, response, kStatusConflict);
        if (errno == ENOSPC)
          return ErrorHandler::basicResponse(request, response, kStatusInsufficientStorage);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::move(RequestReader & request,
                    ResponseWriter & response) const
    {
      if (!can_move_)
        return ErrorHandler::basicResponse(request, response, kStatusForbidden);

      std::string source_real_path = checkPath(request);
      std::string destination;
      uri::normalizePath(request.destination().c_str(), request.destination().size(),
                         &destination);
      std::string destination_real_path = checkPath(destination);
      if (source_real_path.empty() || destination_real_path.empty()) {
        return ErrorHandler::basicResponse(request, response, kStatusBadRequest);
      }

      if (::rename(source_real_path.c_str(), destination_real_path.c_str())) {
        if (errno == EPERM || errno == EACCES)
          return ErrorHandler::basicResponse(request, response, kStatusForbidden);
        if (errno == EEXIST)
          return ErrorHandler::basicResponse(request, response, kStatusConflict);
        if (errno == ENOSPC)
          return ErrorHandler::basicResponse(request, response, kStatusInsufficientStorage);
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
      }
      return true;
    }

    bool
    FsHandler::streamFile(RequestReader &     request,
                          ResponseWriter &    response,
                          const std::string & real_path)
    {
      struct stat st;

      if (stat(real_path.c_str(), &st))
        return false;
      return streamFile(request, response, real_path, st);
    }

    bool
    FsHandler::streamFile(RequestReader &     request,
                          ResponseWriter &    response,
                          const std::string & real_path,
                          struct stat &       st)
    {
      if (request.hasIfModifiedSince() && request.ifModifiedSince() >= st.st_mtime)
      {
        response.setContentLength(0);
        response.setStatus(kStatusNotModified);
        response.sendHeader();
        return true;
      }

      int fd = ::open(real_path.c_str(), O_RDONLY, 0644);
      if (fd < 0)
        return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);

      int64_t length = st.st_size;

      // to use sendfile and support content-range, we need identity
      response.setContentEncoding(kCodingIdentity);
      response.setContentLength(st.st_size);

      // content-range support
      if (request.hasRange()) {
        ByteRange range = request.range().front();

        switch (range.type_) {
        case ByteRange::kStart:
          range.end_ = st.st_size;
          break;
        case ByteRange::kRange:
          range.end_++;
          break;
        case ByteRange::kSuffix:
          range.start_ = st.st_size - range.end_;
          range.end_   = st.st_size;
          break;
        }

        if (range.end_ <= range.start_ ||
            range.end_ > st.st_size ||
            range.start_ < 0) {
          ::close(fd);
          return ErrorHandler::basicResponse(request, response, kStatusRequestedRangeNotSatisfiable);
        }

        if (range.start_ > 0)
          if (::lseek(fd, request.contentRangeStart(), SEEK_SET) != range.start_) {
            ::close(fd);
            return ErrorHandler::basicResponse(request, response, kStatusInternalServerError);
          }

        length = range.end_ - range.start_;
        response.setStatus(kStatusPartialContent);
        response.setContentRange(range.start_, range.end_, st.st_size);
      }

      // guess content-type
      if (response.contentType().empty())
        response.setContentType(MimeDb::instance().mimeType(real_path));
      response.setLastModified(st.st_mtime);
      response.sendHeader();

      stream::DirectFdStream file(fd);
      stream::DirectFdStream *sock = response.directFdStream();

      int64_t ret;
      if (sock)
        ret = stream::copy(file, *sock, length);
      else
        ret = stream::copy(file, response, length);
      return ret == st.st_size;
    }

    bool
    FsHandler::readDir(RequestReader &     request,
                       ResponseWriter &    response,
                       const std::string & real_path) const
    {
      auto & format = request.queryGet("format");

      if (format == "json")
        return readDirJson(request, response, real_path);
      return readDirHtml(request, response, real_path);
    }

    bool
    FsHandler::readDirHtml(RequestReader &     request,
                           ResponseWriter &    response,
                           const std::string & real_path) const
    {
      DIR * dir = ::opendir(real_path.c_str());
      if (!dir)
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      response.setContentType("text/html");
      response.sendHeader();
      assert(response.transferEncoding() == kCodingChunked);

      std::ostringstream os;

      os << "<!DOCTYPE html>"
        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>"
        "<title>" << request.location() << "</title>"
        "
Directory listing: " << request.location() << "

";

      std::vector<std::string> directories;
      std::vector<std::string> files;

      struct dirent * entry;
      while ((entry = ::readdir(dir)))
      {
        std::ostringstream tmp;
        tmp << real_path << '/' << entry->d_name;

        std::string file_path(tmp.str());

        struct ::stat st;
        if (::stat(file_path.c_str(), &st))
          continue;

        if (S_ISDIR(st.st_mode))
          directories.push_back(entry->d_name);
        else
          files.push_back(entry->d_name);
      }

      std::sort(directories.begin(), directories.end());
      std::sort(files.begin(), files.end());

      for (auto it = directories.begin(); it != directories.end(); ++it)
        os << "<a href=\"" << *it << "/\">" << *it << "/
";

      for (auto it = files.begin(); it != files.end(); ++it)
        os << "<a href=\"" << *it << "\">" << *it << "
";

      os << "";

      ::closedir(dir);
      std::string data(os.str());
      response.write(data.data(), data.size());
      return true;
    }

    bool
    FsHandler::readDirJson(RequestReader &     request,
                           ResponseWriter &    response,
                           const std::string & real_path) const
    {
      DIR * dir = ::opendir(real_path.c_str());
      if (!dir)
        return ErrorHandler::basicResponse(request, response, kStatusNotFound);

      response.setContentType("application/json");
      response.sendHeader();

      stream::Stream::Ptr buf(new stream::BufferedStream(&response));
      json::Encoder enc(buf);

      enc.startArray();
      struct dirent * entry;
      while ((entry = ::readdir(dir)))
      {
        std::ostringstream tmp;
        tmp << real_path << '/' << entry->d_name;

        std::string file_path(tmp.str());
        struct ::stat st;
        if (::stat(file_path.c_str(), &st))
          continue;

        enc.startObject();

        enc.pushString("name");
        enc.pushString(entry->d_name);

        enc.pushString("size");
        enc.pushNumber(st.st_size);

        enc.pushString("type");
        if (S_ISDIR(st.st_mode))
          enc.pushString("dir");
        else if (S_ISREG(st.st_mode))
          enc.pushString("reg");
        else if (S_ISLNK(st.st_mode))
          enc.pushString("lnk");
        else if (S_ISSOCK(st.st_mode))
          enc.pushString("sock");
        else if (S_ISFIFO(st.st_mode))
          enc.pushString("fifo");
        else if (S_ISCHR(st.st_mode))
          enc.pushString("chr");
        else if (S_ISBLK(st.st_mode))
          enc.pushString("blk");
        else
          enc.pushString("???");

        enc.endObject();
      }
      enc.endArray();
      ::closedir(dir);
      return true;
    }
  }
}
<|endoftext|>