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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

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

=========================================================================*/

#include "mitkBaseRenderer.h"
#include "mitkPlaneGeometry.h"
#include "mitkEventMapper.h"
#include "mitkPositionEvent.h"
#include "mitkGlobalInteraction.h"
#include "mitkDisplayPositionEvent.h"
#include "mitkWeakPointerProperty.h"
#include "mitkSlicedGeometry3D.h"
#include "mitkSliceNavigationController.h"
#include "mitkStatusBar.h"
#include "mitkInteractionConst.h"
#include <vtkTransform.h>

//##ModelId=3E3D2F120050
mitk::BaseRenderer::BaseRenderer() :
  m_MapperID(defaultMapper), m_DataTreeIterator(NULL), m_RenderWindow(NULL), m_LastUpdateTime(0), m_CameraController(NULL), m_Focused(false),
  m_WorldGeometry(NULL), m_TimeSlicedWorldGeometry(NULL), m_CurrentWorldGeometry2D(NULL), m_Slice(0), m_TimeStep(0)
{
  m_Size[0] = 0;
  m_Size[1] = 0;

  //adding this BaseRenderer to the List of all BaseRenderer
  mitk::GlobalInteraction *globalInteraction = dynamic_cast<mitk::GlobalInteraction *>(EventMapper::GetGlobalStateMachine());
  if (globalInteraction != NULL)
	{
    globalInteraction->AddFocusElement(this);
  }

  WeakPointerProperty::Pointer rendererProp = new WeakPointerProperty((itk::Object*)this);

  m_CurrentWorldGeometry2D = mitk::PlaneGeometry::New();

  m_CurrentWorldGeometry2DData = mitk::Geometry2DData::New();
  m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D);
  m_CurrentWorldGeometry2DNode = mitk::DataTreeNode::New();
  m_CurrentWorldGeometry2DNode->SetData(m_CurrentWorldGeometry2DData);
  m_CurrentWorldGeometry2DNode->GetPropertyList()->SetProperty("renderer", rendererProp);
  m_CurrentWorldGeometry2DTransformTime = m_CurrentWorldGeometry2DNode->GetVtkTransform()->GetMTime();

  m_DisplayGeometry = mitk::DisplayGeometry::New();
  m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D);
  m_DisplayGeometryData = mitk::Geometry2DData::New();
  m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry);
  m_DisplayGeometryNode = mitk::DataTreeNode::New();
  m_DisplayGeometryNode->SetData(m_DisplayGeometryData);
  m_DisplayGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp);
  m_DisplayGeometryTransformTime = m_DisplayGeometryNode->GetVtkTransform()->GetMTime();
}

//##ModelId=3E3D2F12008C
mitk::BaseRenderer::~BaseRenderer()
{
  m_DataTreeIterator = NULL;
}

//##ModelId=3D6A1791038B
void mitk::BaseRenderer::SetData(const mitk::DataTreeIteratorBase* iterator)
{
  if(m_DataTreeIterator != iterator)
  {
    if (iterator != NULL)
      m_DataTreeIterator = iterator;
    else
      m_DataTreeIterator = NULL;
    Modified();
  }
}

//##ModelId=3E330C4D0395
const MapperSlotId mitk::BaseRenderer::defaultMapper = 1;

//##ModelId=3E33162C00D0
void mitk::BaseRenderer::Paint()
{
}

//##ModelId=3E331632031E
void mitk::BaseRenderer::Initialize()
{
}

//##ModelId=3E33163703D9
void mitk::BaseRenderer::Resize(int w, int h)
{
  m_Size[0] = w;
  m_Size[1] = h;

  //if(m_CameraController) //see bug #32
  //  m_CameraController->Resize(w, h);

  GetDisplayGeometry()->SetSizeInDisplayUnits(w, h);
  //@FIXME: die nchste Zeile ist nur da, weil der Anpassungsvorgang in SetSizeInDisplayUnits leider noch nicht richtig funktioniert.
  GetDisplayGeometry()->Fit();
}

//##ModelId=3E33163A0261
void mitk::BaseRenderer::InitRenderer(mitk::RenderWindow* renderwindow)
{
  m_RenderWindow = renderwindow;
}

//##ModelId=3E3799250397
void mitk::BaseRenderer::InitSize(int w, int h)
{
  m_Size[0] = w;
  m_Size[1] = h;
  GetDisplayGeometry()->SetSizeInDisplayUnits(w, h, false);
  GetDisplayGeometry()->Fit();
}

void mitk::BaseRenderer::SetSlice(unsigned int slice)
{
  if(m_Slice!=slice)
  {
    m_Slice = slice;
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        if(m_Slice >= slicedWorldGeometry->GetSlices())
          m_Slice = slicedWorldGeometry->GetSlices()-1;
        SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice));
        m_CurrentWorldGeometry = slicedWorldGeometry;
      }
    }
    else
      Modified();
  }
}

void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep)
{
  if(m_TimeStep!=timeStep)
  {
    m_TimeStep = timeStep;
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      if(m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps())
        m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps()-1;
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice));
        m_CurrentWorldGeometry = slicedWorldGeometry;
      }
    }
    else
      Modified();
  }
}

//##ModelId=3E66CC590379
void mitk::BaseRenderer::SetWorldGeometry(mitk::Geometry3D* geometry)
{
  itkDebugMacro("setting WorldGeometry to " << geometry);

  if(m_WorldGeometry != geometry)
  {
    m_WorldGeometry = geometry;
    m_TimeSlicedWorldGeometry=dynamic_cast<TimeSlicedGeometry*>(geometry);
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      itkDebugMacro("setting TimeSlicedWorldGeometry to " << m_TimeSlicedWorldGeometry);
      if(m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps())
        m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps()-1;
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        if(m_Slice >= slicedWorldGeometry->GetSlices())
          m_Slice = slicedWorldGeometry->GetSlices()-1;
      }
      assert(slicedWorldGeometry!=NULL); //only as long as the todo described in SetWorldGeometry is not done
      SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice)); // calls Modified()
      m_CurrentWorldGeometry = slicedWorldGeometry;
    }
    else
    {
      Geometry2D* geometry2d=dynamic_cast<Geometry2D*>(geometry);
      SetCurrentWorldGeometry2D(geometry2d);
      m_CurrentWorldGeometry = geometry2d;
      Modified();
    }
  }
  if(m_CurrentWorldGeometry2D.IsNull())
    itkWarningMacro("m_CurrentWorldGeometry2D is NULL");
}

//##ModelId=3E66CC59026B
void mitk::BaseRenderer::SetDisplayGeometry(mitk::DisplayGeometry* geometry2d)
{
  itkDebugMacro("setting DisplayGeometry to " << geometry2d);
  if (m_DisplayGeometry != geometry2d)
  {
    m_DisplayGeometry = geometry2d;
    m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry);
    m_DisplayGeometryUpdateTime.Modified();
    Modified();
  }
}

void mitk::BaseRenderer::SetCurrentWorldGeometry2D(mitk::Geometry2D* geometry2d)
{
  if (m_CurrentWorldGeometry2D != geometry2d)
  {
    m_CurrentWorldGeometry2D = geometry2d;
    m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D);
    m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D);
    m_CurrentWorldGeometry2DUpdateTime.Modified();
    Modified();
  }
}

void mitk::BaseRenderer::SetGeometry(const itk::EventObject & geometrySendEvent)
{
  const SliceNavigationController::GeometrySendEvent* sendEvent =
    dynamic_cast<const SliceNavigationController::GeometrySendEvent *>(&geometrySendEvent);

  assert(sendEvent !=NULL);
  SetWorldGeometry(sendEvent ->GetTimeSlicedGeometry());
}

void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject & geometrySliceEvent)
{
  const SliceNavigationController::GeometrySliceEvent* sliceEvent =
    dynamic_cast<const SliceNavigationController::GeometrySliceEvent *>(&geometrySliceEvent);

  assert(sliceEvent!=NULL);
  SetSlice(sliceEvent->GetPos());
}

void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject & geometryTimeEvent)
{
  const SliceNavigationController::GeometryTimeEvent * timeEvent =
    dynamic_cast<const SliceNavigationController::GeometryTimeEvent *>(&geometryTimeEvent);

  assert(timeEvent!=NULL);
  SetTimeStep(timeEvent->GetPos());
}

//##ModelId=3E6D5DD30322
void mitk::BaseRenderer::MousePressEvent(mitk::MouseEvent *me)
{
  //set the Focus on the renderer
  mitk::GlobalInteraction *globalInteraction = dynamic_cast<mitk::GlobalInteraction *>(EventMapper::GetGlobalStateMachine());
  if (globalInteraction != NULL)
  {
    bool success = globalInteraction->SetFocus(this);
    if (! success)
      mitk::StatusBar::DisplayText("Warning! from mitkBaseRenderer.cpp: Couldn't focus this BaseRenderer!");
  }

  if (m_CameraController)
  {
    if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MousePressEvent(me);
  }
  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());

    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
//    std::cout << "press event!" << std::endl;
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

