<commit_before>/*********************************************************************
  libvideogfx/graphics/draw/scale.hh

  purpose:
    Functions for extending borders, change format of bitmaps...

  notes:

  to do:

  author(s):
   - Dirk Farin, dirk.farin@gmx.de

  modifications:
    04/Jul/2000 - Dirk Farin - bitmap format conversion and helpers
 ********************************************************************************
    LibVideoGfx - video processing library
    Copyright (C) 2002  Dirk Farin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    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 LIBVIDEOGFX_GRAPHICS_DRAW_SCALE_HH
#define LIBVIDEOGFX_GRAPHICS_DRAW_SCALE_HH

#include <libvideogfx/graphics/datatypes/bitmap.hh>
#include <libvideogfx/graphics/datatypes/image.hh>

namespace videogfx {

  /* TODO: we seem to have a subpixel image shift in the Scale_NN and Scale_Bilinear functions.
     Check that this is correct... Same probably for the BinomialDownsample() function.
  */

  template <class Pel> void Scale_NN      (Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight);
  template <class Pel> void Scale_Bilinear(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight);

  template <class Pel> void DoubleSize_Dup  (Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void DoubleSize_Dup_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void DoubleSize_Dup_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src);

  template <class Pel> void HalfSize_Avg  (Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void HalfSize_Avg_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void HalfSize_Avg_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src);

  template <class Pel> void ScaleDownOctaves_Avg(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int nOctaves);

  /* Copy scaled version of region into another bitmap.
   */
  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src, int srcx0,int srcy0, int sw,int sh);
  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src, int srcx0,int srcy0, int sw,int sh);

  // Same as above, complete image/bitmap is inserted.
  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src);
  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src);

  // ------------------------------- implementation -----------------------------------

  template <class Pel> void DoubleSize_Dup  (Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w*2,h*2);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y*2  ][x*2  ] =
	    dp[y*2  ][x*2+1] =
	    dp[y*2+1][x*2  ] =
	    dp[y*2+1][x*2+1] = sp[y][x];
	}
  }

  template <class Pel> void DoubleSize_Dup_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w*2,h);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y][x*2  ] =
	    dp[y][x*2+1] = sp[y][x];
	}
  }

  template <class Pel> void DoubleSize_Dup_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w,h*2);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y*2  ][x] =
	    dp[y*2+1][x] = sp[y][x];
	}
  }

  template <class Pel> void HalfSize_Avg  (Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int newh = (h+1)/2;
    const int neww = (w+1)/2;

    dst.Create(neww,newh);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h/2;y++)
      for (int x=0;x<w/2;x++)
	{
	  dp[y][x] = (sp[2*y  ][2*x] + sp[2*y  ][2*x+1] +
		      sp[2*y+1][2*x] + sp[2*y+1][2*x+1]) / 4;
	}

    if (neww*2 != w)
      {
	assert(w==neww*2-1);
	for (int y=0;y<newh;y++)
	  dp[y][neww-1] = sp[2*y][w-1];
      }

    if (newh*2 != h)
      {
	assert(h==newh*2-1);
	for (int x=0;x<neww;x++)
	  dp[newh-1][x] = sp[h-1][2*x];
      }
  }

  template <class Pel> void HalfSize_Avg_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int neww = (w+1)/2;

    dst.Create(neww,h);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w/2;x++)
	{
	  dp[y][x] = (sp[y][2*x] + sp[y][2*x+1]) / 2;
	}

    if (neww*2 != w)
      {
	assert(w==neww*2-1);
	for (int y=0;y<h;y++)
	  dp[y][neww-1] = sp[y][w-1];
      }
  }

  template <class Pel> void HalfSize_Avg_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int newh = (h+1)/2;

    dst.Create(w,newh);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h/2;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y][x] = (sp[2*y  ][x] + sp[2*y+1][x]) / 2;
	}

    if (newh*2 != h)
      {
	assert(h==newh*2-1);
	for (int x=0;x<w;x++)
	  dp[newh-1][x] = sp[h-1][x];
      }
  }

  template <class Pel> void ScaleDownOctaves_Avg(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int nOctaves)
  {
    if (nOctaves==0)
      { dst = src.Clone(); }
    else
      {
	HalfSize_Avg(dst,src);
	nOctaves--;

	while (nOctaves>0)
	  {
	    Bitmap<Pel> tmp = dst;
	    dst.Release();

	    HalfSize_Avg(dst,tmp);
	    nOctaves--;
	  }
      }
  }

  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src, int srcx0,int srcy0, int sw,int sh)
  {
    if (src.IsEmpty()) return;

    const Pel*const* sp = src.AskFrame();
    /* */ Pel*const* dp = dst.AskFrame();

    int w = dst.AskWidth();
    int h = dst.AskHeight();
    int srcw = src.AskWidth();
    int srch = src.AskHeight();

    for (int y=std::max(0,-dsty0);y<dh;y++)
      {
	int srcy = srcy0 + y*sh/dh;
	if (srcy<0) continue;
	if (srcy>=srch) break;
	if (dsty0+y>=h) break;

	for (int x=std::max(0,-dstx0);x<dw;x++)
	  {
	    int srcx = srcx0+x*sw/dw;
	    if (srcx<0) continue;
	    if (srcx>srcw) break;
	    if (dstx0+x>=w) break;

	    dp[dsty0+y][dstx0+x] = sp[srcy][srcx];
	  }
      }
  }

  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src, int srcx0,int srcy0, int sw,int sh)
  {
    ImageParam param = src.AskParam();

    for (int i=0;i<4;i++)
      {
	BitmapChannel b = (BitmapChannel)i;
	CopyScaled(dst.AskBitmap(b),
		   param.ChromaScaleH(b,dstx0),param.ChromaScaleV(b,dsty0),
		   param.ChromaScaleH(b,dw), param.ChromaScaleV(b,dh),

		   src.AskBitmap(b),
		   param.ChromaScaleH(b,srcx0),param.ChromaScaleV(b,srcy0),
		   param.ChromaScaleH(b,sw), param.ChromaScaleV(b,sh));
      }
  }

  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src)
  {
    CopyScaled(dst,dstx0,dsty0,dw,dh, src,
	       -src.AskXOffset(),-src.AskYOffset(),src.AskWidth()-src.AskXOffset(),src.AskHeight()-src.AskYOffset());
  }

  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src)
  {
    CopyScaled(dst,dstx0,dsty0,dw,dh, src,
	       -src.AskXOffset(),-src.AskYOffset(),src.AskWidth()-src.AskXOffset(),src.AskHeight()-src.AskYOffset());
  }

  inline void FillScaleMapping(int* mapping, unsigned char* factor, int w, int newW)
  {
    for (int x=0;x<newW;x++)
      {
	if (factor==NULL)
	  { mapping[x] = (w-1)*x/(newW -1); }
	else
	  {
	    int pos = 256*(w-1)*x/(newW -1);
	    mapping[x] = pos/256;
	    factor[x]  = pos%256;
	  }
      }
  }

  template <class Pel> void Scale_NN(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight)
  {
    int* mapX = new int[newWidth];
    int* mapY = new int[newHeight];

    int w = src.getWidth();
    int h = src.getHeight();

    FillScaleMapping(mapX, NULL, w, newWidth);
    FillScaleMapping(mapY, NULL, h, newHeight);

    dst.Create(newWidth, newHeight);

    const Pel*const* in  = src.AskFrame();
    /* */ Pel*const* out = dst.AskFrame();

    for (int y=0;y<newHeight;y++)
      {
	const int iy = mapY[y];

	for (int x=0;x<newWidth;x++)
	  {
	    dst[y][x] = in[iy][ mapX[x] ];
	  }
      }

    delete[] mapX;
    delete[] mapY;
  }

  template <class Pel> void Scale_Bilinear(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight)
  {
    int* mapX = new int[newWidth];
    int* mapY = new int[newHeight];
    unsigned char* factorX = new unsigned char[newWidth];
    unsigned char* factorY = new unsigned char[newHeight];

    int w = src.getWidth();
    int h = src.getHeight();

    // we set the maximum value to w-1 so that we can always access the pixel at mapX[x]+1
    FillScaleMapping(mapX, factorX, w-1, newWidth);
    FillScaleMapping(mapY, factorY, h-1, newHeight);

    dst.Create(newWidth, newHeight);

    const Pel*const* in  = src.AskFrame();
    /* */ Pel*const* out = dst.AskFrame();

    for (int y=0;y<newHeight;y++)
      {
	const int iy = mapY[y];
	const int factor = factorY[y];

	for (int x=0;x<newWidth;x++)
	  {
	    int ix = mapX[x];

	    Pel A = in[iy][ix];
	    Pel B = in[iy][ix+1];
	    Pel C = in[iy+1][ix];
	    Pel D = in[iy+1][ix+1];

	    Pel left  = (A*256 + (C-A)*factor) / 256;
	    Pel right = (B*256 + (D-B)*factor) / 256;

	    dst[y][x] = (left*256 + (right-left)*factorX[x]) / 256;
	  }
      }

    delete[] mapX;
    delete[] mapY;
    delete[] factorX;
    delete[] factorY;
  }

}

