<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DomainMapperTableManager.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: os $ $Date: 2007-05-09 13:55:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include <DomainMapperTableManager.hxx>
#include <doctok/WW8ResourceModel.hxx>
#ifndef INCLUDED_BORDERHANDLER_HXX
#include <BorderHandler.hxx>
#endif
#ifndef INCLUDED_CELLCOLORHANDLER_HXX
#include <CellColorHandler.hxx>
#endif
#ifndef INCLUDED_DMAPPER_CONVERSIONHELPER_HXX
#include <ConversionHelper.hxx>
#endif
#ifndef INCLUDED_MEASUREHANDLER_HXX
#include <MeasureHandler.hxx>
#endif
#ifndef INCLUDED_TDEFTABLEHANDLER_HXX
#include <TDefTableHandler.hxx>
#endif
#ifndef _COM_SUN_STAR_TEXT_HORIORIENTATION_HDL_
#include <com/sun/star/text/HoriOrientation.hpp>
#endif
#ifndef _COM_SUN_STAR_TEXT_SIZETYPE_HDL_
#include <com/sun/star/text/SizeType.hpp>
#endif

namespace dmapper {

using namespace ::com::sun::star;
using namespace ::std;

/*-- 23.04.2007 14:57:49---------------------------------------------------

  -----------------------------------------------------------------------*/
DomainMapperTableManager::DomainMapperTableManager() :
    m_nRow(0),
    m_nCell(0),
    m_nCellBorderIndex(0),
    m_nHeaderRepeat(0),
    m_nGapHalf(0),
    m_nLeftMargin(0),
    m_nTableWidth(0)
{
}
/*-- 23.04.2007 14:57:49---------------------------------------------------

  -----------------------------------------------------------------------*/
DomainMapperTableManager::~DomainMapperTableManager()
{
}
/*-- 23.04.2007 15:25:37---------------------------------------------------

  -----------------------------------------------------------------------*/
bool DomainMapperTableManager::sprm(doctok::Sprm & rSprm)
{
    bool bRet = DomainMapperTableManager_Base_t::sprm(rSprm);
    if( !bRet )
    {
        bRet = true;
        sal_uInt32 nSprmId = rSprm.getId();
        doctok::Value::Pointer_t pValue = rSprm.getValue();
        sal_Int32 nIntValue = ((pValue.get() != NULL) ? pValue->getInt() : 0);
        /* WRITERFILTERSTATUS: table: table_sprmdata */
        switch( nSprmId )
        {
            case 0x5400: // sprmTJc
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                //table justification 0: left, 1: center, 2: right
                sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
                switch( nIntValue )
                {
                    case 1 : nOrient = text::HoriOrientation::CENTER; break;
                    case 2 : nOrient = text::HoriOrientation::RIGHT; break;
                    case 0 :
                    //no break
                    default:;

                }
                PropertyMapPtr pTableMap( new PropertyMap );
                pTableMap->Insert( PROP_HORI_ORIENT, uno::makeAny( nOrient ) );
                insertTableProps( pTableMap );
            }
            break;
            case 0x9601: // sprmTDxaLeft
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
            break;
            case 0x9602: // sprmTDxaGapHalf
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                m_nGapHalf = nIntValue;
                PropertyMapPtr pPropMap( new PropertyMap );
                pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
                insertTableProps(pPropMap);
            }
            break;
            case 0xf661: //sprmTTRLeft left table indent
            case 0xf614: // sprmTTPreferredWidth - preferred table width
            {
                //contains unit and value
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {   //contains attributes x2902 (LN_unit) and x17e2 (LN_trleft)
                    MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
                    pProperties->resolve(*pMeasureHandler);
                    PropertyMapPtr pPropMap( new PropertyMap );
                    if( nSprmId == 0xf661)
                    {
                        m_nLeftMargin = pMeasureHandler->getTwipValue();
                        pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
                    }
                    else
                    {
                        m_nTableWidth = pMeasureHandler->getTwipValue();
                        if( m_nTableWidth )
                            pPropMap->Insert( PROP_WIDTH, uno::makeAny( m_nTableWidth ));
                    }
                    insertTableProps(pPropMap);
                }
            }
            break;
            case 0x3403: // sprmTFCantSplit
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0.5 */
                //row can't break across pages if nIntValue == 1
                PropertyMapPtr pPropMap( new PropertyMap );
                pPropMap->Insert( PROP_IS_SPLIT_ALLOWED, uno::makeAny(sal_Bool( nIntValue == 1 ? sal_False : sal_True ) ));
                insertRowProps(pPropMap);
            }
            break;
            case 0x3404:// sprmTTableHeader
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                // if nIntValue == 1 then the row is a repeated header line
                // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops
                if( nIntValue > 0 && m_nHeaderRepeat >= 0 )
                {
                    ++m_nHeaderRepeat;
                    PropertyMapPtr pPropMap( new PropertyMap );
                    pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( m_nHeaderRepeat ));
                    insertTableProps(pPropMap);
                }
                else
                    m_nHeaderRepeat = -1;
            break;
            case 0x9407: // sprmTDyaRowHeight
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0.5 */
                // table row height - negative values indicate 'exact height' - positive 'at least'
                PropertyMapPtr pPropMap( new PropertyMap );
                bool bMinHeight = true;
                sal_Int16 nHeight = static_cast<sal_Int16>( nIntValue );
                if( nHeight < 0 )
                {
                    bMinHeight = false;
                    nHeight *= -1;
                }
                pPropMap->Insert( PROP_SIZE_TYPE, uno::makeAny(bMinHeight ? text::SizeType::MIN : text::SizeType::FIX ));
                pPropMap->Insert( PROP_HEIGHT, uno::makeAny(ConversionHelper::convertToMM100( nHeight )));
                insertRowProps(pPropMap);
            }
            break;
            case 0xd608: // TDefTable
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    TDefTableHandlerPtr pTDefTableHandler( new TDefTableHandler );
                    pProperties->resolve( *pTDefTableHandler );
                    insertRowProps( pTDefTableHandler->getProperties() );
                    if( !m_nTableWidth )
                    {
                        m_nTableWidth= pTDefTableHandler->getTableWidth();
                        if( m_nTableWidth )
                        {
                            PropertyMapPtr pPropMap( new PropertyMap );
                            pPropMap->Insert( PROP_WIDTH, uno::makeAny( m_nTableWidth ));
                            insertTableProps(pPropMap);
                        }
                    }
                }
            }
            break;
            case 0xD605: // sprmTTableBorders
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    BorderHandlerPtr pBorderHandler( new BorderHandler );
                    pProperties->resolve(*pBorderHandler);
                    cellPropsByCell( m_nCellBorderIndex, PropertyMapPtr( pBorderHandler->getProperties()) );
                    ++m_nCellBorderIndex;
                }
            }
            break;
            case 0xd61a : // sprmTCellTopColor
            case 0xd61b : // sprmTCellLeftColor
            case 0xd61c : // sprmTCellBottomColor
            case 0xd61d : // sprmTCellRightColor
            {
                // each color sprm contains as much colors as cells are in a row
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    CellColorHandlerPtr pCellColorHandler( new CellColorHandler );
                    pProperties->resolve( *pCellColorHandler );
//                    cellPropsByCell(0, PropertyMapPtr( pColorHandler->getProperties()) );
                }
            }
            break;
            default: bRet = false;
        }
    }
    return bRet;
}
/*-- 26.04.2007 08:20:08---------------------------------------------------

  -----------------------------------------------------------------------*/
//void DomainMapperTableManager::attribute(doctok::Id nName, doctok::Value & rVal)
//{
//    sal_Int32 nIntValue = rVal.getInt();
//    rtl::OUString sStringValue = val.getString();
//    /* WRITERFILTERSTATUS: table: tablemanager_attributedata */
//    switch( nName )
//    {
//        case NS_rtf::LN_cellTopColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellLeftColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellBottomColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellRightColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//    }

/*-- 02.05.2007 14:36:26---------------------------------------------------

  -----------------------------------------------------------------------*/
void DomainMapperTableManager::endOfCellAction()
{
    ++m_nCell;
}
/*-- 02.05.2007 14:36:26---------------------------------------------------

  -----------------------------------------------------------------------*/
void DomainMapperTableManager::endOfRowAction()
{
    ++m_nRow;
    m_nCell = 0;
    m_nCellBorderIndex = 0;
}

}
<commit_msg>improved import<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DomainMapperTableManager.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: os $ $Date: 2007-05-21 14:22:16 $
 *
 *  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
 *
 ************************************************************************/
#include <DomainMapperTableManager.hxx>
#include <doctok/WW8ResourceModel.hxx>
#ifndef INCLUDED_BORDERHANDLER_HXX
#include <BorderHandler.hxx>
#endif
#ifndef INCLUDED_CELLCOLORHANDLER_HXX
#include <CellColorHandler.hxx>
#endif
#ifndef INCLUDED_DMAPPER_CONVERSIONHELPER_HXX
#include <ConversionHelper.hxx>
#endif
#ifndef INCLUDED_MEASUREHANDLER_HXX
#include <MeasureHandler.hxx>
#endif
#ifndef INCLUDED_TDEFTABLEHANDLER_HXX
#include <TDefTableHandler.hxx>
#endif
#ifndef _COM_SUN_STAR_TEXT_HORIORIENTATION_HDL_
#include <com/sun/star/text/HoriOrientation.hpp>
#endif
#ifndef _COM_SUN_STAR_TEXT_SIZETYPE_HDL_
#include <com/sun/star/text/SizeType.hpp>
#endif