//##ModelId=3E6D5DD30372
void mitk::BaseRenderer::MouseReleaseEvent(mitk::MouseEvent *me)
{
  if (m_CameraController)
  {
    if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MouseReleaseEvent(me);
  }

  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

//##ModelId=3E6D5DD303C2
void mitk::BaseRenderer::MouseMoveEvent(mitk::MouseEvent *me)
{
  if (m_CameraController)
  {
    if((me->GetButtonState()<=512) || (me->GetButtonState()>=516))// provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MouseMoveEvent(me);
  }
  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

void mitk::BaseRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const
{
  mitk::Point2D worldPoint2D;
  GetDisplayGeometry()->DisplayToMM(displayPoint, worldPoint2D);
  GetDisplayGeometry()->Map(worldPoint2D, worldPoint);
}

void mitk::BaseRenderer::WheelEvent(mitk::WheelEvent *we)
{
  //mitk::Event event(this, ke->type(), Qt::NoButton, Qt::NoButton, ke->key());
  //mitk::EventMapper::MapEvent(&event);
}

//##ModelId=3E6D5DD4002A
void mitk::BaseRenderer::KeyPressEvent(mitk::KeyEvent *ke)
{
  if (m_CameraController)
    m_CameraController->KeyPressEvent(ke);
  mitk::Event event(this, ke->type(), BS_NoButton, BS_NoButton, ke->key());
  mitk::EventMapper::MapEvent(&event);
}

//##ModelId=3EF1627503C4
void mitk::BaseRenderer::MakeCurrent()
{
}
<commit_msg>ENH: comment<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

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

=========================================================================*/

#include "mitkBaseRenderer.h"
#include "mitkPlaneGeometry.h"
#include "mitkEventMapper.h"
#include "mitkPositionEvent.h"
#include "mitkGlobalInteraction.h"
#include "mitkDisplayPositionEvent.h"
#include "mitkWeakPointerProperty.h"
#include "mitkSlicedGeometry3D.h"
#include "mitkSliceNavigationController.h"
#include "mitkStatusBar.h"
#include "mitkInteractionConst.h"
#include <vtkTransform.h>

//##ModelId=3E3D2F120050
mitk::BaseRenderer::BaseRenderer() :
  m_MapperID(defaultMapper), m_DataTreeIterator(NULL), m_RenderWindow(NULL), m_LastUpdateTime(0), m_CameraController(NULL), m_Focused(false),
  m_WorldGeometry(NULL), m_TimeSlicedWorldGeometry(NULL), m_CurrentWorldGeometry2D(NULL), m_Slice(0), m_TimeStep(0)
{
  m_Size[0] = 0;
  m_Size[1] = 0;

  //adding this BaseRenderer to the List of all BaseRenderer
  mitk::GlobalInteraction *globalInteraction = dynamic_cast<mitk::GlobalInteraction *>(EventMapper::GetGlobalStateMachine());
  if (globalInteraction != NULL)
	{
    globalInteraction->AddFocusElement(this);
  }

  WeakPointerProperty::Pointer rendererProp = new WeakPointerProperty((itk::Object*)this);

  m_CurrentWorldGeometry2D = mitk::PlaneGeometry::New();

  m_CurrentWorldGeometry2DData = mitk::Geometry2DData::New();
  m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D);
  m_CurrentWorldGeometry2DNode = mitk::DataTreeNode::New();
  m_CurrentWorldGeometry2DNode->SetData(m_CurrentWorldGeometry2DData);
  m_CurrentWorldGeometry2DNode->GetPropertyList()->SetProperty("renderer", rendererProp);
  m_CurrentWorldGeometry2DTransformTime = m_CurrentWorldGeometry2DNode->GetVtkTransform()->GetMTime();

  m_DisplayGeometry = mitk::DisplayGeometry::New();
  m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D);
  m_DisplayGeometryData = mitk::Geometry2DData::New();
  m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry);
  m_DisplayGeometryNode = mitk::DataTreeNode::New();
  m_DisplayGeometryNode->SetData(m_DisplayGeometryData);
  m_DisplayGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp);
  m_DisplayGeometryTransformTime = m_DisplayGeometryNode->GetVtkTransform()->GetMTime();
}

//##ModelId=3E3D2F12008C
mitk::BaseRenderer::~BaseRenderer()
{
  m_DataTreeIterator = NULL;
}

//##ModelId=3D6A1791038B
void mitk::BaseRenderer::SetData(const mitk::DataTreeIteratorBase* iterator)
{
  if(m_DataTreeIterator != iterator)
  {
    if (iterator != NULL)
      m_DataTreeIterator = iterator;
    else
      m_DataTreeIterator = NULL;
    Modified();
  }
}

//##ModelId=3E330C4D0395
const MapperSlotId mitk::BaseRenderer::defaultMapper = 1;

//##ModelId=3E33162C00D0
void mitk::BaseRenderer::Paint()
{
}

//##ModelId=3E331632031E
void mitk::BaseRenderer::Initialize()
{
}

//##ModelId=3E33163703D9
void mitk::BaseRenderer::Resize(int w, int h)
{
  m_Size[0] = w;
  m_Size[1] = h;

  //if(m_CameraController) //see bug #32 (vtkSizeBug)
  //  m_CameraController->Resize(w, h);

  GetDisplayGeometry()->SetSizeInDisplayUnits(w, h);
  //@FIXME: die nchste Zeile ist nur da, weil der Anpassungsvorgang in SetSizeInDisplayUnits leider noch nicht richtig funktioniert.
  GetDisplayGeometry()->Fit();
}

//##ModelId=3E33163A0261
void mitk::BaseRenderer::InitRenderer(mitk::RenderWindow* renderwindow)
{
  m_RenderWindow = renderwindow;
}

//##ModelId=3E3799250397
void mitk::BaseRenderer::InitSize(int w, int h)
{
  m_Size[0] = w;
  m_Size[1] = h;
  GetDisplayGeometry()->SetSizeInDisplayUnits(w, h, false);
  GetDisplayGeometry()->Fit();
}

void mitk::BaseRenderer::SetSlice(unsigned int slice)
{
  if(m_Slice!=slice)
  {
    m_Slice = slice;
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        if(m_Slice >= slicedWorldGeometry->GetSlices())
          m_Slice = slicedWorldGeometry->GetSlices()-1;
        SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice));
        m_CurrentWorldGeometry = slicedWorldGeometry;
      }
    }
    else
      Modified();
  }
}

void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep)
{
  if(m_TimeStep!=timeStep)
  {
    m_TimeStep = timeStep;
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      if(m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps())
        m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps()-1;
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice));
        m_CurrentWorldGeometry = slicedWorldGeometry;
      }
    }
    else
      Modified();
  }
}

//##ModelId=3E66CC590379
void mitk::BaseRenderer::SetWorldGeometry(mitk::Geometry3D* geometry)
{
  itkDebugMacro("setting WorldGeometry to " << geometry);

  if(m_WorldGeometry != geometry)
  {
    m_WorldGeometry = geometry;
    m_TimeSlicedWorldGeometry=dynamic_cast<TimeSlicedGeometry*>(geometry);
    if(m_TimeSlicedWorldGeometry.IsNotNull())
    {
      itkDebugMacro("setting TimeSlicedWorldGeometry to " << m_TimeSlicedWorldGeometry);
      if(m_TimeStep >= m_TimeSlicedWorldGeometry->GetTimeSteps())
        m_TimeStep = m_TimeSlicedWorldGeometry->GetTimeSteps()-1;
      SlicedGeometry3D* slicedWorldGeometry=dynamic_cast<SlicedGeometry3D*>(m_TimeSlicedWorldGeometry->GetGeometry3D(m_TimeStep));
      if(slicedWorldGeometry!=NULL)
      {
        if(m_Slice >= slicedWorldGeometry->GetSlices())
          m_Slice = slicedWorldGeometry->GetSlices()-1;
      }
      assert(slicedWorldGeometry!=NULL); //only as long as the todo described in SetWorldGeometry is not done
      SetCurrentWorldGeometry2D(slicedWorldGeometry->GetGeometry2D(m_Slice)); // calls Modified()
      m_CurrentWorldGeometry = slicedWorldGeometry;
    }
    else
    {
      Geometry2D* geometry2d=dynamic_cast<Geometry2D*>(geometry);
      SetCurrentWorldGeometry2D(geometry2d);
      m_CurrentWorldGeometry = geometry2d;
      Modified();
    }
  }
  if(m_CurrentWorldGeometry2D.IsNull())
    itkWarningMacro("m_CurrentWorldGeometry2D is NULL");
}

//##ModelId=3E66CC59026B
void mitk::BaseRenderer::SetDisplayGeometry(mitk::DisplayGeometry* geometry2d)
{
  itkDebugMacro("setting DisplayGeometry to " << geometry2d);
  if (m_DisplayGeometry != geometry2d)
  {
    m_DisplayGeometry = geometry2d;
    m_DisplayGeometryData->SetGeometry2D(m_DisplayGeometry);
    m_DisplayGeometryUpdateTime.Modified();
    Modified();
  }
}

void mitk::BaseRenderer::SetCurrentWorldGeometry2D(mitk::Geometry2D* geometry2d)
{
  if (m_CurrentWorldGeometry2D != geometry2d)
  {
    m_CurrentWorldGeometry2D = geometry2d;
    m_CurrentWorldGeometry2DData->SetGeometry2D(m_CurrentWorldGeometry2D);
    m_DisplayGeometry->SetWorldGeometry(m_CurrentWorldGeometry2D);
    m_CurrentWorldGeometry2DUpdateTime.Modified();
    Modified();
  }
}

void mitk::BaseRenderer::SetGeometry(const itk::EventObject & geometrySendEvent)
{
  const SliceNavigationController::GeometrySendEvent* sendEvent =
    dynamic_cast<const SliceNavigationController::GeometrySendEvent *>(&geometrySendEvent);

  assert(sendEvent !=NULL);
  SetWorldGeometry(sendEvent ->GetTimeSlicedGeometry());
}

void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject & geometrySliceEvent)
{
  const SliceNavigationController::GeometrySliceEvent* sliceEvent =
    dynamic_cast<const SliceNavigationController::GeometrySliceEvent *>(&geometrySliceEvent);

  assert(sliceEvent!=NULL);
  SetSlice(sliceEvent->GetPos());
}

void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject & geometryTimeEvent)
{
  const SliceNavigationController::GeometryTimeEvent * timeEvent =
    dynamic_cast<const SliceNavigationController::GeometryTimeEvent *>(&geometryTimeEvent);

  assert(timeEvent!=NULL);
  SetTimeStep(timeEvent->GetPos());
}

//##ModelId=3E6D5DD30322
void mitk::BaseRenderer::MousePressEvent(mitk::MouseEvent *me)
{
  //set the Focus on the renderer
  mitk::GlobalInteraction *globalInteraction = dynamic_cast<mitk::GlobalInteraction *>(EventMapper::GetGlobalStateMachine());
  if (globalInteraction != NULL)
  {
    bool success = globalInteraction->SetFocus(this);
    if (! success)
      mitk::StatusBar::DisplayText("Warning! from mitkBaseRenderer.cpp: Couldn't focus this BaseRenderer!");
  }

  if (m_CameraController)
  {
    if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MousePressEvent(me);
  }
  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());

    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
//    std::cout << "press event!" << std::endl;
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

