<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Copyright (C) 2001 by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include "csutil/scf.h"
#include "ivaria/reporter.h"
#include "csgeom/csrect.h"
#include "csutil/cfgacc.h"
#include "xextf86vm.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_FACTORY (csXExtF86VM)

SCF_EXPORT_CLASS_TABLE (xext86vm)
  SCF_EXPORT_CLASS (csXExtF86VM, "crystalspace.window.x.extf86vm",
    "X-Window Shared Memory Extension plugin for Crystal Space")
SCF_EXPORT_CLASS_TABLE_END

SCF_IMPLEMENT_IBASE(csXExtF86VM)
  SCF_IMPLEMENTS_INTERFACE(iXExtF86VM)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csXExtF86VM::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

csXExtF86VM::csXExtF86VM (iBase* parent)
{
  SCF_CONSTRUCT_IBASE (parent);
  SCF_CONSTRUCT_EMBEDDED_IBASE (scfiComponent);
  dpy = NULL;
  screen_num = 0;
  width = height = 0;
  fs_win = wm_win = ctx_win = 0;
}

csXExtF86VM::~csXExtF86VM ()
{

}

bool csXExtF86VM::Initialize (iObjectRegistry *object_reg)
{
  this->object_reg = object_reg;
  csConfigAccess Config(object_reg, "/config/video.cfg");
  full_screen = Config->GetBool ("Video.FullScreen", false);

  return true;
}

void csXExtF86VM::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.window.x.extf86vm", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csXExtF86VM::Open (Display *dpy, int screen_num,
			XVisualInfo *xvis, Colormap cmap)
{
  if (!ctx_win || !wm_win)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "No Windows Set\n");
    return false;
  }

  this->dpy = dpy;
  this->screen_num = screen_num;
  unsigned long cw_fs_mask  = (CWOverrideRedirect |
			       CWBorderPixel |
			       (cmap ? CWColormap : 0));
  XSetWindowAttributes swa;
  memset (&swa, 0, sizeof(swa));
  swa.colormap = cmap;
  swa.override_redirect = True;
  swa.background_pixel = 0;
  swa.border_pixel = 0;
  swa.event_mask = 0;

  fs_win = XCreateWindow (dpy,
			  RootWindow (dpy, screen_num),
			  0, 0, 1, 1,
			  0,
			  xvis->depth,
			  InputOutput,
			  xvis->visual,
			  cw_fs_mask,
			  &swa);

  XStoreName (dpy, fs_win, "Full Screen");
  XSetWindowBackground (dpy, fs_win, BlackPixel (dpy, screen_num));
  XSelectInput (dpy, fs_win, 0);

  if (full_screen)
  {
    full_screen = false;
    EnterFullScreen ();
    return full_screen;
  }
  return true;
}

void csXExtF86VM::Close ()
{
  ctx_win = wm_win = 0;
  if (full_screen)
    LeaveFullScreen ();
  XDestroyWindow (dpy, fs_win);
  fs_win = 0;
}

bool csXExtF86VM::SetFullScreen (bool yesno)
{
  if (!ctx_win)
  {
    // In initialization phase and configuring
    full_screen = yesno;
    return false;
  }
  if (full_screen != yesno)
  {
    if (yesno)
      EnterFullScreen ();
    else
      LeaveFullScreen ();
    return (full_screen == yesno);
  }
  return false;
}

static Bool GetModeInfo (Display *dpy, int scr, XF86VidModeModeInfo *info)
{
  XF86VidModeModeLine *l;

  l = (XF86VidModeModeLine *) ((char *)info + sizeof(info->dotclock));

  return XF86VidModeGetModeLine (dpy, scr, (int *)&info->dotclock, l);
}

void csXExtF86VM::ChangeVideoMode (int zoom)
{
  XF86VidModeLockModeSwitch (dpy, screen_num, false);
  if (XF86VidModeSwitchMode (dpy, screen_num, zoom))
  {
    if (!GetModeInfo (dpy, screen_num, &fs_mode))
      Report (CS_REPORTER_SEVERITY_ERROR, "Unable to retrieve mode info ");
    width = fs_mode.hdisplay;
    height = fs_mode.vdisplay;
    XResizeWindow (dpy, fs_win, fs_mode.hdisplay, fs_mode.vdisplay);
    XF86VidModeSetViewPort(dpy, screen_num, 0, 0);
    Report (CS_REPORTER_SEVERITY_NOTIFY, "%s VIDEOMODE: %d, %d\n",
	    zoom == -1 ? "UP" : "DOWN",
	    width, height);
  }
  XF86VidModeLockModeSwitch (dpy, screen_num, true);
}

static int cmp_modes (const void *va, const void *vb)
{
  XF86VidModeModeInfo *a = *(XF86VidModeModeInfo **) va;
  XF86VidModeModeInfo *b = *(XF86VidModeModeInfo **) vb;

  if (a->hdisplay > b->hdisplay)
    return -1;
  else
    return b->vdisplay - a->vdisplay;
}

void csXExtF86VM::FindBestMode (int ctx_width, int ctx_height)
{
  XF86VidModeModeLine mode;
  XF86VidModeModeInfo **modes;
  int i, nModes, best_mode;
  bool valid = false;
  unsigned int diff;
  unsigned int best_diff = (unsigned int) -1;
  if (XF86VidModeGetModeLine(dpy, screen_num, &i, &mode)
   && XF86VidModeGetAllModeLines (dpy, screen_num, &nModes, &modes))
  {
    qsort (modes, nModes, sizeof (*modes), cmp_modes);

    // find best full screen mode
    for (i = nModes - 1; i >= 0; --i)
    {
      if (modes[i]->hdisplay >= ctx_width && modes[i]->vdisplay >= ctx_height)
      {
        fs_mode = *modes[i];
	valid = true;
        break;
      }
      diff = ctx_width - modes[i]->hdisplay;
      if (diff < best_diff)
	best_mode = i;
    }
    if (!valid)
      fs_mode = *modes[best_mode];

    XFree (modes);
  }
}

bool csXExtF86VM::SwitchMode (XF86VidModeModeInfo *to_mode,
			      XF86VidModeModeInfo *from_mode,
			      bool lock, int vp_x, int vp_y)
{
  XF86VidModeLockModeSwitch (dpy, screen_num, lock);
  if (to_mode->hdisplay != from_mode->hdisplay ||
      to_mode->vdisplay != from_mode->vdisplay)
  {
    if (!XF86VidModeSwitchToMode (dpy, screen_num, to_mode))
    {
      Report (CS_REPORTER_SEVERITY_ERROR, "Unable to restore mode %dx%d",
	      to_mode->hdisplay, to_mode->vdisplay);
      return false;
    }
  }
  XF86VidModeSetViewPort(dpy, screen_num, vp_x, vp_y);
  return true;
}

void csXExtF86VM::EnterFullScreen ()
{
  XWindowAttributes wa;
  // only switch if needed
  if (full_screen)
    return;
  if (!XGetWindowAttributes (dpy, ctx_win, &wa))
    return;

  FindBestMode (wa.width, wa.height);

  printf ("Entering fullscreen: win %d, %d to fs_mode %d, %d\n\n",
	  wa.width, wa.height, fs_mode.hdisplay, fs_mode.vdisplay);

  XResizeWindow (dpy, fs_win, fs_mode.hdisplay, fs_mode.vdisplay);
  XClearWindow (dpy, fs_win);
  XMapRaised (dpy, fs_win);

  // save current display information
  GetModeInfo (dpy, screen_num, &wm_mode);
  XF86VidModeGetViewPort (dpy, screen_num, &viewport_x, &viewport_y);

  // grab pointer and keyboard in fullscreen mode
  if ((XGrabPointer (dpy, fs_win, True,
		    0, GrabModeAsync, GrabModeAsync,
		    fs_win, None, CurrentTime) == GrabSuccess) &&
      (XGrabKeyboard (dpy, wm_win, True, GrabModeAsync,
		      GrabModeAsync, CurrentTime) == GrabSuccess) &&
      SwitchMode (&fs_mode, &wm_mode, true, 0, 0))
  {
    full_screen = true;

    XReparentWindow (dpy, ctx_win, fs_win, 0, 0);
    XWarpPointer (dpy, None, ctx_win,
		  0, 0, 0, 0,
		  fs_mode.hdisplay >> 1,
		  fs_mode.vdisplay >> 1);

    width = fs_mode.hdisplay;
    height = fs_mode.vdisplay;
    Report (CS_REPORTER_SEVERITY_NOTIFY, "FULL SCREEN: %d, %d", width, height);
    XSync (dpy, False);
  }
  else
  {
    XUnmapWindow (dpy, fs_win);
    Report (CS_REPORTER_SEVERITY_ERROR, "Unable to switch mode");
  }
}

void csXExtF86VM::LeaveFullScreen ()
{
  XWindowAttributes wa;
  XF86VidModeModeInfo mode;
  if (!full_screen)
    return;

  GetModeInfo (dpy, screen_num, &mode);

  bool ret = SwitchMode (&wm_mode, &fs_mode, false, viewport_x, viewport_y);
  XUngrabPointer (dpy, CurrentTime);
  XUngrabKeyboard (dpy, CurrentTime);

  if (!ret)
  {
    printf ("Unable to return to windowed mode....aborting\n");
    exit (-1);
  }

  if (wm_win != 0)
  {
    if (!XGetWindowAttributes (dpy, wm_win, &wa))
      return;
    XReparentWindow (dpy, ctx_win, wm_win, 0, 0);
    width = wa.width;
    height = wa.height;
    XWarpPointer (dpy, None, ctx_win,
		  0, 0, 0, 0,
		  wa.width >> 1,
		  wa.height >> 1);
  }
  full_screen = false;
  XUnmapWindow (dpy, fs_win);
  XSync (dpy, False);
}
<commit_msg>Eliminated compilation warning.<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Copyright (C) 2001 by Samuel Humphreys

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include "cssysdef.h"
#include "cssys/sysfunc.h"
#include "csutil/scf.h"
#include "ivaria/reporter.h"
#include "csgeom/csrect.h"
#include "csutil/cfgacc.h"
#include "xextf86vm.h"

CS_IMPLEMENT_PLUGIN

SCF_IMPLEMENT_FACTORY (csXExtF86VM)

SCF_EXPORT_CLASS_TABLE (xext86vm)
  SCF_EXPORT_CLASS (csXExtF86VM, "crystalspace.window.x.extf86vm",
    "X-Window Shared Memory Extension plugin for Crystal Space")
SCF_EXPORT_CLASS_TABLE_END

SCF_IMPLEMENT_IBASE(csXExtF86VM)
  SCF_IMPLEMENTS_INTERFACE(iXExtF86VM)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csXExtF86VM::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

csXExtF86VM::csXExtF86VM (iBase* parent)
{
  SCF_CONSTRUCT_IBASE (parent);
  SCF_CONSTRUCT_EMBEDDED_IBASE (scfiComponent);
  dpy = NULL;
  screen_num = 0;
  width = height = 0;
  fs_win = wm_win = ctx_win = 0;
}

csXExtF86VM::~csXExtF86VM ()
{

}

bool csXExtF86VM::Initialize (iObjectRegistry *object_reg)
{
  this->object_reg = object_reg;
  csConfigAccess Config(object_reg, "/config/video.cfg");
  full_screen = Config->GetBool ("Video.FullScreen", false);

  return true;
}