namespace dmapper {

using namespace ::com::sun::star;
using namespace ::std;

/*-- 23.04.2007 14:57:49---------------------------------------------------

  -----------------------------------------------------------------------*/
DomainMapperTableManager::DomainMapperTableManager() :
    m_nRow(0),
    m_nCell(0),
    m_nCellBorderIndex(0),
    m_nHeaderRepeat(0),
    m_nGapHalf(0),
    m_nLeftMargin(0),
    m_nTableWidth(0)
{
}
/*-- 23.04.2007 14:57:49---------------------------------------------------

  -----------------------------------------------------------------------*/
DomainMapperTableManager::~DomainMapperTableManager()
{
}
/*-- 23.04.2007 15:25:37---------------------------------------------------

  -----------------------------------------------------------------------*/
bool DomainMapperTableManager::sprm(doctok::Sprm & rSprm)
{
    bool bRet = DomainMapperTableManager_Base_t::sprm(rSprm);
    if( !bRet )
    {
        bRet = true;
        sal_uInt32 nSprmId = rSprm.getId();
        doctok::Value::Pointer_t pValue = rSprm.getValue();
        sal_Int32 nIntValue = ((pValue.get() != NULL) ? pValue->getInt() : 0);
        /* WRITERFILTERSTATUS: table: table_sprmdata */
        switch( nSprmId )
        {
            case 0x5400: // sprmTJc
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                //table justification 0: left, 1: center, 2: right
                sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
                switch( nIntValue )
                {
                    case 1 : nOrient = text::HoriOrientation::CENTER; break;
                    case 2 : nOrient = text::HoriOrientation::RIGHT; break;
                    case 0 :
                    //no break
                    default:;

                }
                PropertyMapPtr pTableMap( new PropertyMap );
                pTableMap->Insert( PROP_HORI_ORIENT, uno::makeAny( nOrient ) );
                insertTableProps( pTableMap );
            }
            break;
            case 0x9601: // sprmTDxaLeft
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
            break;
            case 0x9602: // sprmTDxaGapHalf
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                m_nGapHalf = nIntValue;
                PropertyMapPtr pPropMap( new PropertyMap );
                pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
                insertTableProps(pPropMap);
            }
            break;
            case 0xf661: //sprmTTRLeft left table indent
            case 0xf614: // sprmTTPreferredWidth - preferred table width
            {
                //contains unit and value
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {   //contains attributes x2902 (LN_unit) and x17e2 (LN_trleft)
                    MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
                    pProperties->resolve(*pMeasureHandler);
                    PropertyMapPtr pPropMap( new PropertyMap );
                    if( nSprmId == 0xf661)
                    {
                        m_nLeftMargin = pMeasureHandler->getTwipValue();
                        pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
                    }
                    else
                    {
                        m_nTableWidth = pMeasureHandler->getTwipValue();
                        if( m_nTableWidth )
                            pPropMap->Insert( PROP_WIDTH, uno::makeAny( m_nTableWidth ));
                    }
                    insertTableProps(pPropMap);
                }
            }
            break;
            case 0x3403: // sprmTFCantSplit
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0.5 */
                //row can't break across pages if nIntValue == 1
                PropertyMapPtr pPropMap( new PropertyMap );
                pPropMap->Insert( PROP_IS_SPLIT_ALLOWED, uno::makeAny(sal_Bool( nIntValue == 1 ? sal_False : sal_True ) ));
                insertRowProps(pPropMap);
            }
            break;
            case 0x3404:// sprmTTableHeader
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                // if nIntValue == 1 then the row is a repeated header line
                // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops
                if( nIntValue > 0 && m_nHeaderRepeat >= 0 )
                {
                    ++m_nHeaderRepeat;
                    PropertyMapPtr pPropMap( new PropertyMap );
                    pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( m_nHeaderRepeat ));
                    insertTableProps(pPropMap);
                }
                else
                    m_nHeaderRepeat = -1;
            break;
            case 0x9407: // sprmTDyaRowHeight
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0.5 */
                // table row height - negative values indicate 'exact height' - positive 'at least'
                PropertyMapPtr pPropMap( new PropertyMap );
                bool bMinHeight = true;
                sal_Int16 nHeight = static_cast<sal_Int16>( nIntValue );
                if( nHeight < 0 )
                {
                    bMinHeight = false;
                    nHeight *= -1;
                }
                pPropMap->Insert( PROP_SIZE_TYPE, uno::makeAny(bMinHeight ? text::SizeType::MIN : text::SizeType::FIX ));
                pPropMap->Insert( PROP_HEIGHT, uno::makeAny(ConversionHelper::convertToMM100( nHeight )));
                insertRowProps(pPropMap);
            }
            break;
            case 0xd608: // TDefTable
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    TDefTableHandlerPtr pTDefTableHandler( new TDefTableHandler );
                    pProperties->resolve( *pTDefTableHandler );
                    insertRowProps( pTDefTableHandler->getRowProperties() );
                    if( !m_nTableWidth )
                    {
                        m_nTableWidth= pTDefTableHandler->getTableWidth();
                        if( m_nTableWidth )
                        {
                            PropertyMapPtr pPropMap( new PropertyMap );
                            pPropMap->Insert( PROP_WIDTH, uno::makeAny( m_nTableWidth ));
                            insertTableProps(pPropMap);
                        }
                    }
                    for( size_t nCell = 0; nCell < pTDefTableHandler->getCellCount(); ++nCell )
                        cellPropsByCell( nCell, pTDefTableHandler->getCellProperties( nCell ) );
                }
            }
            break;
            case 0xD605: // sprmTTableBorders
            {
                /* WRITERFILTERSTATUS: done: 0, planned: 2, spent: 0 */
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    BorderHandlerPtr pBorderHandler( new BorderHandler );
                    pProperties->resolve(*pBorderHandler);
                    cellPropsByCell( m_nCellBorderIndex, PropertyMapPtr( pBorderHandler->getProperties()) );
                    ++m_nCellBorderIndex;
                }
            }
            break;
            case 0xd61a : // sprmTCellTopColor
            case 0xd61b : // sprmTCellLeftColor
            case 0xd61c : // sprmTCellBottomColor
            case 0xd61d : // sprmTCellRightColor
            {
                // each color sprm contains as much colors as cells are in a row
                doctok::Reference<doctok::Properties>::Pointer_t pProperties = rSprm.getProps();
                if( pProperties.get())
                {
                    CellColorHandlerPtr pCellColorHandler( new CellColorHandler );
                    pProperties->resolve( *pCellColorHandler );
//                    cellPropsByCell(0, PropertyMapPtr( pColorHandler->getProperties()) );
                }
            }
            break;
            case 0xd632 : //sprmTNewSpacing
            case 0xd634 : //sprmTNewSpacing
                //TODO: sprms contain default (TNew) and actual border spacing of cells - not resolvable yet
            break;
            case 0xd613: //sprmTGridLineProps
                // TODO: needs a handler
                /*contains:
                 GridLineProps">
                    rtf:LINEPROPSTOP
                    rtf:LINEPROPSLEFT
                    rtf:LINEPROPSBOTTOM
                    rtf:LINEPROPSRIGHT
                    rtf:LINEPROPSHORIZONTAL
                    rtf:LINEPROPSVERTICAL
                        rtf:LINECOLOR
                        rtf:LINEWIDTH
                        rtf:LINETYPE

                */
            break;
            case 0x740a : //sprmTTlp
                //TODO: Table look specifier
            break;
            case 0x6816 : //unknown
            case 0x3466 : //unknown
            case 0x3615 : //unknown
            case 0x646b : //unknown - expandable sprm - see ww8scan.cxx
            case 0x7479 : //unknown
            case 0xf617 : //unknown
            case 0xf618 : //unknown
                bRet = false;
            break;
            default: bRet = false;
        }
    }
    return bRet;
}
/*-- 26.04.2007 08:20:08---------------------------------------------------

  -----------------------------------------------------------------------*/
//void DomainMapperTableManager::attribute(doctok::Id nName, doctok::Value & rVal)
//{
//    sal_Int32 nIntValue = rVal.getInt();
//    rtl::OUString sStringValue = val.getString();
//    /* WRITERFILTERSTATUS: table: tablemanager_attributedata */
//    switch( nName )
//    {
//        case NS_rtf::LN_cellTopColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellLeftColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellBottomColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//        case NS_rtf::LN_cellRightColor:
//            /* WRITERFILTERSTATUS: done: 0, planned: 0.5, spent: 0 */
//            break;
//    }

/*-- 02.05.2007 14:36:26---------------------------------------------------

  -----------------------------------------------------------------------*/
void DomainMapperTableManager::endOfCellAction()
{
    ++m_nCell;
}
/*-- 02.05.2007 14:36:26---------------------------------------------------

  -----------------------------------------------------------------------*/
void DomainMapperTableManager::endOfRowAction()
{
    ++m_nRow;
    m_nCell = 0;
    m_nCellBorderIndex = 0;
}

}
<|endoftext|>


<commit_before>/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics,
                       Institute for Analysis and Scientific Computing,
                       TU Wien.

                            -----------------
                     ViennaGrid - The Vienna Grid Library
                            -----------------

   Authors:      Karl Rupp                           rupp@iue.tuwien.ac.at
                 Josef Weinbub                    weinbub@iue.tuwien.ac.at

   (A list of additional contributors can be found in the PDF manual)

   License:      MIT (X11), see file LICENSE in the base directory
======================================================================= */

#ifdef _MSC_VER      //Visual Studio complains about potentially dangerous things, which are perfectly legal in our context
  #pragma warning( disable : 4355 )     //use of this in member initializer list
  #pragma warning( disable : 4503 )     //truncated name decoration
#endif

#include "viennagrid/forwards.hpp"
#include "viennagrid/config/domain_config.hpp"
#include "viennagrid/io/netgen_reader.hpp"
#include "viennagrid/io/vtk_writer.hpp"

