<commit_before>/************************************************************************/
/*                                                                      */
/*                 Copyright 2011 by Ullrich Koethe                     */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_DENSE_REFERENCE_MAP_HXX
#define VIGRA_DENSE_REFERENCE_MAP_HXX

/*vigra*/
//#include <vigra/array_vector.hxx>
#include <vigra/multi_array.hxx>
#include <vigra/graph_generalization.hxx>
#include <vigra/graphs.hxx>

namespace vigra{

template<class T,class KEY,class REF,class CREF>
class DenseReferenceMap
: public MultiArray<1,T>
{
public:
    typedef KEY  Key;
    typedef T    Value;
    typedef REF  Reference;
    typedef CREF ConstReference;

    typedef Key             key_type;
    typedef Value           value_type;
    typedef Reference       reference;
    typedef ConstReference  const_reference;
    typedef boost::read_write_property_map_tag category;

    typedef typename MultiArray<1,T>::difference_type Shape1Type;

    DenseReferenceMap()
    : MultiArray<1,T>(){
    }
    DenseReferenceMap(const size_t maxKey)
    : MultiArray<1,T>(Shape1Type(maxKey+1)){
    }
    DenseReferenceMap(const size_t maxKey,ConstReference  value)
    : MultiArray<1,T>(Shape1Type(maxKey+1),value){
    }

    ConstReference operator[](const KEY & key)const{
        //return this->operator[](key.id());
        return MultiArray<1,T>::operator()(key.id());
    }
    Reference operator[](const KEY & key){
        return MultiArray<1,T>::operator()(key.id());
    }

    size_t size()const{
        return this->shape(0);
    }
protected:
    void assign(const size_t maxKey){
        this->reshape(Shape1Type(maxKey+1));
    }
private:
    // NONE
};

template<class GRAPH,class ITEM,class T,class REF,class CREF>
class DenseGraphItemReferenceMap
: public DenseReferenceMap<T,ITEM,REF,CREF>
{
    typedef GRAPH Graph;
    typedef ITEM  Item;
    typedef DenseReferenceMap<T,ITEM,REF,CREF> DenseReferenceMapType;
    typedef GraphItemHelper<Graph,ITEM> ItemHelper;
    typedef typename ItemHelper::ItemIt ItemIt;

public:
    DenseGraphItemReferenceMap()
    :   DenseReferenceMapType(){

    }
    DenseGraphItemReferenceMap(const Graph & g)
    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g) ){

    }
    DenseGraphItemReferenceMap(const Graph & g,typename DenseReferenceMapType::ConstReference value)
    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g)){

    }
    void assign(const Graph & g){
    }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseNodeReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Node,T,REF,CREF>
{
    typedef typename GRAPH::Node Node;
    typedef DenseGraphItemReferenceMap<GRAPH,Node,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseNodeReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseNodeReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseNodeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseEdgeReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Edge,T,REF,CREF>
{
    typedef typename GRAPH::Edge Edge;
    typedef DenseGraphItemReferenceMap<GRAPH,Edge,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseEdgeReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseEdgeReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseEdgeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseArcReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Arc,T,REF,CREF>
{
    typedef typename GRAPH::Arc Arc;
    typedef DenseGraphItemReferenceMap<GRAPH,Arc,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseArcReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseArcReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseArcReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

} // end namespace vigra

#endif //VIGRA_DENSE_REFERENCE_MAP_HXX <commit_msg>fixed bug in dense graph maps<commit_after>/************************************************************************/
/*                                                                      */
/*                 Copyright 2011 by Ullrich Koethe                     */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

#ifndef VIGRA_DENSE_REFERENCE_MAP_HXX
#define VIGRA_DENSE_REFERENCE_MAP_HXX

/*vigra*/
//#include <vigra/array_vector.hxx>
#include <vigra/multi_array.hxx>
#include <vigra/graph_generalization.hxx>
#include <vigra/graphs.hxx>

namespace vigra{

template<class T,class KEY,class REF,class CREF>
class DenseReferenceMap
: public MultiArray<1,T>
{
public:
    typedef KEY  Key;
    typedef T    Value;
    typedef REF  Reference;
    typedef CREF ConstReference;

    typedef Key             key_type;
    typedef Value           value_type;
    typedef Reference       reference;
    typedef ConstReference  const_reference;
    typedef boost::read_write_property_map_tag category;

    typedef typename MultiArray<1,T>::difference_type Shape1Type;

    DenseReferenceMap()
    : MultiArray<1,T>(){
    }
    DenseReferenceMap(const size_t maxKey)
    : MultiArray<1,T>(Shape1Type(maxKey+1)){
    }
    DenseReferenceMap(const size_t maxKey,ConstReference  value)
    : MultiArray<1,T>(Shape1Type(maxKey+1),value){
    }

    ConstReference operator[](const KEY & key)const{
        //return this->operator[](key.id());
        return MultiArray<1,T>::operator()(key.id());
    }
    Reference operator[](const KEY & key){
        return MultiArray<1,T>::operator()(key.id());
    }

    size_t size()const{
        return this->shape(0);
    }
protected:
    void assign(const size_t maxKey){
        this->reshape(Shape1Type(maxKey+1));
    }
private:
    // NONE
};

template<class GRAPH,class ITEM,class T,class REF,class CREF>
class DenseGraphItemReferenceMap
: public DenseReferenceMap<T,ITEM,REF,CREF>
{
    typedef GRAPH Graph;
    typedef ITEM  Item;
    typedef DenseReferenceMap<T,ITEM,REF,CREF> DenseReferenceMapType;
    typedef GraphItemHelper<Graph,ITEM> ItemHelper;
    typedef typename ItemHelper::ItemIt ItemIt;

public:
    DenseGraphItemReferenceMap()
    :   DenseReferenceMapType(){

    }
    DenseGraphItemReferenceMap(const Graph & g)
    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g) ){

    }
    DenseGraphItemReferenceMap(const Graph & g,typename DenseReferenceMapType::ConstReference value)
    :   DenseReferenceMapType(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g)){

    }
    void assign(const Graph & g){
        this->assign(ItemHelper::itemNum(g)==0 ? 0: ItemHelper::maxItemId(g));
    }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseNodeReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Node,T,REF,CREF>
{
    typedef typename GRAPH::Node Node;
    typedef DenseGraphItemReferenceMap<GRAPH,Node,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseNodeReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseNodeReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseNodeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseEdgeReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Edge,T,REF,CREF>
{
    typedef typename GRAPH::Edge Edge;
    typedef DenseGraphItemReferenceMap<GRAPH,Edge,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseEdgeReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseEdgeReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseEdgeReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

template<class GRAPH,class T,class REF= T & ,class CREF = const T & >
class DenseArcReferenceMap
: public DenseGraphItemReferenceMap<GRAPH,typename GRAPH::Arc,T,REF,CREF>
{
    typedef typename GRAPH::Arc Arc;
    typedef DenseGraphItemReferenceMap<GRAPH,Arc,T,REF,CREF> DenseGraphItemReferenceMapType;
    public:
        DenseArcReferenceMap()
        : DenseGraphItemReferenceMapType(){
        }
        DenseArcReferenceMap(const GRAPH & g)
        : DenseGraphItemReferenceMapType(g){
        }
        DenseArcReferenceMap(const GRAPH & g,typename DenseGraphItemReferenceMapType::ConstReference value)
        : DenseGraphItemReferenceMapType(g,value){
        }
};

} // end namespace vigra

#endif //VIGRA_DENSE_REFERENCE_MAP_HXX <|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: syswin.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2007-12-12 13:19:22 $
 *
 *  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 _SV_SYSWIN_HXX
#define _SV_SYSWIN_HXX

#ifndef _SV_SV_H
#include <vcl/sv.h>
#endif
#ifndef _VCL_DLLAPI_H
#include <vcl/dllapi.h>
#endif

#ifndef _SV_WINDOW_HXX
#include <vcl/window.hxx>
#endif

class ModalDialog;
class MenuBar;
class TaskPaneList;

// --------------
// - Icon-Types -
// --------------

#define ICON_DEFAULT                    0
#define ICON_SO_DEFAULT                 1
#define ICON_TEXT_DOCUMENT              2
#define ICON_TEXT_TEMPLATE              3
#define ICON_SPREADSHEET_DOCUMENT       4
#define ICON_SPREADSHEET_TEMPLATE       5
#define ICON_DRAWING_DOCUMENT           6
#define ICON_DRAWING_TEMPLATE           7
#define ICON_PRESENTATION_DOCUMENT      8
#define ICON_PRESENTATION_TEMPLATE      9
#define ICON_PRESENTATION_COMPRESSED    10
#define ICON_GLOBAL_DOCUMENT            11
#define ICON_HTML_DOCUMENT              12
#define ICON_CHART_DOCUMENT             13
#define ICON_DATABASE_DOCUMENT          14
#define ICON_MATH_DOCUMENT              15
#define ICON_TEMPLATE                   16
#define ICON_MACROLIBRARY               17
#define ICON_PLAYER                     100
#define ICON_SETUP                      500

// -------------------
// - WindowStateData -
// -------------------

#define WINDOWSTATE_MASK_X                  ((ULONG)0x00000001)
#define WINDOWSTATE_MASK_Y                  ((ULONG)0x00000002)
#define WINDOWSTATE_MASK_WIDTH              ((ULONG)0x00000004)
#define WINDOWSTATE_MASK_HEIGHT             ((ULONG)0x00000008)
#define WINDOWSTATE_MASK_STATE              ((ULONG)0x00000010)
#define WINDOWSTATE_MASK_MINIMIZED          ((ULONG)0x00000020)
#define WINDOWSTATE_MASK_MAXIMIZED_X        ((ULONG)0x00000100)
#define WINDOWSTATE_MASK_MAXIMIZED_Y        ((ULONG)0x00000200)
#define WINDOWSTATE_MASK_MAXIMIZED_WIDTH    ((ULONG)0x00000400)
#define WINDOWSTATE_MASK_MAXIMIZED_HEIGHT   ((ULONG)0x00000800)
#define WINDOWSTATE_MASK_POS  (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y)
#define WINDOWSTATE_MASK_ALL  (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y | WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT | WINDOWSTATE_MASK_MAXIMIZED_X | WINDOWSTATE_MASK_MAXIMIZED_Y | WINDOWSTATE_MASK_MAXIMIZED_WIDTH | WINDOWSTATE_MASK_MAXIMIZED_HEIGHT | WINDOWSTATE_MASK_STATE | WINDOWSTATE_MASK_MINIMIZED)

#define WINDOWSTATE_STATE_NORMAL         ((ULONG)0x00000001)
#define WINDOWSTATE_STATE_MINIMIZED      ((ULONG)0x00000002)
#define WINDOWSTATE_STATE_MAXIMIZED      ((ULONG)0x00000004)
#define WINDOWSTATE_STATE_ROLLUP         ((ULONG)0x00000008)
#define WINDOWSTATE_STATE_MAXIMIZED_HORZ ((ULONG)0x00000010)
#define WINDOWSTATE_STATE_MAXIMIZED_VERT ((ULONG)0x00000020)

class VCL_DLLPUBLIC WindowStateData
{
private:
    sal_uInt32          mnValidMask;
    int                 mnX;
    int                 mnY;
    unsigned int        mnWidth;
    unsigned int        mnHeight;
    int                 mnMaximizedX;
    int                 mnMaximizedY;
    unsigned int        mnMaximizedWidth;
    unsigned int        mnMaximizedHeight;
    sal_uInt32          mnState;

public:
                WindowStateData()
                {
                    mnValidMask = mnX = mnY = mnWidth = mnHeight = mnState = 0;
                    mnMaximizedX = mnMaximizedY = mnMaximizedWidth = mnMaximizedHeight = 0;
                }

    void        SetMask( ULONG nValidMask ) { mnValidMask = nValidMask; }
    sal_uInt32  GetMask() const { return mnValidMask; }

    void         SetX( int nX ) { mnX = nX; }
    int          GetX() const { return mnX; }
    void         SetY( int nY ) { mnY = nY; }
    int          GetY() const { return mnY; }
    void         SetWidth( unsigned int nWidth ) { mnWidth = nWidth; }
    unsigned int GetWidth() const { return mnWidth; }
    void         SetHeight( unsigned int nHeight ) { mnHeight = nHeight; }
    unsigned int GetHeight() const { return mnHeight; }
    void         SetState( sal_uInt32 nState ) { mnState = nState; }
    sal_uInt32   GetState() const { return mnState; }
    void         SetMaximizedX( int nRX ) { mnMaximizedX = nRX; }
    int          GetMaximizedX() const { return mnMaximizedX; }
    void         SetMaximizedY( int nRY ) { mnMaximizedY = nRY; }
    int          GetMaximizedY() const { return mnMaximizedY; }
    void         SetMaximizedWidth( unsigned int nRWidth ) { mnMaximizedWidth = nRWidth; }
    unsigned int GetMaximizedWidth() const { return mnMaximizedWidth; }
    void         SetMaximizedHeight( unsigned int nRHeight ) { mnMaximizedHeight = nRHeight; }
    unsigned int GetMaximizedHeight() const { return mnMaximizedHeight; }
};

// ----------------------
// - SystemWindow-Types -
// ----------------------

#define MENUBAR_MODE_NORMAL         ((USHORT)0)
#define MENUBAR_MODE_HIDE           ((USHORT)1)

#define TITLE_BUTTON_DOCKING        ((USHORT)1)
#define TITLE_BUTTON_HIDE           ((USHORT)2)
#define TITLE_BUTTON_MENU           ((USHORT)4)

// ----------------
// - SystemWindow -
// ----------------

class VCL_DLLPUBLIC SystemWindow : public Window
{
    friend class WorkWindow;
    class ImplData;

private:
    MenuBar*        mpMenuBar;
    Size            maOrgSize;
    Size            maRollUpOutSize;
    Size            maMinOutSize;
    BOOL            mbPined;
    BOOL            mbRollUp;
    BOOL            mbRollFunc;
    BOOL            mbDockBtn;
    BOOL            mbHideBtn;
    BOOL            mbSysChild;
    USHORT          mnMenuBarMode;
    USHORT          mnIcon;
    ImplData*       mpImplData;

//#if 0 // _SOLAR__PRIVATE
public:
    using Window::ImplIsInTaskPaneList;
    SAL_DLLPRIVATE BOOL ImplIsInTaskPaneList( Window* pWin );
//#endif

private:
    // Default construction is forbidden and not implemented.
    SystemWindow();

    // Copy assignment is forbidden and not implemented.
    SystemWindow (const SystemWindow &);
    SystemWindow & operator= (const SystemWindow &);

protected:
    // Single argument ctors shall be explicit.
    explicit        SystemWindow( WindowType nType );

    void            SetWindowStateData( const WindowStateData& rData );

public:
                    ~SystemWindow();
    virtual long    Notify( NotifyEvent& rNEvt );
    virtual long    PreNotify( NotifyEvent& rNEvt );

    virtual BOOL    Close();
    virtual void    TitleButtonClick( USHORT nButton );
    virtual void    Pin();
    virtual void    Roll();
    virtual void    Resizing( Size& rSize );

    void            SetIcon( USHORT nIcon );
    USHORT          GetIcon() const { return mnIcon; }

    void            SetZLevel( BYTE nLevel );
    BYTE            GetZLevel() const;

    void            EnableSaveBackground( BOOL bSave = TRUE );
    BOOL            IsSaveBackgroundEnabled() const;

    void            ShowTitleButton( USHORT nButton, BOOL bVisible = TRUE );
    BOOL            IsTitleButtonVisible( USHORT nButton ) const;

    void            SetPin( BOOL bPin );
    BOOL            IsPined() const { return mbPined; }

    void            RollUp();
    void            RollDown();
    BOOL            IsRollUp() const { return mbRollUp; }

    void            SetRollUpOutputSizePixel( const Size& rSize ) { maRollUpOutSize = rSize; }
    Size            GetRollUpOutputSizePixel() const { return maRollUpOutSize; }

    void            SetMinOutputSizePixel( const Size& rSize );
    const Size&     GetMinOutputSizePixel() const { return maMinOutSize; }
    void            SetMaxOutputSizePixel( const Size& rSize );
    const Size&     GetMaxOutputSizePixel() const;
    Size            GetResizeOutputSizePixel() const;

    void            SetWindowState( const ByteString& rStr );
    ByteString      GetWindowState( ULONG nMask = WINDOWSTATE_MASK_ALL ) const;

    void            SetMenuBar( MenuBar* pMenuBar );
    MenuBar*        GetMenuBar() const { return mpMenuBar; }
    void            SetMenuBarMode( USHORT nMode );
    USHORT          GetMenuBarMode() const { return mnMenuBarMode; }

    TaskPaneList*   GetTaskPaneList();
    void            GetWindowStateData( WindowStateData& rData ) const;
};

#endif // _SV_SYSWIN_HXX
<commit_msg>INTEGRATION: CWS presenterview (1.2.24); FILE MERGED 2008/02/26 09:05:31 af 1.2.24.2: RESYNC: (1.2-1.3); FILE MERGED 2007/10/12 13:25:56 pl 1.2.24.1: #i82554# add WB_SYSTEMCHILDWINDOW<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: syswin.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-03 15:47:39 $
 *
 *  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 _SV_SYSWIN_HXX
#define _SV_SYSWIN_HXX

#ifndef _SV_SV_H
#include <vcl/sv.h>
#endif
#ifndef _VCL_DLLAPI_H
#include <vcl/dllapi.h>
#endif

#ifndef _SV_WINDOW_HXX
#include <vcl/window.hxx>
#endif

class ModalDialog;
class MenuBar;
class TaskPaneList;

// --------------
// - Icon-Types -
// --------------

#define ICON_DEFAULT                    0
#define ICON_SO_DEFAULT                 1
#define ICON_TEXT_DOCUMENT              2
#define ICON_TEXT_TEMPLATE              3
#define ICON_SPREADSHEET_DOCUMENT       4
#define ICON_SPREADSHEET_TEMPLATE       5
#define ICON_DRAWING_DOCUMENT           6
#define ICON_DRAWING_TEMPLATE           7
#define ICON_PRESENTATION_DOCUMENT      8
#define ICON_PRESENTATION_TEMPLATE      9
#define ICON_PRESENTATION_COMPRESSED    10
#define ICON_GLOBAL_DOCUMENT            11
#define ICON_HTML_DOCUMENT              12
#define ICON_CHART_DOCUMENT             13
#define ICON_DATABASE_DOCUMENT          14
#define ICON_MATH_DOCUMENT              15
#define ICON_TEMPLATE                   16
#define ICON_MACROLIBRARY               17
#define ICON_PLAYER                     100
#define ICON_SETUP                      500

// -------------------
// - WindowStateData -
// -------------------

#define WINDOWSTATE_MASK_X                  ((ULONG)0x00000001)
#define WINDOWSTATE_MASK_Y                  ((ULONG)0x00000002)
#define WINDOWSTATE_MASK_WIDTH              ((ULONG)0x00000004)
#define WINDOWSTATE_MASK_HEIGHT             ((ULONG)0x00000008)
#define WINDOWSTATE_MASK_STATE              ((ULONG)0x00000010)
#define WINDOWSTATE_MASK_MINIMIZED          ((ULONG)0x00000020)
#define WINDOWSTATE_MASK_MAXIMIZED_X        ((ULONG)0x00000100)
#define WINDOWSTATE_MASK_MAXIMIZED_Y        ((ULONG)0x00000200)
#define WINDOWSTATE_MASK_MAXIMIZED_WIDTH    ((ULONG)0x00000400)
#define WINDOWSTATE_MASK_MAXIMIZED_HEIGHT   ((ULONG)0x00000800)
#define WINDOWSTATE_MASK_POS  (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y)
#define WINDOWSTATE_MASK_ALL  (WINDOWSTATE_MASK_X | WINDOWSTATE_MASK_Y | WINDOWSTATE_MASK_WIDTH | WINDOWSTATE_MASK_HEIGHT | WINDOWSTATE_MASK_MAXIMIZED_X | WINDOWSTATE_MASK_MAXIMIZED_Y | WINDOWSTATE_MASK_MAXIMIZED_WIDTH | WINDOWSTATE_MASK_MAXIMIZED_HEIGHT | WINDOWSTATE_MASK_STATE | WINDOWSTATE_MASK_MINIMIZED)

#define WINDOWSTATE_STATE_NORMAL         ((ULONG)0x00000001)
#define WINDOWSTATE_STATE_MINIMIZED      ((ULONG)0x00000002)
#define WINDOWSTATE_STATE_MAXIMIZED      ((ULONG)0x00000004)
#define WINDOWSTATE_STATE_ROLLUP         ((ULONG)0x00000008)
#define WINDOWSTATE_STATE_MAXIMIZED_HORZ ((ULONG)0x00000010)
#define WINDOWSTATE_STATE_MAXIMIZED_VERT ((ULONG)0x00000020)

class VCL_DLLPUBLIC WindowStateData
{
private:
    sal_uInt32          mnValidMask;
    int                 mnX;
    int                 mnY;
    unsigned int        mnWidth;
    unsigned int        mnHeight;
    int                 mnMaximizedX;
    int                 mnMaximizedY;
    unsigned int        mnMaximizedWidth;
    unsigned int        mnMaximizedHeight;
    sal_uInt32          mnState;

public:
                WindowStateData()
                {
                    mnValidMask = mnX = mnY = mnWidth = mnHeight = mnState = 0;
                    mnMaximizedX = mnMaximizedY = mnMaximizedWidth = mnMaximizedHeight = 0;
                }

    void        SetMask( ULONG nValidMask ) { mnValidMask = nValidMask; }
    sal_uInt32  GetMask() const { return mnValidMask; }

    void         SetX( int nX ) { mnX = nX; }
    int          GetX() const { return mnX; }
    void         SetY( int nY ) { mnY = nY; }
    int          GetY() const { return mnY; }
    void         SetWidth( unsigned int nWidth ) { mnWidth = nWidth; }
    unsigned int GetWidth() const { return mnWidth; }
    void         SetHeight( unsigned int nHeight ) { mnHeight = nHeight; }
    unsigned int GetHeight() const { return mnHeight; }
    void         SetState( sal_uInt32 nState ) { mnState = nState; }
    sal_uInt32   GetState() const { return mnState; }
    void         SetMaximizedX( int nRX ) { mnMaximizedX = nRX; }
    int          GetMaximizedX() const { return mnMaximizedX; }
    void         SetMaximizedY( int nRY ) { mnMaximizedY = nRY; }
    int          GetMaximizedY() const { return mnMaximizedY; }
    void         SetMaximizedWidth( unsigned int nRWidth ) { mnMaximizedWidth = nRWidth; }
    unsigned int GetMaximizedWidth() const { return mnMaximizedWidth; }
    void         SetMaximizedHeight( unsigned int nRHeight ) { mnMaximizedHeight = nRHeight; }
    unsigned int GetMaximizedHeight() const { return mnMaximizedHeight; }
};

// ----------------------
// - SystemWindow-Types -
// ----------------------

#define MENUBAR_MODE_NORMAL         ((USHORT)0)
#define MENUBAR_MODE_HIDE           ((USHORT)1)

#define TITLE_BUTTON_DOCKING        ((USHORT)1)
#define TITLE_BUTTON_HIDE           ((USHORT)2)
#define TITLE_BUTTON_MENU           ((USHORT)4)

// ----------------
// - SystemWindow -
// ----------------

class VCL_DLLPUBLIC SystemWindow : public Window
{
    friend class WorkWindow;
    class ImplData;

private:
    MenuBar*        mpMenuBar;
    Size            maOrgSize;
    Size            maRollUpOutSize;
    Size            maMinOutSize;
    BOOL            mbPined;
    BOOL            mbRollUp;
    BOOL            mbRollFunc;
    BOOL            mbDockBtn;
    BOOL            mbHideBtn;
    BOOL            mbSysChild;
    USHORT          mnMenuBarMode;
    USHORT          mnIcon;
    ImplData*       mpImplData;

#if _SOLAR__PRIVATE
public:
    using Window::ImplIsInTaskPaneList;
    SAL_DLLPRIVATE BOOL ImplIsInTaskPaneList( Window* pWin );
#endif

private:
    // Default construction is forbidden and not implemented.
    SystemWindow();

    // Copy assignment is forbidden and not implemented.
    SystemWindow (const SystemWindow &);
    SystemWindow & operator= (const SystemWindow &);

protected:
    // Single argument ctors shall be explicit.
    explicit        SystemWindow( WindowType nType );

    void            SetWindowStateData( const WindowStateData& rData );

public:
                    ~SystemWindow();
    virtual long    Notify( NotifyEvent& rNEvt );
    virtual long    PreNotify( NotifyEvent& rNEvt );

    virtual BOOL    Close();
    virtual void    TitleButtonClick( USHORT nButton );
    virtual void    Pin();
    virtual void    Roll();
    virtual void    Resizing( Size& rSize );

    void            SetIcon( USHORT nIcon );
    USHORT          GetIcon() const { return mnIcon; }

    void            SetZLevel( BYTE nLevel );
    BYTE            GetZLevel() const;

    void            EnableSaveBackground( BOOL bSave = TRUE );
    BOOL            IsSaveBackgroundEnabled() const;

    void            ShowTitleButton( USHORT nButton, BOOL bVisible = TRUE );
    BOOL            IsTitleButtonVisible( USHORT nButton ) const;

    void            SetPin( BOOL bPin );
    BOOL            IsPined() const { return mbPined; }

    void            RollUp();
    void            RollDown();
    BOOL            IsRollUp() const { return mbRollUp; }

    void            SetRollUpOutputSizePixel( const Size& rSize ) { maRollUpOutSize = rSize; }
    Size            GetRollUpOutputSizePixel() const { return maRollUpOutSize; }

    void            SetMinOutputSizePixel( const Size& rSize );
    const Size&     GetMinOutputSizePixel() const { return maMinOutSize; }
    void            SetMaxOutputSizePixel( const Size& rSize );
    const Size&     GetMaxOutputSizePixel() const;
    Size            GetResizeOutputSizePixel() const;

    void            SetWindowState( const ByteString& rStr );
    ByteString      GetWindowState( ULONG nMask = WINDOWSTATE_MASK_ALL ) const;

    void            SetMenuBar( MenuBar* pMenuBar );
    MenuBar*        GetMenuBar() const { return mpMenuBar; }
    void            SetMenuBarMode( USHORT nMode );
    USHORT          GetMenuBarMode() const { return mnMenuBarMode; }

    TaskPaneList*   GetTaskPaneList();
    void            GetWindowStateData( WindowStateData& rData ) const;

    /**
    Returns the screen number the window is on

    The screen number is counted the same way that
    Application::GetScreenPosSizePixel,
    Application::GetWorkAreaPosSizePixel,
    Application::GetScreenName
    and of course SystemWindow::SetScreenNumber
    are counted in.

    In case the window is positioned on multiple screens the
    screen number returned will be of the screen containing the
    upper left pixel of the frame area (that is of the client
    area on system decorated windows, or the frame area of
    undecorated resp. owner decorated windows.

    @returns the screen number

    @see SystemWindow::SetScreenNumber
    */
    unsigned int    GetScreenNumber() const;
    /**
    Move the Window to a new screen. The same rules for
    positioning apply as in SystemWindow::GetScreenNumber

    The screen number is counted the same way that
    Application::GetScreenPosSizePixel,
    Application::GetWorkAreaPosSizePixel,
    Application::GetScreenName
    and of course SystemWindow::GetScreenNumber
    are counted in.

    @see GetScreenNumber
    */
    void            SetScreenNumber( unsigned int nNewScreen );
};

#endif // _SV_SYSWIN_HXX
<|endoftext|>


<commit_before>#ifdef __linux__

#include <codecvt>
#include <dlfcn.h>
#include <locale>
#include <string>
#include <sys/ioctl.h>
#include <unistd.h>

#include "linux_fsnotifier.h"

#define EVENT_BUFFER_SIZE (16 * 1024)

#define EVENT_MASK (IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_EXCL_UNLINK | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_ONLYDIR)

InotifyInstanceLimitTooLowException::InotifyInstanceLimitTooLowException()
    : InsufficientResourcesFileWatcherException("Inotify instance limit too low") {
}

InotifyWatchesLimitTooLowException::InotifyWatchesLimitTooLowException()
    : InsufficientResourcesFileWatcherException("Inotify watches limit too low") {
}

WatchPoint::WatchPoint(const u16string& path, shared_ptr<Inotify> inotify, int watchDescriptor, ino_t inode)
    : status(WatchPointStatus::LISTENING)
    , watchDescriptor(watchDescriptor)
    , inotify(inotify)
    , path(path)
    , inode(inode) {
}

CancelResult WatchPoint::cancel() {
    if (status == WatchPointStatus::CANCELLED) {
        return CancelResult::ALREADY_CANCELLED;
    }
    status = WatchPointStatus::CANCELLED;
    if (inotify_rm_watch(inotify->fd, watchDescriptor) != 0) {
        switch (errno) {
            case EINVAL:
                logToJava(LogLevel::INFO, "Couldn't stop watching %s (probably because the directory was removed)", utf16ToUtf8String(path).c_str());
                return CancelResult::NOT_CANCELLED;
                break;
            default:
                throw FileWatcherException("Couldn't stop watching", path, errno);
        }
    }
    return CancelResult::CANCELLED;
}

Inotify::Inotify()
    : fd(inotify_init1(IN_CLOEXEC | IN_NONBLOCK)) {
    if (fd == -1) {
        if (errno == EMFILE) {
            throw InotifyInstanceLimitTooLowException();
        }
        throw FileWatcherException("Couldn't register inotify handle", errno);
    }
}

Inotify::~Inotify() {
    close(fd);
}

ShutdownEvent::ShutdownEvent()
    : fd(eventfd(0, 0)) {
    if (fd == -1) {
        throw FileWatcherException("Couldn't register event source", errno);
    }
}
ShutdownEvent::~ShutdownEvent() {
    close(fd);
}

void ShutdownEvent::trigger() const {
    const uint64_t increment = 1;
    write(fd, &increment, sizeof(increment));
}

void ShutdownEvent::consume() const {
    uint64_t counter;
    ssize_t bytesRead = read(fd, &counter, sizeof(counter));
    if (bytesRead == -1) {
        throw FileWatcherException("Couldn't read from termination event notifier", errno);
    }
}

Server::Server(JNIEnv* env, jobject watcherCallback)
    : AbstractServer(env, watcherCallback)
    , inotify(new Inotify()) {
    buffer.reserve(EVENT_BUFFER_SIZE);
    jclass listClass = env->FindClass("java/util/List");
    this->listAddMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
}

void Server::initializeRunLoop() {
}

void Server::shutdownRunLoop() {
    shutdownEvent.trigger();
}

void Server::runLoop() {
    int forever = numeric_limits<int>::max();

    while (!shouldTerminate) {
        processQueues(forever);
    }

    // No need to clean up watch points, they will be cancelled
    // and closed when the Inotify destructs
}

void Server::processQueues(int timeout) {
    struct pollfd fds[2];
    fds[0].fd = shutdownEvent.fd;
    fds[1].fd = inotify->fd;
    fds[0].events = POLLIN;
    fds[1].events = POLLIN;

    int ret = poll(fds, 2, timeout);
    if (ret == -1) {
        throw FileWatcherException("Couldn't poll for events", errno);
    }

    if (IS_SET(fds[0].revents, POLLIN)) {
        shutdownEvent.consume();
        // Ignore counter, we only care about the notification itself
        shouldTerminate = true;
        return;
    }

    if (IS_SET(fds[1].revents, POLLIN)) {
        try {
            handleEvents();
        } catch (const exception& ex) {
            reportFailure(getThreadEnv(), ex);
        }
    }
}

void Server::handleEvents() {
    unsigned int available;
    ioctl(inotify->fd, FIONREAD, &available);

    while (available > 0) {
        ssize_t bytesRead = read(inotify->fd, &buffer[0], buffer.capacity());

        switch (bytesRead) {
            case -1:
                if (errno == EAGAIN) {
                    // For a non-blocking read, we receive EAGAIN here if there is nothing to read.
                    // This may happen when the inotify is already closed.
                    return;
                } else {
                    throw FileWatcherException("Couldn't read from inotify", errno);
                }
                break;
            case 0:
                throw FileWatcherException("EOF reading from inotify", errno);
                break;
            default:
                // Handle events
                unique_lock<recursive_mutex> lock(mutationMutex);
                JNIEnv* env = getThreadEnv();
                logToJava(LogLevel::FINE, "Processing %d bytes worth of events", bytesRead);
                int index = 0;
                int count = 0;
                while (index < bytesRead) {
                    const struct inotify_event* event = (struct inotify_event*) &buffer[index];
                    handleEvent(env, event);
                    index += sizeof(struct inotify_event) + event->len;
                    count++;
                }
                logToJava(LogLevel::FINE, "Processed %d events", count);
                break;
        }
        available -= bytesRead;
    }
}

void Server::handleEvent(JNIEnv* env, const inotify_event* event) {
    uint32_t mask = event->mask;
    const char* eventName = (event->len == 0)
        ? ""
        : event->name;
    logToJava(LogLevel::FINE, "Event mask: 0x%x for %s (wd = %d, cookie = 0x%x, len = %d)", mask, eventName, event->wd, event->cookie, event->len);
    if (IS_SET(mask, IN_UNMOUNT)) {
        return;
    }

    // Overflow received, handle gracefully
    if (IS_SET(mask, IN_Q_OVERFLOW)) {
        for (auto it : watchPoints) {
            auto path = it.first;
            reportOverflow(env, path);
        }
        return;
    }

    auto iWatchRoot = watchRoots.find(event->wd);
    if (iWatchRoot == watchRoots.end()) {
        auto iRecentlyUnregisteredWatchPoint = recentlyUnregisteredWatchRoots.find(event->wd);
        if (iRecentlyUnregisteredWatchPoint == recentlyUnregisteredWatchRoots.end()) {
            logToJava(LogLevel::INFO, "Received event for unknown watch descriptor %d", event->wd);
        } else {
            // We've removed this via unregisterPath() not long ago
            auto& path = iRecentlyUnregisteredWatchPoint->second;
            if (IS_SET(mask, IN_IGNORED)) {
                logToJava(LogLevel::FINE, "Finished watching recently unregistered watch point '%s' (wd = %d)",
                    utf16ToUtf8String(path).c_str(), event->wd);
                recentlyUnregisteredWatchRoots.erase(iRecentlyUnregisteredWatchPoint);
            } else {
                logToJava(LogLevel::FINE, "Ignoring incoming events for recently removed watch descriptor for '%s' (wd = %d)",
                    utf16ToUtf8String(path).c_str(), event->wd);
            }
        }
        return;
    }

    auto path = iWatchRoot->second;
    auto& watchPoint = watchPoints.at(path);

    if (IS_SET(mask, IN_IGNORED)) {
        // Finished with watch point
        logToJava(LogLevel::FINE, "Finished watching still registered '%s' (wd = %d)",
            utf16ToUtf8String(path).c_str(), event->wd);
        watchRoots.erase(event->wd);
        watchPoints.erase(path);
        return;
    }

    if (watchPoint.status != WatchPointStatus::LISTENING) {
        logToJava(LogLevel::FINE, "Ignoring incoming events for %s as watch-point is not listening (status = %d)",
            utf16ToUtf8String(path).c_str(), watchPoint.status);
        return;
    }

    if (shouldTerminate) {
        logToJava(LogLevel::FINE, "Ignoring incoming events for %s because server is terminating (status = %d)",
            utf16ToUtf8String(path).c_str(), watchPoint.status);
        return;
    }

    ChangeType type;
    const u16string name = utf8ToUtf16String(eventName);

    if (!name.empty()) {
        path.append(u"/");
        path.append(name);
    }

    if (IS_SET(mask, IN_CREATE | IN_MOVED_TO)) {
        type = ChangeType::CREATED;
    } else if (IS_SET(mask, IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM)) {
        type = ChangeType::REMOVED;
    } else if (IS_SET(mask, IN_MODIFY)) {
        type = ChangeType::MODIFIED;
    } else {
        logToJava(LogLevel::WARNING, "Unknown event 0x%x for %s", mask, utf16ToUtf8String(path).c_str());
        reportUnknownEvent(env, path);
        return;
    }

    reportChangeEvent(env, type, path);
}

void Server::registerPaths(const vector<u16string>& paths) {
    unique_lock<recursive_mutex> lock(mutationMutex);
    for (auto& path : paths) {
        registerPath(path);
    }
}

bool Server::unregisterPaths(const vector<u16string>& paths) {
    unique_lock<recursive_mutex> lock(mutationMutex);
    bool success = true;
    for (auto& path : paths) {
        success &= unregisterPath(path);
    }
    return success;
}

void Server::registerPath(const u16string& path) {
    auto it = watchPoints.find(path);
    if (it != watchPoints.end()) {
        throw FileWatcherException("Already watching path", path);
    }
    string pathNarrow = utf16ToUtf8String(path);
    struct stat st;
    if (lstat(pathNarrow.c_str(), &st) != 0) {
        throw FileWatcherException("Couldn't add watch, stat failed", path, errno);
    }

    int watchDescriptor = inotify_add_watch(inotify->fd, pathNarrow.c_str(), EVENT_MASK);
    if (watchDescriptor == -1) {
        if (errno == ENOSPC) {
            rethrowAsJavaException(getThreadEnv(), InotifyWatchesLimitTooLowException(), linuxJniConstants->inotifyWatchesLimitTooLowExceptionClass.get());
            throw JavaExceptionThrownException();
        }
        throw FileWatcherException("Couldn't add watch, inotify_add_watch failed", path, errno);
    }
    if (watchRoots.find(watchDescriptor) != watchRoots.end()) {
        throw FileWatcherException("Already watching path", path);
    }

    watchPoints.emplace(piecewise_construct,
        forward_as_tuple(path),
        forward_as_tuple(path, inotify, watchDescriptor, st.st_ino));
    watchRoots[watchDescriptor] = path;
}

bool Server::unregisterPath(const u16string& path) {
    auto it = watchPoints.find(path);
    if (it == watchPoints.end()) {
        logToJava(LogLevel::INFO, "Path is not watched: %s", utf16ToUtf8String(path).c_str());
        return false;
    }
    auto& watchPoint = it->second;
    int wd = watchPoint.watchDescriptor;
    CancelResult ret = watchPoint.cancel();
    if (ret == CancelResult::ALREADY_CANCELLED) {
        return false;
    }
    recentlyUnregisteredWatchRoots.emplace(wd, path);
    watchRoots.erase(wd);
    // We use the path instead erase(it) here because on Alpine Linux we've seen crashes happen here
    // when inside a Docker container a host-mapped directory is watched. There is no good theory as
    // of this writing why the problem occurs, but not using the iterator here fixes it.
    watchPoints.erase(path);
    return ret == CancelResult::CANCELLED;
}

void Server::stopWatchingMovedPaths(jobjectArray absolutePathsToCheck, jobject droppedPaths) {
    JNIEnv* env = getThreadEnv();
    int count = env->GetArrayLength(absolutePathsToCheck);
    for (int i = 0; i < count; i++) {
        jstring jPathToCheck = reinterpret_cast<jstring>(env->GetObjectArrayElement(absolutePathsToCheck, i));
        auto pathToCheck = javaToUtf16String(env, jPathToCheck);

        auto it = watchPoints.find(pathToCheck);
        if (it == watchPoints.end()) {
            addToList(env, droppedPaths, jPathToCheck);
            continue;
        }
        auto& watchPoint = it->second;
        if (watchPoint.status != WatchPointStatus::LISTENING) {
            addToList(env, droppedPaths, jPathToCheck);
            continue;
        }

        string pathNarrow = utf16ToUtf8String(watchPoint.path);
        struct stat st;
        if (lstat(pathNarrow.c_str(), &st) == 0 && st.st_ino == watchPoint.inode) {
            continue;
        }

        addToList(env, droppedPaths, jPathToCheck);

        watchPoint.cancel();
    }
}

void Server::addToList(JNIEnv* env, jobject jList, jstring jString) {
        env->CallBooleanMethod(jList, listAddMethod, jString);
}

JNIEXPORT jobject JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_startWatcher0(JNIEnv* env, jclass, jobject javaCallback) {
    try {
        return wrapServer(env, new Server(env, javaCallback));
    } catch (const InotifyInstanceLimitTooLowException& e) {
        rethrowAsJavaException(env, e, linuxJniConstants->inotifyInstanceLimitTooLowExceptionClass.get());
        return NULL;
    }
}

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_isGlibc0(JNIEnv*, jclass) {
    void* libcLibrary = dlopen("libc.so.6", RTLD_LAZY);
    if (!libcLibrary) {
        return false;
    }
    void* libcVerCheck = dlsym(libcLibrary, "gnu_get_libc_version");
    jboolean isValid = libcVerCheck != NULL;
    dlclose(libcLibrary);
    return isValid;
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_00024LinuxFileWatcher_stopWatchingMovedPaths0(JNIEnv* env, jobject, jobject javaServer, jobjectArray absolutePathsToCheck, jobject jDroppedPaths) {
    try {
        Server* server = (Server*) getServer(env, javaServer);
        server->stopWatchingMovedPaths(absolutePathsToCheck, jDroppedPaths);
    } catch (const exception& e) {
        rethrowAsJavaException(env, e);
    }
}

LinuxJniConstants::LinuxJniConstants(JavaVM* jvm)
    : JniSupport(jvm)
    , inotifyWatchesLimitTooLowExceptionClass(getThreadEnv(), "net/rubygrapefruit/platform/internal/jni/InotifyWatchesLimitTooLowException")
    , inotifyInstanceLimitTooLowExceptionClass(getThreadEnv(), "net/rubygrapefruit/platform/internal/jni/InotifyInstanceLimitTooLowException") {
}
#endif
<commit_msg>Revert change to parameter<commit_after>#ifdef __linux__

#include <codecvt>
#include <dlfcn.h>
#include <locale>
#include <string>
#include <sys/ioctl.h>
#include <unistd.h>

#include "linux_fsnotifier.h"

#define EVENT_BUFFER_SIZE (16 * 1024)

#define EVENT_MASK (IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_EXCL_UNLINK | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_ONLYDIR)

InotifyInstanceLimitTooLowException::InotifyInstanceLimitTooLowException()
    : InsufficientResourcesFileWatcherException("Inotify instance limit too low") {
}

InotifyWatchesLimitTooLowException::InotifyWatchesLimitTooLowException()
    : InsufficientResourcesFileWatcherException("Inotify watches limit too low") {
}

WatchPoint::WatchPoint(const u16string& path, shared_ptr<Inotify> inotify, int watchDescriptor, ino_t inode)
    : status(WatchPointStatus::LISTENING)
    , watchDescriptor(watchDescriptor)
    , inotify(inotify)
    , path(path)
    , inode(inode) {
}

CancelResult WatchPoint::cancel() {
    if (status == WatchPointStatus::CANCELLED) {
        return CancelResult::ALREADY_CANCELLED;
    }
    status = WatchPointStatus::CANCELLED;
    if (inotify_rm_watch(inotify->fd, watchDescriptor) != 0) {
        switch (errno) {
            case EINVAL:
                logToJava(LogLevel::INFO, "Couldn't stop watching %s (probably because the directory was removed)", utf16ToUtf8String(path).c_str());
                return CancelResult::NOT_CANCELLED;
                break;
            default:
                throw FileWatcherException("Couldn't stop watching", path, errno);
        }
    }
    return CancelResult::CANCELLED;
}

Inotify::Inotify()
    : fd(inotify_init1(IN_CLOEXEC | IN_NONBLOCK)) {
    if (fd == -1) {
        if (errno == EMFILE) {
            throw InotifyInstanceLimitTooLowException();
        }
        throw FileWatcherException("Couldn't register inotify handle", errno);
    }
}

Inotify::~Inotify() {
    close(fd);
}

ShutdownEvent::ShutdownEvent()
    : fd(eventfd(0, 0)) {
    if (fd == -1) {
        throw FileWatcherException("Couldn't register event source", errno);
    }
}
ShutdownEvent::~ShutdownEvent() {
    close(fd);
}

void ShutdownEvent::trigger() const {
    const uint64_t increment = 1;
    write(fd, &increment, sizeof(increment));
}

void ShutdownEvent::consume() const {
    uint64_t counter;
    ssize_t bytesRead = read(fd, &counter, sizeof(counter));
    if (bytesRead == -1) {
        throw FileWatcherException("Couldn't read from termination event notifier", errno);
    }
}

Server::Server(JNIEnv* env, jobject watcherCallback)
    : AbstractServer(env, watcherCallback)
    , inotify(new Inotify()) {
    buffer.reserve(EVENT_BUFFER_SIZE);
    jclass listClass = env->FindClass("java/util/List");
    this->listAddMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
}

void Server::initializeRunLoop() {
}

void Server::shutdownRunLoop() {
    shutdownEvent.trigger();
}

void Server::runLoop() {
    int forever = numeric_limits<int>::max();

    while (!shouldTerminate) {
        processQueues(forever);
    }

    // No need to clean up watch points, they will be cancelled
    // and closed when the Inotify destructs
}

void Server::processQueues(int timeout) {
    struct pollfd fds[2];
    fds[0].fd = shutdownEvent.fd;
    fds[1].fd = inotify->fd;
    fds[0].events = POLLIN;
    fds[1].events = POLLIN;

    int ret = poll(fds, 2, timeout);
    if (ret == -1) {
        throw FileWatcherException("Couldn't poll for events", errno);
    }

    if (IS_SET(fds[0].revents, POLLIN)) {
        shutdownEvent.consume();
        // Ignore counter, we only care about the notification itself
        shouldTerminate = true;
        return;
    }

    if (IS_SET(fds[1].revents, POLLIN)) {
        try {
            handleEvents();
        } catch (const exception& ex) {
            reportFailure(getThreadEnv(), ex);
        }
    }
}

void Server::handleEvents() {
    unsigned int available;
    ioctl(inotify->fd, FIONREAD, &available);

    while (available > 0) {
        ssize_t bytesRead = read(inotify->fd, &buffer[0], buffer.capacity());

        switch (bytesRead) {
            case -1:
                if (errno == EAGAIN) {
                    // For a non-blocking read, we receive EAGAIN here if there is nothing to read.
                    // This may happen when the inotify is already closed.
                    return;
                } else {
                    throw FileWatcherException("Couldn't read from inotify", errno);
                }
                break;
            case 0:
                throw FileWatcherException("EOF reading from inotify", errno);
                break;
            default:
                // Handle events
                unique_lock<recursive_mutex> lock(mutationMutex);
                JNIEnv* env = getThreadEnv();
                logToJava(LogLevel::FINE, "Processing %d bytes worth of events", bytesRead);
                int index = 0;
                int count = 0;
                while (index < bytesRead) {
                    const struct inotify_event* event = (struct inotify_event*) &buffer[index];
                    handleEvent(env, event);
                    index += sizeof(struct inotify_event) + event->len;
                    count++;
                }
                logToJava(LogLevel::FINE, "Processed %d events", count);
                break;
        }
        available -= bytesRead;
    }
}

void Server::handleEvent(JNIEnv* env, const inotify_event* event) {
    uint32_t mask = event->mask;
    const char* eventName = (event->len == 0)
        ? ""
        : event->name;
    logToJava(LogLevel::FINE, "Event mask: 0x%x for %s (wd = %d, cookie = 0x%x, len = %d)", mask, eventName, event->wd, event->cookie, event->len);
    if (IS_SET(mask, IN_UNMOUNT)) {
        return;
    }

    // Overflow received, handle gracefully
    if (IS_SET(mask, IN_Q_OVERFLOW)) {
        for (auto it : watchPoints) {
            auto path = it.first;
            reportOverflow(env, path);
        }
        return;
    }

    auto iWatchRoot = watchRoots.find(event->wd);
    if (iWatchRoot == watchRoots.end()) {
        auto iRecentlyUnregisteredWatchPoint = recentlyUnregisteredWatchRoots.find(event->wd);
        if (iRecentlyUnregisteredWatchPoint == recentlyUnregisteredWatchRoots.end()) {
            logToJava(LogLevel::INFO, "Received event for unknown watch descriptor %d", event->wd);
        } else {
            // We've removed this via unregisterPath() not long ago
            auto& path = iRecentlyUnregisteredWatchPoint->second;
            if (IS_SET(mask, IN_IGNORED)) {
                logToJava(LogLevel::FINE, "Finished watching recently unregistered watch point '%s' (wd = %d)",
                    utf16ToUtf8String(path).c_str(), event->wd);
                recentlyUnregisteredWatchRoots.erase(iRecentlyUnregisteredWatchPoint);
            } else {
                logToJava(LogLevel::FINE, "Ignoring incoming events for recently removed watch descriptor for '%s' (wd = %d)",
                    utf16ToUtf8String(path).c_str(), event->wd);
            }
        }
        return;
    }

    auto path = iWatchRoot->second;
    auto& watchPoint = watchPoints.at(path);

    if (IS_SET(mask, IN_IGNORED)) {
        // Finished with watch point
        logToJava(LogLevel::FINE, "Finished watching still registered '%s' (wd = %d)",
            utf16ToUtf8String(path).c_str(), event->wd);
        watchRoots.erase(event->wd);
        watchPoints.erase(path);
        return;
    }

    if (watchPoint.status != WatchPointStatus::LISTENING) {
        logToJava(LogLevel::FINE, "Ignoring incoming events for %s as watch-point is not listening (status = %d)",
            utf16ToUtf8String(path).c_str(), watchPoint.status);
        return;
    }

    if (shouldTerminate) {
        logToJava(LogLevel::FINE, "Ignoring incoming events for %s because server is terminating (status = %d)",
            utf16ToUtf8String(path).c_str(), watchPoint.status);
        return;
    }

    ChangeType type;
    const u16string name = utf8ToUtf16String(eventName);

    if (!name.empty()) {
        path.append(u"/");
        path.append(name);
    }

    if (IS_SET(mask, IN_CREATE | IN_MOVED_TO)) {
        type = ChangeType::CREATED;
    } else if (IS_SET(mask, IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM)) {
        type = ChangeType::REMOVED;
    } else if (IS_SET(mask, IN_MODIFY)) {
        type = ChangeType::MODIFIED;
    } else {
        logToJava(LogLevel::WARNING, "Unknown event 0x%x for %s", mask, utf16ToUtf8String(path).c_str());
        reportUnknownEvent(env, path);
        return;
    }

    reportChangeEvent(env, type, path);
}

void Server::registerPaths(const vector<u16string>& paths) {
    unique_lock<recursive_mutex> lock(mutationMutex);
    for (auto& path : paths) {
        registerPath(path);
    }
}

bool Server::unregisterPaths(const vector<u16string>& paths) {
    unique_lock<recursive_mutex> lock(mutationMutex);
    bool success = true;
    for (auto& path : paths) {
        success &= unregisterPath(path);
    }
    return success;
}

void Server::registerPath(const u16string& path) {
    auto it = watchPoints.find(path);
    if (it != watchPoints.end()) {
        throw FileWatcherException("Already watching path", path);
    }
    string pathNarrow = utf16ToUtf8String(path);
    struct stat st;
    if (lstat(pathNarrow.c_str(), &st) != 0) {
        throw FileWatcherException("Couldn't add watch, stat failed", path, errno);
    }

    int watchDescriptor = inotify_add_watch(inotify->fd, pathNarrow.c_str(), EVENT_MASK);
    if (watchDescriptor == -1) {
        if (errno == ENOSPC) {
            rethrowAsJavaException(getThreadEnv(), InotifyWatchesLimitTooLowException(), linuxJniConstants->inotifyWatchesLimitTooLowExceptionClass.get());
            throw JavaExceptionThrownException();
        }
        throw FileWatcherException("Couldn't add watch, inotify_add_watch failed", path, errno);
    }
    if (watchRoots.find(watchDescriptor) != watchRoots.end()) {
        throw FileWatcherException("Already watching path", path);
    }

    watchPoints.emplace(piecewise_construct,
        forward_as_tuple(path),
        forward_as_tuple(path, inotify, watchDescriptor, st.st_ino));
    watchRoots[watchDescriptor] = path;
}

bool Server::unregisterPath(const u16string& path) {
    auto it = watchPoints.find(path);
    if (it == watchPoints.end()) {
        logToJava(LogLevel::INFO, "Path is not watched: %s", utf16ToUtf8String(path).c_str());
        return false;
    }
    auto& watchPoint = it->second;
    int wd = watchPoint.watchDescriptor;
    CancelResult ret = watchPoint.cancel();
    if (ret == CancelResult::ALREADY_CANCELLED) {
        return false;
    }
    recentlyUnregisteredWatchRoots.emplace(wd, path);
    watchRoots.erase(wd);
    // We use the path instead erase(it) here because on Alpine Linux we've seen crashes happen here
    // when inside a Docker container a host-mapped directory is watched. There is no good theory as
    // of this writing why the problem occurs, but not using the iterator here fixes it.
    watchPoints.erase(path);
    return ret == CancelResult::CANCELLED;
}

void Server::stopWatchingMovedPaths(jobjectArray absolutePathsToCheck, jobject droppedPaths) {
    JNIEnv* env = getThreadEnv();
    int count = env->GetArrayLength(absolutePathsToCheck);
    for (int i = 0; i < count; i++) {
        jstring jPathToCheck = reinterpret_cast<jstring>(env->GetObjectArrayElement(absolutePathsToCheck, i));
        auto pathToCheck = javaToUtf16String(env, jPathToCheck);

        auto it = watchPoints.find(pathToCheck);
        if (it == watchPoints.end()) {
            addToList(env, droppedPaths, jPathToCheck);
            continue;
        }
        auto& watchPoint = it->second;
        if (watchPoint.status != WatchPointStatus::LISTENING) {
            addToList(env, droppedPaths, jPathToCheck);
            continue;
        }

        string pathNarrow = utf16ToUtf8String(watchPoint.path);
        struct stat st;
        if (lstat(pathNarrow.c_str(), &st) == 0 && st.st_ino == watchPoint.inode) {
            continue;
        }

        addToList(env, droppedPaths, jPathToCheck);

        watchPoint.cancel();
    }
}

void Server::addToList(JNIEnv* env, jobject jList, jstring jString) {
        env->CallBooleanMethod(jList, listAddMethod, jString);
}

JNIEXPORT jobject JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_startWatcher0(JNIEnv* env, jclass, jobject javaCallback) {
    try {
        return wrapServer(env, new Server(env, javaCallback));
    } catch (const InotifyInstanceLimitTooLowException& e) {
        rethrowAsJavaException(env, e, linuxJniConstants->inotifyInstanceLimitTooLowExceptionClass.get());
        return NULL;
    }
}

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_isGlibc0(JNIEnv*, jclass) {
    void* libcLibrary = dlopen("libc.so.6", RTLD_LAZY);
    if (!libcLibrary) {
        return false;
    }
    void* libcVerCheck = dlsym(libcLibrary, "gnu_get_libc_version");
    jboolean isValid = libcVerCheck != NULL;
    dlclose(libcLibrary);
    return isValid;
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_LinuxFileEventFunctions_00024LinuxFileWatcher_stopWatchingMovedPaths0(JNIEnv* env, jobject, jobject javaServer, jobjectArray jAbsolutePathsToCheck, jobject jDroppedPaths) {
    try {
        Server* server = (Server*) getServer(env, javaServer);
        server->stopWatchingMovedPaths(jAbsolutePathsToCheck, jDroppedPaths);
    } catch (const exception& e) {
        rethrowAsJavaException(env, e);
    }
}

LinuxJniConstants::LinuxJniConstants(JavaVM* jvm)
    : JniSupport(jvm)
    , inotifyWatchesLimitTooLowExceptionClass(getThreadEnv(), "net/rubygrapefruit/platform/internal/jni/InotifyWatchesLimitTooLowException")
    , inotifyInstanceLimitTooLowExceptionClass(getThreadEnv(), "net/rubygrapefruit/platform/internal/jni/InotifyInstanceLimitTooLowException") {
}
#endif
<|endoftext|>


<commit_before>// Copyright 2018 Global Phasing Ltd.
//
// Iterators. Currently each of them is a BidirectionalIterator.

#ifndef GEMMI_ITERBASE_HPP_
#define GEMMI_ITERBASE_HPP_
#include <iterator>  // for bidirectional_iterator_tag
#include <vector>

namespace gemmi {

// implements concept BidirectionalIterator
template <typename Policy>
struct BidirIterator : Policy {
  typedef typename Policy::value_type value_type;
  typedef std::ptrdiff_t difference_type;
  typedef value_type* pointer;
  typedef value_type& reference;
  typedef std::bidirectional_iterator_tag iterator_category;

  BidirIterator() = default;
  BidirIterator(Policy&& p) : Policy(p) {}

  BidirIterator &operator++() { Policy::increment(); return *this; }
  BidirIterator operator++(int) { BidirIterator x = *this; ++*this; return x; }
  BidirIterator &operator--() { Policy::decrement(); return *this; }
  BidirIterator operator--(int) { BidirIterator x = *this; --*this; return x; }
  bool operator==(const BidirIterator &o) const { return Policy::equal(o); }
  bool operator!=(const BidirIterator &o) const { return !Policy::equal(o); }
  reference operator*() { return Policy::dereference(); }
  pointer operator->() { return &Policy::dereference(); }
  using const_variant = BidirIterator<typename Policy::const_policy>;
  operator const_variant() const {
    return const_variant(static_cast<const Policy&>(*this));
  }
};

template<typename Value>
class StrideIterPolicy {
public:
  typedef Value value_type;
  StrideIterPolicy() : cur_(nullptr), offset_(0), stride_(0) {}
  StrideIterPolicy(Value* ptr, std::size_t offset, unsigned stride)
    : cur_(ptr), offset_(offset), stride_(stride) {}
  void increment() { cur_ += stride_; }
  void decrement() { cur_ -= stride_; }
  bool equal(const StrideIterPolicy& o) const { return cur_ == o.cur_; }
  Value& dereference() { return cur_[offset_]; }
  using const_policy = StrideIterPolicy<Value const>;
  operator const_policy() const { return const_policy(cur_, offset_, stride_); }
private:
  Value* cur_;
  unsigned offset_;
  unsigned stride_;
};
template<typename Value>
using StrideIter = BidirIterator<StrideIterPolicy<Value>>;

template<typename Redirect, typename Value>
class IndirectIterPolicy {
public:
  typedef Value value_type;
  IndirectIterPolicy() : redir_(nullptr) {}
  IndirectIterPolicy(Redirect* redir, std::vector<int>::const_iterator cur)
    : redir_(redir), cur_(cur) {}
  void increment() { ++cur_; }
  void decrement() { --cur_; }
  bool equal(const IndirectIterPolicy& o) const { return cur_ == o.cur_; }
  Value& dereference() { return redir_->value_at(*cur_); }
  using const_policy = IndirectIterPolicy<Redirect const, Value const>;
  operator const_policy() const { return const_policy(redir_, cur_); }
  // TODO: what should be done with absent optional tags (*cur_ < 0)?
private:
  Redirect* redir_;
  std::vector<int>::const_iterator cur_; // points into positions
};
template<typename Redirect, typename Value>
using IndirectIter = BidirIterator<IndirectIterPolicy<Redirect, Value>>;

template<typename Vector, typename Value>
class UniqIterPolicy {
public:
  typedef Value value_type;
  UniqIterPolicy() : vec_(nullptr), pos_(0) {}
  UniqIterPolicy(Vector* vec, std::size_t pos) : vec_(vec), pos_(pos) {}
  void increment() {
    std::size_t old = pos_++;
    while (pos_ != vec_->size() && (*vec_)[old].same_group((*vec_)[pos_]))
        ++pos_;
  }
  void decrement() {
    --pos_;
    while (pos_ != 0 && (*vec_)[pos_ - 1].same_group((*vec_)[pos_]))
        --pos_;
  }
  bool equal(const UniqIterPolicy& o) const { return pos_ == o.pos_; }
  Value& dereference() { return (*vec_)[pos_]; }
  using const_policy = UniqIterPolicy<Vector const, Value const>;
  operator const_policy() const { return const_policy(vec_, pos_); }
private:
  Vector* vec_;
  std::size_t pos_;
};
template<typename Vector, typename Value>
using UniqIter = BidirIterator<UniqIterPolicy<Vector, Value>>;

template<typename Value, typename Vector=std::vector<Value>>
struct UniqProxy {
  Vector& vec;
  using iterator = UniqIter<Vector, Value>;
  iterator begin() { return {{&vec, 0}}; }
  iterator end() { return {{&vec, vec.size()}}; }
};
template<typename Value, typename Vector=std::vector<Value>>
struct ConstUniqProxy {
  const Vector& vec;
  using iterator = UniqIter<const Vector, const Value>;
  iterator begin() const { return {{&vec, 0}}; }
  iterator end() const { return {{&vec, vec.size()}}; }
};

template<typename Filter, typename Vector, typename Value>
class FilterIterPolicy {
public:
  typedef Value value_type;
  FilterIterPolicy() : vec_(nullptr), pos_(0) {}
  FilterIterPolicy(const Filter* filter, Vector* vec, std::size_t pos)
      : filter_(filter), vec_(vec), pos_(pos) {
    while (pos_ != vec_->size() && !matches(pos_)) ++pos_;
  }
  bool matches(std::size_t p) const { return filter_->matches((*vec_)[p]); }
  void increment() { while (pos_ != vec_->size() && !matches(++pos_)) {} }
  void decrement() { while (pos_ != 0 && !matches(--pos_)) {} }
  bool equal(const FilterIterPolicy& o) const { return pos_ == o.pos_; }
  Value& dereference() { return (*vec_)[pos_]; }
  using const_policy = FilterIterPolicy<Filter, Vector const, Value const>;
  operator const_policy() const { return const_policy(vec_, pos_); }
private:
  const Filter* filter_;
  Vector* vec_;
  std::size_t pos_;
};
template<typename Filter, typename Vector, typename Value>
using FilterIter = BidirIterator<FilterIterPolicy<Filter, Vector, Value>>;

template<typename Filter, typename Value>
struct FilterProxy {
  const Filter& filter;
  std::vector<Value>& vec;
  using iterator = FilterIter<Filter, std::vector<Value>, Value>;
  iterator begin() { return {{&filter, &vec, 0}}; }
  iterator end() { return {{&filter, &vec, vec.size()}}; }
};

template<typename Filter, typename Value>
struct ConstFilterProxy {
  const Filter& filter;
  const std::vector<Value>& vec;
  using iterator = FilterIter<Filter, const std::vector<Value>, const Value>;
  iterator begin() const { return {{&filter, &vec, 0}}; }
  iterator end() const { return {{&filter, &vec, vec.size()}}; }
};

} // namespace gemmi
#endif
// vim:sw=2:ts=2:et
<commit_msg>make Iterator::value_type non-const<commit_after>// Copyright 2018 Global Phasing Ltd.
//
// Iterators. Currently each of them is a BidirectionalIterator.

#ifndef GEMMI_ITERBASE_HPP_
#define GEMMI_ITERBASE_HPP_
#include <iterator>     // for bidirectional_iterator_tag
#include <type_traits>  // for remove_cv
#include <vector>

namespace gemmi {

// implements concept BidirectionalIterator
template <typename Policy>
struct BidirIterator : Policy {
  typedef typename std::remove_cv<typename Policy::value_type>::type value_type;
  typedef std::ptrdiff_t difference_type;
  typedef typename Policy::value_type* pointer;
  typedef typename Policy::value_type& reference;
  typedef std::bidirectional_iterator_tag iterator_category;

  BidirIterator() = default;
  BidirIterator(Policy&& p) : Policy(p) {}

  BidirIterator &operator++() { Policy::increment(); return *this; }
  BidirIterator operator++(int) { BidirIterator x = *this; ++*this; return x; }
  BidirIterator &operator--() { Policy::decrement(); return *this; }
  BidirIterator operator--(int) { BidirIterator x = *this; --*this; return x; }
  bool operator==(const BidirIterator &o) const { return Policy::equal(o); }
  bool operator!=(const BidirIterator &o) const { return !Policy::equal(o); }
  reference operator*() { return Policy::dereference(); }
  pointer operator->() { return &Policy::dereference(); }
  using const_variant = BidirIterator<typename Policy::const_policy>;
  operator const_variant() const {
    return const_variant(static_cast<const Policy&>(*this));
  }
};

template<typename Value>
class StrideIterPolicy {
public:
  typedef Value value_type;
  StrideIterPolicy() : cur_(nullptr), offset_(0), stride_(0) {}
  StrideIterPolicy(Value* ptr, std::size_t offset, unsigned stride)
    : cur_(ptr), offset_(offset), stride_(stride) {}
  void increment() { cur_ += stride_; }
  void decrement() { cur_ -= stride_; }
  bool equal(const StrideIterPolicy& o) const { return cur_ == o.cur_; }
  Value& dereference() { return cur_[offset_]; }
  using const_policy = StrideIterPolicy<Value const>;
  operator const_policy() const { return const_policy(cur_, offset_, stride_); }
private:
  Value* cur_;
  unsigned offset_;
  unsigned stride_;
};
template<typename Value>
using StrideIter = BidirIterator<StrideIterPolicy<Value>>;

template<typename Redirect, typename Value>
class IndirectIterPolicy {
public:
  typedef Value value_type;
  IndirectIterPolicy() : redir_(nullptr) {}
  IndirectIterPolicy(Redirect* redir, std::vector<int>::const_iterator cur)
    : redir_(redir), cur_(cur) {}
  void increment() { ++cur_; }
  void decrement() { --cur_; }
  bool equal(const IndirectIterPolicy& o) const { return cur_ == o.cur_; }
  Value& dereference() { return redir_->value_at(*cur_); }
  using const_policy = IndirectIterPolicy<Redirect const, Value const>;
  operator const_policy() const { return const_policy(redir_, cur_); }
  // TODO: what should be done with absent optional tags (*cur_ < 0)?
private:
  Redirect* redir_;
  std::vector<int>::const_iterator cur_; // points into positions
};
template<typename Redirect, typename Value>
using IndirectIter = BidirIterator<IndirectIterPolicy<Redirect, Value>>;

template<typename Vector, typename Value>
class UniqIterPolicy {
public:
  typedef Value value_type;
  UniqIterPolicy() : vec_(nullptr), pos_(0) {}
  UniqIterPolicy(Vector* vec, std::size_t pos) : vec_(vec), pos_(pos) {}
  void increment() {
    std::size_t old = pos_++;
    while (pos_ != vec_->size() && (*vec_)[old].same_group((*vec_)[pos_]))
        ++pos_;
  }
  void decrement() {
    --pos_;
    while (pos_ != 0 && (*vec_)[pos_ - 1].same_group((*vec_)[pos_]))
        --pos_;
  }
  bool equal(const UniqIterPolicy& o) const { return pos_ == o.pos_; }
  Value& dereference() { return (*vec_)[pos_]; }
  using const_policy = UniqIterPolicy<Vector const, Value const>;
  operator const_policy() const { return const_policy(vec_, pos_); }
private:
  Vector* vec_;
  std::size_t pos_;
};
template<typename Vector, typename Value>
using UniqIter = BidirIterator<UniqIterPolicy<Vector, Value>>;

template<typename Value, typename Vector=std::vector<Value>>
struct UniqProxy {
  Vector& vec;
  using iterator = UniqIter<Vector, Value>;
  iterator begin() { return {{&vec, 0}}; }
  iterator end() { return {{&vec, vec.size()}}; }
};
template<typename Value, typename Vector=std::vector<Value>>
struct ConstUniqProxy {
  const Vector& vec;
  using iterator = UniqIter<const Vector, const Value>;
  iterator begin() const { return {{&vec, 0}}; }
  iterator end() const { return {{&vec, vec.size()}}; }
};

template<typename Filter, typename Vector, typename Value>
class FilterIterPolicy {
public:
  typedef Value value_type;
  FilterIterPolicy() : vec_(nullptr), pos_(0) {}
  FilterIterPolicy(const Filter* filter, Vector* vec, std::size_t pos)
      : filter_(filter), vec_(vec), pos_(pos) {
    while (pos_ != vec_->size() && !matches(pos_)) ++pos_;
  }
  bool matches(std::size_t p) const { return filter_->matches((*vec_)[p]); }
  void increment() { while (pos_ != vec_->size() && !matches(++pos_)) {} }
  void decrement() { while (pos_ != 0 && !matches(--pos_)) {} }
  bool equal(const FilterIterPolicy& o) const { return pos_ == o.pos_; }
  Value& dereference() { return (*vec_)[pos_]; }
  using const_policy = FilterIterPolicy<Filter, Vector const, Value const>;
  operator const_policy() const { return const_policy(vec_, pos_); }
private:
  const Filter* filter_;
  Vector* vec_;
  std::size_t pos_;
};
template<typename Filter, typename Vector, typename Value>
using FilterIter = BidirIterator<FilterIterPolicy<Filter, Vector, Value>>;

template<typename Filter, typename Value>
struct FilterProxy {
  const Filter& filter;
  std::vector<Value>& vec;
  using iterator = FilterIter<Filter, std::vector<Value>, Value>;
  iterator begin() { return {{&filter, &vec, 0}}; }
  iterator end() { return {{&filter, &vec, vec.size()}}; }
};

template<typename Filter, typename Value>
struct ConstFilterProxy {
  const Filter& filter;
  const std::vector<Value>& vec;
  using iterator = FilterIter<Filter, const std::vector<Value>, const Value>;
  iterator begin() const { return {{&filter, &vec, 0}}; }
  iterator end() const { return {{&filter, &vec, vec.size()}}; }
};

} // namespace gemmi
#endif
// vim:sw=2:ts=2:et
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#ifndef INCLUDED_GDALUTILS_HPP
#define INCLUDED_GDALUTILS_HPP

#include <pdal/pdal_internal.hpp>

#include <pdal/Log.hpp>

#include <sstream>

#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <cpl_port.h>
#include "gdal.h"
#include <cpl_vsi.h>

namespace pdal
{
namespace gdal
{

class PDAL_DLL Debug
{
public:

    Debug(bool isDebug, pdal::LogPtr log);
    ~Debug();

    static void CPL_STDCALL trampoline(::CPLErr code, int num, char const* msg)
    {
#if ((GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR >= 9) || (GDAL_VERSION_MAJOR > 1))
        static_cast<Debug*>(CPLGetErrorHandlerUserData())->m_gdal_callback(code, num, msg);
#else
        if (code == CE_Failure || code == CE_Fatal)
        {
            std::ostringstream oss;
            oss <<"GDAL Failure number=" << num << ": " << msg;
            throw gdal_error(oss.str());
        }
        else if (code == CE_Debug)
        {
            std::clog << " (no log control stdlog) GDAL debug pdal::gdal::Debug: " << msg << std::endl;
        }
        else
        {
            return;
        }
#endif
    }

    void log(::CPLErr code, int num, char const* msg);
    void error(::CPLErr code, int num, char const* msg);

private:
    boost::function<void(CPLErr, int, char const*)> m_gdal_callback;
    bool m_isDebug;
    pdal::LogPtr m_log;
};

class PDAL_DLL VSILFileBuffer
{
public:
    typedef boost::iostreams::seekable_device_tag category;
    typedef char char_type;

    VSILFileBuffer(VSILFILE* fp);

    std::streamsize read(char* s, std::streamsize n);
    std::streamsize write(const char* s, std::streamsize n);
    std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way);

private:
    VSILFILE* m_fp;
};

}
} // namespace pdal::gdal

#endif
<commit_msg>try to trap conditions where Debug* is no longer available<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#ifndef INCLUDED_GDALUTILS_HPP
#define INCLUDED_GDALUTILS_HPP

#include <pdal/pdal_internal.hpp>

#include <pdal/Log.hpp>

#include <sstream>

#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <cpl_port.h>
#include "gdal.h"
#include <cpl_vsi.h>

namespace pdal
{
namespace gdal
{

class PDAL_DLL Debug
{
public:

    Debug(bool isDebug, pdal::LogPtr log);
    ~Debug();

    static void CPL_STDCALL trampoline(::CPLErr code, int num, char const* msg)
    {
#if ((GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR >= 9) || (GDAL_VERSION_MAJOR > 1))

        Debug* debug = static_cast<Debug*>(CPLGetErrorHandlerUserData());
        if (!debug)
            return;

        debug->m_gdal_callback(code, num, msg);

        if (!debug->m_log->get()) return;
#else
        if (code == CE_Failure || code == CE_Fatal)
        {
            std::ostringstream oss;
            oss <<"GDAL Failure number=" << num << ": " << msg;
            throw gdal_error(oss.str());
        }
        else if (code == CE_Debug)
        {
            std::clog << " (no log control stdlog) GDAL debug pdal::gdal::Debug: " << msg << std::endl;
        }
        else
        {
            return;
        }
#endif
    }

    void log(::CPLErr code, int num, char const* msg);
    void error(::CPLErr code, int num, char const* msg);

private:
    boost::function<void(CPLErr, int, char const*)> m_gdal_callback;
    bool m_isDebug;
    pdal::LogPtr m_log;
};

class PDAL_DLL VSILFileBuffer
{
public:
    typedef boost::iostreams::seekable_device_tag category;
    typedef char char_type;

    VSILFileBuffer(VSILFILE* fp);

    std::streamsize read(char* s, std::streamsize n);
    std::streamsize write(const char* s, std::streamsize n);
    std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way);

private:
    VSILFILE* m_fp;
};

}
} // namespace pdal::gdal

#endif
<|endoftext|>


<commit_before>#pragma once

#include "rapidcheck/Show.h"

namespace rc {

template <typename T>
class Seq<T>::ISeqImpl {
public:
  virtual Maybe<T> next() = 0;
  virtual std::unique_ptr<ISeqImpl> copy() const = 0;
  virtual ~ISeqImpl() = default;
};

template <typename T>
template <typename Impl>
class Seq<T>::SeqImpl : public Seq<T>::ISeqImpl {
public:
  template <typename... Args>
  SeqImpl(Args &&... args)
      : m_impl(std::forward<Args>(args)...) {}

  Maybe<T> next() override { return m_impl(); }

  std::unique_ptr<ISeqImpl> copy() const override {
    return std::unique_ptr<ISeqImpl>(new SeqImpl(*this));
  }

private:
  Impl m_impl;
};

template <typename T>
Seq<T>::Seq(NothingType) noexcept {}

template <typename T>
template <typename Impl, typename>
Seq<T>::Seq(Impl &&impl)
    : m_impl(new SeqImpl<Decay<Impl>>(std::forward<Impl>(impl))) {}

template <typename T>
Maybe<T> Seq<T>::next() noexcept {
  try {
    return m_impl ? m_impl->next() : Nothing;
  } catch (...) {
    m_impl.reset();
    return Nothing;
  }
}

template <typename T>
Seq<T>::Seq(const Seq &other)
    : m_impl(other.m_impl ? other.m_impl->copy() : nullptr) {}

template <typename T>
Seq<T> &Seq<T>::operator=(const Seq &rhs) {
  m_impl = rhs.m_impl->copy();
  return *this;
}

template <typename Impl, typename... Args>
Seq<typename std::result_of<Impl()>::type::ValueType> makeSeq(Args &&... args) {
  using SeqT = Seq<typename std::result_of<Impl()>::type::ValueType>;
  using ImplT = typename SeqT::template SeqImpl<Impl>;

  SeqT seq;
  seq.m_impl.reset(new ImplT(std::forward<Args>(args)...));
  return seq;
}

template <typename T>
bool operator==(Seq<T> lhs, Seq<T> rhs) {
  while (true) {
    Maybe<T> a(lhs.next());
    Maybe<T> b(rhs.next());
    if (a != b) {
      return false;
    }

    if (!a && !b) {
      return true;
    }
  }
}

template <typename T>
bool operator!=(Seq<T> lhs, Seq<T> rhs) {
  return !(std::move(lhs) == std::move(rhs));
}

template <typename T>
std::ostream &operator<<(std::ostream &os, Seq<T> seq) {
  os << "[";
  int n = 1;
  auto first = seq.next();
  if (first) {
    show(*first, os);
    while (true) {
      const auto value = seq.next();
      if (!value) {
        break;
      }

      os << ", ";
      // Don't print infinite sequences...
      if (n++ >= 1000) {
        os << "...";
        break;
      }

      show(*value, os);
    }
  }
  os << "]";
  return os;
}

} // namespace rc
<commit_msg>Apply Visual Studio 15.5 work-around<commit_after>#pragma once

#include "rapidcheck/Show.h"

namespace rc {

template <typename T>
class Seq<T>::ISeqImpl {
public:
  virtual Maybe<T> next() = 0;
  virtual std::unique_ptr<ISeqImpl> copy() const = 0;
  virtual ~ISeqImpl() = default;
};

template <typename T>
template <typename Impl>
class Seq<T>::SeqImpl : public Seq<T>::ISeqImpl {
public:
  template <typename... Args>
  SeqImpl(Args &&... args)
      : m_impl(std::forward<Args>(args)...) {}

  Maybe<T> next() override { return m_impl(); }

  std::unique_ptr<ISeqImpl> copy() const override {
    return std::unique_ptr<ISeqImpl>(new SeqImpl(*this));
  }

private:
  Impl m_impl;
};

template <typename T>
Seq<T>::Seq(NothingType) noexcept {}

template <typename T>
template <typename Impl, typename>
Seq<T>::Seq(Impl &&impl)
    : m_impl(new SeqImpl<Decay<Impl>>(std::forward<Impl>(impl))) {}

template <typename T>
Maybe<T> Seq<T>::next() noexcept {
  try {
    return m_impl ? m_impl->next() : Nothing;
  } catch (...) {
    m_impl.reset();
    return Nothing;
  }
}

template <typename T>
Seq<T>::Seq(const Seq &other)
    : m_impl(other.m_impl ? other.m_impl->copy() : nullptr) {}

template <typename T>
Seq<T> &Seq<T>::operator=(const Seq &rhs) {
  m_impl = rhs.m_impl->copy();
  return *this;
}

template <typename Impl, typename... Args>
Seq<typename std::result_of<Impl(void)>::type::ValueType> makeSeq(Args &&... args) {
  using SeqT = Seq<typename std::result_of<Impl(void)>::type::ValueType>;
  using ImplT = typename SeqT::template SeqImpl<Impl>;

  SeqT seq;
  seq.m_impl.reset(new ImplT(std::forward<Args>(args)...));
  return seq;
}

template <typename T>
bool operator==(Seq<T> lhs, Seq<T> rhs) {
  while (true) {
    Maybe<T> a(lhs.next());
    Maybe<T> b(rhs.next());
    if (a != b) {
      return false;
    }

    if (!a && !b) {
      return true;
    }
  }
}

template <typename T>
bool operator!=(Seq<T> lhs, Seq<T> rhs) {
  return !(std::move(lhs) == std::move(rhs));
}

template <typename T>
std::ostream &operator<<(std::ostream &os, Seq<T> seq) {
  os << "[";
  int n = 1;
  auto first = seq.next();
  if (first) {
    show(*first, os);
    while (true) {
      const auto value = seq.next();
      if (!value) {
        break;
      }

      os << ", ";
      // Don't print infinite sequences...
      if (n++ >= 1000) {
        os << "...";
        break;
      }

      show(*value, os);
    }
  }
  os << "]";
  return os;
}

} // namespace rc
<|endoftext|>