void csXExtF86VM::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.window.x.extf86vm", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csXExtF86VM::Open (Display *dpy, int screen_num,
			XVisualInfo *xvis, Colormap cmap)
{
  if (!ctx_win || !wm_win)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "No Windows Set\n");
    return false;
  }

  this->dpy = dpy;
  this->screen_num = screen_num;
  unsigned long cw_fs_mask  = (CWOverrideRedirect |
			       CWBorderPixel |
			       (cmap ? CWColormap : 0));
  XSetWindowAttributes swa;
  memset (&swa, 0, sizeof(swa));
  swa.colormap = cmap;
  swa.override_redirect = True;
  swa.background_pixel = 0;
  swa.border_pixel = 0;
  swa.event_mask = 0;

  fs_win = XCreateWindow (dpy,
			  RootWindow (dpy, screen_num),
			  0, 0, 1, 1,
			  0,
			  xvis->depth,
			  InputOutput,
			  xvis->visual,
			  cw_fs_mask,
			  &swa);

  XStoreName (dpy, fs_win, "Full Screen");
  XSetWindowBackground (dpy, fs_win, BlackPixel (dpy, screen_num));
  XSelectInput (dpy, fs_win, 0);

  if (full_screen)
  {
    full_screen = false;
    EnterFullScreen ();
    return full_screen;
  }
  return true;
}

void csXExtF86VM::Close ()
{
  ctx_win = wm_win = 0;
  if (full_screen)
    LeaveFullScreen ();
  XDestroyWindow (dpy, fs_win);
  fs_win = 0;
}

bool csXExtF86VM::SetFullScreen (bool yesno)
{
  if (!ctx_win)
  {
    // In initialization phase and configuring
    full_screen = yesno;
    return false;
  }
  if (full_screen != yesno)
  {
    if (yesno)
      EnterFullScreen ();
    else
      LeaveFullScreen ();
    return (full_screen == yesno);
  }
  return false;
}

static Bool GetModeInfo (Display *dpy, int scr, XF86VidModeModeInfo *info)
{
  XF86VidModeModeLine *l;

  l = (XF86VidModeModeLine *) ((char *)info + sizeof(info->dotclock));

  return XF86VidModeGetModeLine (dpy, scr, (int *)&info->dotclock, l);
}

void csXExtF86VM::ChangeVideoMode (int zoom)
{
  XF86VidModeLockModeSwitch (dpy, screen_num, false);
  if (XF86VidModeSwitchMode (dpy, screen_num, zoom))
  {
    if (!GetModeInfo (dpy, screen_num, &fs_mode))
      Report (CS_REPORTER_SEVERITY_ERROR, "Unable to retrieve mode info ");
    width = fs_mode.hdisplay;
    height = fs_mode.vdisplay;
    XResizeWindow (dpy, fs_win, fs_mode.hdisplay, fs_mode.vdisplay);
    XF86VidModeSetViewPort(dpy, screen_num, 0, 0);
    Report (CS_REPORTER_SEVERITY_NOTIFY, "%s VIDEOMODE: %d, %d\n",
	    zoom == -1 ? "UP" : "DOWN",
	    width, height);
  }
  XF86VidModeLockModeSwitch (dpy, screen_num, true);
}

static int cmp_modes (const void *va, const void *vb)
{
  XF86VidModeModeInfo *a = *(XF86VidModeModeInfo **) va;
  XF86VidModeModeInfo *b = *(XF86VidModeModeInfo **) vb;

  if (a->hdisplay > b->hdisplay)
    return -1;
  else
    return b->vdisplay - a->vdisplay;
}

void csXExtF86VM::FindBestMode (int ctx_width, int ctx_height)
{
  XF86VidModeModeLine mode;
  XF86VidModeModeInfo **modes;
  int i, nModes, best_mode = 0;
  bool valid = false;
  unsigned int diff;
  unsigned int best_diff = (unsigned int) -1;
  if (XF86VidModeGetModeLine(dpy, screen_num, &i, &mode)
   && XF86VidModeGetAllModeLines (dpy, screen_num, &nModes, &modes))
  {
    qsort (modes, nModes, sizeof (*modes), cmp_modes);

    // find best full screen mode
    for (i = nModes - 1; i >= 0; --i)
    {
      if (modes[i]->hdisplay >= ctx_width && modes[i]->vdisplay >= ctx_height)
      {
        fs_mode = *modes[i];
	valid = true;
        break;
      }
      diff = ctx_width - modes[i]->hdisplay;
      if (diff < best_diff)
	best_mode = i;
    }
    if (!valid)
      fs_mode = *modes[best_mode];

    XFree (modes);
  }
}

bool csXExtF86VM::SwitchMode (XF86VidModeModeInfo *to_mode,
			      XF86VidModeModeInfo *from_mode,
			      bool lock, int vp_x, int vp_y)
{
  XF86VidModeLockModeSwitch (dpy, screen_num, lock);
  if (to_mode->hdisplay != from_mode->hdisplay ||
      to_mode->vdisplay != from_mode->vdisplay)
  {
    if (!XF86VidModeSwitchToMode (dpy, screen_num, to_mode))
    {
      Report (CS_REPORTER_SEVERITY_ERROR, "Unable to restore mode %dx%d",
	      to_mode->hdisplay, to_mode->vdisplay);
      return false;
    }
  }
  XF86VidModeSetViewPort(dpy, screen_num, vp_x, vp_y);
  return true;
}

void csXExtF86VM::EnterFullScreen ()
{
  XWindowAttributes wa;
  // only switch if needed
  if (full_screen)
    return;
  if (!XGetWindowAttributes (dpy, ctx_win, &wa))
    return;

  FindBestMode (wa.width, wa.height);

  printf ("Entering fullscreen: win %d, %d to fs_mode %d, %d\n\n",
	  wa.width, wa.height, fs_mode.hdisplay, fs_mode.vdisplay);

  XResizeWindow (dpy, fs_win, fs_mode.hdisplay, fs_mode.vdisplay);
  XClearWindow (dpy, fs_win);
  XMapRaised (dpy, fs_win);

  // save current display information
  GetModeInfo (dpy, screen_num, &wm_mode);
  XF86VidModeGetViewPort (dpy, screen_num, &viewport_x, &viewport_y);

  // grab pointer and keyboard in fullscreen mode
  if ((XGrabPointer (dpy, fs_win, True,
		    0, GrabModeAsync, GrabModeAsync,
		    fs_win, None, CurrentTime) == GrabSuccess) &&
      (XGrabKeyboard (dpy, wm_win, True, GrabModeAsync,
		      GrabModeAsync, CurrentTime) == GrabSuccess) &&
      SwitchMode (&fs_mode, &wm_mode, true, 0, 0))
  {
    full_screen = true;

    XReparentWindow (dpy, ctx_win, fs_win, 0, 0);
    XWarpPointer (dpy, None, ctx_win,
		  0, 0, 0, 0,
		  fs_mode.hdisplay >> 1,
		  fs_mode.vdisplay >> 1);

    width = fs_mode.hdisplay;
    height = fs_mode.vdisplay;
    Report (CS_REPORTER_SEVERITY_NOTIFY, "FULL SCREEN: %d, %d", width, height);
    XSync (dpy, False);
  }
  else
  {
    XUnmapWindow (dpy, fs_win);
    Report (CS_REPORTER_SEVERITY_ERROR, "Unable to switch mode");
  }
}

void csXExtF86VM::LeaveFullScreen ()
{
  XWindowAttributes wa;
  XF86VidModeModeInfo mode;
  if (!full_screen)
    return;

  GetModeInfo (dpy, screen_num, &mode);

  bool ret = SwitchMode (&wm_mode, &fs_mode, false, viewport_x, viewport_y);
  XUngrabPointer (dpy, CurrentTime);
  XUngrabKeyboard (dpy, CurrentTime);

  if (!ret)
  {
    printf ("Unable to return to windowed mode....aborting\n");
    exit (-1);
  }

  if (wm_win != 0)
  {
    if (!XGetWindowAttributes (dpy, wm_win, &wa))
      return;
    XReparentWindow (dpy, ctx_win, wm_win, 0, 0);
    width = wa.width;
    height = wa.height;
    XWarpPointer (dpy, None, ctx_win,
		  0, 0, 0, 0,
		  wa.width >> 1,
		  wa.height >> 1);
  }
  full_screen = false;
  XUnmapWindow (dpy, fs_win);
  XSync (dpy, False);
}
<|endoftext|>


<commit_before>#include "сomplex_t.hpp"
complex_t::complex_t() : real(0.0), image(0.0)
{}
complex_t::complex_t(double r, double im) : real(r), image(im)
{}
complex_t::complex_t(const complex_t&copy)
{
	real = copy.real;
	image = copy.image;
}
double complex_t::real_() const
{
	return real;
}

double complex_t::image_() const
{
	return image;
}
bool complex_t::operator == (const complex_t& m2) const
{
	if ((real == m2.real) && (image == m2.image))
		return true;
}

complex_t complex_t::operator = (const complex_t& result)
{
	if (this != &result)
	{
	real = result.real;
	image = result.image;
	return *this;
	}

}

istream& operator >> (istream& is, complex_t& result)
{
	cout << "Please enter real complex part:" << endl;
	is >> result.real;
	cout << "Please enter imaginary complex part:" << endl;
	is >> result.image;
	cout << endl;
	return is;
}

ostream& operator << (ostream& os,const complex_t& result)
{
	if (result.image < 0)
	{
		os << result.real << result.image << "i" << endl;
	}
	else
		os << result.real << "+" << result.image << "i" << endl;
	return os;
}

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

complex_t complex_t::operator * (const complex_t& m2) const
{
	return complex_t(real*m2.real - image*m2.image, real*m2.image + m2.real*image);
}

complex_t complex_t::operator / (const complex_t& m2) const
{
	return complex_t((real*m2.real + image*m2.image) / (m2.real*m2.real + m2.image*m2.image), (m2.real*image - real*m2.image) / (m2.real*m2.real + m2.image*m2.image));
}

complex_t complex_t::operator += (const complex_t& m2)
{
	real += m2.real;
	image += m2.image;
	return *this;
}

complex_t complex_t::operator -= (const complex_t& m2)
{
	real -= m2.real;
	image -= m2.image;
	return *this;
}

complex_t complex_t::operator /= (const complex_t& m2)
{
	float real_ = (real*m2.real + image*m2.image) / (m2.real*m2.real + m2.image*m2.image);
	image = (m2.real*image - real*m2.image) / (m2.real*m2.real + m2.image*m2.image);
	real = real_;
	return *this;
}

complex_t complex_t::operator *= (const complex_t& m2)
{
	float real_ = real*m2.real - image*m2.image;
	image = real*m2.image + m2.real*image;
	real = real_;
	return *this;
}
<commit_msg>Update сomplex_t.cpp<commit_after>#include "iteratorsort.hpp"
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "HTMLAnchorElementImp.h"

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

#include "utf.h"

namespace org
{
namespace w3c
{
namespace dom
{
namespace bootstrap
{

HTMLAnchorElementImp::HTMLAnchorElementImp(HTMLAnchorElementImp* org, bool deep) :
    ObjectMixin(org, deep),
    clickListener(boost::bind(&HTMLAnchorElementImp::handleClick, this, _1))
{
    addEventListener(u"click", &clickListener);
}

HTMLAnchorElementImp::HTMLAnchorElementImp(DocumentImp* ownerDocument) :
    ObjectMixin(ownerDocument, u"a"),
    clickListener(boost::bind(&HTMLAnchorElementImp::handleClick, this, _1))
{
    addEventListener(u"click", &clickListener);
}

HTMLAnchorElementImp::~HTMLAnchorElementImp()
{
}

void HTMLAnchorElementImp::handleClick(events::Event event)
{
    if (event.getDefaultPrevented())
        return;
    std::u16string href = getHref();
    if (!href.empty())
        getOwnerDocument().setLocation(href);
}

std::u16string HTMLAnchorElementImp::getHref()
{
    return getAttribute(u"href");
}

void HTMLAnchorElementImp::setHref(std::u16string href)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getTarget()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setTarget(std::u16string target)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPing()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPing(std::u16string ping)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getRel()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setRel(std::u16string rel)
{
    // TODO: implement me!
}

DOMTokenList HTMLAnchorElementImp::getRelList()
{
    // TODO: implement me!
    return static_cast<Object*>(0);
}

std::u16string HTMLAnchorElementImp::getMedia()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setMedia(std::u16string media)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHreflang()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHreflang(std::u16string hreflang)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getType()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setType(std::u16string type)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getText()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setText(std::u16string text)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getProtocol()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setProtocol(std::u16string protocol)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHost()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHost(std::u16string host)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHostname()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHostname(std::u16string hostname)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPort()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPort(std::u16string port)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPathname()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPathname(std::u16string pathname)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getSearch()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setSearch(std::u16string search)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHash()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHash(std::u16string hash)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getCoords()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setCoords(std::u16string coords)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getCharset()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setCharset(std::u16string charset)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getName()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setName(std::u16string name)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getRev()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setRev(std::u16string rev)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getShape()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setShape(std::u16string shape)
{
    // TODO: implement me!
}

}
}
}
}
<commit_msg>(HTMLAnchorElementImp::handleClick) : Check click by the primary button only.<commit_after>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "HTMLAnchorElementImp.h"

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