//Point-based algorithms:
#include "viennagrid/algorithm/cross_prod.hpp"
#include "viennagrid/algorithm/inner_prod.hpp"
#include "viennagrid/algorithm/norm.hpp"
#include "viennagrid/algorithm/spanned_volume.hpp"

//Cell-based algorithms:
#include "viennagrid/algorithm/centroid.hpp"
#include "viennagrid/algorithm/circumcenter.hpp"
#include "viennagrid/algorithm/surface.hpp"
#include "viennagrid/algorithm/volume.hpp"
#include "viennagrid/algorithm/closest_points.hpp"
#include "viennagrid/algorithm/distance.hpp"

//Domain-based algorithms:
#include "viennagrid/algorithm/boundary.hpp"
#include "viennagrid/algorithm/refine.hpp"
#include "viennagrid/algorithm/voronoi.hpp"

#include <typeinfo>

class my_domain_config
{
  private:
    //typedef viennagrid::storage::pointer_handle_tag handle_tag;
    //typedef viennagrid::storage::iterator_handle_tag handle_tag;
    typedef viennagrid::storage::id_handle_tag          handle_tag;

  public:

    typedef viennagrid::point_t<double, viennagrid::cartesian_cs<3> > PointType;
    typedef viennagrid::config::result_of::full_domain_config< viennagrid::tetrahedron_tag, PointType, viennagrid::storage::pointer_handle_tag >::type type;
};

int main()
{

  typedef my_domain_config::PointType PointType;

  typedef viennagrid::domain_t< my_domain_config > Domain;
  typedef viennagrid::result_of::segmentation<Domain>::type Segmentation;
  typedef viennagrid::result_of::domain_view<Domain>::type Segment;

  typedef viennagrid::tetrahedron_tag CellTag;

  typedef viennagrid::result_of::element<Domain, viennagrid::tetrahedron_tag>::type    CellType;
  typedef viennagrid::result_of::element<Domain, viennagrid::triangle_tag>::type       TriangleType;
  typedef viennagrid::result_of::element<Domain, viennagrid::line_tag>::type           EdgeType;
  typedef viennagrid::result_of::element<Domain, viennagrid::vertex_tag>::type         VertexType;
  typedef viennagrid::result_of::handle<Domain, viennagrid::vertex_tag>::type    VertexHandleType;

  typedef viennagrid::result_of::element_range<Domain, viennagrid::vertex_tag>::type       VertexRange;
  typedef viennagrid::result_of::element_range<Domain, viennagrid::tetrahedron_tag>::type       CellRange;

  std::cout << "------------------------------------------------------------ " << std::endl;
  std::cout << "-- ViennaGrid tutorial: Algorithms on points and elements -- " << std::endl;
  std::cout << "------------------------------------------------------------ " << std::endl;
  std::cout << std::endl;

  Domain domain;
  Segmentation segmentation(domain);

  //
  // Read domain from Netgen file
  //
  try
  {
    viennagrid::io::netgen_reader reader;
    reader(domain, segmentation, "../../examples/data/cube48.mesh");
  }
  catch (std::exception & e)
  {
    std::cout << "Error reading Netgen mesh file: " << std::endl;
    std::cout << e.what() << std::endl;
    return EXIT_FAILURE;
  }

  //
  // Part 1: Point-based algorithms:
  //

  // Extract the first four points of the domain:
  VertexRange vertices = viennagrid::elements<viennagrid::vertex_tag>(domain);

  PointType const & p0 = viennagrid::point(domain, vertices[0]);
  PointType const & p1 = viennagrid::point(domain, vertices[1]);
  PointType const & p2 = viennagrid::point(domain, vertices[2]);
  PointType const & p3 = viennagrid::point(domain, vertices[3]);

  std::cout << "Point p0: " << p0 << std::endl;
  std::cout << "Point p1: " << p1 << std::endl;
  std::cout << "Point p2: " << p2 << std::endl;
  std::cout << "Point p3: " << p3 << std::endl;

  // Run a few algorithms:
  std::cout << "Cross-product of p1 and p2: " << viennagrid::cross_prod(p1, p2) << std::endl;
  std::cout << "Inner product of p1 and p2: " << viennagrid::inner_prod(p1, p2) << std::endl;
  std::cout << "1-Norm of p2: "               << viennagrid::norm_1(p2) << std::endl;
  std::cout << "2-Norm of p2: "               << viennagrid::norm_2(p2) << std::endl;
  std::cout << "Inf-Norm of p2: "             << viennagrid::norm_inf(p2) << std::endl;
  std::cout << "Length of line [p0, p1]: "    << viennagrid::spanned_volume(p0, p1) << std::endl;
  std::cout << "Area of triangle [p0, p1, p2]: " << viennagrid::spanned_volume(p0, p1, p2) << std::endl;
  std::cout << "Volume of tetrahedron [p0, p1, p2, p3]: " << viennagrid::spanned_volume(p0, p1, p2, p3) << std::endl;

  std::cout << std::endl << "--------------------------------" << std::endl << std::endl;

  //
  // Part 2: Cell-based algorithms:
  //

  // Extract first cell from domain:
  CellType const & cell = viennagrid::elements<CellTag>(domain)[0];

  std::cout << "cell: " << std::endl << cell << std::endl;

  // Run algorithms:
  std::cout << "Centroid of cell: "     << viennagrid::centroid(cell) << std::endl;
  std::cout << "Circumcenter of cell: " << viennagrid::circumcenter(cell) << std::endl;
  std::cout << "Surface of cell: "      << viennagrid::surface(cell) << std::endl;
  std::cout << "Volume of cell: "       << viennagrid::volume(cell) << std::endl;
  std::cout << std::endl;

  std::cout << "Volume of domain: "       << viennagrid::volume(domain) << std::endl;
  std::cout << "Surface of domain: "       << viennagrid::surface(domain) << std::endl;

//   CellType const & cell2 = viennagrid::elements<CellTag>(domain)[1];
//   std::cout << "Distance between cells: " << viennagrid::boundary_distance(cell, cell2) << std::endl;

  //
  // Part 3: Domain-based algorithms (except interfaces. Refer to the multi-segment tutorial multi_segment.cpp)
  //

  typedef viennagrid::result_of::const_handle<Domain, CellType>::type    ConstCellHandleType;

  std::deque<double> interface_areas;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > interface_contributions;

  std::deque<double> vertex_box_volumes;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > vertex_box_volume_contributions;

  std::deque<double> edge_box_volumes;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > edge_box_volume_contributions;

  // Write Voronoi info to default ViennaData keys:
  viennagrid::apply_voronoi<CellType>(
          domain,
          viennagrid::make_accessor<EdgeType>(interface_areas),
          viennagrid::make_accessor<EdgeType>(interface_contributions),
          viennagrid::make_accessor<VertexType>(vertex_box_volumes),
          viennagrid::make_accessor<VertexType>(vertex_box_volume_contributions),
          viennagrid::make_accessor<EdgeType>(edge_box_volumes),
          viennagrid::make_accessor<EdgeType>(edge_box_volume_contributions)
  );

  // Write Voronoi info again, this time using custom keys
  std::cout << "Voronoi box volume at first vertex: "
            << vertex_box_volumes[ vertices[0].id().get() ]
            << std::endl;

  //
  // Refine domain uniformly:
  Domain uniformly_refined_domain;
  viennagrid::cell_refine_uniformly(domain, uniformly_refined_domain);

  {
    viennagrid::io::vtk_writer<Domain> writer;
    writer(uniformly_refined_domain, "uniform_refinement.vtu");
  }

  Domain adaptively_refined_domain;

  std::deque<bool> cell_refinement_flag;
  viennagrid::result_of::accessor< std::deque<bool>, CellType >::type cell_refinement_accessor(cell_refinement_flag);

  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[0] ) = true;
  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[3] ) = true;
  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[8] ) = true;
  cell_refinement_accessor.resize( viennagrid::elements<CellTag>(domain).size() );

  viennagrid::element_refine<viennagrid::tetrahedron_tag>(domain, adaptively_refined_domain, cell_refinement_accessor);

  {
    viennagrid::io::vtk_writer<Domain> writer;
    writer(adaptively_refined_domain, "adaptively_refinement.vtu");
  }

  //
  // Get boundary information of first vertex with respect to the full domain:

            for (VertexRange::iterator it = vertices.begin(); it != vertices.end(); ++it)
  std::cout << *it << " " << viennagrid::point(domain, *it) << " "
            << viennagrid::is_boundary(domain, *it)    //second argument is the enclosing complex (either a domain or a segment)
            << std::endl << std::endl;

  std::cout << "-----------------------------------------------" << std::endl;
  std::cout << " \\o/    Tutorial finished successfully!    \\o/ " << std::endl;
  std::cout << "-----------------------------------------------" << std::endl;

  return EXIT_SUCCESS;
}
<commit_msg>adapted to accessor/field concept<commit_after>/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics,
                       Institute for Analysis and Scientific Computing,
                       TU Wien.

                            -----------------
                     ViennaGrid - The Vienna Grid Library
                            -----------------

   Authors:      Karl Rupp                           rupp@iue.tuwien.ac.at
                 Josef Weinbub                    weinbub@iue.tuwien.ac.at

   (A list of additional contributors can be found in the PDF manual)

   License:      MIT (X11), see file LICENSE in the base directory
======================================================================= */

#ifdef _MSC_VER      //Visual Studio complains about potentially dangerous things, which are perfectly legal in our context
  #pragma warning( disable : 4355 )     //use of this in member initializer list
  #pragma warning( disable : 4503 )     //truncated name decoration
#endif

#include "viennagrid/forwards.hpp"
#include "viennagrid/config/domain_config.hpp"
#include "viennagrid/io/netgen_reader.hpp"
#include "viennagrid/io/vtk_writer.hpp"