#endif
<commit_msg>corrected sub-pixel shift in scaling routines<commit_after>/*********************************************************************
  libvideogfx/graphics/draw/scale.hh

  purpose:
    Functions for extending borders, change format of bitmaps...

  notes:

  to do:

  author(s):
   - Dirk Farin, dirk.farin@gmx.de

  modifications:
    04/Jul/2000 - Dirk Farin - bitmap format conversion and helpers
 ********************************************************************************
    LibVideoGfx - video processing library
    Copyright (C) 2002  Dirk Farin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    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 LIBVIDEOGFX_GRAPHICS_DRAW_SCALE_HH
#define LIBVIDEOGFX_GRAPHICS_DRAW_SCALE_HH

#include <libvideogfx/graphics/datatypes/bitmap.hh>
#include <libvideogfx/graphics/datatypes/image.hh>

namespace videogfx {

  template <class Pel> void Scale_NN      (Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight);
  template <class Pel> void Scale_Bilinear(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight);

  template <class Pel> void DoubleSize_Dup  (Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void DoubleSize_Dup_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void DoubleSize_Dup_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src);

  template <class Pel> void HalfSize_Avg  (Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void HalfSize_Avg_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src);
  template <class Pel> void HalfSize_Avg_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src);

  template <class Pel> void ScaleDownOctaves_Avg(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int nOctaves);

  /* Copy scaled version of region into another bitmap.
   */
  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src, int srcx0,int srcy0, int sw,int sh);
  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src, int srcx0,int srcy0, int sw,int sh);

  // Same as above, complete image/bitmap is inserted.
  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src);
  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src);

  // ------------------------------- implementation -----------------------------------

  template <class Pel> void DoubleSize_Dup  (Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w*2,h*2);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y*2  ][x*2  ] =
	    dp[y*2  ][x*2+1] =
	    dp[y*2+1][x*2  ] =
	    dp[y*2+1][x*2+1] = sp[y][x];
	}
  }

  template <class Pel> void DoubleSize_Dup_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w*2,h);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y][x*2  ] =
	    dp[y][x*2+1] = sp[y][x];
	}
  }

  template <class Pel> void DoubleSize_Dup_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    dst.Create(w,h*2);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y*2  ][x] =
	    dp[y*2+1][x] = sp[y][x];
	}
  }

  template <class Pel> void HalfSize_Avg  (Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int newh = (h+1)/2;
    const int neww = (w+1)/2;

    dst.Create(neww,newh);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h/2;y++)
      for (int x=0;x<w/2;x++)
	{
	  dp[y][x] = (sp[2*y  ][2*x] + sp[2*y  ][2*x+1] +
		      sp[2*y+1][2*x] + sp[2*y+1][2*x+1]) / 4;
	}

    if (neww*2 != w)
      {
	assert(w==neww*2-1);
	for (int y=0;y<newh;y++)
	  dp[y][neww-1] = sp[2*y][w-1];
      }

    if (newh*2 != h)
      {
	assert(h==newh*2-1);
	for (int x=0;x<neww;x++)
	  dp[newh-1][x] = sp[h-1][2*x];
      }
  }

  template <class Pel> void HalfSize_Avg_H(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int neww = (w+1)/2;

    dst.Create(neww,h);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h;y++)
      for (int x=0;x<w/2;x++)
	{
	  dp[y][x] = (sp[y][2*x] + sp[y][2*x+1]) / 2;
	}

    if (neww*2 != w)
      {
	assert(w==neww*2-1);
	for (int y=0;y<h;y++)
	  dp[y][neww-1] = sp[y][w-1];
      }
  }

  template <class Pel> void HalfSize_Avg_V(Bitmap<Pel>& dst,const Bitmap<Pel>& src)
  {
    assert(&dst != &src);

    const int w = src.AskWidth();
    const int h = src.AskHeight();

    const int newh = (h+1)/2;

    dst.Create(w,newh);

    const Pel*const* sp = src.AskFrame();
    Pel*const* dp = dst.AskFrame();

    for (int y=0;y<h/2;y++)
      for (int x=0;x<w;x++)
	{
	  dp[y][x] = (sp[2*y  ][x] + sp[2*y+1][x]) / 2;
	}

    if (newh*2 != h)
      {
	assert(h==newh*2-1);
	for (int x=0;x<w;x++)
	  dp[newh-1][x] = sp[h-1][x];
      }
  }

  template <class Pel> void ScaleDownOctaves_Avg(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int nOctaves)
  {
    if (nOctaves==0)
      { dst = src.Clone(); }
    else
      {
	HalfSize_Avg(dst,src);
	nOctaves--;

	while (nOctaves>0)
	  {
	    Bitmap<Pel> tmp = dst;
	    dst.Release();

	    HalfSize_Avg(dst,tmp);
	    nOctaves--;
	  }
      }
  }

  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src, int srcx0,int srcy0, int sw,int sh)
  {
    if (src.IsEmpty()) return;

    const Pel*const* sp = src.AskFrame();
    /* */ Pel*const* dp = dst.AskFrame();

    int w = dst.AskWidth();
    int h = dst.AskHeight();
    int srcw = src.AskWidth();
    int srch = src.AskHeight();

    for (int y=std::max(0,-dsty0);y<dh;y++)
      {
	int srcy = srcy0 + y*sh/dh;
	if (srcy<0) continue;
	if (srcy>=srch) break;
	if (dsty0+y>=h) break;

	for (int x=std::max(0,-dstx0);x<dw;x++)
	  {
	    int srcx = srcx0+x*sw/dw;
	    if (srcx<0) continue;
	    if (srcx>srcw) break;
	    if (dstx0+x>=w) break;

	    dp[dsty0+y][dstx0+x] = sp[srcy][srcx];
	  }
      }
  }

  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src, int srcx0,int srcy0, int sw,int sh)
  {
    ImageParam param = src.AskParam();

    for (int i=0;i<4;i++)
      {
	BitmapChannel b = (BitmapChannel)i;
	CopyScaled(dst.AskBitmap(b),
		   param.ChromaScaleH(b,dstx0),param.ChromaScaleV(b,dsty0),
		   param.ChromaScaleH(b,dw), param.ChromaScaleV(b,dh),

		   src.AskBitmap(b),
		   param.ChromaScaleH(b,srcx0),param.ChromaScaleV(b,srcy0),
		   param.ChromaScaleH(b,sw), param.ChromaScaleV(b,sh));
      }
  }

  template <class Pel> void CopyScaled(Bitmap<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Bitmap<Pel>& src)
  {
    CopyScaled(dst,dstx0,dsty0,dw,dh, src,
	       -src.AskXOffset(),-src.AskYOffset(),src.AskWidth()-src.AskXOffset(),src.AskHeight()-src.AskYOffset());
  }

  template <class Pel> void CopyScaled(Image<Pel>& dst,       int dstx0,int dsty0, int dw,int dh,
				       const Image<Pel>& src)
  {
    CopyScaled(dst,dstx0,dsty0,dw,dh, src,
	       -src.AskXOffset(),-src.AskYOffset(),src.AskWidth()-src.AskXOffset(),src.AskHeight()-src.AskYOffset());
  }

  inline void FillScaleMapping(int* mapping, unsigned char* factor, int w, int newW)
  {
    for (int x=0;x<newW;x++)
      {
	if (factor==NULL)
	  {
	    mapping[x] = ((w-1)*x + (newW-1)/2)/(newW -1);
	  }
	else
	  {
	    // The -1 (A) is to prevent setting mapping[x] to the maximum value.
	    // Hence, we can simply access mapping[x]+1 in the interpolation algorithm without the danger of overflow.
	    int pos = (256*(w-1) -1/*A*/ )*x/(newW -1);
	    mapping[x] = pos/256;
	    factor[x]  = pos%256;
	  }
      }
  }

  template <class Pel> void Scale_NN(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight)
  {
    int* mapX = new int[newWidth];
    int* mapY = new int[newHeight];

    int w = src.getWidth();
    int h = src.getHeight();

    FillScaleMapping(mapX, NULL, w, newWidth);
    FillScaleMapping(mapY, NULL, h, newHeight);

    dst.Create(newWidth, newHeight);

    const Pel*const* in  = src.AskFrame();
    /* */ Pel*const* out = dst.AskFrame();

    for (int y=0;y<newHeight;y++)
      {
	const int iy = mapY[y];

	for (int x=0;x<newWidth;x++)
	  {
	    dst[y][x] = in[iy][ mapX[x] ];
	  }
      }

    delete[] mapX;
    delete[] mapY;
  }

  template <class Pel> void Scale_Bilinear(Bitmap<Pel>& dst,const Bitmap<Pel>& src, int newWidth, int newHeight)
  {
    int* mapX = new int[newWidth];
    int* mapY = new int[newHeight];
    unsigned char* factorX = new unsigned char[newWidth];
    unsigned char* factorY = new unsigned char[newHeight];

    int w = src.getWidth();
    int h = src.getHeight();

    // we set the maximum value to w-1 so that we can always access the pixel at mapX[x]+1
    FillScaleMapping(mapX, factorX, w, newWidth);
    FillScaleMapping(mapY, factorY, h, newHeight);

    dst.Create(newWidth, newHeight);

    const Pel*const* in  = src.AskFrame();
    /* */ Pel*const* out = dst.AskFrame();

    for (int y=0;y<newHeight;y++)
      {
	const int iy = mapY[y];
	const int factor = factorY[y];

	for (int x=0;x<newWidth;x++)
	  {
	    int ix = mapX[x];

	    Pel A = in[iy][ix];
	    Pel B = in[iy][ix+1];
	    Pel C = in[iy+1][ix];
	    Pel D = in[iy+1][ix+1];

	    Pel left  = (A*256 + (C-A)*factor) / 256;
	    Pel right = (B*256 + (D-B)*factor) / 256;

	    dst[y][x] = (left*256 + (right-left)*factorX[x]) / 256;
	  }
      }

    delete[] mapX;
    delete[] mapY;
    delete[] factorX;
    delete[] factorY;
  }

}

#endif
<|endoftext|>


<commit_before>// Empty externs implementation for Android compatibility with unused iOS Externs defined in GoogleMobileAds.iOS namespace.
#include <jni.h>
#include <string>