//##ModelId=3E6D5DD30372
void mitk::BaseRenderer::MouseReleaseEvent(mitk::MouseEvent *me)
{
  if (m_CameraController)
  {
    if(me->GetButtonState()!=512) // provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MouseReleaseEvent(me);
  }

  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

//##ModelId=3E6D5DD303C2
void mitk::BaseRenderer::MouseMoveEvent(mitk::MouseEvent *me)
{
  if (m_CameraController)
  {
    if((me->GetButtonState()<=512) || (me->GetButtonState()>=516))// provisorisch: Ctrl nicht durchlassen. Bald wird aus m_CameraController eine StateMachine
      m_CameraController->MouseMoveEvent(me);
  }
  if(m_MapperID==1)
  {
    Point2D p(me->GetDisplayPosition());
    Point2D p_mm;
    Point3D position;
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    GetDisplayGeometry()->DisplayToMM(p, p_mm);
    GetDisplayGeometry()->Map(p_mm, position);
    mitk::PositionEvent event(this, me->GetType(), me->GetButton(), me->GetButtonState(), mitk::Key_unknown, p, position);
    mitk::EventMapper::MapEvent(&event);
  }
  else if(m_MapperID==2)
  {
    Point2D p(me->GetDisplayPosition());
    GetDisplayGeometry()->ULDisplayToDisplay(p,p);
    me->SetDisplayPosition(p);
    mitk::EventMapper::MapEvent(me);
  }
}

void mitk::BaseRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const
{
  mitk::Point2D worldPoint2D;
  GetDisplayGeometry()->DisplayToMM(displayPoint, worldPoint2D);
  GetDisplayGeometry()->Map(worldPoint2D, worldPoint);
}

void mitk::BaseRenderer::WheelEvent(mitk::WheelEvent *we)
{
  //mitk::Event event(this, ke->type(), Qt::NoButton, Qt::NoButton, ke->key());
  //mitk::EventMapper::MapEvent(&event);
}

//##ModelId=3E6D5DD4002A
void mitk::BaseRenderer::KeyPressEvent(mitk::KeyEvent *ke)
{
  if (m_CameraController)
    m_CameraController->KeyPressEvent(ke);
  mitk::Event event(this, ke->type(), BS_NoButton, BS_NoButton, ke->key());
  mitk::EventMapper::MapEvent(&event);
}

//##ModelId=3EF1627503C4
void mitk::BaseRenderer::MakeCurrent()
{
}
<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __RDMAAGGREGATOR_HPP__
#define __RDMAAGGREGATOR_HPP__

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "Communicator.hpp"
#include "tasks/Thread.hpp"
#include "tasks/TaskingScheduler.hpp"
#include "Tasking.hpp"
#include "Addressing.hpp"
//#include "PerformanceTools.hpp"

#include "ConditionVariable.hpp"
#include "FullEmpty.hpp"
#include "MessageBase.hpp"

namespace Grappa {

  typedef Node Core;

  /// Internal messaging functions
  namespace impl {

    /// @addtogroup Communication
    /// @{

    class MessageBase;

    /// global aggregator instance
    class RDMAAggregator;
    extern Grappa::impl::RDMAAggregator global_rdma_aggregator;

    struct MessageList {
      union {
        struct {
          unsigned count_ : 16;
          intptr_t pointer_ : 48;
        };
        intptr_t raw_; // unnecessary; just to ensure alignment
      };
    };

    struct PrefetchEntry {
      union {
        struct {
          unsigned size_ : 16;
          intptr_t pointer_ : 48;
        };
        intptr_t raw_; // unnecessary; just to ensure alignment
      };
    };

    /// used to start deaggregation of remote message
    struct SendBufferInfo {
      int8_t offset;
      int32_t actual_size;
    };

    /// refers to a buffer on the remote machine
    struct ReceiveBufferInfo {
      char * buffer;
      FullEmpty< SendBufferInfo > * info_ptr;
    };

    /// accesor for pointer in message lists
    template< typename MessageListOrPrefetchEntry >
    static inline Grappa::impl::MessageBase * get_pointer( MessageListOrPrefetchEntry * ml ) {
      return reinterpret_cast< Grappa::impl::MessageBase * >( ml->pointer_ );
    }

    /// accesor for wait list in synchronization object
    template< typename MessageListOrPrefetchEntry >
    static inline void set_pointer( MessageListOrPrefetchEntry * ml, Grappa::impl::MessageBase * m ) {
      ml->pointer_ = reinterpret_cast< intptr_t >( m );
    }

    static const int prefetch_dist = 5;
    static const int prefetch_type = 0; // 0 (non-temporal) or 3 (L1) are probably the best choice

    struct CoreData {
      // things that must be included per core:
      //
      // pointer to message list
      // size of message list
      // index into prefetch queue
      //
      // prefetch queue
      //
      // pointer to list of shared destinations for cross-core aggregation
      //
      // pointer to list of messages to receive
      //

      // should we use shared memory?

      Grappa::impl::MessageList messages_;
      Grappa::impl::PrefetchEntry prefetch_queue_[ prefetch_dist ];

      // lowest-numbered core that is on a node
      Core representative_core_;

      Grappa::FullEmpty< ReceiveBufferInfo > remote_buffer_info_;

      Grappa::impl::MessageBase * received_messages_;

      CoreData()
        : messages_()
        , prefetch_queue_()
        , remote_buffer_info_()
        , received_messages_(NULL)
      { }
    } __attribute__ ((aligned(64)));

    /// New aggregator design
    class RDMAAggregator {
    private:

      Core mycore_;
      Node mynode_;
      Core cores_per_node_;

      /// actual aggregation buffers
      /// TODO: one process allocate on shared pages
      /// assume colocated cores are stored next to each other

      std::vector< CoreData > cores_;

      /// Active message to walk a buffer of received deserializers/functors and call them.
      static void deserialize_buffer_am( gasnet_token_t token, void * buf, size_t size );
      int deserialize_buffer_handle_;

      /// Active message to deserialize/call the first entry of a buffer of received deserializers/functors
      static void deserialize_first_am( gasnet_token_t token, void * buf, size_t size );
      int deserialize_first_handle_;

      /// Chase a list of messages and serialize them into a buffer.
      /// Modifies pointer to list to support size-limited-ish aggregation
      /// TODO: make this a hard limit?
      char * aggregate_to_buffer( char * buffer, Grappa::impl::MessageBase ** message_ptr, size_t max = -1 );

      // Deserialize and call a buffer of messages
      static char * deaggregate_buffer( char * buffer, size_t size );

      /// Sender size of RDMA transmission.
      void send_rdma( Core core );

      /// task that is run to allocate space to receive a message
      static void deaggregation_task( GlobalAddress< FullEmpty < ReceiveBufferInfo > > callback_ptr );

    public:

      RDMAAggregator()
        : mycore_( -1 )
        , mynode_( -1 )
        , cores_per_node_( -1 )
        , deserialize_buffer_handle_( -1 )
        , deserialize_first_handle_( -1 )
      {
      }

      // initialize and register with communicator
      void init() {
        cores_.resize( global_communicator.nodes() );
        mycore_ = global_communicator.mynode();
        deserialize_buffer_handle_ = global_communicator.register_active_message_handler( &deserialize_buffer_am );
        deserialize_first_handle_ = global_communicator.register_active_message_handler( &deserialize_first_am );
      }

      // void poll( ) {
      //   // there are two places
      //   MessageBase * received = &cores_[ mynode_ ];
      //   if( received ) {
      //     LOG(INFO) << "Receiving buffer through poll";
      //     Grappa::impl::MessageBase::deserialize_buffer( static_cast< char * >( received ) );
      //     received = NULL;
      //   }
      // }

      /// Enqueue message to be sent
      inline void enqueue( Grappa::impl::MessageBase * m ) {
        // get destination pointer
        CoreData * dest = &cores_[ m->destination_ ];
        //Grappa::impl::MessageBase ** dest_ptr = &dest->messages_;
        Grappa::impl::MessageList * dest_ptr = &(dest->messages_);
        Grappa::impl::MessageList old_ml, new_ml;
        int count;

        // stitch in message
        do {
          // set pointer in new value to current message
          set_pointer( &new_ml, m );

          // read previous value
          old_ml = *dest_ptr;

          // count this message
          new_ml.count_ = count = old_ml.count_ + 1;

          // insert current message
        } while( !__sync_bool_compare_and_swap( &(dest_ptr->raw_), old_ml.raw_, new_ml.raw_ ) );

        // append previous list to current message
        m->next_ = get_pointer( &old_ml );
	// set prefetch to the oldest pointer we remember
        m->prefetch_ = get_pointer( &(dest->prefetch_queue_[ (count + 1 ) % prefetch_dist ]) );

        // now compute prefetch
        PrefetchEntry new_pe;
        set_pointer( &(dest->prefetch_queue_[ count % prefetch_dist ]), m );

	// and size
	size_t size = dest->prefetch_queue_[ ( count - 1 ) % prefetch_dist ].size_ + m->size();
        dest->prefetch_queue_[ count % prefetch_dist ].size_ = size;

      }

      /// send a message that will be run in active message context. This requires very limited messages.
      void send_immediate( Grappa::impl::MessageBase * m ) {
        // create temporary buffer
        const size_t size = m->size();
        char buf[ size ] __attribute__ ((aligned (16)));

        // serialize to buffer
        Grappa::impl::MessageBase * tmp = m;
        DVLOG(5) << "Serializing message from " << tmp;
        char * end = aggregate_to_buffer( &buf[0], &tmp, size );
        DVLOG(5) << "After serializing, pointer was " << tmp;
        DCHECK_EQ( end - buf, size );

        // send
        GASNET_CHECK( gasnet_AMRequestMedium0( m->destination_, deserialize_buffer_handle_, buf, size ) );
      }

      void flush( Core c ) {
        LOG(INFO) << "Flushing";
        send_rdma( c );
        LOG(INFO) << "Flush complete.";
      }

    };

    /// @}
  };
};

#endif
<commit_msg>Flush on a new task; flush if buffer gets large<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#ifndef __RDMAAGGREGATOR_HPP__
#define __RDMAAGGREGATOR_HPP__

#include <gflags/gflags.h>
#include <glog/logging.h>

#include "Communicator.hpp"
#include "tasks/Thread.hpp"
#include "tasks/TaskingScheduler.hpp"
#include "Tasking.hpp"
#include "Addressing.hpp"
//#include "PerformanceTools.hpp"

#include "ConditionVariable.hpp"
#include "FullEmpty.hpp"
#include "MessageBase.hpp"

namespace Grappa {

  typedef Node Core;

  /// Internal messaging functions
  namespace impl {

    /// @addtogroup Communication
    /// @{

    class MessageBase;

    /// global aggregator instance
    class RDMAAggregator;
    extern Grappa::impl::RDMAAggregator global_rdma_aggregator;

    struct MessageList {
      union {
        struct {
          unsigned count_ : 16;
          intptr_t pointer_ : 48;
        };
        intptr_t raw_; // unnecessary; just to ensure alignment
      };
    };

    struct PrefetchEntry {
      union {
        struct {
          unsigned size_ : 16;
          intptr_t pointer_ : 48;
        };
        intptr_t raw_; // unnecessary; just to ensure alignment
      };
    };

    /// used to start deaggregation of remote message
    struct SendBufferInfo {
      int8_t offset;
      int32_t actual_size;
    };

    /// refers to a buffer on the remote machine
    struct ReceiveBufferInfo {
      char * buffer;
      FullEmpty< SendBufferInfo > * info_ptr;
    };

    /// accesor for pointer in message lists
    template< typename MessageListOrPrefetchEntry >
    static inline Grappa::impl::MessageBase * get_pointer( MessageListOrPrefetchEntry * ml ) {
      return reinterpret_cast< Grappa::impl::MessageBase * >( ml->pointer_ );
    }

    /// accesor for wait list in synchronization object
    template< typename MessageListOrPrefetchEntry >
    static inline void set_pointer( MessageListOrPrefetchEntry * ml, Grappa::impl::MessageBase * m ) {
      ml->pointer_ = reinterpret_cast< intptr_t >( m );
    }

    static const int prefetch_dist = 5;
    static const int prefetch_type = 0; // 0 (non-temporal) or 3 (L1) are probably the best choice

    struct CoreData {
      // things that must be included per core:
      //
      // pointer to message list
      // size of message list
      // index into prefetch queue
      //
      // prefetch queue
      //
      // pointer to list of shared destinations for cross-core aggregation
      //
      // pointer to list of messages to receive
      //

      // should we use shared memory?

      Grappa::impl::MessageList messages_;
      Grappa::impl::PrefetchEntry prefetch_queue_[ prefetch_dist ];

      // lowest-numbered core that is on a node
      Core representative_core_;

      Grappa::FullEmpty< ReceiveBufferInfo > remote_buffer_info_;

      Grappa::impl::MessageBase * received_messages_;

      CoreData()
        : messages_()
        , prefetch_queue_()
        , remote_buffer_info_()
        , received_messages_(NULL)
      { }
    } __attribute__ ((aligned(64)));

    /// New aggregator design
    class RDMAAggregator {
    private:

      Core mycore_;
      Node mynode_;
      Core cores_per_node_;

      /// actual aggregation buffers
      /// TODO: one process allocate on shared pages
      /// assume colocated cores are stored next to each other

      std::vector< CoreData > cores_;

      /// Active message to walk a buffer of received deserializers/functors and call them.
      static void deserialize_buffer_am( gasnet_token_t token, void * buf, size_t size );
      int deserialize_buffer_handle_;

      /// Active message to deserialize/call the first entry of a buffer of received deserializers/functors
      static void deserialize_first_am( gasnet_token_t token, void * buf, size_t size );
      int deserialize_first_handle_;

      /// Chase a list of messages and serialize them into a buffer.
      /// Modifies pointer to list to support size-limited-ish aggregation
      /// TODO: make this a hard limit?
      char * aggregate_to_buffer( char * buffer, Grappa::impl::MessageBase ** message_ptr, size_t max = -1 );

      // Deserialize and call a buffer of messages
      static char * deaggregate_buffer( char * buffer, size_t size );

      /// Sender size of RDMA transmission.
      void send_rdma( Core core );

      /// task that is run to allocate space to receive a message
      static void deaggregation_task( GlobalAddress< FullEmpty < ReceiveBufferInfo > > callback_ptr );

    public:

      RDMAAggregator()
        : mycore_( -1 )
        , mynode_( -1 )
        , cores_per_node_( -1 )
        , deserialize_buffer_handle_( -1 )
        , deserialize_first_handle_( -1 )
      {
      }

      // initialize and register with communicator
      void init() {
        cores_.resize( global_communicator.nodes() );
        mycore_ = global_communicator.mynode();
        deserialize_buffer_handle_ = global_communicator.register_active_message_handler( &deserialize_buffer_am );
        deserialize_first_handle_ = global_communicator.register_active_message_handler( &deserialize_first_am );
      }

      // void poll( ) {
      //   // there are two places
      //   MessageBase * received = &cores_[ mynode_ ];
      //   if( received ) {
      //     LOG(INFO) << "Receiving buffer through poll";
      //     Grappa::impl::MessageBase::deserialize_buffer( static_cast< char * >( received ) );
      //     received = NULL;
      //   }
      // }

      /// Enqueue message to be sent
      inline void enqueue( Grappa::impl::MessageBase * m ) {
        // get destination pointer
        CoreData * dest = &cores_[ m->destination_ ];
        //Grappa::impl::MessageBase ** dest_ptr = &dest->messages_;
        Grappa::impl::MessageList * dest_ptr = &(dest->messages_);
        Grappa::impl::MessageList old_ml, new_ml;
        int count;

        // stitch in message
        do {
          // set pointer in new value to current message
          set_pointer( &new_ml, m );

          // read previous value
          old_ml = *dest_ptr;

          // count this message
          new_ml.count_ = count = old_ml.count_ + 1;

          // insert current message
        } while( !__sync_bool_compare_and_swap( &(dest_ptr->raw_), old_ml.raw_, new_ml.raw_ ) );

        // append previous list to current message
        m->next_ = get_pointer( &old_ml );
	// set prefetch to the oldest pointer we remember
        m->prefetch_ = get_pointer( &(dest->prefetch_queue_[ (count + 1 ) % prefetch_dist ]) );

        // now compute prefetch
        PrefetchEntry new_pe;
        set_pointer( &(dest->prefetch_queue_[ count % prefetch_dist ]), m );

	// and size
	size_t size = dest->prefetch_queue_[ ( count - 1 ) % prefetch_dist ].size_ + m->size();
        dest->prefetch_queue_[ count % prefetch_dist ].size_ = size;

	if( size > (1 << 17) ) {
	  Core c = m->destination_;
	  Grappa::privateTask( [ this, c ] {
	      send_rdma( c );
	    });
	}
      }

      /// send a message that will be run in active message context. This requires very limited messages.
      void send_immediate( Grappa::impl::MessageBase * m ) {
        // create temporary buffer
        const size_t size = m->size();
        char buf[ size ] __attribute__ ((aligned (16)));

        // serialize to buffer
        Grappa::impl::MessageBase * tmp = m;
        DVLOG(5) << "Serializing message from " << tmp;
        char * end = aggregate_to_buffer( &buf[0], &tmp, size );
        DVLOG(5) << "After serializing, pointer was " << tmp;
        DCHECK_EQ( end - buf, size );

        // send
        GASNET_CHECK( gasnet_AMRequestMedium0( m->destination_, deserialize_buffer_handle_, buf, size ) );
      }

      void flush( Core c ) {
	Grappa::ConditionVariable cv;
	// run on its own task so it has a full stack
	Grappa::privateTask( [&cv, c, this ] {
	    send_rdma( c );
	    Grappa::signal( &cv );
	  } );
	Grappa::wait( &cv );
      }

    };

    /// @}
  };
};

#endif
<|endoftext|>


<commit_before>#include "http/URLParser.hpp"
#include <cstring>

using std::string;

char hexToChar(char hex1, char hex2) {
    return (hex1 - '0') * 16 + (hex2 - '0');
}

bool decodeURLEntities(const char* in, size_t length, std::string& out) {
    out.clear();
    out.reserve(length);
    for (size_t i = 0; i < length; i++) {
        if (in[i] == '%') {
            if (i + 3 <= length) {
                int value = 0;
                out += hexToChar(in[i+1], in[i+2]);
                i += 2;
            } else {
                return false;
            }
        } else if (in[i] == '+') {
            out += ' ';
        } else {
            out += in[i];
        }
    }
    return true;
}

std::string decodeURLEntities(const char* in, size_t length) {
    std::string ret;
    if(!decodeURLEntities(in, length, ret)) {
        return ""; //On error
    }
    return ret;
}

std::string decodeURLEntities(const std::string& in) {
    return decodeURLEntities(in.data(), in.size());
}

bool decodeURLEntities(const std::string& in, std::string& out) {
    return decodeURLEntities(in.data(), in.size(), out);
}

void parseQueryPart(const char* query, std::map<std::string, std::string>& map) {
    //Skip '?' at the beginning, if any
    if(query[0] == '?') {
        query++;
    }

    while(true) {
        const char* kvSeparator = strchr(query, '=');
        if(kvSeparator == nullptr) {
            //No separator -- no argument left
            //This branch won't execute for correct inputs
            break;
        }
        const char* argSeparator = strchr(kvSeparator, '&');
        string key = decodeURLEntities(query, (kvSeparator - query));
        if(argSeparator == nullptr) {
            //last argument
            map[key] = decodeURLEntities(kvSeparator + 1, strlen(kvSeparator + 1));
            break;
        } else {
            map[key] = decodeURLEntities(kvSeparator + 1, argSeparator - kvSeparator - 1);
        }
        query = argSeparator + 1;
    }
}

static const char* hexLUT = "0123456789ABCDEF";

std::string escapeJSON(const std::string& in) {
    return escapeJSON(in.data(), in.size());
}

std::string escapeJSON(const char* data, size_t inSize) {
    string out;
    for(size_t i = 0; i < inSize; i++) {
        if(data[i] < 0x20) {
            //Ignore unicode characters, just serialize the hex byte value
            char temp[] = "\\u0000";
            temp[4] = hexLUT[(data[i] & 0xF0) >> 4];
            temp[5] = hexLUT[data[i] & 0x0F];
            out += string(temp, 6);
        } else if(data[i] == '\\') {
            out += "\\\\";
        } else if(data[i] == '\"') {
            out += "\\\"";
        } else {
            out += data[i];
        }
    }
    return out;
}
<commit_msg>Fix unused variable (warning)<commit_after>#include "http/URLParser.hpp"
#include <cstring>

using std::string;

char hexToChar(char hex1, char hex2) {
    return (hex1 - '0') * 16 + (hex2 - '0');
}

bool decodeURLEntities(const char* in, size_t length, std::string& out) {
    out.clear();
    out.reserve(length);
    for (size_t i = 0; i < length; i++) {
        if (in[i] == '%') {
            if (i + 3 <= length) {
                out += hexToChar(in[i+1], in[i+2]);
                i += 2;
            } else {
                return false;
            }
        } else if (in[i] == '+') {
            out += ' ';
        } else {
            out += in[i];
        }
    }
    return true;
}

std::string decodeURLEntities(const char* in, size_t length) {
    std::string ret;
    if(!decodeURLEntities(in, length, ret)) {
        return ""; //On error
    }
    return ret;
}

std::string decodeURLEntities(const std::string& in) {
    return decodeURLEntities(in.data(), in.size());
}

bool decodeURLEntities(const std::string& in, std::string& out) {
    return decodeURLEntities(in.data(), in.size(), out);
}

void parseQueryPart(const char* query, std::map<std::string, std::string>& map) {
    //Skip '?' at the beginning, if any
    if(query[0] == '?') {
        query++;
    }

    while(true) {
        const char* kvSeparator = strchr(query, '=');
        if(kvSeparator == nullptr) {
            //No separator -- no argument left
            //This branch won't execute for correct inputs
            break;
        }
        const char* argSeparator = strchr(kvSeparator, '&');
        string key = decodeURLEntities(query, (kvSeparator - query));
        if(argSeparator == nullptr) {
            //last argument
            map[key] = decodeURLEntities(kvSeparator + 1, strlen(kvSeparator + 1));
            break;
        } else {
            map[key] = decodeURLEntities(kvSeparator + 1, argSeparator - kvSeparator - 1);
        }
        query = argSeparator + 1;
    }
}

static const char* hexLUT = "0123456789ABCDEF";

std::string escapeJSON(const std::string& in) {
    return escapeJSON(in.data(), in.size());
}

std::string escapeJSON(const char* data, size_t inSize) {
    string out;
    for(size_t i = 0; i < inSize; i++) {
        if(data[i] < 0x20) {
            //Ignore unicode characters, just serialize the hex byte value
            char temp[] = "\\u0000";
            temp[4] = hexLUT[(data[i] & 0xF0) >> 4];
            temp[5] = hexLUT[data[i] & 0x0F];
            out += string(temp, 6);
        } else if(data[i] == '\\') {
            out += "\\\\";
        } else if(data[i] == '\"') {
            out += "\\\"";
        } else {
            out += data[i];
        }
    }
    return out;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <algorithm>
#include <iterator>
#include <map>
#include <string>

#include "caf/string_view.hpp"

namespace caf {

/// Maps strings to values of type `V`, but unlike `std::map<std::string, V>`
/// accepts `string_view` for looking up keys efficiently.
template <class V>
class dictionary {
public:
  // -- member types ----------------------------------------------------------

  using map_type = std::map<std::string, V>;

  using key_type = typename map_type::key_type;

  using mapped_type = typename map_type::mapped_type;

  using value_type = typename map_type::value_type;

  using allocator_type = typename map_type::allocator_type;

  using size_type = typename map_type::size_type;

  using difference_type = typename map_type::difference_type;

  using reference = typename map_type::reference;

  using const_reference = typename map_type::const_reference;

  using pointer = typename map_type::pointer;

  using const_pointer = typename map_type::const_pointer;

  using iterator = typename map_type::iterator;

  using const_iterator = typename map_type::const_iterator;

  using reverse_iterator = typename map_type::reverse_iterator;

  using const_reverse_iterator = typename map_type::const_reverse_iterator;

  using iterator_bool_pair = std::pair<iterator, bool>;

  struct mapped_type_less {
    inline bool operator()(const value_type& x, string_view y) const {
      return x.first < y;
    }

    inline bool operator()(const value_type& x, const value_type& y) const {
      return x.first < y.first;
    }

    inline bool operator()(string_view x, const value_type& y) const {
      return x < y.first;
    }
  };

  // -- constructors, destructors, and assignment operators -------------------

  dictionary() = default;

  dictionary(dictionary&&) = default;

  dictionary(const dictionary&) = default;

  dictionary(std::initializer_list<value_type> xs) : xs_(xs) {
    // nop
  }

  template <class InputIterator>
  dictionary(InputIterator first, InputIterator last) : xs_(first, last) {
    // nop
  }

  dictionary& operator=(dictionary&&) = default;

  dictionary& operator=(const dictionary&) = default;

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return begin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator crbegin() const noexcept {
    return rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  const_reverse_iterator crend() const noexcept {
    return rend();
  }

  // -- size -------------------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  map_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const map_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(dictionary& other) {
    xs_.swap(other.xs_);
  }

  // -- insertion --------------------------------------------------------------

  template <class K, class T>
  iterator_bool_pair emplace(K&& key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)});
    if (i->first == key)
      return {i, false};
    return {xs_.emplace_hint(i, copy(std::forward<K>(key)),
                             V{std::forward<T>(value)}),
            true};
  }

  iterator_bool_pair insert(value_type kvp) {
    return emplace(kvp.first, std::move(kvp.second));
  }

  iterator insert(iterator hint, value_type kvp) {
    return emplace_hint(hint, kvp.first, std::move(kvp.second));
  }

  template <class T>
  iterator_bool_pair insert(string_view key, T&& value) {
    return emplace(key, V{std::forward<T>(value)});
  }

  template <class K, class T>
  iterator emplace_hint(iterator hint, K&& key, T&& value) {
    if (hint == end() || hint->first > key)
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)})
             .first;
    if (hint->first == key)
      return hint;
    return xs_.emplace_hint(hint, copy(std::forward<K>(key)),
                            V{std::forward<T>(value)});
  }

  template <class T>
  iterator insert(iterator hint, string_view key, T&& value) {
    return emplace_hint(hint, key, std::forward<T>(value));
  }

  template <class T>
  iterator_bool_pair insert_or_assign(string_view key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(key), V{std::forward<T>(value)});
    if (i->first == key) {
      i->second = V{std::forward<T>(value)};
      return {i, false};
    }
    return {xs_.emplace_hint(i, copy(key), V{std::forward<T>(value)}), true};
  }

  template <class T>
  iterator insert_or_assign(iterator hint, string_view key, T&& value) {
    if (hint == end() || hint->first > key)
      return insert_or_assign(key, std::forward<T>(value)).first;
    hint = lower_bound(hint, key);
    if (hint != end() && hint->first == key) {
      hint->second = std::forward<T>(value);
      return hint;
    }
    return xs_.emplace_hint(hint, copy(key), V{std::forward<T>(value)});
  }

  // -- lookup -----------------------------------------------------------------

  bool contains(string_view key) const noexcept {
    auto i = lower_bound(key);
    return !(i == end() || i->first != key);
  }

  size_t count(string_view key) const noexcept {
    return contains(key) ? 1u : 0u;
  }

  iterator find(string_view key) noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  const_iterator find(string_view key) const noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  iterator lower_bound(string_view key) {
    return lower_bound(begin(), key);
  }

  const_iterator lower_bound(string_view key) const {
    return lower_bound(begin(), key);
  }

  iterator upper_bound(string_view key) {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  const_iterator upper_bound(string_view key) const {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  // -- element access ---------------------------------------------------------

  mapped_type& operator[](string_view key) {
    return insert(key, mapped_type{}).first->second;
  }

private:
  iterator lower_bound(iterator from, string_view key) {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  const_iterator lower_bound(const_iterator from, string_view key) const {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  template <size_t N>
  static inline std::string copy(const char (&str)[N]) {
    return std::string{str};
  }

  // Copies the content of `str` into a new string.
  static inline std::string copy(string_view str) {
    return std::string{str.begin(), str.end()};
  }

  // Moves the content of `str` into a new string.
  static inline std::string copy(std::string str) {
    return str;
  }

  map_type xs_;
};

// @relates dictionary
template <class T>
bool operator==(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() == ys.container();
}

// @relates dictionary
template <class T>
bool operator!=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() != ys.container();
}

// @relates dictionary
template <class T>
bool operator<(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() < ys.container();
}

// @relates dictionary
template <class T>
bool operator<=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() <= ys.container();
}

// @relates dictionary
template <class T>
bool operator>(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() > ys.container();
}

// @relates dictionary
template <class T>
bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() >= ys.container();
}

} // namespace caf
<commit_msg>Add missing function overload<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <algorithm>
#include <iterator>
#include <map>
#include <string>