//Point-based algorithms:
#include "viennagrid/algorithm/cross_prod.hpp"
#include "viennagrid/algorithm/inner_prod.hpp"
#include "viennagrid/algorithm/norm.hpp"
#include "viennagrid/algorithm/spanned_volume.hpp"

//Cell-based algorithms:
#include "viennagrid/algorithm/centroid.hpp"
#include "viennagrid/algorithm/circumcenter.hpp"
#include "viennagrid/algorithm/surface.hpp"
#include "viennagrid/algorithm/volume.hpp"
#include "viennagrid/algorithm/closest_points.hpp"
#include "viennagrid/algorithm/distance.hpp"

//Domain-based algorithms:
#include "viennagrid/algorithm/boundary.hpp"
#include "viennagrid/algorithm/refine.hpp"
#include "viennagrid/algorithm/voronoi.hpp"

#include <typeinfo>

class my_domain_config
{
  private:
    //typedef viennagrid::storage::pointer_handle_tag handle_tag;
    //typedef viennagrid::storage::iterator_handle_tag handle_tag;
    typedef viennagrid::storage::id_handle_tag          handle_tag;

  public:

    typedef viennagrid::point_t<double, viennagrid::cartesian_cs<3> > PointType;
    typedef viennagrid::config::result_of::full_domain_config< viennagrid::tetrahedron_tag, PointType, viennagrid::storage::pointer_handle_tag >::type type;
};

int main()
{

  typedef my_domain_config::PointType PointType;

  typedef viennagrid::domain_t< my_domain_config > Domain;
  typedef viennagrid::result_of::segmentation<Domain>::type Segmentation;
  typedef viennagrid::result_of::domain_view<Domain>::type Segment;

  typedef viennagrid::tetrahedron_tag CellTag;

  typedef viennagrid::result_of::element<Domain, viennagrid::tetrahedron_tag>::type    CellType;
  typedef viennagrid::result_of::element<Domain, viennagrid::triangle_tag>::type       TriangleType;
  typedef viennagrid::result_of::element<Domain, viennagrid::line_tag>::type           EdgeType;
  typedef viennagrid::result_of::element<Domain, viennagrid::vertex_tag>::type         VertexType;
  typedef viennagrid::result_of::handle<Domain, viennagrid::vertex_tag>::type    VertexHandleType;

  typedef viennagrid::result_of::element_range<Domain, viennagrid::vertex_tag>::type       VertexRange;
  typedef viennagrid::result_of::element_range<Domain, viennagrid::tetrahedron_tag>::type       CellRange;

  std::cout << "------------------------------------------------------------ " << std::endl;
  std::cout << "-- ViennaGrid tutorial: Algorithms on points and elements -- " << std::endl;
  std::cout << "------------------------------------------------------------ " << std::endl;
  std::cout << std::endl;

  Domain domain;
  Segmentation segmentation(domain);

  //
  // Read domain from Netgen file
  //
  try
  {
    viennagrid::io::netgen_reader reader;
    reader(domain, segmentation, "../../examples/data/cube48.mesh");
  }
  catch (std::exception & e)
  {
    std::cout << "Error reading Netgen mesh file: " << std::endl;
    std::cout << e.what() << std::endl;
    return EXIT_FAILURE;
  }

  //
  // Part 1: Point-based algorithms:
  //

  // Extract the first four points of the domain:
  VertexRange vertices = viennagrid::elements<viennagrid::vertex_tag>(domain);

  PointType const & p0 = viennagrid::point(domain, vertices[0]);
  PointType const & p1 = viennagrid::point(domain, vertices[1]);
  PointType const & p2 = viennagrid::point(domain, vertices[2]);
  PointType const & p3 = viennagrid::point(domain, vertices[3]);

  std::cout << "Point p0: " << p0 << std::endl;
  std::cout << "Point p1: " << p1 << std::endl;
  std::cout << "Point p2: " << p2 << std::endl;
  std::cout << "Point p3: " << p3 << std::endl;

  // Run a few algorithms:
  std::cout << "Cross-product of p1 and p2: " << viennagrid::cross_prod(p1, p2) << std::endl;
  std::cout << "Inner product of p1 and p2: " << viennagrid::inner_prod(p1, p2) << std::endl;
  std::cout << "1-Norm of p2: "               << viennagrid::norm_1(p2) << std::endl;
  std::cout << "2-Norm of p2: "               << viennagrid::norm_2(p2) << std::endl;
  std::cout << "Inf-Norm of p2: "             << viennagrid::norm_inf(p2) << std::endl;
  std::cout << "Length of line [p0, p1]: "    << viennagrid::spanned_volume(p0, p1) << std::endl;
  std::cout << "Area of triangle [p0, p1, p2]: " << viennagrid::spanned_volume(p0, p1, p2) << std::endl;
  std::cout << "Volume of tetrahedron [p0, p1, p2, p3]: " << viennagrid::spanned_volume(p0, p1, p2, p3) << std::endl;

  std::cout << std::endl << "--------------------------------" << std::endl << std::endl;

  //
  // Part 2: Cell-based algorithms:
  //

  // Extract first cell from domain:
  CellType const & cell = viennagrid::elements<CellTag>(domain)[0];

  std::cout << "cell: " << std::endl << cell << std::endl;

  // Run algorithms:
  std::cout << "Centroid of cell: "     << viennagrid::centroid(cell) << std::endl;
  std::cout << "Circumcenter of cell: " << viennagrid::circumcenter(cell) << std::endl;
  std::cout << "Surface of cell: "      << viennagrid::surface(cell) << std::endl;
  std::cout << "Volume of cell: "       << viennagrid::volume(cell) << std::endl;
  std::cout << std::endl;

  std::cout << "Volume of domain: "       << viennagrid::volume(domain) << std::endl;
  std::cout << "Surface of domain: "       << viennagrid::surface(domain) << std::endl;

//   CellType const & cell2 = viennagrid::elements<CellTag>(domain)[1];
//   std::cout << "Distance between cells: " << viennagrid::boundary_distance(cell, cell2) << std::endl;

  //
  // Part 3: Domain-based algorithms (except interfaces. Refer to the multi-segment tutorial multi_segment.cpp)
  //

  typedef viennagrid::result_of::const_handle<Domain, CellType>::type    ConstCellHandleType;

  std::deque<double> interface_areas;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > interface_contributions;

  std::deque<double> vertex_box_volumes;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > vertex_box_volume_contributions;

  std::deque<double> edge_box_volumes;
  std::deque< viennagrid::result_of::voronoi_cell_contribution<ConstCellHandleType>::type > edge_box_volume_contributions;

  // Write Voronoi info to default ViennaData keys:
  viennagrid::apply_voronoi<CellType>(
          domain,
          viennagrid::make_accessor<EdgeType>(interface_areas),
          viennagrid::make_accessor<EdgeType>(interface_contributions),
          viennagrid::make_accessor<VertexType>(vertex_box_volumes),
          viennagrid::make_accessor<VertexType>(vertex_box_volume_contributions),
          viennagrid::make_accessor<EdgeType>(edge_box_volumes),
          viennagrid::make_accessor<EdgeType>(edge_box_volume_contributions)
  );

  // Write Voronoi info again, this time using custom keys
  std::cout << "Voronoi box volume at first vertex: "
            << vertex_box_volumes[ vertices[0].id().get() ]
            << std::endl;

  //
  // Refine domain uniformly:
  Domain uniformly_refined_domain;
  viennagrid::cell_refine_uniformly(domain, uniformly_refined_domain);

  {
    viennagrid::io::vtk_writer<Domain> writer;
    writer(uniformly_refined_domain, "uniform_refinement.vtu");
  }

  Domain adaptively_refined_domain;

  std::deque<bool> cell_refinement_flag;
  viennagrid::result_of::accessor< std::deque<bool>, CellType >::type cell_refinement_accessor(cell_refinement_flag);

  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[0] ) = true;
  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[3] ) = true;
  cell_refinement_accessor( viennagrid::elements<CellTag>(domain)[8] ) = true;

  viennagrid::element_refine<viennagrid::tetrahedron_tag>(domain, adaptively_refined_domain, cell_refinement_accessor);

  {
    viennagrid::io::vtk_writer<Domain> writer;
    writer(adaptively_refined_domain, "adaptively_refinement.vtu");
  }

  //
  // Get boundary information of first vertex with respect to the full domain:

            for (VertexRange::iterator it = vertices.begin(); it != vertices.end(); ++it)
  std::cout << *it << " " << viennagrid::point(domain, *it) << " "
            << viennagrid::is_boundary(domain, *it)    //second argument is the enclosing complex (either a domain or a segment)
            << std::endl << std::endl;

  std::cout << "-----------------------------------------------" << std::endl;
  std::cout << " \\o/    Tutorial finished successfully!    \\o/ " << std::endl;
  std::cout << "-----------------------------------------------" << std::endl;

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <cstring>
#include "CTokenizer.h"
#include "CClassifier.h"
#include "util.h"