extern "C" {
    void GADUInitialize(const char *appId) {}

    void GADUInitializeWithCallback(void *mobileAdsClientRef,
                                    void *callback) {}

    const char *GADUGetInitDescription(void *statusRef,
                                       const char *className) {
        return nullptr;
    }

    int GADUGetInitLatency(void *statusRef, const char *className) {
        return 0;
    }

    int GADUGetInitState(void *statusRef, const char *className) {
        return 0;
    }

    const char **GADUGetInitAdapterClasses(void *statusRef) {
        const char **stringArray;

        return stringArray;
    }

    int GADUGetInitNumberOfAdapterClasses(void *statusRef) {
        return 0;
    }

    void GADUSetApplicationVolume(float volume) {}

    void GADUSetApplicationMuted(bool muted) {}

    void GADUSetiOSAppPauseOnBackground(bool pause) {}

    float GADUDeviceScale() {
        return 0.0;
    }

    int GADUDeviceSafeWidth() {
        return 0;
    }

    void *GADUCreateBannerView(void **bannerClient, const char *adUnitID,
                               int width, int height,
                               int adPosition) {
        return nullptr;
    }

    void *GADUCreateBannerViewWithCustomPosition(void **bannerClient,
                                                 const char *adUnitID, int width,
                                                 int height, int x,
                                                 int y) {
        return nullptr;
    }

    void *GADUCreateSmartBannerView(void **bannerClient,
                                    const char *adUnitID, int adPosition) {
        return nullptr;
    }

    void *GADUCreateSmartBannerViewWithCustomPosition(void **bannerClient,
                                                      const char *adUnitID, int x,
                                                      int y) {
        return nullptr;
    }

    void *GADUCreateAnchoredAdaptiveBannerView(void **bannerClient,
                                               const char *adUnitID, int width,
                                               int orientation,
                                               int adPosition) {
        return nullptr;
    }

    void *GADUCreateAnchoredAdaptiveBannerViewWithCustomPosition(
            void **bannerClient, const char *adUnitID, int width,
            int orientation, int x, int y) {
        return nullptr;
    }

    void *GADUCreateInterstitial(void **interstitialClient,
                                 const char *adUnitID) {
        return nullptr;
    }

    void *GADUCreateRewardBasedVideoAd(
            void **rewardBasedVideoAdClient) {
        return nullptr;
    }

    void *GADUCreateRewardedAd(void **rewardedAdClient,
                               const char *adUnitID) {
        return nullptr;

    }

    void *GADUCreateAdLoader(void **adLoaderClient,
                             const char *adUnitID,
                             const char **templateIDs, int templateIDLength,
                             struct AdTypes *types, bool returnUrlsForImageAssets) {
        return nullptr;
    }

    void GADUSetBannerCallbacks(void *banner,
                                void *adReceivedCallback,
                                void *adFailedCallback,
                                void *willPresentCallback,
                                void *didDismissCallback,
                                void *willLeaveCallback,
                                void *paidEventCallback
    ) {}

    void GADUSetInterstitialCallbacks(
            void *interstitial, void *adReceivedCallback,
            void *adFailedCallback,
            void *willPresentCallback,
            void *didDismissCallback,
            void *willLeaveCallback,
            void *paidEventCallback
    ) {}

    void GADUSetRewardBasedVideoAdCallbacks(
            void *rewardBasedVideoAd,
            void *adReceivedCallback,
            void *adFailedCallback,
            void *didOpenCallback,
            void *didStartCallback,
            void *didCloseCallback,
            void *didRewardCallback,
            void *willLeaveCallback,
            void *didCompleteCallback) {}

    void GADUSetRewardedAdCallbacks(
            void *rewardedAd, void *adReceivedCallback,
            void *adFailedToLoadCallback,
            void *adFailedToShowCallback,
            void *didOpenCallback, void *didCloseCallback,
            void *didEarnRewardCallback,
            void *paidEventCallback
    ) {}

    void GADUSetAdLoaderCallbacks(
            void *adLoader,
            void *customTemplateAdReceivedCallback,
            void *adFailedCallback) {}

    void GADUHideBannerView(void *banner) {}

    void GADUShowBannerView(void *banner) {}

    void GADURemoveBannerView(void *banner) {}

    float GADUGetBannerViewHeightInPixels(void *banner) {
        return 0.0;
    }

    float GADUGetBannerViewWidthInPixels(void *banner) {
        return 0.0;
    }

    bool GADUInterstitialReady(void *interstitial) {
        return false;
    }

    void GADUShowInterstitial(void *interstitial) {}

    bool GADURewardBasedVideoAdReady(void *rewardBasedVideo) {
        return false;
    }

    void GADUSetRewardBasedVideoAdUserId(void *rewardBasedVideo,
                                         const char *userId) {}

    void GADUShowRewardBasedVideoAd(void *rewardBasedVideoAd) {}

    bool GADURewardedAdReady(void *rewardedAd) {
        return false;
    }

    void GADUShowRewardedAd(void *rewardedAd) {}

    const char *GADURewardedAdGetRewardType(void *rewardedAd) {
        return nullptr;
    }

    double GADURewardedAdGetRewardAmount(void *rewardedAd) {
        return 0.0;
    }

    void *GADUCreateRequest() {
        return nullptr;
    }

    void GADUAddTestDevice(void *request, const char *deviceID) {}

    void GADUAddKeyword(void *request, const char *keyword) {}

    void GADUSetRequestAgent(void *request, const char *requestAgent) {}

    void GADUSetBirthday(void *request, int year, int month, int day) {}

    void GADUSetGender(void *request, int genderCode) {}

    void GADUTagForChildDirectedTreatment(void *request, bool childDirectedTreatment) {}

    void *GADUCreateServerSideVerificationOptions() {
        return nullptr;
    }

    void GADUServerSideVerificationOptionsSetUserId(void *options,
                                                    const char *userId) {}

    void GADUServerSideVerificationOptionsSetCustomRewardString(
            void *options, const char *customRewardString) {}

    void *GADUCreateMutableDictionary() {
        return nullptr;
    }

    void GADUMutableDictionarySetValue(void *dictionary, const char *key,
                                       const char *value) {}

    void GADUSetMediationExtras(void *request, void *dictionary,
                                const char *adNetworkExtraClassName) {}

    void GADUSetExtra(void *request, const char *key, const char *value) {}

    void GADURequestBannerAd(void *banner, void *request) {}

    void GADUSetBannerViewAdPosition(void *banner, int position) {}

    void GADUSetBannerViewCustomPosition(void *banner, int x, int y) {}

    void GADURequestInterstitial(void *interstitial, void *request) {}

    void GADURequestRewardBasedVideoAd(void *rewardBasedVideoAd,
                                       void *request, const char *adUnitID) {}

    void GADURequestRewardedAd(void *rewardedAd, void *request) {}

    void GADURequestNativeAd(void *adLoader, void *request) {}

    void GADURewardedAdSetServerSideVerificationOptions(
            void *rewardedAd, void *options) {}

    #pragma mark - Native Custom Template Ad methods
    const char *GADUNativeCustomTemplateAdTemplateID(
            void *nativeCustomTemplateAd) {
        return nullptr;
    }

    const char *GADUNativeCustomTemplateAdImageAsBytesForKey(
            void *nativeCustomTemplateAd, const char *key) {
        return nullptr;
    }

    const char *GADUNativeCustomTemplateAdStringForKey(
            void *nativeCustomTemplateAd, const char *key) {
        return nullptr;
    }

    void GADUNativeCustomTemplateAdRecordImpression(
            void *nativeCustomTemplateAd) {}

    void GADUNativeCustomTemplateAdPerformClickOnAssetWithKey(
            void *nativeCustomTemplateAd, const char *key,
            bool customClickAction) {}

    const char **GADUNativeCustomTemplateAdAvailableAssetKeys(
            void *nativeCustomTemplateAd) {
        const char **ptr;
        return ptr;
    }

    int GADUNativeCustomTemplateAdNumberOfAvailableAssetKeys(
            void *nativeCustomTemplateAd) {
        return 0;
    }

    void GADUSetNativeCustomTemplateAdUnityClient(
            void *nativeCustomTemplateAd,
            void *nativeCustomTemplateClient) {}

    void GADUSetNativeCustomTemplateAdCallbacks(
            void *nativeCustomTemplateAd,
            void *adClickedCallback) {}

    #pragma mark - Other methods
    void GADURelease(void *ref) {}

    const char *GADUMediationAdapterClassNameForBannerView(void *bannerView) {
        return nullptr;
    }

    const char *GADUMediationAdapterClassNameForRewardedVideo(void *rewardedVideo) {
        return nullptr;
    }

    const char *GADUMediationAdapterClassNameForRewardedAd(void *rewardedAd) {
        return nullptr;
    }

    const char *GADUMediationAdapterClassNameForInterstitial(void *interstitial) {
        return nullptr;
    }
}
<commit_msg>Replace nullptr in externs.cpp with NULL for C++98 support in legacy Unity versions. Fixes #1200.<commit_after>// Empty externs implementation for Android compatibility with unused iOS Externs defined in GoogleMobileAds.iOS namespace.
#include <jni.h>
#include <string>