#include <org/w3c/dom/events/MouseEvent.h>

#include "utf.h"

namespace org
{
namespace w3c
{
namespace dom
{
namespace bootstrap
{

HTMLAnchorElementImp::HTMLAnchorElementImp(HTMLAnchorElementImp* org, bool deep) :
    ObjectMixin(org, deep),
    clickListener(boost::bind(&HTMLAnchorElementImp::handleClick, this, _1))
{
    addEventListener(u"click", &clickListener);
}

HTMLAnchorElementImp::HTMLAnchorElementImp(DocumentImp* ownerDocument) :
    ObjectMixin(ownerDocument, u"a"),
    clickListener(boost::bind(&HTMLAnchorElementImp::handleClick, this, _1))
{
    addEventListener(u"click", &clickListener);
}

HTMLAnchorElementImp::~HTMLAnchorElementImp()
{
}

void HTMLAnchorElementImp::handleClick(events::Event event)
{
    if (event.getDefaultPrevented())
        return;
    events::MouseEvent mouse = interface_cast<events::MouseEvent>(event);
    std::u16string href = getHref();
    if (!href.empty() && mouse.getButton() == 0)
        getOwnerDocument().setLocation(href);
}

std::u16string HTMLAnchorElementImp::getHref()
{
    return getAttribute(u"href");
}

void HTMLAnchorElementImp::setHref(std::u16string href)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getTarget()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setTarget(std::u16string target)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPing()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPing(std::u16string ping)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getRel()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setRel(std::u16string rel)
{
    // TODO: implement me!
}

DOMTokenList HTMLAnchorElementImp::getRelList()
{
    // TODO: implement me!
    return static_cast<Object*>(0);
}

std::u16string HTMLAnchorElementImp::getMedia()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setMedia(std::u16string media)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHreflang()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHreflang(std::u16string hreflang)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getType()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setType(std::u16string type)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getText()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setText(std::u16string text)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getProtocol()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setProtocol(std::u16string protocol)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHost()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHost(std::u16string host)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHostname()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHostname(std::u16string hostname)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPort()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPort(std::u16string port)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getPathname()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setPathname(std::u16string pathname)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getSearch()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setSearch(std::u16string search)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getHash()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setHash(std::u16string hash)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getCoords()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setCoords(std::u16string coords)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getCharset()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setCharset(std::u16string charset)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getName()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setName(std::u16string name)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getRev()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setRev(std::u16string rev)
{
    // TODO: implement me!
}

std::u16string HTMLAnchorElementImp::getShape()
{
    // TODO: implement me!
    return u"";
}

void HTMLAnchorElementImp::setShape(std::u16string shape)
{
    // TODO: implement me!
}

}
}
}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "passes.h"
#include "resolveIntents.h"

bool intentsResolved = false;

static IntentTag constIntentForType(Type* t) {
#if 1
  // TODO: After some discussion, we are leaning toward reverting this change
  // and instead changing the specified intent on extern procs to "in" for
  // structs passed by value to extern routines written in C.
  if (t->symbol->hasFlag(FLAG_EXTERN)) {
    // Now that we respect ref, we don't want to convert
    //  extern record S { var x,y : int; }
    //  extern proc foo(s:S) : void ;
    // into
    //  void foo(S const * s);
    // We put this case first, so instead we get
    //  void foo(S const s);
    // by avoiding the case for "isRecord(t)" below.
    return INTENT_CONST_IN;
  }
#endif
  else if (isSyncType(t) ||
      isRecordWrappedType(t) ||  // domain, array, or distribution
      isRecord(t)) { // may eventually want to decide based on size
    return INTENT_CONST_REF;
  } else if (is_bool_type(t) ||
             is_int_type(t) ||
             is_uint_type(t) ||
             is_real_type(t) ||
             is_imag_type(t) ||
             is_complex_type(t) ||
             is_enum_type(t) ||
             isClass(t) ||
             isUnion(t) ||
             isAtomicType(t) ||
             t == dtOpaque ||
             t == dtTaskID ||
             t == dtFile ||
             t == dtTaskList ||
             t == dtNil ||
             t == dtStringC ||
             t == dtStringCopy ||
             t->symbol->hasFlag(FLAG_EXTERN)) {
    return INTENT_CONST_IN;
  }
  INT_FATAL(t, "Unhandled type in constIntentForType()");
  return INTENT_CONST;
}

IntentTag blankIntentForType(Type* t) {
  if (isSyncType(t) ||
      isAtomicType(t) ||
      t->symbol->hasFlag(FLAG_ARRAY)) {
    return INTENT_REF;
  } else if (is_bool_type(t) ||
             is_int_type(t) ||
             is_uint_type(t) ||
             is_real_type(t) ||
             is_imag_type(t) ||
             is_complex_type(t) ||
             is_enum_type(t) ||
             t == dtStringC ||
             t == dtStringCopy ||
             isClass(t) ||
             isRecord(t) ||
             isUnion(t) ||
             t == dtTaskID ||
             t == dtFile ||
             t == dtTaskList ||
             t == dtNil ||
             t == dtOpaque ||
             t->symbol->hasFlag(FLAG_DOMAIN) ||
             t->symbol->hasFlag(FLAG_DISTRIBUTION) ||
             t->symbol->hasFlag(FLAG_EXTERN)) {
    return constIntentForType(t);
  }
  INT_FATAL(t, "Unhandled type in blankIntentForType()");
  return INTENT_BLANK;
}

IntentTag concreteIntent(IntentTag existingIntent, Type* t) {
  if (existingIntent == INTENT_BLANK) {
    return blankIntentForType(t);
  } else if (existingIntent == INTENT_CONST) {
    return constIntentForType(t);
  } else {
    return existingIntent;
  }
}

static IntentTag blankIntentForThisArg(Type* t) {
  // todo: be honest when 't' is an array or domain
  return INTENT_CONST_IN;
}

void resolveArgIntent(ArgSymbol* arg) {
  arg->intent =
    arg->hasFlag(FLAG_ARG_THIS) && arg->intent == INTENT_BLANK ?
    blankIntentForThisArg(arg->type) :
    concreteIntent(arg->intent, arg->type);
}

// In Chapel, there is only one reference level: there are no references to
// references (ignoring the wide case and class variables for simplicity).
// This routine adjusts the type of the argument to match the REF flag of its
// concrete intent, which in turn controls how the argument is passed in the
// generated code.
//
// Application of this function to various arguments will temporarily violate
// the invariant that the types of formal and actual arguments match.  The calls
// to insertReferenceTemps() and insertDerefTemps() will correct that.
static void adjustRefLevel(ArgSymbol* arg)
{
  if (arg->intent & INTENT_FLAG_REF)
  {
    // This conditional is only present for debugging purposes.
    // It may be removed when this change-of-type seems obvious.
    Type* t = arg->type;

    // There is only one level of referencing in Chapel, so of this arg is
    // already a ref type, we are done.
    if (t->symbol->hasFlag(FLAG_REF))
      return;

    // Type arguments are always passed by "value".
    if (t->symbol->hasFlag(FLAG_TYPE_VARIABLE))
      return;

    // Do not do this for record-wrapped types, because somewhere else we
    // believe that RWTs should always be passed around by value(!?)
    if (isRecordWrappedType(t))
        return;

    // This argument wants to be passed by ref.
    // But is not.  Let's fix that.
    INT_ASSERT(arg->type->refType);
    arg->type = arg->type->refType;
  }
}

void resolveIntents() {
  forv_Vec(ArgSymbol, arg, gArgSymbols) {
    resolveArgIntent(arg);
    adjustRefLevel(arg);
  }
  insertReferenceTemps();
  insertDerefTemps();
  intentsResolved = true;
}
<commit_msg>Respect Chapel intents in extern proc declarations.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "passes.h"
#include "resolveIntents.h"

bool intentsResolved = false;

static IntentTag constIntentForType(Type* t) {
  if (isSyncType(t) ||
      isRecordWrappedType(t) ||  // domain, array, or distribution
      isRecord(t)) { // may eventually want to decide based on size
    return INTENT_CONST_REF;
  } else if (is_bool_type(t) ||
             is_int_type(t) ||
             is_uint_type(t) ||
             is_real_type(t) ||
             is_imag_type(t) ||
             is_complex_type(t) ||
             is_enum_type(t) ||
             isClass(t) ||
             isUnion(t) ||
             isAtomicType(t) ||
             t == dtOpaque ||
             t == dtTaskID ||
             t == dtFile ||
             t == dtTaskList ||
             t == dtNil ||
             t == dtStringC ||
             t == dtStringCopy ||
             t->symbol->hasFlag(FLAG_EXTERN)) {
    return INTENT_CONST_IN;
  }
  INT_FATAL(t, "Unhandled type in constIntentForType()");
  return INTENT_CONST;
}

IntentTag blankIntentForType(Type* t) {
  if (isSyncType(t) ||
      isAtomicType(t) ||
      t->symbol->hasFlag(FLAG_ARRAY)) {
    return INTENT_REF;
  } else if (is_bool_type(t) ||
             is_int_type(t) ||
             is_uint_type(t) ||
             is_real_type(t) ||
             is_imag_type(t) ||
             is_complex_type(t) ||
             is_enum_type(t) ||
             t == dtStringC ||
             t == dtStringCopy ||
             isClass(t) ||
             isRecord(t) ||
             isUnion(t) ||
             t == dtTaskID ||
             t == dtFile ||
             t == dtTaskList ||
             t == dtNil ||
             t == dtOpaque ||
             t->symbol->hasFlag(FLAG_DOMAIN) ||
             t->symbol->hasFlag(FLAG_DISTRIBUTION) ||
             t->symbol->hasFlag(FLAG_EXTERN)) {
    return constIntentForType(t);
  }
  INT_FATAL(t, "Unhandled type in blankIntentForType()");
  return INTENT_BLANK;
}

IntentTag concreteIntent(IntentTag existingIntent, Type* t) {
  if (existingIntent == INTENT_BLANK) {
    return blankIntentForType(t);
  } else if (existingIntent == INTENT_CONST) {
    return constIntentForType(t);
  } else {
    return existingIntent;
  }
}

static IntentTag blankIntentForThisArg(Type* t) {
  // todo: be honest when 't' is an array or domain
  return INTENT_CONST_IN;
}

void resolveArgIntent(ArgSymbol* arg) {
  arg->intent =
    arg->hasFlag(FLAG_ARG_THIS) && arg->intent == INTENT_BLANK ?
    blankIntentForThisArg(arg->type) :
    concreteIntent(arg->intent, arg->type);
}

// In Chapel, there is only one reference level: there are no references to
// references (ignoring the wide case and class variables for simplicity).
// This routine adjusts the type of the argument to match the REF flag of its
// concrete intent, which in turn controls how the argument is passed in the
// generated code.
//
// Application of this function to various arguments will temporarily violate
// the invariant that the types of formal and actual arguments match.  The calls
// to insertReferenceTemps() and insertDerefTemps() will correct that.
static void adjustRefLevel(ArgSymbol* arg)
{
  if (arg->intent & INTENT_FLAG_REF)
  {
    // This conditional is only present for debugging purposes.
    // It may be removed when this change-of-type seems obvious.
    Type* t = arg->type;

    // There is only one level of referencing in Chapel, so of this arg is
    // already a ref type, we are done.
    if (t->symbol->hasFlag(FLAG_REF))
      return;

    // Type arguments are always passed by "value".
    if (t->symbol->hasFlag(FLAG_TYPE_VARIABLE))
      return;

    // Do not do this for record-wrapped types, because somewhere else we
    // believe that RWTs should always be passed around by value(!?)
    if (isRecordWrappedType(t))
        return;

    // This argument wants to be passed by ref.
    // But is not.  Let's fix that.
    INT_ASSERT(arg->type->refType);
    arg->type = arg->type->refType;
  }
}

void resolveIntents() {
  forv_Vec(ArgSymbol, arg, gArgSymbols) {
    resolveArgIntent(arg);
    adjustRefLevel(arg);
  }
  insertReferenceTemps();
  insertDerefTemps();
  intentsResolved = true;
}
<|endoftext|>


<commit_before>/*******************************
Copyright (C) 2013-2016 gregoire ANGERAND

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

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
**********************************/

#include "ShaderModuleBase.h"

#include <yave/Device.h>

#include <spirv_cross/spirv.hpp>
#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>

namespace yave {

template<typename M>
static void merge(M& into, const M& o) {
	into.insert(o.begin(), o.end());
}

static vk::ShaderModule create_shader_module(DevicePtr dptr, const SpirVData& data) {
	if(data.is_empty()) {
		return VK_NULL_HANDLE;
	}
	return dptr->vk_device().createShaderModule(vk::ShaderModuleCreateInfo()
			.setCodeSize(data.size())
			.setPCode(data.data())
		);
}

static ShaderType module_type(const spirv_cross::CompilerGLSL& compiler) {
	switch(compiler.get_execution_model()) {
		case spv::ExecutionModelVertex:
			return ShaderType::Vertex;
		case spv::ExecutionModelFragment:
			return ShaderType::Fragment;
		case spv::ExecutionModelGeometry:
			return ShaderType::Geomery;

		case spv::ExecutionModelGLCompute:
		case spv::ExecutionModelKernel:
			return ShaderType::Compute;

		default:
			break;
	}
	return fatal("Unknown shader execution model");
}

static vk::DescriptorSetLayoutBinding create_binding(u32 index, ShaderType, vk::DescriptorType type) {
	return vk::DescriptorSetLayoutBinding()
			.setBinding(index)
			.setDescriptorCount(1)
			.setDescriptorType(type)
			.setStageFlags(vk::ShaderStageFlagBits::eAll)
		;
}

static auto create_bindings(const spirv_cross::CompilerGLSL& compiler, const std::vector<spirv_cross::Resource>& resources, ShaderType shader_type, vk::DescriptorType type) {
	auto bindings = std::unordered_map<u32, core::Vector<vk::DescriptorSetLayoutBinding>>();
	for(auto r : resources) {
		auto id = r.id;
		bindings[compiler.get_decoration(id, spv::DecorationDescriptorSet)] << create_binding(compiler.get_decoration(id, spv::DecorationBinding), shader_type, type);
	}
	return bindings;
}

ShaderModuleBase::ShaderModuleBase(DevicePtr dptr, const SpirVData& data) : DeviceLinked(dptr), _module(create_shader_module(dptr, data)) {
	spirv_cross::CompilerGLSL compiler(std::vector<u32>(data.data(), data.data() + data.size() / 4));

	_type = module_type(compiler);

	auto resources = compiler.get_shader_resources();
	merge(_bindings, create_bindings(compiler, resources.uniform_buffers, _type, vk::DescriptorType::eUniformBuffer));
	merge(_bindings, create_bindings(compiler, resources.sampled_images, _type, vk::DescriptorType::eCombinedImageSampler));
}

vk::ShaderModule ShaderModuleBase::vk_shader_module() const {
	return _module;
}

ShaderModuleBase::~ShaderModuleBase() {
	destroy(_module);
}

void ShaderModuleBase::swap(ShaderModuleBase& other) {
	DeviceLinked::swap(other);
	std::swap(_module, other._module);
}

}
<commit_msg>Shader support for storage buffer.<commit_after>/*******************************
Copyright (C) 2013-2016 gregoire ANGERAND

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

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
**********************************/

#include "ShaderModuleBase.h"

#include <yave/Device.h>

#include <spirv_cross/spirv.hpp>
#include <spirv_cross/spirv_cross.hpp>
#include <spirv_cross/spirv_glsl.hpp>

namespace yave {

template<typename M>
static void merge(M& into, const M& o) {
	into.insert(o.begin(), o.end());
}

static vk::ShaderModule create_shader_module(DevicePtr dptr, const SpirVData& data) {
	if(data.is_empty()) {
		return VK_NULL_HANDLE;
	}
	return dptr->vk_device().createShaderModule(vk::ShaderModuleCreateInfo()
			.setCodeSize(data.size())
			.setPCode(data.data())
		);
}

static ShaderType module_type(const spirv_cross::CompilerGLSL& compiler) {
	switch(compiler.get_execution_model()) {
		case spv::ExecutionModelVertex:
			return ShaderType::Vertex;
		case spv::ExecutionModelFragment:
			return ShaderType::Fragment;
		case spv::ExecutionModelGeometry:
			return ShaderType::Geomery;

		case spv::ExecutionModelGLCompute:
		case spv::ExecutionModelKernel:
			return ShaderType::Compute;

		default:
			break;
	}
	return fatal("Unknown shader execution model");
}

static vk::DescriptorSetLayoutBinding create_binding(u32 index, ShaderType, vk::DescriptorType type) {
	return vk::DescriptorSetLayoutBinding()
			.setBinding(index)
			.setDescriptorCount(1)
			.setDescriptorType(type)
			.setStageFlags(vk::ShaderStageFlagBits::eAll)
		;
}

static auto create_bindings(const spirv_cross::CompilerGLSL& compiler, const std::vector<spirv_cross::Resource>& resources, ShaderType shader_type, vk::DescriptorType type) {
	auto bindings = std::unordered_map<u32, core::Vector<vk::DescriptorSetLayoutBinding>>();
	for(auto r : resources) {
		auto id = r.id;
		bindings[compiler.get_decoration(id, spv::DecorationDescriptorSet)] << create_binding(compiler.get_decoration(id, spv::DecorationBinding), shader_type, type);
	}
	return bindings;
}

static void fail_not_empty(const std::vector<spirv_cross::Resource>& res) {
	if(!res.empty()) {
		fatal("Unsupported resource type");
	}
}

ShaderModuleBase::ShaderModuleBase(DevicePtr dptr, const SpirVData& data) : DeviceLinked(dptr), _module(create_shader_module(dptr, data)) {
	spirv_cross::CompilerGLSL compiler(std::vector<u32>(data.data(), data.data() + data.size() / 4));

	_type = module_type(compiler);

	auto resources = compiler.get_shader_resources();
	merge(_bindings, create_bindings(compiler, resources.uniform_buffers, _type, vk::DescriptorType::eUniformBuffer));
	merge(_bindings, create_bindings(compiler, resources.storage_buffers, _type, vk::DescriptorType::eStorageBuffer));
	merge(_bindings, create_bindings(compiler, resources.sampled_images, _type, vk::DescriptorType::eCombinedImageSampler));

	// these are attribs & other stages stuff
	/*fail_not_empty(resources.stage_inputs);
	fail_not_empty(resources.stage_outputs);
	fail_not_empty(resources.subpass_inputs);*/

	fail_not_empty(resources.storage_images);
	fail_not_empty(resources.atomic_counters);
	fail_not_empty(resources.push_constant_buffers);
	fail_not_empty(resources.separate_images);
	fail_not_empty(resources.separate_samplers);
}

vk::ShaderModule ShaderModuleBase::vk_shader_module() const {
	return _module;
}

ShaderModuleBase::~ShaderModuleBase() {
	destroy(_module);
}

void ShaderModuleBase::swap(ShaderModuleBase& other) {
	DeviceLinked::swap(other);
	std::swap(_module, other._module);
}

}
<|endoftext|>


<commit_before>//
//  yl_table.cpp
//
//  Created by Edmund Kapusniak on 21/04/2015.
//  Copyright (c) 2015 Edmund Kapusniak. All rights reserved.
//

#include "yl_table.h"
#include <intmath.h>
#include "yl_function.h"

yl_bucketlist::bucket::bucket()
    :   next( YL_EMPTY_BUCKET )
{
}

yl_bucketlist* yl_bucketlist::alloc( size_t size )
{
    size_t s = sizeof( yl_bucketlist ) + sizeof( bucket ) * size;
    void* p = yl_current->malloc( s );
    return new ( p ) yl_bucketlist( size );
}

yl_bucketlist::yl_bucketlist( size_t size )
    :   yl_heapobj( YLOBJ_BUCKETLIST )
    ,   _size( size )
{
    for ( size_t i = 0; i < _size; ++i )
    {
        new ( _elements + i ) bucket();
    }
}

yl_bucketlist::~yl_bucketlist()
{
    for ( size_t i = 0; i < _size; ++i )
    {
        _elements[ i ].~bucket();
    }
}

size_t yl_bucketlist::size() const
{
    return _size;
}

const yl_bucketlist::bucket& yl_bucketlist::at( size_t index ) const
{
    assert( index < _size );
    return _elements[ index ];
}

yl_bucketlist::bucket& yl_bucketlist::at( size_t index )
{
    assert( index < _size );
    return _elements[ index ];
}

yl_table* yl_table::alloc( size_t capacity )
{
    return alloc( yl_current->proto_table(), capacity );
}

yl_table* yl_table::alloc( yl_object* prototype, size_t capacity )
{
    void* p = yl_current->malloc( sizeof( yl_table ) );
    return new ( p ) yl_table( prototype, capacity );
}

yl_table::yl_table( yl_object* prototype, size_t capacity )
    :   yl_object( YLOBJ_TABLE, prototype )
    ,   _occupancy( 0 )
    ,   _buckets( capacity ? yl_bucketlist::alloc( capacity ) : nullptr )
{
}

yl_value yl_table::get_index( yl_value key ) const
{
    bucket* b = lookup( key );
    if ( b )
    {
        return b->value.get();
    }
    else
    {
        return yl_undef;
    }
}

void yl_table::set_index( yl_value key, yl_value value )
{
    // Lookup in case key already exists.
    bucket* b = lookup( key );
    if ( b )
    {
        b->value.set( value );
        return;
    }

    // Grow hash if necessary.
    yl_bucketlist* buckets = _buckets.get();
    size_t capacity = buckets ? buckets->size() : 0;
    if ( _occupancy >= capacity - ( capacity >> 3 ) )
    {
        rehash( _occupancy + ( _occupancy / 7 ) + 1  );
    }

    // Occupancy will increase.
    _occupancy += 1;

    // Check if element can be placed in its main position.
    bucket* insert = main_position( key );
    if ( insert->next == YL_EMPTY_BUCKET )
    {
        insert->key.set( key );
        insert->value.set( value );
        insert->next = nullptr;
        return;
    }

    // Bucket is not empty.  Find main position of occupying element.
    bucket* cuckoo = main_position( insert->key.get() );

    // The only way that the occupying element is blocking us is if its main
    // position is occupied, either by itself or another element.
    assert( cuckoo->next != YL_EMPTY_BUCKET );

    // Find free bucket near the main position of the occupying element.
    bucket* free = free_position( cuckoo );
    assert( free->next == YL_EMPTY_BUCKET );

    if ( cuckoo == insert )
    {
        // Hash collision, as both the occupying element and the new one
        // hash to the same bucket.  Place new element in the free position
        // and link it into the list.

        free->key.set( key );
        free->value.set( value );
        free->next = insert->next;
        insert->next = free;
    }
    else
    {
        // The occupying element (stored in insert) isn't in its main position.
        // It's part of the linked list starting at cuckoo.  Move the occupying
        // element in insert to the free bucket, and replace insert with free
        // in the linked list starting from cuckoo.

        free->key.set( insert->key.get() );
        free->value.set( insert->value.get() );

        bucket* previous = cuckoo;
        while ( previous->next != insert )
        {
            previous = previous->next;
        }
        previous->next = free;
        free->next = insert->next;

        // Now insert is free to hold our inserted element.
        insert->key.set( key );
        insert->value.set( value );
        insert->next = nullptr;
    }

}

yl_bucketlist::bucket* yl_table::lookup( yl_value key ) const
{
    // Check for value in main position.
    bucket* lookup = main_position( key );
    if ( lookup && lookup->next == YL_EMPTY_BUCKET )
    {
        return nullptr;
    }

    // Follow linked list of buckets from main position.
    for ( ; lookup; lookup = lookup->next )
    {
        if ( equal( lookup->key.get(), key ) )
        {
            return lookup;
        }
    }

    // Not found.
    return nullptr;
}

yl_bucketlist::bucket* yl_table::main_position( yl_value key ) const
{
    yl_bucketlist* buckets = _buckets.get();
    if ( buckets && buckets->size() )
    {
        return &buckets->at( hash( key ) % buckets->size() );
    }
    else
    {
        return nullptr;
    }
}

yl_bucketlist::bucket* yl_table::free_position( bucket* near )
{
    yl_bucketlist* buckets = _buckets.get();

    bucket* begin   = &buckets->at( 0 );
    bucket* end     = &buckets->at( 0 ) + buckets->size();

    for ( bucket* free = near + 1; free < end; ++free )
    {
        if ( free->next == YL_EMPTY_BUCKET )
        {
            return free;
        }
    }

    for ( bucket* free = near - 1; free >= begin; --free )
    {
        if ( free->next == YL_EMPTY_BUCKET )
        {
            return free;
        }
    }

    assert( ! "no free bucket" );
    return nullptr;

}

void yl_table::rehash( size_t capacity )
{
    // Grab old bucket list.
    yl_bucketlist* old_buckets = _buckets.get();

    // Allocate new bucket list.
    capacity = ceil_pow2( std::max( _occupancy, capacity ) );
    _occupancy = 0;
    _buckets.set( yl_bucketlist::alloc( capacity ) );

    // Reinsert elements.
    if ( old_buckets )
    {
        for ( size_t i = 0; i < old_buckets->size(); ++i )
        {
            const bucket& old_bucket = old_buckets->at( i );
            set_index( old_bucket.key.get(), old_bucket.value.get() );
        }
    }

    /*
        Allow the old bucket list to be garbage collected.  Note that
        old_buckets won't be GCed in this function because if the GC is
        initiated before (or at) the allocation of the new bucket list, the
        old one will be marked, and a new GC cycle cannot be initiated until
        the _next_ allocation after this function returns.
    */
}

yl_object* yl_table::make_prototype()
{
    yl_object* proto = yl_object::alloc( yl_current->proto_object() );
    proto->set_key( yl_string::alloc( "length" )->symbol(),
        yl_value( YLOBJ_THUNKOBJ, yl_thunkobj::alloc( &thunk_length ) ) );
    return proto;
}

yl_table* yl_table::thunk_this( yl_callframe& xf )
{
    yl_heapobj* heapobj = xf.get_heapobj( 1 );
    if ( ! heapobj || heapobj->kind() != YLOBJ_TABLE )
    {
        throw yl_exception( "expected table" );
    }
    return (yl_table*)heapobj;
}

void yl_table::thunk_length( yl_callframe& xf )
{
    yl_table* table = thunk_this( xf );
    xf.clear();
    xf.push( table->length() );
}

<commit_msg>make sure that it asserts rather than endlessly rehashing<commit_after>//
//  yl_table.cpp
//
//  Created by Edmund Kapusniak on 21/04/2015.
//  Copyright (c) 2015 Edmund Kapusniak. All rights reserved.
//

#include "yl_table.h"
#include <intmath.h>
#include "yl_function.h"

yl_bucketlist::bucket::bucket()
    :   next( YL_EMPTY_BUCKET )
{
}

yl_bucketlist* yl_bucketlist::alloc( size_t size )
{
    size_t s = sizeof( yl_bucketlist ) + sizeof( bucket ) * size;
    void* p = yl_current->malloc( s );
    return new ( p ) yl_bucketlist( size );
}

yl_bucketlist::yl_bucketlist( size_t size )
    :   yl_heapobj( YLOBJ_BUCKETLIST )
    ,   _size( size )
{
    for ( size_t i = 0; i < _size; ++i )
    {
        new ( _elements + i ) bucket();
    }
}

yl_bucketlist::~yl_bucketlist()
{
    for ( size_t i = 0; i < _size; ++i )
    {
        _elements[ i ].~bucket();
    }
}

size_t yl_bucketlist::size() const
{
    return _size;
}

const yl_bucketlist::bucket& yl_bucketlist::at( size_t index ) const
{
    assert( index < _size );
    return _elements[ index ];
}

yl_bucketlist::bucket& yl_bucketlist::at( size_t index )
{
    assert( index < _size );
    return _elements[ index ];
}

yl_table* yl_table::alloc( size_t capacity )
{
    return alloc( yl_current->proto_table(), capacity );
}

yl_table* yl_table::alloc( yl_object* prototype, size_t capacity )
{
    void* p = yl_current->malloc( sizeof( yl_table ) );
    return new ( p ) yl_table( prototype, capacity );
}

yl_table::yl_table( yl_object* prototype, size_t capacity )
    :   yl_object( YLOBJ_TABLE, prototype )
    ,   _occupancy( 0 )
    ,   _buckets( capacity ? yl_bucketlist::alloc( capacity ) : nullptr )
{
}

yl_value yl_table::get_index( yl_value key ) const
{
    bucket* b = lookup( key );
    if ( b )
    {
        return b->value.get();
    }
    else
    {
        return yl_undef;
    }
}

void yl_table::set_index( yl_value key, yl_value value )
{
    // Lookup in case key already exists.
    bucket* b = lookup( key );
    if ( b )
    {
        b->value.set( value );
        return;
    }

    // Grow hash if necessary.
    yl_bucketlist* buckets = _buckets.get();
    size_t capacity = buckets ? buckets->size() : 0;
    if ( _occupancy >= capacity - ( capacity >> 3 ) )
    {
        size_t new_capacity = _occupancy + _occupancy / 7 + 1;
        assert( _occupancy < new_capacity - ( new_capacity >> 3 ) );
        rehash( new_capacity );
    }

    // Occupancy will increase.
    _occupancy += 1;

    // Check if element can be placed in its main position.
    bucket* insert = main_position( key );
    if ( insert->next == YL_EMPTY_BUCKET )
    {
        insert->key.set( key );
        insert->value.set( value );
        insert->next = nullptr;
        return;
    }

    // Bucket is not empty.  Find main position of occupying element.
    bucket* cuckoo = main_position( insert->key.get() );

    // The only way that the occupying element is blocking us is if its main
    // position is occupied, either by itself or another element.
    assert( cuckoo->next != YL_EMPTY_BUCKET );

    // Find free bucket near the main position of the occupying element.
    bucket* free = free_position( cuckoo );
    assert( free->next == YL_EMPTY_BUCKET );

    if ( cuckoo == insert )
    {
        // Hash collision, as both the occupying element and the new one
        // hash to the same bucket.  Place new element in the free position
        // and link it into the list.

        free->key.set( key );
        free->value.set( value );
        free->next = insert->next;
        insert->next = free;
    }
    else
    {
        // The occupying element (stored in insert) isn't in its main position.
        // It's part of the linked list starting at cuckoo.  Move the occupying
        // element in insert to the free bucket, and replace insert with free
        // in the linked list starting from cuckoo.

        free->key.set( insert->key.get() );
        free->value.set( insert->value.get() );

        bucket* previous = cuckoo;
        while ( previous->next != insert )
        {
            previous = previous->next;
        }
        previous->next = free;
        free->next = insert->next;

        // Now insert is free to hold our inserted element.
        insert->key.set( key );
        insert->value.set( value );
        insert->next = nullptr;
    }

}

yl_bucketlist::bucket* yl_table::lookup( yl_value key ) const
{
    // Check for value in main position.
    bucket* lookup = main_position( key );
    if ( lookup && lookup->next == YL_EMPTY_BUCKET )
    {
        return nullptr;
    }

    // Follow linked list of buckets from main position.
    for ( ; lookup; lookup = lookup->next )
    {
        if ( equal( lookup->key.get(), key ) )
        {
            return lookup;
        }
    }

    // Not found.
    return nullptr;
}

yl_bucketlist::bucket* yl_table::main_position( yl_value key ) const
{
    yl_bucketlist* buckets = _buckets.get();
    if ( buckets && buckets->size() )
    {
        return &buckets->at( hash( key ) % buckets->size() );
    }
    else
    {
        return nullptr;
    }
}

yl_bucketlist::bucket* yl_table::free_position( bucket* near )
{
    yl_bucketlist* buckets = _buckets.get();

    bucket* begin   = &buckets->at( 0 );
    bucket* end     = &buckets->at( 0 ) + buckets->size();

    for ( bucket* free = near + 1; free < end; ++free )
    {
        if ( free->next == YL_EMPTY_BUCKET )
        {
            return free;
        }
    }

    for ( bucket* free = near - 1; free >= begin; --free )
    {
        if ( free->next == YL_EMPTY_BUCKET )
        {
            return free;
        }
    }

    assert( ! "no free bucket" );
    return nullptr;

}

void yl_table::rehash( size_t capacity )
{
    // Grab old bucket list.
    yl_bucketlist* old_buckets = _buckets.get();

    // Allocate new bucket list.
    capacity = ceil_pow2( std::max( _occupancy, capacity ) );
    _occupancy = 0;
    _buckets.set( yl_bucketlist::alloc( capacity ) );

    // Reinsert elements.
    if ( old_buckets )
    {
        for ( size_t i = 0; i < old_buckets->size(); ++i )
        {
            const bucket& old_bucket = old_buckets->at( i );
            set_index( old_bucket.key.get(), old_bucket.value.get() );
        }
    }

    /*
        Allow the old bucket list to be garbage collected.  Note that
        old_buckets won't be GCed in this function because if the GC is
        initiated before (or at) the allocation of the new bucket list, the
        old one will be marked, and a new GC cycle cannot be initiated until
        the _next_ allocation after this function returns.
    */
}

yl_object* yl_table::make_prototype()
{
    yl_object* proto = yl_object::alloc( yl_current->proto_object() );
    proto->set_key( yl_string::alloc( "length" )->symbol(),
        yl_value( YLOBJ_THUNKOBJ, yl_thunkobj::alloc( &thunk_length ) ) );
    return proto;
}

yl_table* yl_table::thunk_this( yl_callframe& xf )
{
    yl_heapobj* heapobj = xf.get_heapobj( 1 );
    if ( ! heapobj || heapobj->kind() != YLOBJ_TABLE )
    {
        throw yl_exception( "expected table" );
    }
    return (yl_table*)heapobj;
}

void yl_table::thunk_length( yl_callframe& xf )
{
    yl_table* table = thunk_this( xf );
    xf.clear();
    xf.push( table->length() );
}

<|endoftext|>


<commit_before>//===-- iOperators.cpp - Implement the Binary & Unary Operators --*- C++ -*--=//
//
// This file implements the nontrivial binary & unary operator instructions.
//
//===----------------------------------------------------------------------===//

#include "llvm/iOperators.h"
#include "llvm/Type.h"
using std::cerr;

//===----------------------------------------------------------------------===//
//                              UnaryOperator Class
//===----------------------------------------------------------------------===//

UnaryOperator *UnaryOperator::create(UnaryOps Op, Value *Source,
                                     const std::string &Name) {
  switch (Op) {
  case Not:  return new GenericUnaryInst(Op, Source, Name);
  default:
    cerr << "Don't know how to Create UnaryOperator " << Op << "\n";
    return 0;
  }
}

//===----------------------------------------------------------------------===//
//                             BinaryOperator Class
//===----------------------------------------------------------------------===//

BinaryOperator *BinaryOperator::create(BinaryOps Op, Value *S1, Value *S2,
				       const std::string &Name) {
  switch (Op) {
  // Binary comparison operators...
  case SetLT: case SetGT: case SetLE:
  case SetGE: case SetEQ: case SetNE:
    return new SetCondInst(Op, S1, S2, Name);

  default:
    return new GenericBinaryInst(Op, S1, S2, Name);
  }
}

// swapOperands - Exchange the two operands to this instruction.  This
// instruction is safe to use on any binary instruction and does not
// modify the semantics of the instruction.  If the instruction is
// order dependant (SetLT f.e.) the opcode is changed.
//
bool BinaryOperator::swapOperands() {
  switch (getOpcode()) {
    // Instructions that don't need opcode modification
  case Add: case Mul:
  case And: case Xor:
  case Or:
  case SetEQ: case SetNE:
    break;
    // Instructions that need opcode modification
  case SetGT: iType = SetLT; break;
  case SetLT: iType = SetGT; break;
  case SetGE: iType = SetLE; break;
  case SetLE: iType = SetGE; break;
    // Error on the side of caution
  default:
    return true;
  }
  std::swap(Operands[0], Operands[1]);
  return false;
}

//===----------------------------------------------------------------------===//
//                             SetCondInst Class
//===----------------------------------------------------------------------===//

SetCondInst::SetCondInst(BinaryOps opType, Value *S1, Value *S2,
                         const std::string &Name)
  : BinaryOperator(opType, S1, S2, Name) {

  OpType = opType;
  setType(Type::BoolTy);   // setcc instructions always return bool type.

  // Make sure it's a valid type...
  assert(getOpcodeName() != 0);
}
<commit_msg>Implement two constructor functions for "unary" instructions<commit_after>//===-- iOperators.cpp - Implement the Binary & Unary Operators --*- C++ -*--=//
//
// This file implements the nontrivial binary & unary operator instructions.
//
//===----------------------------------------------------------------------===//

#include "llvm/iOperators.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
using std::cerr;

//===----------------------------------------------------------------------===//
//                              UnaryOperator Class
//===----------------------------------------------------------------------===//

UnaryOperator *UnaryOperator::create(UnaryOps Op, Value *Source,
                                     const std::string &Name) {
  switch (Op) {
  case Not:  return new GenericUnaryInst(Op, Source, Name);
  default:
    cerr << "Don't know how to Create UnaryOperator " << Op << "\n";
    return 0;
  }
}

//===----------------------------------------------------------------------===//
//                             BinaryOperator Class
//===----------------------------------------------------------------------===//

BinaryOperator *BinaryOperator::create(BinaryOps Op, Value *S1, Value *S2,
				       const std::string &Name) {
  switch (Op) {
  // Binary comparison operators...
  case SetLT: case SetGT: case SetLE:
  case SetGE: case SetEQ: case SetNE:
    return new SetCondInst(Op, S1, S2, Name);

  default:
    return new GenericBinaryInst(Op, S1, S2, Name);
  }
}

BinaryOperator *BinaryOperator::createNeg(Value *Op, const std::string &Name) {
  return new GenericBinaryInst(Instruction::Sub,
                               Constant::getNullValue(Op->getType()), Op, Name);
}

BinaryOperator *BinaryOperator::createNot(Value *Op, const std::string &Name) {
  return new GenericBinaryInst(Instruction::Xor, Op,
                               ConstantIntegral::getAllOnesValue(Op->getType()),
                               Name);
}

// swapOperands - Exchange the two operands to this instruction.  This
// instruction is safe to use on any binary instruction and does not
// modify the semantics of the instruction.  If the instruction is
// order dependant (SetLT f.e.) the opcode is changed.
//
bool BinaryOperator::swapOperands() {
  switch (getOpcode()) {
    // Instructions that don't need opcode modification
  case Add: case Mul:
  case And: case Xor:
  case Or:
  case SetEQ: case SetNE:
    break;
    // Instructions that need opcode modification
  case SetGT: iType = SetLT; break;
  case SetLT: iType = SetGT; break;
  case SetGE: iType = SetLE; break;
  case SetLE: iType = SetGE; break;
    // Error on the side of caution
  default:
    return true;
  }
  std::swap(Operands[0], Operands[1]);
  return false;
}

//===----------------------------------------------------------------------===//
//                             SetCondInst Class
//===----------------------------------------------------------------------===//

SetCondInst::SetCondInst(BinaryOps opType, Value *S1, Value *S2,
                         const std::string &Name)
  : BinaryOperator(opType, S1, S2, Name) {

  OpType = opType;
  setType(Type::BoolTy);   // setcc instructions always return bool type.

  // Make sure it's a valid type...
  assert(getOpcodeName() != 0);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "multigrid.hpp"

namespace mfem
{

Multigrid::Multigrid()
   : cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1)
{}

Multigrid::Multigrid(const Array<Operator*>& operators_,
                     const Array<Solver*>& smoothers_,
                     const Array<Operator*>& prolongations_,
                     const Array<bool>& ownedOperators_,
                     const Array<bool>& ownedSmoothers_,
                     const Array<bool>& ownedProlongations_)
   : Solver(operators_.Last()->NumRows()), cycleType(CycleType::VCYCLE),
     preSmoothingSteps(1), postSmoothingSteps(1),
     X(operators_.Size()), Y(X.Size()), R(X.Size()), Z(X.Size())
{
   operators_.Copy(operators);
   smoothers_.Copy(smoothers);
   prolongations_.Copy(prolongations);
   ownedOperators_.Copy(ownedOperators);
   ownedSmoothers_.Copy(ownedSmoothers);
   ownedProlongations_.Copy(ownedProlongations);

   for (int level = 0; level < operators.Size(); ++level)
   {
      X[level] = new Vector(operators[level]->NumRows());
      *X[level] = 0.0;
      Y[level] = new Vector(operators[level]->NumRows());
      *Y[level] = 0.0;
      R[level] = new Vector(operators[level]->NumRows());
      *R[level] = 0.0;
      Z[level] = new Vector(operators[level]->NumRows());
      *Z[level] = 0.0;
   }
}

Multigrid::~Multigrid()
{
   for (int i = 0; i < operators.Size(); ++i)
   {
      if (ownedOperators[i])
      {
         delete operators[i];
      }
      if (ownedSmoothers[i])
      {
         delete smoothers[i];
      }
      if (ownedProlongations[i])
      {
         delete prolongations[i];
      }
      delete X[i];
      delete Y[i];
      delete R[i];
      delete Z[i];
   }

   operators.DeleteAll();
   smoothers.DeleteAll();
   X.DeleteAll();
   Y.DeleteAll();
   R.DeleteAll();
   Z.DeleteAll();
}

void Multigrid::AddLevel(Operator* opr, Solver* smoother, bool ownOperator,
                         bool ownSmoother)
{
   operators.Append(opr);
   smoothers.Append(smoother);
   ownedOperators.Append(ownOperator);
   ownedSmoothers.Append(ownSmoother);
   width = opr->Width();
   height = opr->Height();

   X.Append(new Vector(height));
   *X.Last() = 0.0;
   Y.Append(new Vector(height));
   *Y.Last() = 0.0;
   R.Append(new Vector(height));
   *R.Last() = 0.0;
   Z.Append(new Vector(height));
   *Z.Last() = 0.0;
}

int Multigrid::NumLevels() const { return operators.Size(); }

int Multigrid::GetFinestLevelIndex() const { return NumLevels() - 1; }

const Operator* Multigrid::GetOperatorAtLevel(int level) const
{
   return operators[level];
}

Operator* Multigrid::GetOperatorAtLevel(int level)
{
   return operators[level];
}

const Operator* Multigrid::GetOperatorAtFinestLevel() const
{
   return GetOperatorAtLevel(operators.Size() - 1);
}

Operator* Multigrid::GetOperatorAtFinestLevel()
{
   return GetOperatorAtLevel(operators.Size() - 1);
}

Solver* Multigrid::GetSmootherAtLevel(int level) const
{
   return smoothers[level];
}

Solver* Multigrid::GetSmootherAtLevel(int level)
{
   return smoothers[level];
}

void Multigrid::SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
                             int postSmoothingSteps_)
{
   cycleType = cycleType_;
   preSmoothingSteps = preSmoothingSteps_;
   postSmoothingSteps = postSmoothingSteps_;
}

void Multigrid::Mult(const Vector& x, Vector& y) const
{
   MFEM_ASSERT(NumLevels() > 0, "");
   *X.Last() = x;
   *Y.Last() = 0.0;
   Cycle(GetFinestLevelIndex());
   y = *Y.Last();
}

void Multigrid::SetOperator(const Operator& op)
{
   MFEM_ABORT("SetOperator not supported in Multigrid");
}

void Multigrid::SmoothingStep(int level, bool transpose) const
{
   GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]); // r = A x
   subtract(*X[level], *R[level], *R[level]);             // r = b - A x
   if (transpose)
   {
      GetSmootherAtLevel(level)->MultTranspose(*R[level], *Z[level]); // z = S r
   }
   else
   {
      GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
   }
   add(*Y[level], 1.0, *Z[level], *Y[level]);             // x = x + S (b - A x)
}