const int CTokenizer::ms_iTransitions [ CTokenizer::NUMSTATES ] [ CClassifier::GROUP_MAX ] = {
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q0  */ {  4,    13,     4,    -1,    -1,     9,     9,     9,     8,     8,     8,     7,     2,     3,     1,     6,    -1   },
/* q1  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     1,    -1,    -1   },
/* q2  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,    -1,    -1,    -1   },
/* q3  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q4  */ {  4,     4,     4,    -1,     5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q5  */ {  4,     4,     4,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q6  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q7  */ { -1,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,    10,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q8  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q9  */ { -1,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q10 */ { 10,    10,    10,    10,    10,    10,    10,    10,    10,    10,    11,    10,    10,    10,    10,    10,    10   },
/* q11 */ { 10,    10,    10,    10,    10,    10,    10,    10,    10,    10,    11,    12,    10,    10,    10,    10,    10   },
/* q12 */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q13 */ { -1,    13,    -1,    14,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q14 */ { -1,    15,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q15 */ { -1,    15,    16,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q16 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    17,    17,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q17 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q18 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   }
};

const CTokenizer::ETokenType CTokenizer::ms_eFinalStates [ CTokenizer::NUMSTATES ] = {
/* q0  */ UNKNOWN,
/* q1  */ SPACE,
/* q2  */ NEWLINE,
/* q3  */ NEWLINE,
/* q4  */ IDENTIFIER,
/* q5  */ UNKNOWN,
/* q6  */ SEPARATOR,
/* q7  */ OPERATOR,
/* q8  */ OPERATOR,
/* q9  */ OPERATOR,
/* q10 */ UNKNOWN,
/* q11 */ UNKNOWN,
/* q12 */ COMMENT,
/* q13 */ INTEGER,
/* q14 */ UNKNOWN,
/* q15 */ REAL,
/* q16 */ UNKNOWN,
/* q17 */ UNKNOWN,
/* q18 */ REAL
};

CTokenizer::fn_stateTrigger CTokenizer::ms_fnTriggers [ CTokenizer::NUMSTATES ] = {
/* q0  */ 0,
/* q1  */ 0,
/* q2  */ 0,
/* q3  */ 0,
/* q4  */ 0,
/* q5  */ 0,
/* q6  */ 0,
/* q7  */ 0,
/* q8  */ 0,
/* q9  */ 0,
/* q10 */ 0,
/* q11 */ 0,
/* q12 */ 0,
/* q13 */ 0,
/* q14 */ 0,
/* q15 */ 0,
/* q16 */ 0,
/* q17 */ 0,
/* q18 */ 0
};

const char* CTokenizer::ms_szErrors [ CTokenizer::NUMSTATES ] = {
/* q0  */ "Unknown token",
/* q1  */ 0,
/* q2  */ 0,
/* q3  */ 0,
/* q4  */ 0,
/* q5  */ "Invalid identifier: Must start with an alphabetic character and followed by alphanumeric characters or single inserted underscores.",
/* q6  */ 0,
/* q7  */ 0,
/* q8  */ 0,
/* q9  */ 0,
/* q10 */ "Non closed comment",
/* q11 */ "Non closed comment",
/* q12 */ 0,
/* q13 */ 0,
/* q14 */ "Invalid real number format. It must be in scientific notation.",
/* q15 */ 0,
/* q16 */ "Invalid real number format. It must be in scientific notation.",
/* q17 */ "Invalid real number format. It must be in scientific notation.",
/* q18 */ 0
};

const char* CTokenizer::ms_szReserved [ ] = {
    "programa",
    "procedimiento",
    "funcion",
    "retorna",
    "retornar",
    "comienzo",
    "fin",
    "variables",
    "entero",
    "real",
    "booleano",
    "array",
    "de",
    "entrada",
    "salida",
    "si",
    "entonces",
    "hacer",
    "mientras",
    "salir",
    "get",
    "put_line",
    "true",
    "false"
};

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

CTokenizer::CTokenizer ( std::istream& isInput )
: m_buffer ( isInput )
, m_uiState ( 0 )
, m_isInput ( isInput )
{
}

CTokenizer::~CTokenizer() {
}

bool CTokenizer::ReadToken ( SToken* pToken )
{
    bool bFailed = false;
    unsigned char c;
    CClassifier classifier;
    CClassifier::ECharacterGroup eGroup;

    // Inicializamos el buffer del token para ir añadiendo lo que leamos.
    if ( pToken != 0 )
    {
        memset ( pToken->value, 0, sizeof ( pToken->value ) );
        pToken->uiValueLength = 0;
        pToken->uiCol = m_buffer.GetCol ();
        pToken->uiLine = m_buffer.GetLine ();
    }

    // Inicializamos el autómata.
    m_uiState = 0;

    do
    {
        // Leemos el siguiente caracter del buffer.
        if ( m_buffer.Get ( &c ) == false )
        {
            bFailed = ( m_uiState == 0 );
            break;
        }

        // Clasificamos el caracter y comprobamos que exista una transición
        // desde el estado actual.
        eGroup = classifier [ c ];
        if ( ms_iTransitions [ m_uiState ] [ (unsigned int)eGroup ] == -1 )
        {
            if ( m_uiState != 0 )
                m_buffer.Rollback ();
            else
            {
                // Añadimos el caracter recientemente leído al token.
                if ( pToken != 0 )
                {
                    pToken->value [ pToken->uiValueLength ] = c;
                    pToken->uiValueLength++;
                }
            }
            break;
        }

        // Cambiamos de estado.
        m_uiState = ms_iTransitions [ m_uiState ] [ (unsigned int)eGroup ];

        // Añadimos el caracter recientemente leído al token.
        if ( pToken != 0 )
        {
            pToken->value [ pToken->uiValueLength ] = c;
            pToken->uiValueLength++;
        }

        if ( ms_fnTriggers [ m_uiState ] != 0 )
            ((*this).*(ms_fnTriggers [ m_uiState ])) ( c );
    } while ( true );

    // Clasificamos el tipo token.
    if ( pToken != 0 )
    {
        pToken->eType = ms_eFinalStates [ m_uiState ];
        pToken->uiState = m_uiState;
    }

    return !bFailed;
}

bool CTokenizer::NextToken ( SToken* pToken, bool bIgnoreWhiteSpaces )
{
    SToken token;
    bool bContinueSearching = true;
    bool bRetval = true;

    do
    {
        bRetval = ReadToken ( &token );
        if ( bRetval == false )
            break;

        switch ( token.eType )
        {
            case NEWLINE:
            case COMMENT:
            case SPACE:
                if ( bIgnoreWhiteSpaces == false )
                    bContinueSearching = false;
                break;
            case IDENTIFIER:
                if ( IsReserved ( token.value ) == true )
                    token.eType = RESERVED;
                bContinueSearching = false;
                break;
            default:
                bContinueSearching = false;
        }
    } while ( bContinueSearching == true );

    if ( pToken != 0 )
        *pToken = token;

    return bRetval;
}

const char* CTokenizer::NameThisToken ( ETokenType eType ) const
{
#define TOKTYPE(x) case x : return #x ; break
    switch ( eType )
    {
        TOKTYPE(INTEGER);
        TOKTYPE(REAL);
        TOKTYPE(IDENTIFIER);
        TOKTYPE(RESERVED);
        TOKTYPE(OPERATOR);
        TOKTYPE(COMMENT);
        TOKTYPE(SPACE);
        TOKTYPE(NEWLINE);
        TOKTYPE(SEPARATOR);
        TOKTYPE(UNKNOWN);
        default:
            return "";
    }
#undef TOKTYPE
}

bool CTokenizer::IsReserved ( const char* szTokenValue ) const
{
    for ( unsigned int i = 0; i < NUMELEMS(ms_szReserved); ++i )
    {
        if ( strcasecmp ( szTokenValue, ms_szReserved [ i ] ) == 0 )
            return true;
    }
    return false;
}
<commit_msg>Más palabras reservadas (and, or, not).<commit_after>#include <cstring>
#include "CTokenizer.h"
#include "CClassifier.h"
#include "util.h"

const int CTokenizer::ms_iTransitions [ CTokenizer::NUMSTATES ] [ CClassifier::GROUP_MAX ] = {
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q0  */ {  4,    13,     4,    -1,    -1,     9,     9,     9,     8,     8,     8,     7,     2,     3,     1,     6,    -1   },
/* q1  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     1,    -1,    -1   },
/* q2  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,    -1,    -1,    -1   },
/* q3  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q4  */ {  4,     4,     4,    -1,     5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q5  */ {  4,     4,     4,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q6  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q7  */ { -1,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,    10,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q8  */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q9  */ { -1,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q10 */ { 10,    10,    10,    10,    10,    10,    10,    10,    10,    10,    11,    10,    10,    10,    10,    10,    10   },
/* q11 */ { 10,    10,    10,    10,    10,    10,    10,    10,    10,    10,    11,    12,    10,    10,    10,    10,    10   },
/* q12 */ { -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q13 */ { -1,    13,    -1,    14,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q14 */ { -1,    15,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/*          ALPHA  DIGIT  eE     DOT    UNDER  EQUAL  LT     GT     PLUS   MINUS  STAR   SLASH  CR     LF     SPACE  SEP    UNKN */
/* q15 */ { -1,    15,    16,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q16 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    17,    17,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q17 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   },
/* q18 */ { -1,    18,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1   }
};

const CTokenizer::ETokenType CTokenizer::ms_eFinalStates [ CTokenizer::NUMSTATES ] = {
/* q0  */ UNKNOWN,
/* q1  */ SPACE,
/* q2  */ NEWLINE,
/* q3  */ NEWLINE,
/* q4  */ IDENTIFIER,
/* q5  */ UNKNOWN,
/* q6  */ SEPARATOR,
/* q7  */ OPERATOR,
/* q8  */ OPERATOR,
/* q9  */ OPERATOR,
/* q10 */ UNKNOWN,
/* q11 */ UNKNOWN,
/* q12 */ COMMENT,
/* q13 */ INTEGER,
/* q14 */ UNKNOWN,
/* q15 */ REAL,
/* q16 */ UNKNOWN,
/* q17 */ UNKNOWN,
/* q18 */ REAL
};

CTokenizer::fn_stateTrigger CTokenizer::ms_fnTriggers [ CTokenizer::NUMSTATES ] = {
/* q0  */ 0,
/* q1  */ 0,
/* q2  */ 0,
/* q3  */ 0,
/* q4  */ 0,
/* q5  */ 0,
/* q6  */ 0,
/* q7  */ 0,
/* q8  */ 0,
/* q9  */ 0,
/* q10 */ 0,
/* q11 */ 0,
/* q12 */ 0,
/* q13 */ 0,
/* q14 */ 0,
/* q15 */ 0,
/* q16 */ 0,
/* q17 */ 0,
/* q18 */ 0
};

const char* CTokenizer::ms_szErrors [ CTokenizer::NUMSTATES ] = {
/* q0  */ "Unknown token",
/* q1  */ 0,
/* q2  */ 0,
/* q3  */ 0,
/* q4  */ 0,
/* q5  */ "Invalid identifier: Must start with an alphabetic character and followed by alphanumeric characters or single inserted underscores.",
/* q6  */ 0,
/* q7  */ 0,
/* q8  */ 0,
/* q9  */ 0,
/* q10 */ "Non closed comment",
/* q11 */ "Non closed comment",
/* q12 */ 0,
/* q13 */ 0,
/* q14 */ "Invalid real number format. It must be in scientific notation.",
/* q15 */ 0,
/* q16 */ "Invalid real number format. It must be in scientific notation.",
/* q17 */ "Invalid real number format. It must be in scientific notation.",
/* q18 */ 0
};

const char* CTokenizer::ms_szReserved [ ] = {
    "programa",
    "procedimiento",
    "funcion",
    "retorna",
    "retornar",
    "comienzo",
    "fin",
    "variables",
    "entero",
    "real",
    "booleano",
    "array",
    "de",
    "entrada",
    "salida",
    "si",
    "entonces",
    "hacer",
    "mientras",
    "salir",
    "get",
    "put_line",
    "true",
    "false",
    "or",
    "and",
    "not"
};

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

CTokenizer::CTokenizer ( std::istream& isInput )
: m_buffer ( isInput )
, m_uiState ( 0 )
, m_isInput ( isInput )
{
}

CTokenizer::~CTokenizer() {
}

bool CTokenizer::ReadToken ( SToken* pToken )
{
    bool bFailed = false;
    unsigned char c;
    CClassifier classifier;
    CClassifier::ECharacterGroup eGroup;

    // Inicializamos el buffer del token para ir añadiendo lo que leamos.
    if ( pToken != 0 )
    {
        memset ( pToken->value, 0, sizeof ( pToken->value ) );
        pToken->uiValueLength = 0;
        pToken->uiCol = m_buffer.GetCol ();
        pToken->uiLine = m_buffer.GetLine ();
    }

    // Inicializamos el autómata.
    m_uiState = 0;

    do
    {
        // Leemos el siguiente caracter del buffer.
        if ( m_buffer.Get ( &c ) == false )
        {
            bFailed = ( m_uiState == 0 );
            break;
        }

        // Clasificamos el caracter y comprobamos que exista una transición
        // desde el estado actual.
        eGroup = classifier [ c ];
        if ( ms_iTransitions [ m_uiState ] [ (unsigned int)eGroup ] == -1 )
        {
            if ( m_uiState != 0 )
                m_buffer.Rollback ();
            else
            {
                // Añadimos el caracter recientemente leído al token.
                if ( pToken != 0 )
                {
                    pToken->value [ pToken->uiValueLength ] = c;
                    pToken->uiValueLength++;
                }
            }
            break;
        }

        // Cambiamos de estado.
        m_uiState = ms_iTransitions [ m_uiState ] [ (unsigned int)eGroup ];

        // Añadimos el caracter recientemente leído al token.
        if ( pToken != 0 )
        {
            pToken->value [ pToken->uiValueLength ] = c;
            pToken->uiValueLength++;
        }

        if ( ms_fnTriggers [ m_uiState ] != 0 )
            ((*this).*(ms_fnTriggers [ m_uiState ])) ( c );
    } while ( true );

    // Clasificamos el tipo token.
    if ( pToken != 0 )
    {
        pToken->eType = ms_eFinalStates [ m_uiState ];
        pToken->uiState = m_uiState;
    }

    return !bFailed;
}

bool CTokenizer::NextToken ( SToken* pToken, bool bIgnoreWhiteSpaces )
{
    SToken token;
    bool bContinueSearching = true;
    bool bRetval = true;

    do
    {
        bRetval = ReadToken ( &token );
        if ( bRetval == false )
            break;

        switch ( token.eType )
        {
            case NEWLINE:
            case COMMENT:
            case SPACE:
                if ( bIgnoreWhiteSpaces == false )
                    bContinueSearching = false;
                break;
            case IDENTIFIER:
                if ( IsReserved ( token.value ) == true )
                    token.eType = RESERVED;
                bContinueSearching = false;
                break;
            default:
                bContinueSearching = false;
        }
    } while ( bContinueSearching == true );

    if ( pToken != 0 )
        *pToken = token;

    return bRetval;
}

const char* CTokenizer::NameThisToken ( ETokenType eType ) const
{
#define TOKTYPE(x) case x : return #x ; break
    switch ( eType )
    {
        TOKTYPE(INTEGER);
        TOKTYPE(REAL);
        TOKTYPE(IDENTIFIER);
        TOKTYPE(RESERVED);
        TOKTYPE(OPERATOR);
        TOKTYPE(COMMENT);
        TOKTYPE(SPACE);
        TOKTYPE(NEWLINE);
        TOKTYPE(SEPARATOR);
        TOKTYPE(UNKNOWN);
        default:
            return "";
    }
#undef TOKTYPE
}

bool CTokenizer::IsReserved ( const char* szTokenValue ) const
{
    for ( unsigned int i = 0; i < NUMELEMS(ms_szReserved); ++i )
    {
        if ( strcasecmp ( szTokenValue, ms_szReserved [ i ] ) == 0 )
            return true;
    }
    return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <iosfwd>

#include "mutation_partition.hh"
#include "keys.hh"
#include "schema_fwd.hh"
#include "dht/i_partitioner.hh"
#include "hashing.hh"
#include "mutation_fragment.hh"
#include "mutation_consumer_concepts.hh"

#include <seastar/util/optimized_optional.hh>

template<typename Result>
struct mutation_consume_result {
    stop_iteration stop;
    Result result;
};

template<>
struct mutation_consume_result<void> {
    stop_iteration stop;
};

enum class consume_in_reverse {
    no = 0,
    yes,
    legacy_half_reverse,
};

class mutation final {
private:
    struct data {
        schema_ptr _schema;
        dht::decorated_key _dk;
        mutation_partition _p;

        data(dht::decorated_key&& key, schema_ptr&& schema);
        data(partition_key&& key, schema_ptr&& schema);
        data(schema_ptr&& schema, dht::decorated_key&& key, const mutation_partition& mp);
        data(schema_ptr&& schema, dht::decorated_key&& key, mutation_partition&& mp);
    };
    std::unique_ptr<data> _ptr;
private:
    mutation() = default;
    explicit operator bool() const { return bool(_ptr); }
    friend class optimized_optional<mutation>;
public:
    mutation(schema_ptr schema, dht::decorated_key key)
        : _ptr(std::make_unique<data>(std::move(key), std::move(schema)))
    { }
    mutation(schema_ptr schema, partition_key key_)
        : _ptr(std::make_unique<data>(std::move(key_), std::move(schema)))
    { }
    mutation(schema_ptr schema, dht::decorated_key key, const mutation_partition& mp)
        : _ptr(std::make_unique<data>(std::move(schema), std::move(key), mp))
    { }
    mutation(schema_ptr schema, dht::decorated_key key, mutation_partition&& mp)
        : _ptr(std::make_unique<data>(std::move(schema), std::move(key), std::move(mp)))
    { }
    mutation(const mutation& m)
    {
        if (m._ptr) {
            _ptr = std::make_unique<data>(schema_ptr(m.schema()), dht::decorated_key(m.decorated_key()), m.partition());
        }
    }
    mutation(mutation&&) = default;
    mutation& operator=(mutation&& x) = default;
    mutation& operator=(const mutation& m);

    void set_static_cell(const column_definition& def, atomic_cell_or_collection&& value);
    void set_static_cell(const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_clustered_cell(const clustering_key& key, const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_clustered_cell(const clustering_key& key, const column_definition& def, atomic_cell_or_collection&& value);
    void set_cell(const clustering_key_prefix& prefix, const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_cell(const clustering_key_prefix& prefix, const column_definition& def, atomic_cell_or_collection&& value);

    // Upgrades this mutation to a newer schema. The new schema must
    // be obtained using only valid schema transformation:
    //  * primary key column count must not change
    //  * column types may only change to those with compatible representations
    //
    // After upgrade, mutation's partition should only be accessed using the new schema. User must
    // ensure proper isolation of accesses.
    //
    // Strong exception guarantees.
    //
    // Note that the conversion may lose information, it's possible that m1 != m2 after:
    //
    //   auto m2 = m1;
    //   m2.upgrade(s2);
    //   m2.upgrade(m1.schema());
    //
    void upgrade(const schema_ptr&);

    const partition_key& key() const { return _ptr->_dk._key; };
    const dht::decorated_key& decorated_key() const { return _ptr->_dk; };
    dht::ring_position ring_position() const { return { decorated_key() }; }
    const dht::token& token() const { return _ptr->_dk._token; }
    const schema_ptr& schema() const { return _ptr->_schema; }
    const mutation_partition& partition() const { return _ptr->_p; }
    mutation_partition& partition() { return _ptr->_p; }
    const utils::UUID& column_family_id() const { return _ptr->_schema->id(); }
    // Consistent with hash<canonical_mutation>
    bool operator==(const mutation&) const;
    bool operator!=(const mutation&) const;
public:
    // Consumes the mutation's content.
    //
    // The mutation is in a moved-from alike state after consumption.
    // There are tree ways to consume the mutation:
    // * consume_in_reverse::no - consume in forward order, as defined by the
    //   schema.
    // * consume_in_reverse::yes - consume in reverse order, as if the schema
    //   had the opposite clustering order. This effectively reverses the
    //   mutation's content, according to the native reverse order[1].
    // * consume_in_reverse::legacy_half_reverse - consume rows and range
    //   tombstones in legacy reverse order[2].
    //
    // For definition of [1] and [2] see docs/design-notes/reverse-reads.md.
    template<FlattenedConsumer Consumer>
    auto consume(Consumer& consumer, consume_in_reverse reverse) && -> mutation_consume_result<decltype(consumer.consume_end_of_stream())>;

    // See mutation_partition::live_row_count()
    uint64_t live_row_count(gc_clock::time_point query_time = gc_clock::time_point::min()) const;

    void apply(mutation&&);
    void apply(const mutation&);
    void apply(const mutation_fragment&);

    mutation operator+(const mutation& other) const;
    mutation& operator+=(const mutation& other);
    mutation& operator+=(mutation&& other);

    // Returns a subset of this mutation holding only information relevant for given clustering ranges.
    // Range tombstones will be trimmed to the boundaries of the clustering ranges.
    mutation sliced(const query::clustering_row_ranges&) const;
private:
    friend std::ostream& operator<<(std::ostream& os, const mutation& m);
};

namespace {

template<consume_in_reverse reverse, FlattenedConsumer Consumer>
stop_iteration consume_clustering_fragments(schema_ptr s, mutation_partition& partition, Consumer& consumer) {
    using crs_type = mutation_partition::rows_type;
    using crs_iterator_type = std::conditional_t<reverse == consume_in_reverse::legacy_half_reverse || reverse == consume_in_reverse::yes, crs_type::reverse_iterator, crs_type::iterator>;
    using rts_type = range_tombstone_list;
    using rts_iterator_type = std::conditional_t<reverse == consume_in_reverse::legacy_half_reverse, rts_type::reverse_iterator, rts_type::iterator>;

    if constexpr (reverse == consume_in_reverse::yes) {
        s = s->make_reversed();
    }

    // only used when reverse == consume_in_reverse::yes
    range_tombstone_list reversed_range_tombstones(*s);

    crs_iterator_type crs_it, crs_end;
    rts_iterator_type rts_it, rts_end;
    if constexpr (reverse == consume_in_reverse::legacy_half_reverse) {
        crs_it = partition.clustered_rows().rbegin();
        crs_end = partition.clustered_rows().rend();
        rts_it = partition.row_tombstones().rbegin();
        rts_end = partition.row_tombstones().rend();
    } else if constexpr (reverse == consume_in_reverse::yes) {
        crs_it = partition.clustered_rows().rbegin();
        crs_end = partition.clustered_rows().rend();

        while (!partition.row_tombstones().empty()) {
            auto rt = partition.mutable_row_tombstones().pop_front_and_lock();
            rt.reverse();
            reversed_range_tombstones.apply(*s, std::move(rt));
        }
        rts_it = reversed_range_tombstones.begin();
        rts_end = reversed_range_tombstones.end();
    } else {
        crs_it = partition.clustered_rows().begin();
        crs_end = partition.clustered_rows().end();
        rts_it = partition.row_tombstones().begin();
        rts_end = partition.row_tombstones().end();
    }

    stop_iteration stop = stop_iteration::no;

    position_in_partition::tri_compare cmp(*s);

    while (!stop && (crs_it != crs_end || rts_it != rts_end)) {
        bool emit_rt;
        if (crs_it != crs_end && rts_it != rts_end) {
            const auto cmp_res = cmp(rts_it->position(), crs_it->position());
            if constexpr (reverse == consume_in_reverse::legacy_half_reverse) {
                emit_rt = cmp_res > 0;
            } else {
                emit_rt = cmp_res < 0;
            }
        } else {
            emit_rt = rts_it != rts_end;
        }
        if (emit_rt) {
            stop = consumer.consume(std::move(rts_it->tombstone()));
            ++rts_it;
        } else {
            // Dummy rows are part of the in-memory representation but should be
            // invisible to reads.
            if (!crs_it->dummy()) {
                stop = consumer.consume(clustering_row(std::move(*crs_it)));
            }
            ++crs_it;
        }
    }

    return stop;
}

} // anonymous namespace

template<FlattenedConsumer Consumer>
auto mutation::consume(Consumer& consumer, consume_in_reverse reverse) && -> mutation_consume_result<decltype(consumer.consume_end_of_stream())> {
    consumer.consume_new_partition(_ptr->_dk);

    auto& partition = _ptr->_p;

    if (partition.partition_tombstone()) {
        consumer.consume(partition.partition_tombstone());
    }

    stop_iteration stop = stop_iteration::no;
    if (!partition.static_row().empty()) {
        stop = consumer.consume(static_row(std::move(partition.static_row().get_existing())));
    }

    if (reverse == consume_in_reverse::yes) {
        stop = consume_clustering_fragments<consume_in_reverse::yes>(_ptr->_schema, partition, consumer);
    } else if (reverse == consume_in_reverse::legacy_half_reverse) {
        stop = consume_clustering_fragments<consume_in_reverse::legacy_half_reverse>(_ptr->_schema, partition, consumer);
    } else {
        stop = consume_clustering_fragments<consume_in_reverse::no>(_ptr->_schema, partition, consumer);
    }

    const auto stop_consuming = consumer.consume_end_of_partition();
    using consume_res_type = decltype(consumer.consume_end_of_stream());
    if constexpr (std::is_same_v<consume_res_type, void>) {
        consumer.consume_end_of_stream();
        return mutation_consume_result<void>{stop_consuming};
    } else {
        return mutation_consume_result<consume_res_type>{stop_consuming, consumer.consume_end_of_stream()};
    }
}

struct mutation_equals_by_key {
    bool operator()(const mutation& m1, const mutation& m2) const {
        return m1.schema() == m2.schema()
                && m1.decorated_key().equal(*m1.schema(), m2.decorated_key());
    }
};

struct mutation_hash_by_key {
    size_t operator()(const mutation& m) const {
        auto dk_hash = std::hash<dht::decorated_key>();
        return dk_hash(m.decorated_key());
    }
};

struct mutation_decorated_key_less_comparator {
    bool operator()(const mutation& m1, const mutation& m2) const;
};

using mutation_opt = optimized_optional<mutation>;

// Consistent with operator==()
// Consistent across the cluster, so should not rely on particular
// serialization format, only on actual data stored.
template<>
struct appending_hash<mutation> {
    template<typename Hasher>
    void operator()(Hasher& h, const mutation& m) const {
        const schema& s = *m.schema();
        feed_hash(h, m.key(), s);
        m.partition().feed_hash(h, s);
    }
};

inline
void apply(mutation_opt& dst, mutation&& src) {
    if (!dst) {
        dst = std::move(src);
    } else {
        dst->apply(std::move(src));
    }
}

inline
void apply(mutation_opt& dst, mutation_opt&& src) {
    if (src) {
        apply(dst, std::move(*src));
    }
}

// Returns a range into partitions containing mutations covered by the range.
// partitions must be sorted according to decorated key.
// range must not wrap around.
boost::iterator_range<std::vector<mutation>::const_iterator> slice(
    const std::vector<mutation>& partitions,
    const dht::partition_range&);

class flat_mutation_reader;

// Reads a single partition from a reader. Returns empty optional if there are no more partitions to be read.
future<mutation_opt> read_mutation_from_flat_mutation_reader(flat_mutation_reader& reader);

// Reverses the mutation as if it was created with a schema with reverse
// clustering order. The resulting mutation will contain a reverse schema too.
mutation reverse(mutation mut);
<commit_msg>mutation: consume(): restructure clustering iterator initialization<commit_after>/*
 * Copyright (C) 2014-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <iosfwd>

#include "mutation_partition.hh"
#include "keys.hh"
#include "schema_fwd.hh"
#include "dht/i_partitioner.hh"
#include "hashing.hh"
#include "mutation_fragment.hh"
#include "mutation_consumer_concepts.hh"

#include <seastar/util/optimized_optional.hh>

template<typename Result>
struct mutation_consume_result {
    stop_iteration stop;
    Result result;
};

template<>
struct mutation_consume_result<void> {
    stop_iteration stop;
};

enum class consume_in_reverse {
    no = 0,
    yes,
    legacy_half_reverse,
};

class mutation final {
private:
    struct data {
        schema_ptr _schema;
        dht::decorated_key _dk;
        mutation_partition _p;

        data(dht::decorated_key&& key, schema_ptr&& schema);
        data(partition_key&& key, schema_ptr&& schema);
        data(schema_ptr&& schema, dht::decorated_key&& key, const mutation_partition& mp);
        data(schema_ptr&& schema, dht::decorated_key&& key, mutation_partition&& mp);
    };
    std::unique_ptr<data> _ptr;
private:
    mutation() = default;
    explicit operator bool() const { return bool(_ptr); }
    friend class optimized_optional<mutation>;
public:
    mutation(schema_ptr schema, dht::decorated_key key)
        : _ptr(std::make_unique<data>(std::move(key), std::move(schema)))
    { }
    mutation(schema_ptr schema, partition_key key_)
        : _ptr(std::make_unique<data>(std::move(key_), std::move(schema)))
    { }
    mutation(schema_ptr schema, dht::decorated_key key, const mutation_partition& mp)
        : _ptr(std::make_unique<data>(std::move(schema), std::move(key), mp))
    { }
    mutation(schema_ptr schema, dht::decorated_key key, mutation_partition&& mp)
        : _ptr(std::make_unique<data>(std::move(schema), std::move(key), std::move(mp)))
    { }
    mutation(const mutation& m)
    {
        if (m._ptr) {
            _ptr = std::make_unique<data>(schema_ptr(m.schema()), dht::decorated_key(m.decorated_key()), m.partition());
        }
    }
    mutation(mutation&&) = default;
    mutation& operator=(mutation&& x) = default;
    mutation& operator=(const mutation& m);

    void set_static_cell(const column_definition& def, atomic_cell_or_collection&& value);
    void set_static_cell(const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_clustered_cell(const clustering_key& key, const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_clustered_cell(const clustering_key& key, const column_definition& def, atomic_cell_or_collection&& value);
    void set_cell(const clustering_key_prefix& prefix, const bytes& name, const data_value& value, api::timestamp_type timestamp, ttl_opt ttl = {});
    void set_cell(const clustering_key_prefix& prefix, const column_definition& def, atomic_cell_or_collection&& value);

    // Upgrades this mutation to a newer schema. The new schema must
    // be obtained using only valid schema transformation:
    //  * primary key column count must not change
    //  * column types may only change to those with compatible representations
    //
    // After upgrade, mutation's partition should only be accessed using the new schema. User must
    // ensure proper isolation of accesses.
    //
    // Strong exception guarantees.
    //
    // Note that the conversion may lose information, it's possible that m1 != m2 after:
    //
    //   auto m2 = m1;
    //   m2.upgrade(s2);
    //   m2.upgrade(m1.schema());
    //
    void upgrade(const schema_ptr&);

    const partition_key& key() const { return _ptr->_dk._key; };
    const dht::decorated_key& decorated_key() const { return _ptr->_dk; };
    dht::ring_position ring_position() const { return { decorated_key() }; }
    const dht::token& token() const { return _ptr->_dk._token; }
    const schema_ptr& schema() const { return _ptr->_schema; }
    const mutation_partition& partition() const { return _ptr->_p; }
    mutation_partition& partition() { return _ptr->_p; }
    const utils::UUID& column_family_id() const { return _ptr->_schema->id(); }
    // Consistent with hash<canonical_mutation>
    bool operator==(const mutation&) const;
    bool operator!=(const mutation&) const;
public:
    // Consumes the mutation's content.
    //
    // The mutation is in a moved-from alike state after consumption.
    // There are tree ways to consume the mutation:
    // * consume_in_reverse::no - consume in forward order, as defined by the
    //   schema.
    // * consume_in_reverse::yes - consume in reverse order, as if the schema
    //   had the opposite clustering order. This effectively reverses the
    //   mutation's content, according to the native reverse order[1].
    // * consume_in_reverse::legacy_half_reverse - consume rows and range
    //   tombstones in legacy reverse order[2].
    //
    // For definition of [1] and [2] see docs/design-notes/reverse-reads.md.
    template<FlattenedConsumer Consumer>
    auto consume(Consumer& consumer, consume_in_reverse reverse) && -> mutation_consume_result<decltype(consumer.consume_end_of_stream())>;

    // See mutation_partition::live_row_count()
    uint64_t live_row_count(gc_clock::time_point query_time = gc_clock::time_point::min()) const;

    void apply(mutation&&);
    void apply(const mutation&);
    void apply(const mutation_fragment&);

    mutation operator+(const mutation& other) const;
    mutation& operator+=(const mutation& other);
    mutation& operator+=(mutation&& other);

    // Returns a subset of this mutation holding only information relevant for given clustering ranges.
    // Range tombstones will be trimmed to the boundaries of the clustering ranges.
    mutation sliced(const query::clustering_row_ranges&) const;
private:
    friend std::ostream& operator<<(std::ostream& os, const mutation& m);
};

namespace {

template<consume_in_reverse reverse, FlattenedConsumer Consumer>
stop_iteration consume_clustering_fragments(schema_ptr s, mutation_partition& partition, Consumer& consumer) {
    constexpr bool crs_in_reverse = reverse == consume_in_reverse::legacy_half_reverse || reverse == consume_in_reverse::yes;
    constexpr bool rts_in_reverse = reverse == consume_in_reverse::legacy_half_reverse;

    using crs_type = mutation_partition::rows_type;
    using crs_iterator_type = std::conditional_t<crs_in_reverse, crs_type::reverse_iterator, crs_type::iterator>;
    using rts_type = range_tombstone_list;
    using rts_iterator_type = std::conditional_t<rts_in_reverse, rts_type::reverse_iterator, rts_type::iterator>;

    if constexpr (reverse == consume_in_reverse::yes) {
        s = s->make_reversed();
    }

    // only used when reverse == consume_in_reverse::yes
    range_tombstone_list reversed_range_tombstones(*s);

    auto* rt_list = &partition.mutable_row_tombstones();
    if constexpr (reverse == consume_in_reverse::yes) {
        while (!rt_list->empty()) {
            auto rt = rt_list->pop_front_and_lock();
            rt.reverse();
            reversed_range_tombstones.apply(*s, std::move(rt));
        }
        rt_list = &reversed_range_tombstones;
    }

    crs_iterator_type crs_it, crs_end;
    rts_iterator_type rts_it, rts_end;

    if constexpr (crs_in_reverse) {
        crs_it = partition.clustered_rows().rbegin();
        crs_end = partition.clustered_rows().rend();
    } else {
        crs_it = partition.clustered_rows().begin();
        crs_end = partition.clustered_rows().end();
    }

    if constexpr (rts_in_reverse) {
        rts_it = rt_list->rbegin();
        rts_end = rt_list->rend();
    } else {
        rts_it = rt_list->begin();
        rts_end = rt_list->end();
    }

    stop_iteration stop = stop_iteration::no;

    position_in_partition::tri_compare cmp(*s);

    while (!stop && (crs_it != crs_end || rts_it != rts_end)) {
        bool emit_rt;
        if (crs_it != crs_end && rts_it != rts_end) {
            const auto cmp_res = cmp(rts_it->position(), crs_it->position());
            if constexpr (reverse == consume_in_reverse::legacy_half_reverse) {
                emit_rt = cmp_res > 0;
            } else {
                emit_rt = cmp_res < 0;
            }
        } else {
            emit_rt = rts_it != rts_end;
        }
        if (emit_rt) {
            stop = consumer.consume(std::move(rts_it->tombstone()));
            ++rts_it;
        } else {
            // Dummy rows are part of the in-memory representation but should be
            // invisible to reads.
            if (!crs_it->dummy()) {
                stop = consumer.consume(clustering_row(std::move(*crs_it)));
            }
            ++crs_it;
        }
    }

    return stop;
}

} // anonymous namespace

template<FlattenedConsumer Consumer>
auto mutation::consume(Consumer& consumer, consume_in_reverse reverse) && -> mutation_consume_result<decltype(consumer.consume_end_of_stream())> {
    consumer.consume_new_partition(_ptr->_dk);

    auto& partition = _ptr->_p;

    if (partition.partition_tombstone()) {
        consumer.consume(partition.partition_tombstone());
    }

    stop_iteration stop = stop_iteration::no;
    if (!partition.static_row().empty()) {
        stop = consumer.consume(static_row(std::move(partition.static_row().get_existing())));
    }

    if (reverse == consume_in_reverse::yes) {
        stop = consume_clustering_fragments<consume_in_reverse::yes>(_ptr->_schema, partition, consumer);
    } else if (reverse == consume_in_reverse::legacy_half_reverse) {
        stop = consume_clustering_fragments<consume_in_reverse::legacy_half_reverse>(_ptr->_schema, partition, consumer);
    } else {
        stop = consume_clustering_fragments<consume_in_reverse::no>(_ptr->_schema, partition, consumer);
    }

    const auto stop_consuming = consumer.consume_end_of_partition();
    using consume_res_type = decltype(consumer.consume_end_of_stream());
    if constexpr (std::is_same_v<consume_res_type, void>) {
        consumer.consume_end_of_stream();
        return mutation_consume_result<void>{stop_consuming};
    } else {
        return mutation_consume_result<consume_res_type>{stop_consuming, consumer.consume_end_of_stream()};
    }
}

struct mutation_equals_by_key {
    bool operator()(const mutation& m1, const mutation& m2) const {
        return m1.schema() == m2.schema()
                && m1.decorated_key().equal(*m1.schema(), m2.decorated_key());
    }
};

struct mutation_hash_by_key {
    size_t operator()(const mutation& m) const {
        auto dk_hash = std::hash<dht::decorated_key>();
        return dk_hash(m.decorated_key());
    }
};

struct mutation_decorated_key_less_comparator {
    bool operator()(const mutation& m1, const mutation& m2) const;
};

using mutation_opt = optimized_optional<mutation>;

// Consistent with operator==()
// Consistent across the cluster, so should not rely on particular
// serialization format, only on actual data stored.
template<>
struct appending_hash<mutation> {
    template<typename Hasher>
    void operator()(Hasher& h, const mutation& m) const {
        const schema& s = *m.schema();
        feed_hash(h, m.key(), s);
        m.partition().feed_hash(h, s);
    }
};

inline
void apply(mutation_opt& dst, mutation&& src) {
    if (!dst) {
        dst = std::move(src);
    } else {
        dst->apply(std::move(src));
    }
}

inline
void apply(mutation_opt& dst, mutation_opt&& src) {
    if (src) {
        apply(dst, std::move(*src));
    }
}

// Returns a range into partitions containing mutations covered by the range.
// partitions must be sorted according to decorated key.
// range must not wrap around.
boost::iterator_range<std::vector<mutation>::const_iterator> slice(
    const std::vector<mutation>& partitions,
    const dht::partition_range&);

class flat_mutation_reader;

// Reads a single partition from a reader. Returns empty optional if there are no more partitions to be read.
future<mutation_opt> read_mutation_from_flat_mutation_reader(flat_mutation_reader& reader);

// Reverses the mutation as if it was created with a schema with reverse
// clustering order. The resulting mutation will contain a reverse schema too.
mutation reverse(mutation mut);
<|endoftext|>