extern "C" {
    void GADUInitialize(const char *appId) {}

    void GADUInitializeWithCallback(void *mobileAdsClientRef,
                                    void *callback) {}

    const char *GADUGetInitDescription(void *statusRef,
                                       const char *className) {
        return NULL;
    }

    int GADUGetInitLatency(void *statusRef, const char *className) {
        return 0;
    }

    int GADUGetInitState(void *statusRef, const char *className) {
        return 0;
    }

    const char **GADUGetInitAdapterClasses(void *statusRef) {
        const char **stringArray;

        return stringArray;
    }

    int GADUGetInitNumberOfAdapterClasses(void *statusRef) {
        return 0;
    }

    void GADUSetApplicationVolume(float volume) {}

    void GADUSetApplicationMuted(bool muted) {}

    void GADUSetiOSAppPauseOnBackground(bool pause) {}

    float GADUDeviceScale() {
        return 0.0;
    }

    int GADUDeviceSafeWidth() {
        return 0;
    }

    void *GADUCreateBannerView(void **bannerClient, const char *adUnitID,
                               int width, int height,
                               int adPosition) {
        return NULL;
    }

    void *GADUCreateBannerViewWithCustomPosition(void **bannerClient,
                                                 const char *adUnitID, int width,
                                                 int height, int x,
                                                 int y) {
        return NULL;
    }

    void *GADUCreateSmartBannerView(void **bannerClient,
                                    const char *adUnitID, int adPosition) {
        return NULL;
    }

    void *GADUCreateSmartBannerViewWithCustomPosition(void **bannerClient,
                                                      const char *adUnitID, int x,
                                                      int y) {
        return NULL;
    }

    void *GADUCreateAnchoredAdaptiveBannerView(void **bannerClient,
                                               const char *adUnitID, int width,
                                               int orientation,
                                               int adPosition) {
        return NULL;
    }

    void *GADUCreateAnchoredAdaptiveBannerViewWithCustomPosition(
            void **bannerClient, const char *adUnitID, int width,
            int orientation, int x, int y) {
        return NULL;
    }

    void *GADUCreateInterstitial(void **interstitialClient,
                                 const char *adUnitID) {
        return NULL;
    }

    void *GADUCreateRewardBasedVideoAd(
            void **rewardBasedVideoAdClient) {
        return NULL;
    }

    void *GADUCreateRewardedAd(void **rewardedAdClient,
                               const char *adUnitID) {
        return NULL;

    }

    void *GADUCreateAdLoader(void **adLoaderClient,
                             const char *adUnitID,
                             const char **templateIDs, int templateIDLength,
                             struct AdTypes *types, bool returnUrlsForImageAssets) {
        return NULL;
    }

    void GADUSetBannerCallbacks(void *banner,
                                void *adReceivedCallback,
                                void *adFailedCallback,
                                void *willPresentCallback,
                                void *didDismissCallback,
                                void *willLeaveCallback,
                                void *paidEventCallback
    ) {}

    void GADUSetInterstitialCallbacks(
            void *interstitial, void *adReceivedCallback,
            void *adFailedCallback,
            void *willPresentCallback,
            void *didDismissCallback,
            void *willLeaveCallback,
            void *paidEventCallback
    ) {}

    void GADUSetRewardBasedVideoAdCallbacks(
            void *rewardBasedVideoAd,
            void *adReceivedCallback,
            void *adFailedCallback,
            void *didOpenCallback,
            void *didStartCallback,
            void *didCloseCallback,
            void *didRewardCallback,
            void *willLeaveCallback,
            void *didCompleteCallback) {}

    void GADUSetRewardedAdCallbacks(
            void *rewardedAd, void *adReceivedCallback,
            void *adFailedToLoadCallback,
            void *adFailedToShowCallback,
            void *didOpenCallback, void *didCloseCallback,
            void *didEarnRewardCallback,
            void *paidEventCallback
    ) {}

    void GADUSetAdLoaderCallbacks(
            void *adLoader,
            void *customTemplateAdReceivedCallback,
            void *adFailedCallback) {}

    void GADUHideBannerView(void *banner) {}

    void GADUShowBannerView(void *banner) {}

    void GADURemoveBannerView(void *banner) {}

    float GADUGetBannerViewHeightInPixels(void *banner) {
        return 0.0;
    }

    float GADUGetBannerViewWidthInPixels(void *banner) {
        return 0.0;
    }

    bool GADUInterstitialReady(void *interstitial) {
        return false;
    }

    void GADUShowInterstitial(void *interstitial) {}

    bool GADURewardBasedVideoAdReady(void *rewardBasedVideo) {
        return false;
    }

    void GADUSetRewardBasedVideoAdUserId(void *rewardBasedVideo,
                                         const char *userId) {}

    void GADUShowRewardBasedVideoAd(void *rewardBasedVideoAd) {}

    bool GADURewardedAdReady(void *rewardedAd) {
        return false;
    }

    void GADUShowRewardedAd(void *rewardedAd) {}

    const char *GADURewardedAdGetRewardType(void *rewardedAd) {
        return NULL;
    }

    double GADURewardedAdGetRewardAmount(void *rewardedAd) {
        return 0.0;
    }

    void *GADUCreateRequest() {
        return NULL;
    }

    void GADUAddTestDevice(void *request, const char *deviceID) {}

    void GADUAddKeyword(void *request, const char *keyword) {}

    void GADUSetRequestAgent(void *request, const char *requestAgent) {}

    void GADUSetBirthday(void *request, int year, int month, int day) {}

    void GADUSetGender(void *request, int genderCode) {}

    void GADUTagForChildDirectedTreatment(void *request, bool childDirectedTreatment) {}

    void *GADUCreateServerSideVerificationOptions() {
        return NULL;
    }

    void GADUServerSideVerificationOptionsSetUserId(void *options,
                                                    const char *userId) {}

    void GADUServerSideVerificationOptionsSetCustomRewardString(
            void *options, const char *customRewardString) {}

    void *GADUCreateMutableDictionary() {
        return NULL;
    }

    void GADUMutableDictionarySetValue(void *dictionary, const char *key,
                                       const char *value) {}

    void GADUSetMediationExtras(void *request, void *dictionary,
                                const char *adNetworkExtraClassName) {}

    void GADUSetExtra(void *request, const char *key, const char *value) {}

    void GADURequestBannerAd(void *banner, void *request) {}

    void GADUSetBannerViewAdPosition(void *banner, int position) {}

    void GADUSetBannerViewCustomPosition(void *banner, int x, int y) {}

    void GADURequestInterstitial(void *interstitial, void *request) {}

    void GADURequestRewardBasedVideoAd(void *rewardBasedVideoAd,
                                       void *request, const char *adUnitID) {}

    void GADURequestRewardedAd(void *rewardedAd, void *request) {}

    void GADURequestNativeAd(void *adLoader, void *request) {}

    void GADURewardedAdSetServerSideVerificationOptions(
            void *rewardedAd, void *options) {}

    #pragma mark - Native Custom Template Ad methods
    const char *GADUNativeCustomTemplateAdTemplateID(
            void *nativeCustomTemplateAd) {
        return NULL;
    }

    const char *GADUNativeCustomTemplateAdImageAsBytesForKey(
            void *nativeCustomTemplateAd, const char *key) {
        return NULL;
    }

    const char *GADUNativeCustomTemplateAdStringForKey(
            void *nativeCustomTemplateAd, const char *key) {
        return NULL;
    }

    void GADUNativeCustomTemplateAdRecordImpression(
            void *nativeCustomTemplateAd) {}

    void GADUNativeCustomTemplateAdPerformClickOnAssetWithKey(
            void *nativeCustomTemplateAd, const char *key,
            bool customClickAction) {}

    const char **GADUNativeCustomTemplateAdAvailableAssetKeys(
            void *nativeCustomTemplateAd) {
        const char **ptr;
        return ptr;
    }

    int GADUNativeCustomTemplateAdNumberOfAvailableAssetKeys(
            void *nativeCustomTemplateAd) {
        return 0;
    }

    void GADUSetNativeCustomTemplateAdUnityClient(
            void *nativeCustomTemplateAd,
            void *nativeCustomTemplateClient) {}

    void GADUSetNativeCustomTemplateAdCallbacks(
            void *nativeCustomTemplateAd,
            void *adClickedCallback) {}

    #pragma mark - Other methods
    void GADURelease(void *ref) {}

    const char *GADUMediationAdapterClassNameForBannerView(void *bannerView) {
        return NULL;
    }

    const char *GADUMediationAdapterClassNameForRewardedVideo(void *rewardedVideo) {
        return NULL;
    }

    const char *GADUMediationAdapterClassNameForRewardedAd(void *rewardedAd) {
        return NULL;
    }

    const char *GADUMediationAdapterClassNameForInterstitial(void *interstitial) {
        return NULL;
    }
}
<|endoftext|>