#include "caf/string_view.hpp"

namespace caf {

/// Maps strings to values of type `V`, but unlike `std::map<std::string, V>`
/// accepts `string_view` for looking up keys efficiently.
template <class V>
class dictionary {
public:
  // -- member types ----------------------------------------------------------

  using map_type = std::map<std::string, V>;

  using key_type = typename map_type::key_type;

  using mapped_type = typename map_type::mapped_type;

  using value_type = typename map_type::value_type;

  using allocator_type = typename map_type::allocator_type;

  using size_type = typename map_type::size_type;

  using difference_type = typename map_type::difference_type;

  using reference = typename map_type::reference;

  using const_reference = typename map_type::const_reference;

  using pointer = typename map_type::pointer;

  using const_pointer = typename map_type::const_pointer;

  using iterator = typename map_type::iterator;

  using const_iterator = typename map_type::const_iterator;

  using reverse_iterator = typename map_type::reverse_iterator;

  using const_reverse_iterator = typename map_type::const_reverse_iterator;

  using iterator_bool_pair = std::pair<iterator, bool>;

  struct mapped_type_less {
    inline bool operator()(const value_type& x, string_view y) const {
      return x.first < y;
    }

    inline bool operator()(const value_type& x, const value_type& y) const {
      return x.first < y.first;
    }