void Multigrid::Cycle(int level) const
{
   if (level == 0)
   {
      GetSmootherAtLevel(level)->Mult(*X[level], *Y[level]);
      return;
   }

   for (int i = 0; i < preSmoothingSteps; i++)
   {
      SmoothingStep(level, false);
   }

   // Compute residual
   GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]);
   subtract(*X[level], *R[level], *R[level]);

   // Restrict residual
   GetProlongationAtLevel(level - 1)->MultTranspose(*R[level], *X[level - 1]);

   // Init zeros
   *Y[level - 1] = 0.0;

   // Corrections
   int corrections = 1;
   if (cycleType == CycleType::WCYCLE)
   {
      corrections = 2;
   }
   for (int correction = 0; correction < corrections; ++correction)
   {
      Cycle(level - 1);
   }

   // Prolongate
   GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]);

   // Add update
   *Y[level] += *R[level];

   // Post-smooth
   for (int i = 0; i < postSmoothingSteps; i++)
   {
      SmoothingStep(level, true);
   }
}

const Operator* Multigrid::GetProlongationAtLevel(int level) const
{
   return prolongations[level];
}

GeometricMultigrid::~GeometricMultigrid()
{
   for (int i = 0; i < bfs.Size(); ++i)
   {
      delete bfs[i];
   }

   bfs.DeleteAll();

   for (int i = 0; i < essentialTrueDofs.Size(); ++i)
   {
      delete essentialTrueDofs[i];
   }

   essentialTrueDofs.DeleteAll();
}