<commit_before>// Copyright Ren Hansen 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers* audioBusBuffers,
			  Steinberg::int32 busCount,
			  const T& func)
{
	if (!audioBusBuffers)
		return;

	for (Steinberg::int32 busIndex = 0; busIndex < busCount; ++busIndex)
	{
		func (audioBusBuffers[busIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers& audioBuffer, const T& func)
{
	for(Steinberg::int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers32 [channelIndex])
			return;

		func (audioBuffer.channelBuffers32 [channelIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IEventList* eventList, const T& func)
{
	if (!eventList)
		return;

	auto eventCount = eventList->getEventCount ();
	for (Steinberg::int32 eventIndex = 0; eventIndex < eventCount; ++eventIndex)
	{
		Steinberg::Vst::Event event = { 0 };
		if (eventList->getEvent (eventIndex, event) != Steinberg::kResultOk)
			continue;

		func (event);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IUnitInfo* unitInfo, const T& func)
{
	if (!unitInfo)
		return;

	for (Steinberg::int32 i = 0; i < unitInfo->getUnitCount(); ++i)
	{
		Steinberg::Vst::UnitInfo info = { 0 };
		if (unitInfo->getUnitInfo(i, info) != Steinberg::kResultOk)
			continue;

		func (info);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach_ProgramListInfo (Steinberg::Vst::IUnitInfo* unitInfo, const T& func)
{
	if (!unitInfo)
		return;

	for (Steinberg::int32 i = 0; i < unitInfo->getUnitCount(); ++i)
	{
		Steinberg::Vst::ProgramListInfo info = { 0 };
		if (unitInfo->getProgramListInfo(i, info) != Steinberg::kResultOk)
			continue;

		func(info);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IParamValueQueue* paramQueue, const T& func)
{
	if (!paramQueue)
		return;

	auto paramId = paramQueue->getParameterId ();
	auto numPoints = paramQueue->getPointCount ();
	for (Steinberg::int32 pointIndex = 0; pointIndex < numPoints; ++pointIndex)
	{
		Steinberg::int32 sampleOffset = 0;
		Steinberg::Vst::ParamValue value = 0;
		if (paramQueue->getPoint (pointIndex, sampleOffset, value) != Steinberg::kResultOk)
			continue;

		func (paramId, sampleOffset, value);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IParameterChanges* changes, const T& func)
{
	if (!changes)
		return;

	auto paramCount = changes->getParameterCount ();
	for (Steinberg::int32 paramIndex = 0; paramIndex < paramCount; ++paramIndex)
	{
		auto paramValueQueue = changes->getParameterData (paramIndex);
		if (!paramValueQueue)
			continue;

		func (paramValueQueue);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers& buffer0,
			  Steinberg::Vst::AudioBusBuffers& buffer1,
			  const T& func)
{
	if (buffer0.numChannels != buffer1.numChannels)
		return;

	for (Steinberg::int32 channelIndex = 0; channelIndex < buffer0.numChannels; ++channelIndex)
	{
		func (buffer0.channelBuffers32[channelIndex], buffer1.channelBuffers32[channelIndex]);
	}
}

//------------------------------------------------------------------------
void copy (Steinberg::Vst::AudioBusBuffers* dst,
		   Steinberg::Vst::AudioBusBuffers* src,
		   Steinberg::int32 sliceSize,
		   Steinberg::int32 beginIndex)
{
	if (!dst || !src)
		return;

	size_t numBytes = sliceSize * sizeof (Steinberg::Vst::Sample32);
	for (int32_t chIdx = 0; chIdx < dst->numChannels && chIdx < dst->numChannels; ++chIdx)
	{
		memcpy (&dst->channelBuffers32[chIdx][beginIndex], src->channelBuffers32[chIdx], numBytes);
	}
}

//------------------------------------------------------------------------
void clear (Steinberg::Vst::AudioBusBuffers* audioBusBuffers,
			Steinberg::int32 sampleCount,
			Steinberg::int32 busCount)
{
	if (!audioBusBuffers)
		return;

	const Steinberg::int32 numBytes = sampleCount * sizeof (Steinberg::Vst::Sample32);
	foreach (audioBusBuffers, busCount, [&](Steinberg::Vst::AudioBusBuffers& audioBuffer)
	{
		foreach (audioBuffer, [&](Steinberg::Vst::Sample32* channelBuffer)
		{
			if (!channelBuffer)
				return;

			memset (channelBuffer, 0, numBytes);
		});
	});
}

//------------------------------------------------------------------------
void mix (Steinberg::Vst::AudioBusBuffers& dst,
		  Steinberg::Vst::AudioBusBuffers& src,
		  Steinberg::int32 sampleCount)
{
	foreach (dst, src, [&](Steinberg::Vst::Sample32* buffer0, Steinberg::Vst::Sample32* buffer1)
	{
#if USE_XMM_INTRIN
		static const Steinberg::int32 kVectorSize = 4;
		if ((sampleCount & (kVectorSize-1)) == 0) // fast modulo: sampleCount % kVectorSize == 0
		{
			for (Steinberg::int32 sampleIdx = 0; sampleIdx < sampleCount; sampleIdx += kVectorSize)
			{
				_mm_store_ps (buffer0, _mm_add_ps  (_mm_load_ps (buffer0), _mm_load_ps (buffer1)));
				_mm_store_ps (buffer1, _mm_set_ps1 (0.f));

				buffer0 += kVectorSize;
				buffer1 += kVectorSize;
			}
		}
		else
#endif
		{
			for (Steinberg::int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
			{
				buffer0[sampleIndex] += buffer1[sampleIndex];
				buffer1[sampleIndex] = 0;
			}
		}
	});
}<commit_msg>Revert "pull request testing"<commit_after>// Copyright Ren Hansen 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers* audioBusBuffers,
			  Steinberg::int32 busCount,
			  const T& func)
{
	if (!audioBusBuffers)
		return;

	for (Steinberg::int32 busIndex = 0; busIndex < busCount; ++busIndex)
	{
		func (audioBusBuffers[busIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers& audioBuffer, const T& func)
{
	for (Steinberg::int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers32 [channelIndex])
			return;

		func (audioBuffer.channelBuffers32 [channelIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IEventList* eventList, const T& func)
{
	if (!eventList)
		return;

	auto eventCount = eventList->getEventCount ();
	for (Steinberg::int32 eventIndex = 0; eventIndex < eventCount; ++eventIndex)
	{
		Steinberg::Vst::Event event = { 0 };
		if (eventList->getEvent (eventIndex, event) != Steinberg::kResultOk)
			continue;

		func (event);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IUnitInfo* unitInfo, const T& func)
{
	if (!unitInfo)
		return;

	for (Steinberg::int32 i = 0; i < unitInfo->getUnitCount(); ++i)
	{
		Steinberg::Vst::UnitInfo info = { 0 };
		if (unitInfo->getUnitInfo(i, info) != Steinberg::kResultOk)
			continue;

		func (info);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach_ProgramListInfo (Steinberg::Vst::IUnitInfo* unitInfo, const T& func)
{
	if (!unitInfo)
		return;

	for (Steinberg::int32 i = 0; i < unitInfo->getUnitCount(); ++i)
	{
		Steinberg::Vst::ProgramListInfo info = { 0 };
		if (unitInfo->getProgramListInfo(i, info) != Steinberg::kResultOk)
			continue;

		func(info);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IParamValueQueue* paramQueue, const T& func)
{
	if (!paramQueue)
		return;

	auto paramId = paramQueue->getParameterId ();
	auto numPoints = paramQueue->getPointCount ();
	for (Steinberg::int32 pointIndex = 0; pointIndex < numPoints; ++pointIndex)
	{
		Steinberg::int32 sampleOffset = 0;
		Steinberg::Vst::ParamValue value = 0;
		if (paramQueue->getPoint (pointIndex, sampleOffset, value) != Steinberg::kResultOk)
			continue;

		func (paramId, sampleOffset, value);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::IParameterChanges* changes, const T& func)
{
	if (!changes)
		return;

	auto paramCount = changes->getParameterCount ();
	for (Steinberg::int32 paramIndex = 0; paramIndex < paramCount; ++paramIndex)
	{
		auto paramValueQueue = changes->getParameterData (paramIndex);
		if (!paramValueQueue)
			continue;

		func (paramValueQueue);
	}
}

//------------------------------------------------------------------------
template <typename T>
void foreach (Steinberg::Vst::AudioBusBuffers& buffer0,
			  Steinberg::Vst::AudioBusBuffers& buffer1,
			  const T& func)
{
	if (buffer0.numChannels != buffer1.numChannels)
		return;

	for (Steinberg::int32 channelIndex = 0; channelIndex < buffer0.numChannels; ++channelIndex)
	{
		func (buffer0.channelBuffers32[channelIndex], buffer1.channelBuffers32[channelIndex]);
	}
}

//------------------------------------------------------------------------
void copy (Steinberg::Vst::AudioBusBuffers* dst,
		   Steinberg::Vst::AudioBusBuffers* src,
		   Steinberg::int32 sliceSize,
		   Steinberg::int32 beginIndex)
{
	if (!dst || !src)
		return;

	size_t numBytes = sliceSize * sizeof (Steinberg::Vst::Sample32);
	for (int32_t chIdx = 0; chIdx < dst->numChannels && chIdx < dst->numChannels; ++chIdx)
	{
		memcpy (&dst->channelBuffers32[chIdx][beginIndex], src->channelBuffers32[chIdx], numBytes);
	}
}

//------------------------------------------------------------------------
void clear (Steinberg::Vst::AudioBusBuffers* audioBusBuffers,
			Steinberg::int32 sampleCount,
			Steinberg::int32 busCount)
{
	if (!audioBusBuffers)
		return;

	const Steinberg::int32 numBytes = sampleCount * sizeof (Steinberg::Vst::Sample32);
	foreach (audioBusBuffers, busCount, [&](Steinberg::Vst::AudioBusBuffers& audioBuffer)
	{
		foreach (audioBuffer, [&](Steinberg::Vst::Sample32* channelBuffer)
		{
			if (!channelBuffer)
				return;

			memset (channelBuffer, 0, numBytes);
		});
	});
}

//------------------------------------------------------------------------
void mix (Steinberg::Vst::AudioBusBuffers& dst,
		  Steinberg::Vst::AudioBusBuffers& src,
		  Steinberg::int32 sampleCount)
{
	foreach (dst, src, [&](Steinberg::Vst::Sample32* buffer0, Steinberg::Vst::Sample32* buffer1)
	{
#if USE_XMM_INTRIN
		static const Steinberg::int32 kVectorSize = 4;
		if ((sampleCount & (kVectorSize-1)) == 0) // fast modulo: sampleCount % kVectorSize == 0
		{
			for (Steinberg::int32 sampleIdx = 0; sampleIdx < sampleCount; sampleIdx += kVectorSize)
			{
				_mm_store_ps (buffer0, _mm_add_ps  (_mm_load_ps (buffer0), _mm_load_ps (buffer1)));
				_mm_store_ps (buffer1, _mm_set_ps1 (0.f));

				buffer0 += kVectorSize;
				buffer1 += kVectorSize;
			}
		}
		else
#endif
		{
			for (Steinberg::int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
			{
				buffer0[sampleIndex] += buffer1[sampleIndex];
				buffer1[sampleIndex] = 0;
			}
		}
	});
}<|endoftext|>


<commit_before>#ifndef AMGCL_BACKEND_EIGEN_HPP
#define AMGCL_BACKEND_EIGEN_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
 * \file   amgcl/backend/eigen.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Sparse matrix in CRS format.
 */

#include <boost/typeof/typeof.hpp>
#include <boost/type_traits.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <Eigen/SparseCore>
#include <amgcl/util.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/solver/skyline_lu.hpp>

namespace amgcl {
namespace backend {

/// Eigen backend.
/**
 * This is a backend that uses types defined in the Eigen library
 * (http://eigen.tuxfamily.org).
 *
 * \param real Value type.
 * \ingroup backends
 */
template <typename real>
struct eigen {
    typedef real      value_type;
    typedef ptrdiff_t index_type;

    typedef
        Eigen::MappedSparseMatrix<value_type, Eigen::RowMajor, index_type>
        matrix;

    typedef Eigen::Matrix<value_type, Eigen::Dynamic, 1> vector;
    typedef Eigen::Matrix<value_type, Eigen::Dynamic, 1> matrix_diagonal;

    typedef solver::skyline_lu<real> direct_solver;

    struct provides_row_iterator : boost::true_type {};

    /// Backend parameters.
    typedef amgcl::detail::empty_params params;

    static std::string name() { return "eigen"; }

    /// Copy matrix from builtin backend.
    static boost::shared_ptr<matrix>
    copy_matrix(boost::shared_ptr< typename builtin<real>::matrix > A, const params&)
    {
        const typename builtin<real>::matrix &a = *A;

        BOOST_AUTO(Aptr, a.ptr_data());
        BOOST_AUTO(Acol, a.col_data());
        BOOST_AUTO(Aval, a.val_data());

        return boost::shared_ptr<matrix>(
                new matrix(
                    rows(*A), cols(*A), nonzeros(*A),
                    const_cast<index_type*>(Aptr),
                    const_cast<index_type*>(Acol),
                    const_cast<value_type*>(Aval)
                    ),
                hold_host(A)
                );
    }

    /// Copy vector from builtin backend.
    static boost::shared_ptr<vector>
    copy_vector(typename builtin<real>::vector const &x, const params&)
    {
        return boost::make_shared<vector>(
                Eigen::Map<const vector>(&x[0], x.size())
                );
    }

    /// Copy vector from builtin backend.
    static boost::shared_ptr<vector>
    copy_vector(boost::shared_ptr< typename builtin<real>::vector > x, const params &prm)
    {
        return copy_vector(*x, prm);
    }

    /// Create vector of the specified size.
    static boost::shared_ptr<vector>
    create_vector(size_t size, const params&)
    {
        return boost::make_shared<vector>(size);
    }

    /// Create direct solver for coarse level
    static boost::shared_ptr<direct_solver>
    create_solver(boost::shared_ptr< typename builtin<real>::matrix > A, const params&)
    {
        return boost::make_shared<direct_solver>(*A);
    }

    private:
        struct hold_host {
            typedef boost::shared_ptr< crs<real, ptrdiff_t, ptrdiff_t> > host_matrix;
            host_matrix host;

            hold_host( host_matrix host ) : host(host) {}

            void operator()(matrix *ptr) const {
                delete ptr;
            }
        };

};

//---------------------------------------------------------------------------
// Backend interface specialization for Eigen types
//---------------------------------------------------------------------------
template <class T, class Enable = void>
struct is_eigen_sparse_matrix : boost::false_type {};

template <class T, class Enable = void>
struct is_eigen_type : boost::false_type {};

template <class T>
struct is_eigen_sparse_matrix<
    T,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename boost::is_arithmetic<typename T::Scalar>::type,
                typename boost::is_base_of<Eigen::SparseMatrixBase<T>, T>::type
            >::type
        >::type
    > : boost::true_type
{};

template <class T>
struct is_eigen_type<
    T,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename boost::is_arithmetic<typename T::Scalar>::type,
                typename boost::is_base_of<Eigen::EigenBase<T>, T>::type
            >::type
        >::type
    > : boost::true_type
{};

template <class T>
struct value_type<
    T,
    typename boost::enable_if<
        typename is_eigen_type<T>::type>::type
    >
{
    typedef typename T::Scalar type;
};

template <class T>
struct rows_impl<
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.rows();
    }
};

template <class T>
struct cols_impl<
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.cols();
    }
};

template <class T>
struct nonzeros_impl<
    T,
    typename boost::enable_if<typename is_eigen_type<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.nonZeros();
    }
};

template <class T>
struct row_iterator <
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    typedef typename T::InnerIterator type;
};

template <class T>
struct row_begin_impl <
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    typedef typename row_iterator<T>::type iterator;
    static iterator get(const T &matrix, size_t row) {
        return iterator(matrix, row);
    }
};

template < class Alpha, class M, class V1, class Beta, class V2 >
struct spmv_impl<
    Alpha, M, V1, Beta, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_sparse_matrix<M>::type,
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(Alpha alpha, const M &A, const V1 &x, Beta beta, V2 &y)
    {
        if (!math::is_zero(beta))
            y = alpha * A * x + beta * y;
        else
            y = alpha * A * x;
    }
};

template < class M, class V1, class V2, class V3 >
struct residual_impl<
    M, V1, V2, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_sparse_matrix<M>::type,
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    static void apply(const V1 &rhs, const M &A, const V2 &x, V3 &r)
    {
        r = rhs - A * x;
    }
};

template < typename V >
struct clear_impl<
    V,
    typename boost::enable_if< typename is_eigen_type<V>::type >::type
    >
{
    static void apply(V &x)
    {
        x.setZero();
    }
};

template < class V1, class V2 >
struct inner_product_impl<
    V1, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    typedef typename value_type<V1>::type real;
    static real get(const V1 &x, const V2 &y)
    {
        return x.dot(y);
    }
};

template < class A, class V1, class B, class V2 >
struct axpby_impl<
    A, V1, B, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(A a, const V1 &x, B b, V2 &y)
    {
        if (!math::is_zero(b))
            y = a * x + b * y;
        else
            y = a * x;
    }
};

template < class A, class V1, class B, class V2, class C, class V3 >
struct axpbypcz_impl<
    A, V1, B, V2, C, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    typedef typename value_type<V1>::type real;

    static void apply(
            real a, const V1 &x,
            real b, const V2 &y,
            real c,       V3 &z
            )
    {
        if (!math::is_zero(c))
            z = a * x + b * y + c * z;
        else
            z = a * x + b * y;
    }
};

template < class Alpha, class V1, class V2, class Beta, class V3 >
struct vmul_impl<
    Alpha, V1, V2, Beta, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    static void apply(Alpha a, const V1 &x, const V2 &y, Beta b, V3 &z)
    {
        if (!math::is_zero(b))
            z.array() = a * x.array() * y.array() + b * z.array();
        else
            z.array() = a * x.array() * y.array();
    }
};

template < class V1, class V2 >
struct copy_impl<
    V1, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(const V1 &x, V2 &y)
    {
        y = x;
    }
};

} // namespace backend
} // namespace amgcl

#endif
<commit_msg>Fix is_eigen_sparse_matrix template for Eigen 3.3<commit_after>#ifndef AMGCL_BACKEND_EIGEN_HPP
#define AMGCL_BACKEND_EIGEN_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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.
*/

/**
 * \file   amgcl/backend/eigen.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Sparse matrix in CRS format.
 */

#include <boost/typeof/typeof.hpp>
#include <boost/type_traits.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <Eigen/SparseCore>
#include <amgcl/util.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/solver/skyline_lu.hpp>

namespace amgcl {
namespace backend {

/// Eigen backend.
/**
 * This is a backend that uses types defined in the Eigen library
 * (http://eigen.tuxfamily.org).
 *
 * \param real Value type.
 * \ingroup backends
 */
template <typename real>
struct eigen {
    typedef real      value_type;
    typedef ptrdiff_t index_type;

    typedef
        Eigen::MappedSparseMatrix<value_type, Eigen::RowMajor, index_type>
        matrix;

    typedef Eigen::Matrix<value_type, Eigen::Dynamic, 1> vector;
    typedef Eigen::Matrix<value_type, Eigen::Dynamic, 1> matrix_diagonal;

    typedef solver::skyline_lu<real> direct_solver;

    struct provides_row_iterator : boost::true_type {};

    /// Backend parameters.
    typedef amgcl::detail::empty_params params;

    static std::string name() { return "eigen"; }

    /// Copy matrix from builtin backend.
    static boost::shared_ptr<matrix>
    copy_matrix(boost::shared_ptr< typename builtin<real>::matrix > A, const params&)
    {
        const typename builtin<real>::matrix &a = *A;

        BOOST_AUTO(Aptr, a.ptr_data());
        BOOST_AUTO(Acol, a.col_data());
        BOOST_AUTO(Aval, a.val_data());

        return boost::shared_ptr<matrix>(
                new matrix(
                    rows(*A), cols(*A), nonzeros(*A),
                    const_cast<index_type*>(Aptr),
                    const_cast<index_type*>(Acol),
                    const_cast<value_type*>(Aval)
                    ),
                hold_host(A)
                );
    }

    /// Copy vector from builtin backend.
    static boost::shared_ptr<vector>
    copy_vector(typename builtin<real>::vector const &x, const params&)
    {
        return boost::make_shared<vector>(
                Eigen::Map<const vector>(&x[0], x.size())
                );
    }

    /// Copy vector from builtin backend.
    static boost::shared_ptr<vector>
    copy_vector(boost::shared_ptr< typename builtin<real>::vector > x, const params &prm)
    {
        return copy_vector(*x, prm);
    }

    /// Create vector of the specified size.
    static boost::shared_ptr<vector>
    create_vector(size_t size, const params&)
    {
        return boost::make_shared<vector>(size);
    }

    /// Create direct solver for coarse level
    static boost::shared_ptr<direct_solver>
    create_solver(boost::shared_ptr< typename builtin<real>::matrix > A, const params&)
    {
        return boost::make_shared<direct_solver>(*A);
    }

    private:
        struct hold_host {
            typedef boost::shared_ptr< crs<real, ptrdiff_t, ptrdiff_t> > host_matrix;
            host_matrix host;

            hold_host( host_matrix host ) : host(host) {}

            void operator()(matrix *ptr) const {
                delete ptr;
            }
        };

};

//---------------------------------------------------------------------------
// Backend interface specialization for Eigen types
//---------------------------------------------------------------------------
template <class T, class Enable = void>
struct is_eigen_sparse_matrix : boost::false_type {};

template <class T, class Enable = void>
struct is_eigen_type : boost::false_type {};

template <typename Scalar, int Flags, typename Storage>
struct is_eigen_sparse_matrix<
    Eigen::MappedSparseMatrix<Scalar, Flags, Storage>
    > : boost::true_type
{};

template <typename Scalar, int Flags, typename Storage>
struct is_eigen_sparse_matrix<
    Eigen::SparseMatrix<Scalar, Flags, Storage>
    > : boost::true_type
{};

template <class T>
struct is_eigen_type<
    T,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename boost::is_arithmetic<typename T::Scalar>::type,
                typename boost::is_base_of<Eigen::EigenBase<T>, T>::type
            >::type
        >::type
    > : boost::true_type
{};

template <class T>
struct value_type<
    T,
    typename boost::enable_if<
        typename is_eigen_type<T>::type>::type
    >
{
    typedef typename T::Scalar type;
};

template <class T>
struct rows_impl<
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.rows();
    }
};

template <class T>
struct cols_impl<
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.cols();
    }
};

template <class T>
struct nonzeros_impl<
    T,
    typename boost::enable_if<typename is_eigen_type<T>::type>::type
    >
{
    static size_t get(const T &matrix) {
        return matrix.nonZeros();
    }
};

template <class T>
struct row_iterator <
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    typedef typename T::InnerIterator type;
};

template <class T>
struct row_begin_impl <
    T,
    typename boost::enable_if<typename is_eigen_sparse_matrix<T>::type>::type
    >
{
    typedef typename row_iterator<T>::type iterator;
    static iterator get(const T &matrix, size_t row) {
        return iterator(matrix, row);
    }
};

template < class Alpha, class M, class V1, class Beta, class V2 >
struct spmv_impl<
    Alpha, M, V1, Beta, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_sparse_matrix<M>::type,
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(Alpha alpha, const M &A, const V1 &x, Beta beta, V2 &y)
    {
        if (!math::is_zero(beta))
            y = alpha * A * x + beta * y;
        else
            y = alpha * A * x;
    }
};

template < class M, class V1, class V2, class V3 >
struct residual_impl<
    M, V1, V2, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_sparse_matrix<M>::type,
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    static void apply(const V1 &rhs, const M &A, const V2 &x, V3 &r)
    {
        r = rhs - A * x;
    }
};

template < typename V >
struct clear_impl<
    V,
    typename boost::enable_if< typename is_eigen_type<V>::type >::type
    >
{
    static void apply(V &x)
    {
        x.setZero();
    }
};

template < class V1, class V2 >
struct inner_product_impl<
    V1, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    typedef typename value_type<V1>::type real;
    static real get(const V1 &x, const V2 &y)
    {
        return x.dot(y);
    }
};

template < class A, class V1, class B, class V2 >
struct axpby_impl<
    A, V1, B, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(A a, const V1 &x, B b, V2 &y)
    {
        if (!math::is_zero(b))
            y = a * x + b * y;
        else
            y = a * x;
    }
};