    inline bool operator()(string_view x, const value_type& y) const {
      return x < y.first;
    }
  };

  // -- constructors, destructors, and assignment operators -------------------

  dictionary() = default;

  dictionary(dictionary&&) = default;

  dictionary(const dictionary&) = default;

  dictionary(std::initializer_list<value_type> xs) : xs_(xs) {
    // nop
  }

  template <class InputIterator>
  dictionary(InputIterator first, InputIterator last) : xs_(first, last) {
    // nop
  }

  dictionary& operator=(dictionary&&) = default;

  dictionary& operator=(const dictionary&) = default;

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return begin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator crbegin() const noexcept {
    return rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  const_reverse_iterator crend() const noexcept {
    return rend();
  }

  // -- size -------------------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  map_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const map_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(dictionary& other) {
    xs_.swap(other.xs_);
  }

  // -- insertion --------------------------------------------------------------

  template <class K, class T>
  iterator_bool_pair emplace(K&& key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)});
    if (i->first == key)
      return {i, false};
    return {xs_.emplace_hint(i, copy(std::forward<K>(key)),
                             V{std::forward<T>(value)}),
            true};
  }

  iterator_bool_pair insert(value_type kvp) {
    return emplace(kvp.first, std::move(kvp.second));
  }

  iterator insert(iterator hint, value_type kvp) {
    return emplace_hint(hint, kvp.first, std::move(kvp.second));
  }

  template <class T>
  iterator_bool_pair insert(string_view key, T&& value) {
    return emplace(key, V{std::forward<T>(value)});
  }

  template <class K, class T>
  iterator emplace_hint(iterator hint, K&& key, T&& value) {
    if (hint == end() || hint->first > key)
      return xs_.emplace(copy(std::forward<K>(key)), V{std::forward<T>(value)})
             .first;
    if (hint->first == key)
      return hint;
    return xs_.emplace_hint(hint, copy(std::forward<K>(key)),
                            V{std::forward<T>(value)});
  }

  template <class T>
  iterator insert(iterator hint, string_view key, T&& value) {
    return emplace_hint(hint, key, std::forward<T>(value));
  }

  void insert(const_iterator first, const_iterator last) {
    xs_.insert(first, last);
  }

  template <class T>
  iterator_bool_pair insert_or_assign(string_view key, T&& value) {
    auto i = lower_bound(key);
    if (i == end())
      return xs_.emplace(copy(key), V{std::forward<T>(value)});
    if (i->first == key) {
      i->second = V{std::forward<T>(value)};
      return {i, false};
    }
    return {xs_.emplace_hint(i, copy(key), V{std::forward<T>(value)}), true};
  }

  template <class T>
  iterator insert_or_assign(iterator hint, string_view key, T&& value) {
    if (hint == end() || hint->first > key)
      return insert_or_assign(key, std::forward<T>(value)).first;
    hint = lower_bound(hint, key);
    if (hint != end() && hint->first == key) {
      hint->second = std::forward<T>(value);
      return hint;
    }
    return xs_.emplace_hint(hint, copy(key), V{std::forward<T>(value)});
  }

  // -- lookup -----------------------------------------------------------------

  bool contains(string_view key) const noexcept {
    auto i = lower_bound(key);
    return !(i == end() || i->first != key);
  }

  size_t count(string_view key) const noexcept {
    return contains(key) ? 1u : 0u;
  }

  iterator find(string_view key) noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  const_iterator find(string_view key) const noexcept {
    auto i = lower_bound(key);
    return i != end() && i->first == key ? i : end();
  }

  iterator lower_bound(string_view key) {
    return lower_bound(begin(), key);
  }

  const_iterator lower_bound(string_view key) const {
    return lower_bound(begin(), key);
  }

  iterator upper_bound(string_view key) {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  const_iterator upper_bound(string_view key) const {
    mapped_type_less cmp;
    return std::upper_bound(begin(), end(), key, cmp);
  }

  // -- element access ---------------------------------------------------------

  mapped_type& operator[](string_view key) {
    return insert(key, mapped_type{}).first->second;
  }

private:
  iterator lower_bound(iterator from, string_view key) {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  const_iterator lower_bound(const_iterator from, string_view key) const {
    mapped_type_less cmp;
    return std::lower_bound(from, end(), key, cmp);
  }

  template <size_t N>
  static inline std::string copy(const char (&str)[N]) {
    return std::string{str};
  }

  // Copies the content of `str` into a new string.
  static inline std::string copy(string_view str) {
    return std::string{str.begin(), str.end()};
  }

  // Moves the content of `str` into a new string.
  static inline std::string copy(std::string str) {
    return str;
  }

  map_type xs_;
};

// @relates dictionary
template <class T>
bool operator==(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() == ys.container();
}

// @relates dictionary
template <class T>
bool operator!=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() != ys.container();
}