void GeometricMultigrid::FormFineLinearSystem(Vector& x, Vector& b,
                                              OperatorHandle& A,
                                              Vector& X, Vector& B)
{
   bfs.Last()->FormLinearSystem(*essentialTrueDofs.Last(), x, b, A, X, B);
}

void GeometricMultigrid::RecoverFineFEMSolution(const Vector& X,
                                                const Vector& b, Vector& x)
{
   bfs.Last()->RecoverFEMSolution(X, b, x);
}

const Operator* GeometricMultigrid::GetProlongationAtLevel(int level) const
{
   return fespaces.GetProlongationAtLevel(level);
}

} // namespace mfem
<commit_msg>fix destructor of Multigrid<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "multigrid.hpp"

namespace mfem
{

Multigrid::Multigrid()
   : cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1)
{}

Multigrid::Multigrid(const Array<Operator*>& operators_,
                     const Array<Solver*>& smoothers_,
                     const Array<Operator*>& prolongations_,
                     const Array<bool>& ownedOperators_,
                     const Array<bool>& ownedSmoothers_,
                     const Array<bool>& ownedProlongations_)
   : Solver(operators_.Last()->NumRows()), cycleType(CycleType::VCYCLE),
     preSmoothingSteps(1), postSmoothingSteps(1),
     X(operators_.Size()), Y(X.Size()), R(X.Size()), Z(X.Size())
{
   operators_.Copy(operators);
   smoothers_.Copy(smoothers);
   prolongations_.Copy(prolongations);
   ownedOperators_.Copy(ownedOperators);
   ownedSmoothers_.Copy(ownedSmoothers);
   ownedProlongations_.Copy(ownedProlongations);

   for (int level = 0; level < operators.Size(); ++level)
   {
      X[level] = new Vector(operators[level]->NumRows());
      *X[level] = 0.0;
      Y[level] = new Vector(operators[level]->NumRows());
      *Y[level] = 0.0;
      R[level] = new Vector(operators[level]->NumRows());
      *R[level] = 0.0;
      Z[level] = new Vector(operators[level]->NumRows());
      *Z[level] = 0.0;
   }
}