template < class A, class V1, class B, class V2, class C, class V3 >
struct axpbypcz_impl<
    A, V1, B, V2, C, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    typedef typename value_type<V1>::type real;

    static void apply(
            real a, const V1 &x,
            real b, const V2 &y,
            real c,       V3 &z
            )
    {
        if (!math::is_zero(c))
            z = a * x + b * y + c * z;
        else
            z = a * x + b * y;
    }
};

template < class Alpha, class V1, class V2, class Beta, class V3 >
struct vmul_impl<
    Alpha, V1, V2, Beta, V3,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type,
                typename is_eigen_type<V3>::type
            >::type
        >::type
    >
{
    static void apply(Alpha a, const V1 &x, const V2 &y, Beta b, V3 &z)
    {
        if (!math::is_zero(b))
            z.array() = a * x.array() * y.array() + b * z.array();
        else
            z.array() = a * x.array() * y.array();
    }
};

template < class V1, class V2 >
struct copy_impl<
    V1, V2,
    typename boost::enable_if<
            typename boost::mpl::and_<
                typename is_eigen_type<V1>::type,
                typename is_eigen_type<V2>::type
            >::type
        >::type
    >
{
    static void apply(const V1 &x, V2 &y)
    {
        y = x;
    }
};

} // namespace backend
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>/*******************************************************************- C++ -****\
 *
 *                           cleanup v2.0
 *                     (c) 2015 Fabian Thüring
 *
 * This file is distributed under the MIT Open Source License. See
 * LICENSE.TXT for details.
 *
\******************************************************************************/

#ifndef FS_TASK_HPP
#define FS_TASK_HPP

#include "trash.hpp"

#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
#include <tbb/task.h>

#include <memory>
#include <string>
#include <cstring>
#include <iostream>
#include <initializer_list>
#include <algorithm>

/// Analyze file system (root call)
void analyze_filesystem(boost::filesystem::path root);

/// TBB Task implemenation to recursively traverse the file system
class fstask : public tbb::task
{
private:
	boost::filesystem::path path_;

public:
    /// Move Constructor
    fstask(boost::filesystem::path&& cur_dir)
    	:	path_(cur_dir)
    {}

    /// Overrides virtual function task::execute
    tbb::task* execute() override;
};

#endif /* fstask.hpp */
<commit_msg>adjust spacing<commit_after>/*******************************************************************- C++ -****\
 *
 *                           cleanup v2.0
 *                     (c) 2015 Fabian Thüring
 *
 * This file is distributed under the MIT Open Source License. See
 * LICENSE.TXT for details.
 *
\******************************************************************************/