// @relates dictionary
template <class T>
bool operator<(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() < ys.container();
}

// @relates dictionary
template <class T>
bool operator<=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() <= ys.container();
}

// @relates dictionary
template <class T>
bool operator>(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() > ys.container();
}

// @relates dictionary
template <class T>
bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
  return xs.container() >= ys.container();
}

} // namespace caf
<|endoftext|>


<commit_before>#include "routing/features_road_graph.hpp"
#include "routing/nearest_edge_finder.hpp"
#include "routing/route.hpp"
#include "routing/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/index.hpp"
#include "indexer/scales.hpp"

#include "geometry/distance_on_sphere.hpp"

#include "base/logging.hpp"
#include "base/macros.hpp"

namespace routing
{

namespace
{
uint32_t constexpr kPowOfTwoForFeatureCacheSize = 10; // cache contains 2 ^ kPowOfTwoForFeatureCacheSize elements

double constexpr kReadCrossEpsilon = 1.0E-4;

double constexpr kMwmCrossingNodeEqualityRadiusMeters = 100.0;

string GetFeatureCountryName(FeatureID const featureId)
{
  /// @todo Rework this function when storage will provide information about mwm's country
  // MwmInfo.GetCountryName returns country name as 'Country' or 'Country_Region', but only 'Country' is needed
  ASSERT(featureId.IsValid(), ());
  string countryName = featureId.m_mwmId.GetInfo()->GetCountryName();
  size_t const pos = countryName.find('_');
  if (string::npos == pos)
    return countryName;
  return countryName.substr(0, pos);
}

MwmSet::MwmHandle GetMwmHandleByMwmId(Index & index, MwmSet::MwmId const & mwmId)
{
  /// @todo Rework this function when storage will provide appropriate function
  ASSERT(mwmId.IsAlive(), ());
  string const countryName = mwmId.GetInfo()->GetCountryName();
  return index.GetMwmHandleByCountryFile(platform::CountryFile(countryName));
}

inline bool PointsAlmostEqualAbs(const m2::PointD & pt1, const m2::PointD & pt2)
{
  double constexpr kEpsilon = 1e-6;
  return my::AlmostEqualAbs(pt1.x, pt2.x, kEpsilon) && my::AlmostEqualAbs(pt1.y, pt2.y, kEpsilon);
}
}  // namespace

FeaturesRoadGraph::CrossCountryVehicleModel::CrossCountryVehicleModel(unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
  : m_vehicleModelFactory(move(vehicleModelFactory))
  , m_maxSpeedKMPH(m_vehicleModelFactory->GetVehicleModel()->GetMaxSpeed())
{
}

double FeaturesRoadGraph::CrossCountryVehicleModel::GetSpeed(FeatureType const & f) const
{
  return GetVehicleModel(f.GetID())->GetSpeed(f);
}

double FeaturesRoadGraph::CrossCountryVehicleModel::GetMaxSpeed() const
{
  return m_maxSpeedKMPH;
}

bool FeaturesRoadGraph::CrossCountryVehicleModel::IsOneWay(FeatureType const & f) const
{
  return GetVehicleModel(f.GetID())->IsOneWay(f);
}

IVehicleModel * FeaturesRoadGraph::CrossCountryVehicleModel::GetVehicleModel(FeatureID const & featureId) const
{
  auto itr = m_cache.find(featureId.m_mwmId);
  if (itr != m_cache.end())
    return itr->second.get();

  string const country = GetFeatureCountryName(featureId);
  auto const vehicleModel = m_vehicleModelFactory->GetVehicleModelForCountry(country);

  ASSERT(nullptr != vehicleModel, ());
  ASSERT_EQUAL(m_maxSpeedKMPH, vehicleModel->GetMaxSpeed(), ());

  itr = m_cache.insert(make_pair(featureId.m_mwmId, move(vehicleModel))).first;
  return itr->second.get();
}

void FeaturesRoadGraph::CrossCountryVehicleModel::Clear()
{
  m_cache.clear();
}

IRoadGraph::RoadInfo & FeaturesRoadGraph::RoadInfoCache::Find(FeatureID const & featureId, bool & found)
{
  auto res = m_cache.insert(make_pair(featureId.m_mwmId, TMwmFeatureCache()));
  if (res.second)
    res.first->second.Init(kPowOfTwoForFeatureCacheSize);
  return res.first->second.Find(featureId.m_index, found);
}

void FeaturesRoadGraph::RoadInfoCache::Clear()
{
  m_cache.clear();
}

FeaturesRoadGraph::FeaturesRoadGraph(Index & index, unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
    : m_index(index),
      m_vehicleModel(move(vehicleModelFactory))
{
}

uint32_t FeaturesRoadGraph::GetStreetReadScale() { return scales::GetUpperScale(); }

class CrossFeaturesLoader
{
public:
  CrossFeaturesLoader(FeaturesRoadGraph const & graph,
                      IRoadGraph::CrossEdgesLoader & edgesLoader)
      : m_graph(graph), m_edgesLoader(edgesLoader)
  {}

  void operator()(FeatureType & ft)
  {
    if (ft.GetFeatureType() != feature::GEOM_LINE)
      return;

    double const speedKMPH = m_graph.GetSpeedKMPHFromFt(ft);
    if (speedKMPH <= 0.0)
      return;

    FeatureID const featureId = ft.GetID();

    IRoadGraph::RoadInfo const & roadInfo = m_graph.GetCachedRoadInfo(featureId, ft, speedKMPH);

    m_edgesLoader(featureId, roadInfo);
  }

private:
  FeaturesRoadGraph const & m_graph;
  IRoadGraph::CrossEdgesLoader & m_edgesLoader;
};

IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId) const
{
  RoadInfo const & ri = GetCachedRoadInfo(featureId);
  ASSERT_GREATER(ri.m_speedKMPH, 0.0, ());
  return ri;
}

double FeaturesRoadGraph::GetSpeedKMPH(FeatureID const & featureId) const
{
  double const speedKMPH = GetCachedRoadInfo(featureId).m_speedKMPH;
  ASSERT_GREATER(speedKMPH, 0.0, ());
  return speedKMPH;
}

double FeaturesRoadGraph::GetMaxSpeedKMPH() const
{
  return m_vehicleModel.GetMaxSpeed();
}

void FeaturesRoadGraph::ForEachFeatureClosestToCross(m2::PointD const & cross,
                                                     CrossEdgesLoader & edgesLoader) const
{
  CrossFeaturesLoader featuresLoader(*this, edgesLoader);
  m_index.ForEachInRect(featuresLoader,
                        m2::RectD(cross.x - kReadCrossEpsilon, cross.y - kReadCrossEpsilon,
                                  cross.x + kReadCrossEpsilon, cross.y + kReadCrossEpsilon),
                        GetStreetReadScale());
}

void FeaturesRoadGraph::FindClosestEdges(m2::PointD const & point, uint32_t count,
                                         vector<pair<Edge, m2::PointD>> & vicinities) const
{
  NearestEdgeFinder finder(point);

  auto const f = [&finder, this](FeatureType & ft)
  {
    if (ft.GetFeatureType() != feature::GEOM_LINE)
      return;

    double const speedKMPH = m_vehicleModel.GetSpeed(ft);
    if (speedKMPH <= 0.0)
      return;

    FeatureID const featureId = ft.GetID();

    IRoadGraph::RoadInfo const & roadInfo = GetCachedRoadInfo(featureId, ft, speedKMPH);

    finder.AddInformationSource(featureId, roadInfo);
  };

  m_index.ForEachInRect(
      f, MercatorBounds::RectByCenterXYAndSizeInMeters(point, kMwmCrossingNodeEqualityRadiusMeters),
      GetStreetReadScale());

  finder.MakeResult(vicinities, count);
}

void FeaturesRoadGraph::GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const
{
  FeatureType ft;
  Index::FeaturesLoaderGuard loader(m_index, featureId.m_mwmId);
  loader.GetFeatureByIndex(featureId.m_index, ft);
  ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, ());

  types = feature::TypesHolder(ft);
}

void FeaturesRoadGraph::GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const
{
  types = feature::TypesHolder();

  m2::PointD const & cross = junction.GetPoint();

  auto const f = [&types, &cross](FeatureType const & ft)
  {
    if (!types.Empty())
      return;

    if (ft.GetFeatureType() != feature::GEOM_POINT)
      return;

    if (!PointsAlmostEqualAbs(ft.GetCenter(), cross))
      return;

    feature::TypesHolder typesHolder(ft);
    if (!typesHolder.Empty())
      types = typesHolder;
  };

  m_index.ForEachInRect(f,
                        m2::RectD(cross.x - kReadCrossEpsilon, cross.y - kReadCrossEpsilon,
                                  cross.x + kReadCrossEpsilon, cross.y + kReadCrossEpsilon),
                        GetStreetReadScale());
}

void FeaturesRoadGraph::ClearState()
{
  m_cache.Clear();
  m_vehicleModel.Clear();
  m_mwmLocks.clear();
}

bool FeaturesRoadGraph::IsOneWay(FeatureType const & ft) const
{
  return m_vehicleModel.IsOneWay(ft);
}

double FeaturesRoadGraph::GetSpeedKMPHFromFt(FeatureType const & ft) const
{
  return m_vehicleModel.GetSpeed(ft);
}

IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId) const
{
  bool found = false;
  RoadInfo & ri = m_cache.Find(featureId, found);

  if (found)
    return ri;

  FeatureType ft;
  Index::FeaturesLoaderGuard loader(m_index, featureId.m_mwmId);
  loader.GetFeatureByIndex(featureId.m_index, ft);
  ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, ());

  ft.ParseGeometry(FeatureType::BEST_GEOMETRY);

  ri.m_bidirectional = !IsOneWay(ft);
  ri.m_speedKMPH = GetSpeedKMPHFromFt(ft);
  ft.SwapPoints(ri.m_points);

  LockFeatureMwm(featureId);

  return ri;
}

IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId,
                                                                  FeatureType & ft,
                                                                  double speedKMPH) const
{
  bool found = false;
  RoadInfo & ri = m_cache.Find(featureId, found);

  if (found)
    return ri;

  // ft must be set
  ASSERT_EQUAL(featureId, ft.GetID(), ());

  ft.ParseGeometry(FeatureType::BEST_GEOMETRY);

  ri.m_bidirectional = !IsOneWay(ft);
  ri.m_speedKMPH = speedKMPH;
  ft.SwapPoints(ri.m_points);

  LockFeatureMwm(featureId);

  return ri;
}

void FeaturesRoadGraph::LockFeatureMwm(FeatureID const & featureId) const
{
  MwmSet::MwmId mwmId = featureId.m_mwmId;
  ASSERT(mwmId.IsAlive(), ());

  auto const itr = m_mwmLocks.find(mwmId);
  if (itr != m_mwmLocks.end())
    return;

  MwmSet::MwmHandle mwmHandle = GetMwmHandleByMwmId(m_index, mwmId);
  ASSERT(mwmHandle.IsAlive(), ());

  m_mwmLocks.insert(make_pair(move(mwmId), move(mwmHandle)));
}

}  // namespace routing
<commit_msg>Removed workaround, Index API is used<commit_after>#include "routing/features_road_graph.hpp"
#include "routing/nearest_edge_finder.hpp"
#include "routing/route.hpp"
#include "routing/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/index.hpp"
#include "indexer/scales.hpp"

#include "geometry/distance_on_sphere.hpp"

#include "base/logging.hpp"
#include "base/macros.hpp"

namespace routing
{

namespace
{
uint32_t constexpr kPowOfTwoForFeatureCacheSize = 10; // cache contains 2 ^ kPowOfTwoForFeatureCacheSize elements

double constexpr kReadCrossEpsilon = 1.0E-4;

double constexpr kMwmCrossingNodeEqualityRadiusMeters = 100.0;

string GetFeatureCountryName(FeatureID const featureId)
{
  /// @todo Rework this function when storage will provide information about mwm's country
  // MwmInfo.GetCountryName returns country name as 'Country' or 'Country_Region', but only 'Country' is needed
  ASSERT(featureId.IsValid(), ());
  string countryName = featureId.m_mwmId.GetInfo()->GetCountryName();
  size_t const pos = countryName.find('_');
  if (string::npos == pos)
    return countryName;
  return countryName.substr(0, pos);
}

inline bool PointsAlmostEqualAbs(const m2::PointD & pt1, const m2::PointD & pt2)
{
  double constexpr kEpsilon = 1e-6;
  return my::AlmostEqualAbs(pt1.x, pt2.x, kEpsilon) && my::AlmostEqualAbs(pt1.y, pt2.y, kEpsilon);
}
}  // namespace

FeaturesRoadGraph::CrossCountryVehicleModel::CrossCountryVehicleModel(unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
  : m_vehicleModelFactory(move(vehicleModelFactory))
  , m_maxSpeedKMPH(m_vehicleModelFactory->GetVehicleModel()->GetMaxSpeed())
{
}

double FeaturesRoadGraph::CrossCountryVehicleModel::GetSpeed(FeatureType const & f) const
{
  return GetVehicleModel(f.GetID())->GetSpeed(f);
}

double FeaturesRoadGraph::CrossCountryVehicleModel::GetMaxSpeed() const
{
  return m_maxSpeedKMPH;
}

bool FeaturesRoadGraph::CrossCountryVehicleModel::IsOneWay(FeatureType const & f) const
{
  return GetVehicleModel(f.GetID())->IsOneWay(f);
}

IVehicleModel * FeaturesRoadGraph::CrossCountryVehicleModel::GetVehicleModel(FeatureID const & featureId) const
{
  auto itr = m_cache.find(featureId.m_mwmId);
  if (itr != m_cache.end())
    return itr->second.get();

  string const country = GetFeatureCountryName(featureId);
  auto const vehicleModel = m_vehicleModelFactory->GetVehicleModelForCountry(country);

  ASSERT(nullptr != vehicleModel, ());
  ASSERT_EQUAL(m_maxSpeedKMPH, vehicleModel->GetMaxSpeed(), ());

  itr = m_cache.insert(make_pair(featureId.m_mwmId, move(vehicleModel))).first;
  return itr->second.get();
}

void FeaturesRoadGraph::CrossCountryVehicleModel::Clear()
{
  m_cache.clear();
}

IRoadGraph::RoadInfo & FeaturesRoadGraph::RoadInfoCache::Find(FeatureID const & featureId, bool & found)
{
  auto res = m_cache.insert(make_pair(featureId.m_mwmId, TMwmFeatureCache()));
  if (res.second)
    res.first->second.Init(kPowOfTwoForFeatureCacheSize);
  return res.first->second.Find(featureId.m_index, found);
}

void FeaturesRoadGraph::RoadInfoCache::Clear()
{
  m_cache.clear();
}

FeaturesRoadGraph::FeaturesRoadGraph(Index & index, unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
    : m_index(index),
      m_vehicleModel(move(vehicleModelFactory))
{
}

uint32_t FeaturesRoadGraph::GetStreetReadScale() { return scales::GetUpperScale(); }

class CrossFeaturesLoader
{
public:
  CrossFeaturesLoader(FeaturesRoadGraph const & graph,
                      IRoadGraph::CrossEdgesLoader & edgesLoader)
      : m_graph(graph), m_edgesLoader(edgesLoader)
  {}

  void operator()(FeatureType & ft)
  {
    if (ft.GetFeatureType() != feature::GEOM_LINE)
      return;

    double const speedKMPH = m_graph.GetSpeedKMPHFromFt(ft);
    if (speedKMPH <= 0.0)
      return;

    FeatureID const featureId = ft.GetID();

    IRoadGraph::RoadInfo const & roadInfo = m_graph.GetCachedRoadInfo(featureId, ft, speedKMPH);

    m_edgesLoader(featureId, roadInfo);
  }

private:
  FeaturesRoadGraph const & m_graph;
  IRoadGraph::CrossEdgesLoader & m_edgesLoader;
};

IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId) const
{
  RoadInfo const & ri = GetCachedRoadInfo(featureId);
  ASSERT_GREATER(ri.m_speedKMPH, 0.0, ());
  return ri;
}

double FeaturesRoadGraph::GetSpeedKMPH(FeatureID const & featureId) const
{
  double const speedKMPH = GetCachedRoadInfo(featureId).m_speedKMPH;
  ASSERT_GREATER(speedKMPH, 0.0, ());
  return speedKMPH;
}

double FeaturesRoadGraph::GetMaxSpeedKMPH() const
{
  return m_vehicleModel.GetMaxSpeed();
}

void FeaturesRoadGraph::ForEachFeatureClosestToCross(m2::PointD const & cross,
                                                     CrossEdgesLoader & edgesLoader) const
{
  CrossFeaturesLoader featuresLoader(*this, edgesLoader);
  m_index.ForEachInRect(featuresLoader,
                        m2::RectD(cross.x - kReadCrossEpsilon, cross.y - kReadCrossEpsilon,
                                  cross.x + kReadCrossEpsilon, cross.y + kReadCrossEpsilon),
                        GetStreetReadScale());
}

void FeaturesRoadGraph::FindClosestEdges(m2::PointD const & point, uint32_t count,
                                         vector<pair<Edge, m2::PointD>> & vicinities) const
{
  NearestEdgeFinder finder(point);

  auto const f = [&finder, this](FeatureType & ft)
  {
    if (ft.GetFeatureType() != feature::GEOM_LINE)
      return;

    double const speedKMPH = m_vehicleModel.GetSpeed(ft);
    if (speedKMPH <= 0.0)
      return;

    FeatureID const featureId = ft.GetID();

    IRoadGraph::RoadInfo const & roadInfo = GetCachedRoadInfo(featureId, ft, speedKMPH);

    finder.AddInformationSource(featureId, roadInfo);
  };

  m_index.ForEachInRect(
      f, MercatorBounds::RectByCenterXYAndSizeInMeters(point, kMwmCrossingNodeEqualityRadiusMeters),
      GetStreetReadScale());

  finder.MakeResult(vicinities, count);
}

void FeaturesRoadGraph::GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const
{
  FeatureType ft;
  Index::FeaturesLoaderGuard loader(m_index, featureId.m_mwmId);
  loader.GetFeatureByIndex(featureId.m_index, ft);
  ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, ());

  types = feature::TypesHolder(ft);
}

void FeaturesRoadGraph::GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const
{
  types = feature::TypesHolder();

  m2::PointD const & cross = junction.GetPoint();

  auto const f = [&types, &cross](FeatureType const & ft)
  {
    if (!types.Empty())
      return;

    if (ft.GetFeatureType() != feature::GEOM_POINT)
      return;

    if (!PointsAlmostEqualAbs(ft.GetCenter(), cross))
      return;

    feature::TypesHolder typesHolder(ft);
    if (!typesHolder.Empty())
      types = typesHolder;
  };

  m_index.ForEachInRect(f,
                        m2::RectD(cross.x - kReadCrossEpsilon, cross.y - kReadCrossEpsilon,
                                  cross.x + kReadCrossEpsilon, cross.y + kReadCrossEpsilon),
                        GetStreetReadScale());
}

void FeaturesRoadGraph::ClearState()
{
  m_cache.Clear();
  m_vehicleModel.Clear();
  m_mwmLocks.clear();
}

bool FeaturesRoadGraph::IsOneWay(FeatureType const & ft) const
{
  return m_vehicleModel.IsOneWay(ft);
}

double FeaturesRoadGraph::GetSpeedKMPHFromFt(FeatureType const & ft) const
{
  return m_vehicleModel.GetSpeed(ft);
}

IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId) const
{
  bool found = false;
  RoadInfo & ri = m_cache.Find(featureId, found);

  if (found)
    return ri;

  FeatureType ft;
  Index::FeaturesLoaderGuard loader(m_index, featureId.m_mwmId);
  loader.GetFeatureByIndex(featureId.m_index, ft);
  ASSERT_EQUAL(ft.GetFeatureType(), feature::GEOM_LINE, ());

  ft.ParseGeometry(FeatureType::BEST_GEOMETRY);

  ri.m_bidirectional = !IsOneWay(ft);
  ri.m_speedKMPH = GetSpeedKMPHFromFt(ft);
  ft.SwapPoints(ri.m_points);

  LockFeatureMwm(featureId);

  return ri;
}

IRoadGraph::RoadInfo const & FeaturesRoadGraph::GetCachedRoadInfo(FeatureID const & featureId,
                                                                  FeatureType & ft,
                                                                  double speedKMPH) const
{
  bool found = false;
  RoadInfo & ri = m_cache.Find(featureId, found);

  if (found)
    return ri;

  // ft must be set
  ASSERT_EQUAL(featureId, ft.GetID(), ());

  ft.ParseGeometry(FeatureType::BEST_GEOMETRY);

  ri.m_bidirectional = !IsOneWay(ft);
  ri.m_speedKMPH = speedKMPH;
  ft.SwapPoints(ri.m_points);

  LockFeatureMwm(featureId);

  return ri;
}