Multigrid::~Multigrid()
{
   for (int i = 0; i < operators.Size(); ++i)
   {
      if (ownedOperators[i])
      {
         delete operators[i];
      }
      if (ownedSmoothers[i])
      {
         delete smoothers[i];
      }
      delete X[i];
      delete Y[i];
      delete R[i];
      delete Z[i];
   }

   for (int i = 0; i < prolongations.Size(); ++i)
   {
      if (ownedProlongations[i])
      {
         delete prolongations[i];
      }
   }

   operators.DeleteAll();
   smoothers.DeleteAll();
   prolongations.DeleteAll();
   X.DeleteAll();
   Y.DeleteAll();
   R.DeleteAll();
   Z.DeleteAll();
}

void Multigrid::AddLevel(Operator* opr, Solver* smoother, bool ownOperator,
                         bool ownSmoother)
{
   operators.Append(opr);
   smoothers.Append(smoother);
   ownedOperators.Append(ownOperator);
   ownedSmoothers.Append(ownSmoother);
   width = opr->Width();
   height = opr->Height();

   X.Append(new Vector(height));
   *X.Last() = 0.0;
   Y.Append(new Vector(height));
   *Y.Last() = 0.0;
   R.Append(new Vector(height));
   *R.Last() = 0.0;
   Z.Append(new Vector(height));
   *Z.Last() = 0.0;
}