#ifndef FS_TASK_HPP
#define FS_TASK_HPP

#include "trash.hpp"

#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
#include <tbb/task.h>

#include <memory>
#include <string>
#include <cstring>
#include <iostream>
#include <initializer_list>
#include <algorithm>

/// Analyze file system (root call)
void analyze_filesystem(boost::filesystem::path root);

/// TBB Task implemenation to recursively traverse the file system
class fstask : public tbb::task
{
private:
	boost::filesystem::path path_;

public:
	/// Move Constructor
	fstask(boost::filesystem::path&& cur_dir)
	:	path_(cur_dir)
	{}

	/// Overrides virtual function task::execute
	tbb::task* execute() override;
};

#endif /* fstask.hpp */
<|endoftext|>


<commit_before>#pragma once

#include <iosfwd>
#include <limits>
#include <stdexcept>
#include <string>

namespace blackhole {
namespace cpp17 {

template<typename Char, typename Traits = std::char_traits<Char>>
class basic_string_view {
public:
    static constexpr std::size_t npos = std::numeric_limits<std::size_t>::max();

    typedef Char value_type;
    typedef Traits traits_type;

private:
    const char* data_;
    /// Size without \0.
    std::size_t size_;

public:
    /// Constructs an empty `string_view`.
    constexpr
    basic_string_view() noexcept:
        data_(nullptr),
        size_(0)
    {}

    template<std::size_t N>
    constexpr
    basic_string_view(const char(&literal)[N]) noexcept:
        data_(literal),
        size_(N - 1)
    {}

    constexpr
    basic_string_view(const char* literal, std::size_t size) noexcept:
        data_(literal),
        size_(size)
    {}

    basic_string_view(const std::string& message) noexcept:
        data_(message.data()),
        size_(message.size())
    {}

    constexpr
    basic_string_view(const basic_string_view& other) = default;

    constexpr
    basic_string_view& operator=(const basic_string_view& other) = default;

    constexpr
    auto data() const noexcept -> const char* {
        return data_;
    }

    constexpr
    auto size() const noexcept -> std::size_t {
        return size_;
    }

    constexpr
    auto operator[](std::size_t id) const -> char {
        return id < size() ?
            data_[id] :
            throw std::out_of_range("out of range");
    }

    /// Operations.

    /// Creates a `std::string` with a copy of the content of the current view.
    template<class Allocator = std::allocator<Char>>
    auto to_string(const Allocator& alloc = Allocator()) const -> std::basic_string<Char, Traits, Allocator> {
        return {data(), size(), alloc};
    }

    /// Returns a view of the substring [pos, pos + rcount), where rcount is the smaller of count
    /// and `size() - pos`.
    constexpr
    auto substr(std::size_t pos = 0, std::size_t count = npos) const -> basic_string_view {
        return pos <= size() ?
            basic_string_view(data() + pos, std::min(count, size() - pos)) :
            throw std::out_of_range("out of range");
    }

    constexpr
    auto operator==(const basic_string_view& other) const -> bool {
        return size() == other.size() && to_string() == other.to_string();
    }
};

template<class Char, class Traits>
std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& stream, const basic_string_view<Char, Traits>& value) {
    return stream << value.to_string();
}

typedef basic_string_view<char> string_view;

}  // namespace cpp17

using cpp17::string_view;

}  // namespace blackhole
<commit_msg>refactor(util): remove unnecessary code<commit_after>#pragma once

#include <iosfwd>
#include <limits>
#include <stdexcept>
#include <string>

namespace blackhole {
namespace cpp17 {

template<typename Char, typename Traits = std::char_traits<Char>>
class basic_string_view {
public:
    static constexpr std::size_t npos = std::numeric_limits<std::size_t>::max();

    typedef Char value_type;
    typedef Traits traits_type;

private:
    const char* data_;
    /// Size without \0.
    std::size_t size_;

public:
    /// Constructs an empty `string_view`.
    constexpr
    basic_string_view() noexcept:
        data_(nullptr),
        size_(0)
    {}

    template<std::size_t N>
    constexpr
    basic_string_view(const char(&literal)[N]) noexcept:
        data_(literal),
        size_(N - 1)
    {}

    constexpr
    basic_string_view(const char* literal, std::size_t size) noexcept:
        data_(literal),
        size_(size)
    {}

    basic_string_view(const std::string& message) noexcept:
        data_(message.data()),
        size_(message.size())
    {}

    constexpr
    auto data() const noexcept -> const char* {
        return data_;
    }

    constexpr
    auto size() const noexcept -> std::size_t {
        return size_;
    }

    constexpr
    auto operator[](std::size_t id) const -> char {
        return id < size() ?
            data_[id] :
            throw std::out_of_range("out of range");
    }

    /// Operations.

    /// Creates a `std::string` with a copy of the content of the current view.
    template<class Allocator = std::allocator<Char>>
    auto to_string(const Allocator& alloc = Allocator()) const -> std::basic_string<Char, Traits, Allocator> {
        return {data(), size(), alloc};
    }

    /// Returns a view of the substring [pos, pos + rcount), where rcount is the smaller of count
    /// and `size() - pos`.
    constexpr
    auto substr(std::size_t pos = 0, std::size_t count = npos) const -> basic_string_view {
        return pos <= size() ?
            basic_string_view(data() + pos, std::min(count, size() - pos)) :
            throw std::out_of_range("out of range");
    }

    constexpr
    auto operator==(const basic_string_view& other) const -> bool {
        return size() == other.size() && to_string() == other.to_string();
    }
};

template<class Char, class Traits>
std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& stream, const basic_string_view<Char, Traits>& value) {
    return stream << value.to_string();
}

typedef basic_string_view<char> string_view;

}  // namespace cpp17

using cpp17::string_view;

}  // namespace blackhole
<|endoftext|>


<commit_before>#pragma once

/**
 * Specialized domains for kill-gen problems.
 **/

#include <crab/common/debug.hpp>
#include <crab/common/stats.hpp>
#include <crab/domains/discrete_domains.hpp>
#include <crab/domains/patricia_trees.hpp>

#include <boost/optional.hpp>

namespace crab {
namespace domains {

// A wrapper for discrete_domain (i.e,. set of Element)
template <class Element> class flat_killgen_domain {

private:
  typedef flat_killgen_domain<Element> flat_killgen_domain_t;
  typedef ikos::discrete_domain<Element> discrete_domain_t;

public:
  typedef typename discrete_domain_t::iterator iterator;
  typedef Element element_t;

private:
  discrete_domain_t _inv;

public:
  flat_killgen_domain(discrete_domain_t inv) : _inv(inv) {}

  static flat_killgen_domain_t top() {
    return flat_killgen_domain(discrete_domain_t::top());
  }

  static flat_killgen_domain_t bottom() {
    return flat_killgen_domain(discrete_domain_t::bottom());
  }

  flat_killgen_domain() : _inv(discrete_domain_t::bottom()) {}

  flat_killgen_domain(Element e) : _inv(e) {}

  flat_killgen_domain(const flat_killgen_domain_t &o) : _inv(o._inv) {}

  flat_killgen_domain(flat_killgen_domain_t &&o) : _inv(std::move(o._inv)) {}

  flat_killgen_domain_t &operator=(const flat_killgen_domain_t &other) {
    if (this != &other)
      _inv = other._inv;
    return *this;
  }

  flat_killgen_domain_t &operator=(flat_killgen_domain_t &&other) {
    _inv = std::move(other._inv);
    return *this;
  }

  iterator begin() { return _inv.begin(); }

  iterator end() { return _inv.end(); }

  unsigned size() { return _inv.size(); }

  bool is_bottom() { return _inv.is_bottom(); }

  bool is_top() { return _inv.is_top(); }

  bool operator==(flat_killgen_domain_t other) {
    return *this <= other && other <= *this;
  }

  bool operator<=(flat_killgen_domain_t other) {
    if (is_bottom())
      return true;
    else if (other.is_top())
      return true;
    else
      return (_inv <= other._inv);
  }

  void operator-=(Element x) {
    if (is_bottom())
      return;
    _inv -= x;
  }

  void operator-=(flat_killgen_domain_t other) {
    if (is_bottom() || other.is_bottom())
      return;

    if (!other._inv.is_top()) {
      for (auto v : other)
        _inv -= v;
    }
  }

  void operator+=(Element x) {
    if (is_top())
      return;
    _inv += x;
  }

  void operator+=(flat_killgen_domain_t other) {
    if (is_top() || other.is_bottom()) {
      return;
    } else if (other.is_top()) {
      _inv = discrete_domain_t::top();
    } else {
      _inv = (_inv | other._inv);
    }
  }

  flat_killgen_domain_t operator|(flat_killgen_domain_t other) {
    return (_inv | other._inv);
  }

  flat_killgen_domain_t operator&(flat_killgen_domain_t other) {
    return (_inv & other._inv);
  }

  void write(crab_os &o) const { _inv.write(o); }
};

template <typename Elem>
inline crab_os &operator<<(crab_os &o, const flat_killgen_domain<Elem> &d) {
  d.write(o);
  return o;
}

// To represent sets of pairs (Key,Value).
// Bottom means empty set rather than failure.
template <typename Key, typename Value> class separate_killgen_domain {

private:
  typedef ikos::patricia_tree<Key, Value> patricia_tree_t;
  typedef typename patricia_tree_t::unary_op_t unary_op_t;
  typedef typename patricia_tree_t::binary_op_t binary_op_t;
  typedef typename patricia_tree_t::partial_order_t partial_order_t;

public:
  typedef separate_killgen_domain<Key, Value> separate_killgen_domain_t;
  typedef typename patricia_tree_t::iterator iterator;
  typedef Key key_type;
  typedef Value value_type;

private:
  bool _is_top;
  patricia_tree_t _tree;

  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         patricia_tree_t t2, bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_killgen_domain(patricia_tree_t t) : _is_top(false), _tree(t) {}

  separate_killgen_domain(bool b) : _is_top(b) {}

  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    }
    bool default_is_absorbing() { return false; }
  }; // class join_op

  class meet_op : public binary_op_t {
    boost::optional<Value> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };
    bool default_is_absorbing() { return true; }
  }; // class meet_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }
    bool default_is_top() { return false; }
  }; // class domain_po