void FeaturesRoadGraph::LockFeatureMwm(FeatureID const & featureId) const
{
  MwmSet::MwmId mwmId = featureId.m_mwmId;
  ASSERT(mwmId.IsAlive(), ());

  auto const itr = m_mwmLocks.find(mwmId);
  if (itr != m_mwmLocks.end())
    return;

  MwmSet::MwmHandle mwmHandle = m_index.GetMwmHandleById(mwmId);
  ASSERT(mwmHandle.IsAlive(), ());

  m_mwmLocks.insert(make_pair(move(mwmId), move(mwmHandle)));
}

}  // namespace routing
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_MATCH_CASE_HPP
#define CAF_MATCH_CASE_HPP

#include <tuple>
#include <type_traits>

#include "caf/none.hpp"
#include "caf/param.hpp"
#include "caf/optional.hpp"
#include "caf/match_case.hpp"
#include "caf/skip.hpp"

#include "caf/detail/int_list.hpp"
#include "caf/detail/try_match.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/pseudo_tuple.hpp"
#include "caf/detail/invoke_result_visitor.hpp"

namespace caf {

class match_case {
public:
  enum result {
    no_match,
    match,
    skip
  };

  match_case(uint32_t tt);

  match_case(match_case&&) = default;
  match_case(const match_case&) = default;

  virtual ~match_case();

  /// Tries to invoke this match case with the contents of `xs`.
  virtual result invoke(detail::invoke_result_visitor& rv,
                        type_erased_tuple& xs) = 0;

  inline uint32_t type_token() const {
    return token_;
  }

private:
  uint32_t token_;
};

template <bool IsVoid, class F>
class lfinvoker {
public:
  lfinvoker(F& fun) : fun_(fun) {
    // nop
  }

  template <class... Ts>
  typename detail::get_callable_trait<F>::result_type operator()(Ts&&... xs) {
    return fun_(std::forward<Ts>(xs)...);
  }

private:
  F& fun_;
};

template <class F>
class lfinvoker<true, F> {
public:
  lfinvoker(F& fun) : fun_(fun) {
    // nop
  }

  template <class... Ts>
  unit_t operator()(Ts&&... xs) {
    fun_(std::forward<Ts>(xs)...);
    return unit;
  }

private:
  F& fun_;
};

template <class F>
class trivial_match_case : public match_case {
public:
  using fun_trait = typename detail::get_callable_trait<F>::type;

  using plain_result_type = typename fun_trait::result_type;

  using result_type =
    typename std::conditional<
      std::is_reference<plain_result_type>::value,
      plain_result_type,
      typename std::remove_const<plain_result_type>::type
    >::type;

  using arg_types = typename fun_trait::arg_types;

  static constexpr bool is_manipulator =
    detail::tl_exists<
      arg_types,
      detail::is_mutable_ref
    >::value;

  using pattern =
    typename detail::tl_map<
      arg_types,
      param_decay
    >::type;

  using decayed_arg_types =
    typename detail::tl_map<
      arg_types,
      std::decay
    >::type;

  using intermediate_pseudo_tuple =
    typename detail::tl_apply<
      decayed_arg_types,
      detail::pseudo_tuple
    >::type;

  trivial_match_case(const trivial_match_case&) = default;
  trivial_match_case& operator=(const trivial_match_case&) = default;

  trivial_match_case(F f)
      : match_case(make_type_token_from_list<pattern>()),
        fun_(std::move(f)) {
    // nop
  }

  match_case::result invoke(detail::invoke_result_visitor& f,
                            type_erased_tuple& xs) override {
    detail::meta_elements<pattern> ms;
    // check if try_match() reports success
    if (!detail::try_match(xs, ms.arr.data(), ms.arr.size()))
      return match_case::no_match;
    typename detail::il_indices<decayed_arg_types>::type indices;
    lfinvoker<std::is_same<result_type, void>::value, F> fun{fun_};
    message tmp;
    auto needs_detaching = is_manipulator && xs.shared();
    if (needs_detaching)
      tmp = message::copy(xs);
    intermediate_pseudo_tuple tup{needs_detaching ? tmp.content() : xs};
    auto fun_res = apply_args(fun, indices, tup);
    return f.visit(fun_res) ? match_case::match : match_case::skip;
  }

protected:
  F fun_;
};

struct match_case_info {
  uint32_t type_token;
  match_case* ptr;
};

inline bool operator<(const match_case_info& x, const match_case_info& y) {
  return x.type_token < y.type_token;
}

template <class F>
typename std::enable_if<
  !std::is_base_of<match_case, F>::value,
  std::tuple<trivial_match_case<F>>
>::type
to_match_case_tuple(F fun) {
  return std::make_tuple(std::move(fun));
}

template <class MatchCase>
typename std::enable_if<
  std::is_base_of<match_case, MatchCase>::value,
  std::tuple<const MatchCase&>
>::type
to_match_case_tuple(const MatchCase& x) {
  return std::tie(x);
}

template <class... Ts>
const std::tuple<Ts...>& to_match_case_tuple(const std::tuple<Ts...>& x) {
  static_assert(detail::conjunction<
                  std::is_base_of<
                    match_case,
                    Ts
                  >::value...
                >::value,
                "to_match_case_tuple received a tuple of non-match_case Ts");
  return x;
}

template <class T, class U>
typename std::enable_if<
  std::is_base_of<match_case, T>::value || std::is_base_of<match_case, U>::value
>::type
operator,(T, U) {
  static_assert(!std::is_same<T, T>::value,
                "this syntax is not supported -> you probably did "
                "something like 'return (...)' instead of 'return {...}'");
}

} // namespace caf

#endif // CAF_MATCH_CASE_HPP
<commit_msg>Fix compile on GCC 4.8<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_MATCH_CASE_HPP
#define CAF_MATCH_CASE_HPP

#include <tuple>
#include <type_traits>

#include "caf/none.hpp"
#include "caf/param.hpp"
#include "caf/optional.hpp"
#include "caf/match_case.hpp"
#include "caf/skip.hpp"

#include "caf/detail/int_list.hpp"
#include "caf/detail/try_match.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/pseudo_tuple.hpp"
#include "caf/detail/invoke_result_visitor.hpp"

namespace caf {

class match_case {
public:
  enum result {
    no_match,
    match,
    skip
  };

  match_case(uint32_t tt);

  match_case(match_case&&) = default;
  match_case(const match_case&) = default;

  virtual ~match_case();

  /// Tries to invoke this match case with the contents of `xs`.
  virtual result invoke(detail::invoke_result_visitor& rv,
                        type_erased_tuple& xs) = 0;

  inline uint32_t type_token() const {
    return token_;
  }

private:
  uint32_t token_;
};

template <bool IsVoid, class F>
class lfinvoker {
public:
  lfinvoker(F& fun) : fun_(fun) {
    // nop
  }

  template <class... Ts>
  typename detail::get_callable_trait<F>::result_type operator()(Ts&&... xs) {
    return fun_(std::forward<Ts>(xs)...);
  }

private:
  F& fun_;
};

template <class F>
class lfinvoker<true, F> {
public:
  lfinvoker(F& fun) : fun_(fun) {
    // nop
  }

  template <class... Ts>
  unit_t operator()(Ts&&... xs) {
    fun_(std::forward<Ts>(xs)...);
    return unit;
  }

private:
  F& fun_;
};

template <class F>
class trivial_match_case : public match_case {
public:
  using fun_trait = typename detail::get_callable_trait<F>::type;

  using plain_result_type = typename fun_trait::result_type;

  using result_type =
    typename std::conditional<
      std::is_reference<plain_result_type>::value,
      plain_result_type,
      typename std::remove_const<plain_result_type>::type
    >::type;

  using arg_types = typename fun_trait::arg_types;

  static constexpr bool is_manipulator =
    detail::tl_exists<
      arg_types,
      detail::is_mutable_ref
    >::value;

  using pattern =
    typename detail::tl_map<
      arg_types,
      param_decay
    >::type;

  using decayed_arg_types =
    typename detail::tl_map<
      arg_types,
      std::decay
    >::type;

  using intermediate_pseudo_tuple =
    typename detail::tl_apply<
      decayed_arg_types,
      detail::pseudo_tuple
    >::type;

  trivial_match_case(trivial_match_case&&) = default;
  trivial_match_case(const trivial_match_case&) = default;
  trivial_match_case& operator=(trivial_match_case&&) = default;
  trivial_match_case& operator=(const trivial_match_case&) = default;

  trivial_match_case(F f)
      : match_case(make_type_token_from_list<pattern>()),
        fun_(std::move(f)) {
    // nop
  }

  match_case::result invoke(detail::invoke_result_visitor& f,
                            type_erased_tuple& xs) override {
    detail::meta_elements<pattern> ms;
    // check if try_match() reports success
    if (!detail::try_match(xs, ms.arr.data(), ms.arr.size()))
      return match_case::no_match;
    typename detail::il_indices<decayed_arg_types>::type indices;
    lfinvoker<std::is_same<result_type, void>::value, F> fun{fun_};
    message tmp;
    auto needs_detaching = is_manipulator && xs.shared();
    if (needs_detaching)
      tmp = message::copy(xs);
    intermediate_pseudo_tuple tup{needs_detaching ? tmp.content() : xs};
    auto fun_res = apply_args(fun, indices, tup);
    return f.visit(fun_res) ? match_case::match : match_case::skip;
  }

protected:
  F fun_;
};

struct match_case_info {
  uint32_t type_token;
  match_case* ptr;
};

inline bool operator<(const match_case_info& x, const match_case_info& y) {
  return x.type_token < y.type_token;
}

template <class F>
typename std::enable_if<
  !std::is_base_of<match_case, F>::value,
  std::tuple<trivial_match_case<F>>
>::type
to_match_case_tuple(F fun) {
  return std::make_tuple(std::move(fun));
}

template <class MatchCase>
typename std::enable_if<
  std::is_base_of<match_case, MatchCase>::value,
  std::tuple<const MatchCase&>
>::type
to_match_case_tuple(const MatchCase& x) {
  return std::tie(x);
}

template <class... Ts>
const std::tuple<Ts...>& to_match_case_tuple(const std::tuple<Ts...>& x) {
  static_assert(detail::conjunction<
                  std::is_base_of<
                    match_case,
                    Ts
                  >::value...
                >::value,
                "to_match_case_tuple received a tuple of non-match_case Ts");
  return x;
}

template <class T, class U>
typename std::enable_if<
  std::is_base_of<match_case, T>::value || std::is_base_of<match_case, U>::value
>::type
operator,(T, U) {
  static_assert(!std::is_same<T, T>::value,
                "this syntax is not supported -> you probably did "
                "something like 'return (...)' instead of 'return {...}'");
}

} // namespace caf

#endif // CAF_MATCH_CASE_HPP
<|endoftext|>