int Multigrid::NumLevels() const { return operators.Size(); }

int Multigrid::GetFinestLevelIndex() const { return NumLevels() - 1; }

const Operator* Multigrid::GetOperatorAtLevel(int level) const
{
   return operators[level];
}

Operator* Multigrid::GetOperatorAtLevel(int level)
{
   return operators[level];
}

const Operator* Multigrid::GetOperatorAtFinestLevel() const
{
   return GetOperatorAtLevel(operators.Size() - 1);
}

Operator* Multigrid::GetOperatorAtFinestLevel()
{
   return GetOperatorAtLevel(operators.Size() - 1);
}

Solver* Multigrid::GetSmootherAtLevel(int level) const
{
   return smoothers[level];
}

Solver* Multigrid::GetSmootherAtLevel(int level)
{
   return smoothers[level];
}

void Multigrid::SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
                             int postSmoothingSteps_)
{
   cycleType = cycleType_;
   preSmoothingSteps = preSmoothingSteps_;
   postSmoothingSteps = postSmoothingSteps_;
}

void Multigrid::Mult(const Vector& x, Vector& y) const
{
   MFEM_ASSERT(NumLevels() > 0, "");
   *X.Last() = x;
   *Y.Last() = 0.0;
   Cycle(GetFinestLevelIndex());
   y = *Y.Last();
}

void Multigrid::SetOperator(const Operator& op)
{
   MFEM_ABORT("SetOperator not supported in Multigrid");
}

void Multigrid::SmoothingStep(int level, bool transpose) const
{
   GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]); // r = A x
   subtract(*X[level], *R[level], *R[level]);             // r = b - A x
   if (transpose)
   {
      GetSmootherAtLevel(level)->MultTranspose(*R[level], *Z[level]); // z = S r
   }
   else
   {
      GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
   }
   add(*Y[level], 1.0, *Z[level], *Y[level]);             // x = x + S (b - A x)
}

void Multigrid::Cycle(int level) const
{
   if (level == 0)
   {
      GetSmootherAtLevel(level)->Mult(*X[level], *Y[level]);
      return;
   }

   for (int i = 0; i < preSmoothingSteps; i++)
   {
      SmoothingStep(level, false);
   }

   // Compute residual
   GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]);
   subtract(*X[level], *R[level], *R[level]);

   // Restrict residual
   GetProlongationAtLevel(level - 1)->MultTranspose(*R[level], *X[level - 1]);

   // Init zeros
   *Y[level - 1] = 0.0;

   // Corrections
   int corrections = 1;
   if (cycleType == CycleType::WCYCLE)
   {
      corrections = 2;
   }
   for (int correction = 0; correction < corrections; ++correction)
   {
      Cycle(level - 1);
   }

   // Prolongate
   GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]);

   // Add update
   *Y[level] += *R[level];

   // Post-smooth
   for (int i = 0; i < postSmoothingSteps; i++)
   {
      SmoothingStep(level, true);
   }
}

const Operator* Multigrid::GetProlongationAtLevel(int level) const
{
   return prolongations[level];
}

GeometricMultigrid::~GeometricMultigrid()
{
   for (int i = 0; i < bfs.Size(); ++i)
   {
      delete bfs[i];
   }

   bfs.DeleteAll();

   for (int i = 0; i < essentialTrueDofs.Size(); ++i)
   {
      delete essentialTrueDofs[i];
   }

   essentialTrueDofs.DeleteAll();
}

void GeometricMultigrid::FormFineLinearSystem(Vector& x, Vector& b,
                                              OperatorHandle& A,
                                              Vector& X, Vector& B)
{
   bfs.Last()->FormLinearSystem(*essentialTrueDofs.Last(), x, b, A, X, B);
}

void GeometricMultigrid::RecoverFineFEMSolution(const Vector& X,
                                                const Vector& b, Vector& x)
{
   bfs.Last()->RecoverFEMSolution(X, b, x);
}

const Operator* GeometricMultigrid::GetProlongationAtLevel(int level) const
{
   return fespaces.GetProlongationAtLevel(level);
}

} // namespace mfem
<|endoftext|>


<commit_before>#include "figurepainter.h"
#include "textpainter.h"

std::vector<std::pair<Point, Point>> generateArrow(const Point &end, const Point &start);

void FigurePainter::accept(figures::Segment &segm) {
    painter.drawLine(scaler(segm.getA()), scaler(segm.getB()));
    if (segm.getArrowedA()) {
        drawArrow(segm.getA(), segm.getB());
    }
    if (segm.getArrowedB()) {
        drawArrow(segm.getB(), segm.getA());
    }
    drawLabel(segm);
}
void FigurePainter::accept(figures::SegmentConnection &segm) {
    accept(static_cast<figures::Segment &>(segm));
}

void FigurePainter::accept(figures::Curve &fig) {
    fig.selfCheck();
    for (size_t i = 0; i + 1 < fig.points.size(); i++) {
        Point a = fig.points[i], b = fig.points[i + 1];
        painter.drawLine(scaler(a), scaler(b));
        if (fig.arrowBegin[i]) {
            for (auto segm : generateArrow(a, b)) {
                painter.drawLine(scaler(segm.first), scaler(segm.second));
            }
        }
        if (fig.arrowEnd[i]) {
            for (auto segm : generateArrow(b, a)) {
                painter.drawLine(scaler(segm.first), scaler(segm.second));
            }
        }
    }
    drawLabel(fig);
}

void FigurePainter::accept(figures::Ellipse &fig) {
    QRectF rect(scaler(fig.getBoundingBox().leftUp),
                scaler(fig.getBoundingBox().rightDown)
               );
    painter.drawEllipse(rect);
    drawLabel(fig);
}

void FigurePainter::accept(figures::Rectangle &fig) {
    QRectF rect(scaler(fig.getBoundingBox().leftUp),
                scaler(fig.getBoundingBox().rightDown)
               );
    painter.drawRect(rect);
    drawLabel(fig);
}

const double ARROW_BRANCH_ANGLE = 25;
const int ARROW_LENGTH = 12;

std::vector<std::pair<Point, Point>> generateArrow(const Point &end, const Point &start) {
    std::vector<std::pair<Point, Point>> result;
    Point dir = start - end;
    if (dir == Point()) {
        return result;
    }
    dir = dir * (ARROW_LENGTH / dir.length());
    for (int k : { -1, 1 }) {
        Point branch = dir;
        branch.rotateBy(k * ARROW_BRANCH_ANGLE * PI / 180.0);
        result.push_back({ end, end + branch });
    }
    return result;
}

void FigurePainter::drawArrow(const Point &end, const Point &start) {
    for (auto segment : generateArrow(end, start)) {
        painter.drawLine(scaler(segment.first), scaler(segment.second));
    }
}

void FigurePainter::drawLabel(Figure &figure) {
    const std::string &label = figure.label();
    if (label.empty()) { return; }

    TextPosition position = getTextPosition(figure);
    QRectF rect(QPointF(), QSizeF(position.width * scaler.scaleFactor, position.height * scaler.scaleFactor));
    painter.save();
    painter.translate(scaler(position.leftUp));
    painter.rotate(position.rotation);
    painter.drawText(rect, Qt::AlignLeft | Qt::AlignTop, QString::fromStdString(label));
    painter.restore();
}

void FigureSvgPainter::printHeader() {
    QFile resource(":/svg-data/header.svg");
    resource.open(QIODevice::ReadOnly);
    QString header = resource.readAll();
    header.replace("{{markerSize}}", QString::number(2 * ARROW_LENGTH));
    header.replace("{{markerCenter}}", QString::number(ARROW_LENGTH));

    for (int id = 0; id < 2; id++) {
        QString path = "";
        Point start(id == 0 ? 0 : 2 * ARROW_LENGTH, ARROW_LENGTH);
        Point end(ARROW_LENGTH, ARROW_LENGTH);

        for (auto segment : generateArrow(end, start)) {
            Point a = segment.first, b = segment.second;
            path += QString("M%1, %2 ").arg(a.x).arg(a.y);
            path += QString("L%1, %2 ").arg(b.x).arg(b.y);
        }
        header.replace(
                    id == 0 ? "{{markerDirectPath}}" : "{{markerReversePath}}",
                    path
                    );
    }
    out << header.toStdString();

}
void FigureSvgPainter::printFooter() {
    QFile resource(":/svg-data/footer.svg");
    resource.open(QIODevice::ReadOnly);
    out << resource.readAll().toStdString();
}

void FigureSvgPainter::accept(figures::Segment &segm) {
    Point a = segm.getA();
    Point b = segm.getB();
    out << "<line x1=\"" << a.x << "\" y1=\"" << a.y << "\" x2=\"" << b.x << "\" y2=\"" << b.y << "\"";
    if (segm.getArrowedA()) {
        out << " marker-start=\"url(#markerReverseArrow)\"";
    }
    if (segm.getArrowedB()) {
        out << " marker-end=\"url(#markerArrow)\"";
    }
    out << "/>\n";
    drawLabel(segm);
}
void FigureSvgPainter::accept(figures::SegmentConnection &segm) {
    accept((figures::Segment &)segm);
}