public:
  static separate_killgen_domain_t top() {
    return separate_killgen_domain_t(true);
  }

  static separate_killgen_domain_t bottom() {
    return separate_killgen_domain_t(false);
  }

  separate_killgen_domain() : _is_top(false), _tree(patricia_tree_t()) {}

  separate_killgen_domain(const separate_killgen_domain_t &o)
      : _is_top(o._is_top), _tree(o._tree) {}

  separate_killgen_domain_t &operator=(separate_killgen_domain_t o) {
    this->_is_top = o._is_top;
    this->_tree = o._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_top()) {
      CRAB_ERROR("Separate killgen domain: trying to invoke iterator on top");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_top()) {
      CRAB_ERROR("Separate killgen domain: trying to invoke iterator on top");
    } else {
      return this->_tree.end();
    }
  }

  bool is_top() const { return _is_top; }

  bool is_bottom() const { return (!is_top() && _tree.empty()); }

  bool operator<=(separate_killgen_domain_t o) {
    domain_po po;
    return (o.is_top() || (!is_top() && (_tree.leq(o._tree, po))));
  }

  separate_killgen_domain_t operator|(separate_killgen_domain_t o) {
    if (is_top() || o.is_top()) {
      return separate_killgen_domain_t::top();
    } else {
      join_op op;
      bool is_bottom;
      patricia_tree_t res = apply_operation(op, _tree, o._tree, is_bottom);
      return separate_killgen_domain_t(std::move(res));
    }
  }

  separate_killgen_domain_t operator&(separate_killgen_domain_t o) {
    if (is_top()) {
      return o;
    } else if (o.is_top()) {
      return *this;
    } else {
      meet_op op;
      bool is_bottom;
      patricia_tree_t res = apply_operation(op, _tree, o._tree, is_bottom);
      if (is_bottom) {
        return separate_killgen_domain_t::bottom();
      } else {
        return separate_killgen_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!is_top()) {
      // if (v.is_bottom()) {
      //   this->_tree.remove(k);
      // } else {
      //   this->_tree.insert(k, v);
      // }
      this->_tree.insert(k, v);
    }
  }

  separate_killgen_domain_t &operator-=(Key k) {
    if (!is_top()) {
      _tree.remove(k);
    }
    return *this;
  }

  Value operator[](Key k) {
    if (is_top())
      return Value::top();
    else {
      boost::optional<Value> v = _tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::bottom();
      }
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_top()) {
      o << "{...}";
    }
    if (_tree.empty()) {
      o << "_|_";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }
}; // class separate_killgen_domain

template <typename Key, typename Value>
inline crab_os &operator<<(crab_os &o,
                           const separate_killgen_domain<Key, Value> &d) {
  d.write(o);
  return o;
}

} // end namespace domains
} // end namespace crab
<commit_msg>fix(killgen_domain): compilation error<commit_after>#pragma once

/**
 * Specialized domains for kill-gen problems.
 **/

#include <crab/common/debug.hpp>
#include <crab/common/stats.hpp>
#include <crab/domains/discrete_domains.hpp>
#include <crab/domains/patricia_trees.hpp>

#include <boost/optional.hpp>

namespace crab {
namespace domains {

// A wrapper for discrete_domain (i.e,. set of Element)
template <class Element> class flat_killgen_domain {

private:
  typedef flat_killgen_domain<Element> flat_killgen_domain_t;
  typedef ikos::discrete_domain<Element> discrete_domain_t;

public:
  typedef typename discrete_domain_t::iterator iterator;
  typedef Element element_t;

private:
  discrete_domain_t _inv;

public:
  flat_killgen_domain(discrete_domain_t inv) : _inv(inv) {}

  static flat_killgen_domain_t top() {
    return flat_killgen_domain(discrete_domain_t::top());
  }

  static flat_killgen_domain_t bottom() {
    return flat_killgen_domain(discrete_domain_t::bottom());
  }

  flat_killgen_domain() : _inv(discrete_domain_t::bottom()) {}

  flat_killgen_domain(Element e) : _inv(e) {}

  flat_killgen_domain(const flat_killgen_domain_t &o) : _inv(o._inv) {}

  flat_killgen_domain(flat_killgen_domain_t &&o) : _inv(std::move(o._inv)) {}

  flat_killgen_domain_t &operator=(const flat_killgen_domain_t &other) {
    if (this != &other)
      _inv = other._inv;
    return *this;
  }

  flat_killgen_domain_t &operator=(flat_killgen_domain_t &&other) {
    _inv = std::move(other._inv);
    return *this;
  }

  iterator begin() { return _inv.begin(); }

  iterator end() { return _inv.end(); }

  unsigned size() { return _inv.size(); }

  bool is_bottom() { return _inv.is_bottom(); }

  bool is_top() { return _inv.is_top(); }

  bool operator==(flat_killgen_domain_t other) {
    return *this <= other && other <= *this;
  }

  bool operator<=(flat_killgen_domain_t other) {
    if (is_bottom())
      return true;
    else if (other.is_top())
      return true;
    else
      return (_inv <= other._inv);
  }

  void operator-=(Element x) {
    if (is_bottom())
      return;
    _inv -= x;
  }

  void operator-=(flat_killgen_domain_t other) {
    if (is_bottom() || other.is_bottom())
      return;

    if (!other._inv.is_top()) {
      for (auto v : other)
        _inv -= v;
    }
  }

  void operator+=(Element x) {
    if (is_top())
      return;
    _inv += x;
  }

  void operator+=(flat_killgen_domain_t other) {
    if (is_top() || other.is_bottom()) {
      return;
    } else if (other.is_top()) {
      _inv = discrete_domain_t::top();
    } else {
      _inv = (_inv | other._inv);
    }
  }

  flat_killgen_domain_t operator|(flat_killgen_domain_t other) {
    return (_inv | other._inv);
  }

  flat_killgen_domain_t operator&(flat_killgen_domain_t other) {
    return (_inv & other._inv);
  }

  void write(crab_os &o) const { _inv.write(o); }
};

template <typename Elem>
inline crab_os &operator<<(crab_os &o, const flat_killgen_domain<Elem> &d) {
  d.write(o);
  return o;
}

// To represent sets of pairs (Key,Value).
// Bottom means empty set rather than failure.
template <typename Key, typename Value> class separate_killgen_domain {

private:
  typedef ikos::patricia_tree<Key, Value> patricia_tree_t;
  typedef typename patricia_tree_t::unary_op_t unary_op_t;
  typedef typename patricia_tree_t::binary_op_t binary_op_t;
  typedef typename patricia_tree_t::partial_order_t partial_order_t;

public:
  typedef separate_killgen_domain<Key, Value> separate_killgen_domain_t;
  typedef typename patricia_tree_t::iterator iterator;
  typedef Key key_type;
  typedef Value value_type;

private:
  bool _is_top;
  patricia_tree_t _tree;

  static patricia_tree_t apply_operation(binary_op_t &o, patricia_tree_t t1,
                                         patricia_tree_t t2, bool &is_bottom) {
    is_bottom = t1.merge_with(t2, o);
    return t1;
  }

  separate_killgen_domain(patricia_tree_t t) : _is_top(false), _tree(t) {}

  separate_killgen_domain(bool b) : _is_top(b) {}

  class join_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator|(y);
      if (z.is_top()) {
        return {false, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    }
    bool default_is_absorbing() { return false; }
  }; // class join_op

  class meet_op : public binary_op_t {
    std::pair<bool, boost::optional<Value>> apply(Value x, Value y) {
      Value z = x.operator&(y);
      if (z.is_bottom()) {
        return {true, boost::optional<Value>()};
      } else {
        return {false, boost::optional<Value>(z)};
      }
    };
    bool default_is_absorbing() { return true; }
  }; // class meet_op

  class domain_po : public partial_order_t {
    bool leq(Value x, Value y) { return x.operator<=(y); }
    bool default_is_top() { return false; }
  }; // class domain_po

public:
  static separate_killgen_domain_t top() {
    return separate_killgen_domain_t(true);
  }

  static separate_killgen_domain_t bottom() {
    return separate_killgen_domain_t(false);
  }

  separate_killgen_domain() : _is_top(false), _tree(patricia_tree_t()) {}

  separate_killgen_domain(const separate_killgen_domain_t &o)
      : _is_top(o._is_top), _tree(o._tree) {}

  separate_killgen_domain_t &operator=(separate_killgen_domain_t o) {
    this->_is_top = o._is_top;
    this->_tree = o._tree;
    return *this;
  }

  iterator begin() const {
    if (this->is_top()) {
      CRAB_ERROR("Separate killgen domain: trying to invoke iterator on top");
    } else {
      return this->_tree.begin();
    }
  }

  iterator end() const {
    if (this->is_top()) {
      CRAB_ERROR("Separate killgen domain: trying to invoke iterator on top");
    } else {
      return this->_tree.end();
    }
  }

  bool is_top() const { return _is_top; }

  bool is_bottom() const { return (!is_top() && _tree.empty()); }

  bool operator<=(separate_killgen_domain_t o) {
    domain_po po;
    return (o.is_top() || (!is_top() && (_tree.leq(o._tree, po))));
  }

  separate_killgen_domain_t operator|(separate_killgen_domain_t o) {
    if (is_top() || o.is_top()) {
      return separate_killgen_domain_t::top();
    } else {
      join_op op;
      bool is_bottom;
      patricia_tree_t res = apply_operation(op, _tree, o._tree, is_bottom);
      return separate_killgen_domain_t(std::move(res));
    }
  }

  separate_killgen_domain_t operator&(separate_killgen_domain_t o) {
    if (is_top()) {
      return o;
    } else if (o.is_top()) {
      return *this;
    } else {
      meet_op op;
      bool is_bottom;
      patricia_tree_t res = apply_operation(op, _tree, o._tree, is_bottom);
      if (is_bottom) {
        return separate_killgen_domain_t::bottom();
      } else {
        return separate_killgen_domain_t(std::move(res));
      }
    }
  }

  void set(Key k, Value v) {
    if (!is_top()) {
      // if (v.is_bottom()) {
      //   this->_tree.remove(k);
      // } else {
      //   this->_tree.insert(k, v);
      // }
      this->_tree.insert(k, v);
    }
  }

  separate_killgen_domain_t &operator-=(Key k) {
    if (!is_top()) {
      _tree.remove(k);
    }
    return *this;
  }

  Value operator[](Key k) {
    if (is_top())
      return Value::top();
    else {
      boost::optional<Value> v = _tree.lookup(k);
      if (v) {
        return *v;
      } else {
        return Value::bottom();
      }
    }
  }

  void write(crab::crab_os &o) const {
    if (this->is_top()) {
      o << "{...}";
    }
    if (_tree.empty()) {
      o << "{}";
    } else {
      o << "{";
      for (typename patricia_tree_t::iterator it = this->_tree.begin();
           it != this->_tree.end();) {
        Key k = it->first;
        k.write(o);
        o << " -> ";
        Value v = it->second;
        v.write(o);
        ++it;
        if (it != this->_tree.end()) {
          o << "; ";
        }
      }
      o << "}";
    }
  }
}; // class separate_killgen_domain

template <typename Key, typename Value>
inline crab_os &operator<<(crab_os &o,
                           const separate_killgen_domain<Key, Value> &d) {
  d.write(o);
  return o;
}

} // end namespace domains
} // end namespace crab
<|endoftext|>