void FigureSvgPainter::accept(figures::Curve &fig) {
    out << "<polyline points=\"";
    for (Point p : fig.points) {
        out << " " << p.x << "," << p.y;
    }
    out << "\"/>\n";
    for (size_t i = 0; i < fig.arrowBegin.size(); i++) {
        std::vector<std::pair<Point, Point>> arrows[] = {
            generateArrow(fig.points[i], fig.points[i + 1]),
            generateArrow(fig.points[i + 1], fig.points[i]),
        };
        if (!fig.arrowBegin[i]) { arrows[0].clear(); }
        if (!fig.arrowEnd[i]) { arrows[1].clear(); }
        for (auto arrow : arrows) if (!arrow.empty()) {
            for (auto segm : arrow) {
                out << "  <path d=\"M" << segm.first.x << "," << segm.first.y << " L" << segm.second.x << "," << segm.second.y << "\"/>\n";
            }
        }
    }
    drawLabel(fig);
}

void FigureSvgPainter::accept(figures::Ellipse &fig) {
    BoundingBox box = fig.getBoundingBox();
    out << "<ellipse cx=\"" << box.center().x << "\" cy=\"" << box.center().y << "\" rx=\"" << box.width() / 2 << "\" ry=\"" << box.height() / 2 << "\" />\n";
    drawLabel(fig);
}

void FigureSvgPainter::accept(figures::Rectangle &fig) {
    BoundingBox box = fig.getBoundingBox();
    out << "<rect x=\"" << box.leftUp.x << "\" y=\"" << box.leftUp.y << "\" width=\"" << box.width() << "\" height=\"" << box.height() << "\" />\n";
    drawLabel(fig);
}

std::vector<std::string> getLines(const std::string &data) {
    std::vector<std::string> result;
    std::stringstream s;
    s << data;
    std::string line;
    while (getline(s, line)) {
        result.push_back(line);
    }
    return result;
}

void FigureSvgPainter::drawLabel(Figure &figure) {
    const std::string &label = figure.label();
    if (label.empty()) { return; }

    std::vector<std::string> lines = getLines(label);

    TextPosition position = getTextPosition(figure);
    Point offset(0, position.height);
    offset.rotateBy(position.rotation * PI / 180);

    Point leftDown = position.leftUp + offset;

    out << "<text x=\"" << leftDown.x << "\" y=\"" << leftDown.y << "\"";
    if (fabs(position.rotation) > 1e-6) {
        out << " transform=\"rotate(" << position.rotation << " " << leftDown.x << " " << leftDown.y << ")\"";
    }
    out << ">";
    if (lines.size() == 1) {
        out << lines[0];
    } else {
        out << "\n";
        // We ignore rotation here, because it's already performed in <text>
        Point step(0, position.height / lines.size());
        Point current = leftDown - step * lines.size();
        for (auto line : lines)  {
            current += step;
            out << "<tspan x=\"" << current.x << "\" y=\"" << current.y << "\">" << line << "</tspan>\n";
        }
    }
    out << "</text>";
}
<commit_msg>figurepainter: some Bezier smoothing was added (#76)<commit_after>#include "figurepainter.h"
#include "textpainter.h"

std::vector<std::pair<Point, Point>> generateArrow(const Point &end, const Point &start);

void FigurePainter::accept(figures::Segment &segm) {
    painter.drawLine(scaler(segm.getA()), scaler(segm.getB()));
    if (segm.getArrowedA()) {
        drawArrow(segm.getA(), segm.getB());
    }
    if (segm.getArrowedB()) {
        drawArrow(segm.getB(), segm.getA());
    }
    drawLabel(segm);
}
void FigurePainter::accept(figures::SegmentConnection &segm) {
    accept(static_cast<figures::Segment &>(segm));
}

Point getControlPoint(Point a, Point b, Point c) {
    Point side1 = a - b, side2 = c - b;
    double needLength = side2.length() * 0.25;
    side1 = side1 * (1.0 / side1.length());
    side2 = side2 * (1.0 / side2.length());
    Point perp = (side1 + side2) * 0.5;
    perp = perp * (1.0 / perp.length());
    if (Point::crossProduct(perp, side2) >= 0) {
        perp.rotateBy(PI / 2);
    } else {
        perp.rotateBy(-PI / 2);
    }
    return b + perp * needLength;
}

void FigurePainter::accept(figures::Curve &fig) {
    fig.selfCheck();
    for (size_t i = 0; i + 1 < fig.points.size(); i++) {
        Point a = fig.points[i], b = fig.points[i + 1];
        Point controlA = b, controlB = a;
        if (i > 0) {
            controlA = getControlPoint(fig.points[i - 1], a, b);
        }
        if (i + 2 < fig.points.size()) {
            controlB = getControlPoint(fig.points[i + 2], b, a);
        }

        QPainterPath path;
        path.moveTo(scaler(a));
        path.cubicTo(scaler(controlA), scaler(controlB), scaler(b));
        painter.drawPath(path);
        //painter.drawLine(scaler(a), scaler(b));
        if (fig.arrowBegin[i]) {
            for (auto segm : generateArrow(a, controlA)) {
                painter.drawLine(scaler(segm.first), scaler(segm.second));
            }
        }
        if (fig.arrowEnd[i]) {
            for (auto segm : generateArrow(b, controlB)) {
                painter.drawLine(scaler(segm.first), scaler(segm.second));
            }
        }
    }
    drawLabel(fig);
}

void FigurePainter::accept(figures::Ellipse &fig) {
    QRectF rect(scaler(fig.getBoundingBox().leftUp),
                scaler(fig.getBoundingBox().rightDown)
               );
    painter.drawEllipse(rect);
    drawLabel(fig);
}

void FigurePainter::accept(figures::Rectangle &fig) {
    QRectF rect(scaler(fig.getBoundingBox().leftUp),
                scaler(fig.getBoundingBox().rightDown)
               );
    painter.drawRect(rect);
    drawLabel(fig);
}

const double ARROW_BRANCH_ANGLE = 25;
const int ARROW_LENGTH = 12;

std::vector<std::pair<Point, Point>> generateArrow(const Point &end, const Point &start) {
    std::vector<std::pair<Point, Point>> result;
    Point dir = start - end;
    if (dir == Point()) {
        return result;
    }
    dir = dir * (ARROW_LENGTH / dir.length());
    for (int k : { -1, 1 }) {
        Point branch = dir;
        branch.rotateBy(k * ARROW_BRANCH_ANGLE * PI / 180.0);
        result.push_back({ end, end + branch });
    }
    return result;
}

void FigurePainter::drawArrow(const Point &end, const Point &start) {
    for (auto segment : generateArrow(end, start)) {
        painter.drawLine(scaler(segment.first), scaler(segment.second));
    }
}

void FigurePainter::drawLabel(Figure &figure) {
    const std::string &label = figure.label();
    if (label.empty()) { return; }

    TextPosition position = getTextPosition(figure);
    QRectF rect(QPointF(), QSizeF(position.width * scaler.scaleFactor, position.height * scaler.scaleFactor));
    painter.save();
    painter.translate(scaler(position.leftUp));
    painter.rotate(position.rotation);
    painter.drawText(rect, Qt::AlignLeft | Qt::AlignTop, QString::fromStdString(label));
    painter.restore();
}

void FigureSvgPainter::printHeader() {
    QFile resource(":/svg-data/header.svg");
    resource.open(QIODevice::ReadOnly);
    QString header = resource.readAll();
    header.replace("{{markerSize}}", QString::number(2 * ARROW_LENGTH));
    header.replace("{{markerCenter}}", QString::number(ARROW_LENGTH));

    for (int id = 0; id < 2; id++) {
        QString path = "";
        Point start(id == 0 ? 0 : 2 * ARROW_LENGTH, ARROW_LENGTH);
        Point end(ARROW_LENGTH, ARROW_LENGTH);

        for (auto segment : generateArrow(end, start)) {
            Point a = segment.first, b = segment.second;
            path += QString("M%1, %2 ").arg(a.x).arg(a.y);
            path += QString("L%1, %2 ").arg(b.x).arg(b.y);
        }
        header.replace(
                    id == 0 ? "{{markerDirectPath}}" : "{{markerReversePath}}",
                    path
                    );
    }
    out << header.toStdString();

}
void FigureSvgPainter::printFooter() {
    QFile resource(":/svg-data/footer.svg");
    resource.open(QIODevice::ReadOnly);
    out << resource.readAll().toStdString();
}

void FigureSvgPainter::accept(figures::Segment &segm) {
    Point a = segm.getA();
    Point b = segm.getB();
    out << "<line x1=\"" << a.x << "\" y1=\"" << a.y << "\" x2=\"" << b.x << "\" y2=\"" << b.y << "\"";
    if (segm.getArrowedA()) {
        out << " marker-start=\"url(#markerReverseArrow)\"";
    }
    if (segm.getArrowedB()) {
        out << " marker-end=\"url(#markerArrow)\"";
    }
    out << "/>\n";
    drawLabel(segm);
}
void FigureSvgPainter::accept(figures::SegmentConnection &segm) {
    accept((figures::Segment &)segm);
}

void FigureSvgPainter::accept(figures::Curve &fig) {
    out << "<polyline points=\"";
    for (Point p : fig.points) {
        out << " " << p.x << "," << p.y;
    }
    out << "\"/>\n";
    for (size_t i = 0; i < fig.arrowBegin.size(); i++) {
        std::vector<std::pair<Point, Point>> arrows[] = {
            generateArrow(fig.points[i], fig.points[i + 1]),
            generateArrow(fig.points[i + 1], fig.points[i]),
        };
        if (!fig.arrowBegin[i]) { arrows[0].clear(); }
        if (!fig.arrowEnd[i]) { arrows[1].clear(); }
        for (auto arrow : arrows) if (!arrow.empty()) {
            for (auto segm : arrow) {
                out << "  <path d=\"M" << segm.first.x << "," << segm.first.y << " L" << segm.second.x << "," << segm.second.y << "\"/>\n";
            }
        }
    }
    drawLabel(fig);
}

void FigureSvgPainter::accept(figures::Ellipse &fig) {
    BoundingBox box = fig.getBoundingBox();
    out << "<ellipse cx=\"" << box.center().x << "\" cy=\"" << box.center().y << "\" rx=\"" << box.width() / 2 << "\" ry=\"" << box.height() / 2 << "\" />\n";
    drawLabel(fig);
}

void FigureSvgPainter::accept(figures::Rectangle &fig) {
    BoundingBox box = fig.getBoundingBox();
    out << "<rect x=\"" << box.leftUp.x << "\" y=\"" << box.leftUp.y << "\" width=\"" << box.width() << "\" height=\"" << box.height() << "\" />\n";
    drawLabel(fig);
}

std::vector<std::string> getLines(const std::string &data) {
    std::vector<std::string> result;
    std::stringstream s;
    s << data;
    std::string line;
    while (getline(s, line)) {
        result.push_back(line);
    }
    return result;
}

void FigureSvgPainter::drawLabel(Figure &figure) {
    const std::string &label = figure.label();
    if (label.empty()) { return; }

    std::vector<std::string> lines = getLines(label);

    TextPosition position = getTextPosition(figure);
    Point offset(0, position.height);
    offset.rotateBy(position.rotation * PI / 180);

    Point leftDown = position.leftUp + offset;

    out << "<text x=\"" << leftDown.x << "\" y=\"" << leftDown.y << "\"";
    if (fabs(position.rotation) > 1e-6) {
        out << " transform=\"rotate(" << position.rotation << " " << leftDown.x << " " << leftDown.y << ")\"";
    }
    out << ">";
    if (lines.size() == 1) {
        out << lines[0];
    } else {
        out << "\n";
        // We ignore rotation here, because it's already performed in <text>
        Point step(0, position.height / lines.size());
        Point current = leftDown - step * lines.size();
        for (auto line : lines)  {
            current += step;
            out << "<tspan x=\"" << current.x << "\" y=\"" << current.y << "\">" << line << "</tspan>\n";
        }
    }
    out << "</text>";
}
<|endoftext|>