<commit_before>#include "transport_sweeper.hpp"

#include <cmath>
#include <iostream>

using std::endl;
using std::cout;

namespace mocc {
    real_t TransportSweeper::total_fission( bool old ) const {
        real_t tfis = 0.0;
        const auto &flux = old ? flux_old_: flux_;
        for( auto &xsr: *xs_mesh_ ) {
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t xsnf = xsr.xsmacnf(ig);
                for (auto &ireg: xsr.reg() ) {
                    tfis += flux((int)ireg, (int)ig)*vol_[ireg]*xsnf;
                }
            }
        }
        return tfis;
    }

    void TransportSweeper::calc_fission_source( real_t k,
            ArrayB1& fission_source ) const {

        real_t rkeff = 1.0/k;
        fission_source = 0.0;
        for( auto &xsr: *xs_mesh_ ) {
            const auto &xsnf = xsr.xsmacnf();
            for( int ig=0; ig<(int)n_group_; ig++ ) {
                for( auto &ireg: xsr.reg() ) {
                    fission_source(ireg) += rkeff * xsnf[ig] *
                        flux_(ireg, ig);
                }
            }
        }
        return;
    }

    ArrayB3 TransportSweeper::pin_powers() const {
        assert(n_reg_ == (int)core_mesh_->n_reg());
        ArrayB3 powers(core_mesh_->nz(), core_mesh_->ny(), core_mesh_->nx());
        powers = 0.0;

        // This isnt the most efficient way to do this, memory-wise, but its
        // quick and simple. Calculate volume x flux x kappa-fission for all
        // flat source regions, then reduce to the pin mesh.
        ArrayB1 fsr_pow(n_reg_);
        fsr_pow = 0.0;
        for( const auto &xsr: *xs_mesh_ ) {
            for( int ig=0; ig<n_group_; ig++ ) {
                for( auto ireg: xsr.reg() ) {
                    fsr_pow(ireg) += flux_(ireg, ig) * xsr.xsmackf(ig) *
                        vol_[ireg];
                }
            }
        }

        int ipin = 0;
        int ireg = 0;
        real_t tot_pow = 0.0;
        for( const auto pin: *core_mesh_ ) {
            const PinMesh &pm = pin->mesh();
            Position pos = core_mesh_->pin_position(ipin);
            for( int ir=0; ir<pm.n_reg(); ir++ ) {
                tot_pow += fsr_pow(ireg);
                powers(pos.z, pos.y, pos.x) += fsr_pow(ireg);
                ireg++;
            }
            ipin++;
        }

        // Normalize!
        tot_pow = powers.size()/tot_pow;
        for( auto &v: powers ) {
            v *= tot_pow;
        }

        return powers;
    }

    ArrayB2 TransportSweeper::get_pin_flux() const {
        assert( core_mesh_ );
        ArrayB2 flux( core_mesh_->n_pin(), n_group_ );

        auto flux_it = flux.begin();

        for( int ig=0; ig<n_group_; ig++ ) {
            ArrayB1 flux_1g( flux(blitz::Range::all(), ig) );
            this->get_pin_flux_1g( ig, flux_1g );
        }

        return flux;
    }

    real_t TransportSweeper::flux_residual() const {
        real_t r = 0.0;
        auto it = flux_.begin();
        auto it_old = flux_.begin();
        auto end = flux_.end();
        while( it != end ) {
            real_t e = *it - *it_old;
            r += e*e;
            ++it;
            ++it_old;
        }
        return std::sqrt(r);
    }

}
<commit_msg>a fixed that was forgotten<commit_after>#include "transport_sweeper.hpp"

#include <cmath>
#include <iostream>

using std::endl;
using std::cout;

namespace mocc {
    real_t TransportSweeper::total_fission( bool old ) const {
        real_t tfis = 0.0;
        const auto &flux = old ? flux_old_: flux_;
        for( auto &xsr: *xs_mesh_ ) {
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t xsnf = xsr.xsmacnf(ig);
                for (auto &ireg: xsr.reg() ) {
                    tfis += flux((int)ireg, (int)ig)*vol_[ireg]*xsnf;
                }
            }
        }
        return tfis;
    }

    void TransportSweeper::calc_fission_source( real_t k,
            ArrayB1& fission_source ) const {

        real_t rkeff = 1.0/k;
        fission_source = 0.0;
        for( auto &xsr: *xs_mesh_ ) {
            const auto &xsnf = xsr.xsmacnf();
            for( int ig=0; ig<(int)n_group_; ig++ ) {
                for( auto &ireg: xsr.reg() ) {
                    fission_source(ireg) += rkeff * xsnf[ig] *
                        flux_(ireg, ig);
                }
            }
        }
        return;
    }

    ArrayB3 TransportSweeper::pin_powers() const {
        assert(n_reg_ == (int)core_mesh_->n_reg());
        ArrayB3 powers(core_mesh_->nz(), core_mesh_->ny(), core_mesh_->nx());
        powers = 0.0;

        // This isnt the most efficient way to do this, memory-wise, but its
        // quick and simple. Calculate volume x flux x kappa-fission for all
        // flat source regions, then reduce to the pin mesh.
        ArrayB1 fsr_pow(n_reg_);
        fsr_pow = 0.0;
        for( const auto &xsr: *xs_mesh_ ) {
            for( int ig=0; ig<n_group_; ig++ ) {
                for( auto ireg: xsr.reg() ) {
                    fsr_pow(ireg) += flux_(ireg, ig) * xsr.xsmackf(ig) *
                        vol_[ireg];
                }
            }
        }

        int ipin = 0;
        int ireg = 0;
        real_t tot_pow = 0.0;
        for( const auto pin: *core_mesh_ ) {
            const PinMesh &pm = pin->mesh();
            Position pos = core_mesh_->pin_position(ipin);
            for( int ir=0; ir<pm.n_reg(); ir++ ) {
                tot_pow += fsr_pow(ireg);
                powers(pos.z, pos.y, pos.x) += fsr_pow(ireg);
                ireg++;
            }
            ipin++;
        }

        // Normalize!
        tot_pow = powers.size()/tot_pow;
        for( auto &v: powers ) {
            v *= tot_pow;
        }

        return powers;
    }

    ArrayB2 TransportSweeper::get_pin_flux() const {
        assert( core_mesh_ );
        ArrayB2 flux( core_mesh_->n_pin(), n_group_ );

        auto flux_it = flux.begin();

        for( int ig=0; ig<n_group_; ig++ ) {
            ArrayB1 flux_1g( flux(blitz::Range::all(), ig) );
            this->get_pin_flux_1g( ig, flux_1g );
        }

        return flux;
    }

    real_t TransportSweeper::flux_residual() const {
        real_t r = 0.0;
        auto it = flux_.begin();
        auto it_old = flux_old_.begin();
        auto end = flux_.end();
        while( it != end ) {
            real_t e = *it - *it_old;
            r += e*e;
            ++it;
            ++it_old;
        }
        return std::sqrt(r);
    }

}
<|endoftext|>


<commit_before>#include "mitkOpenGLRenderer.h"
#include "Mapper.h"
#include "mitkImageMapper2D.h"
#include "BaseVtkMapper2D.h"
#include "BaseVtkMapper3D.h"
#include "LevelWindow.h"
#include "mitkVtkInteractorCameraController.h"
#include "mitkVtkRenderWindow.h"
#include "mitkRenderWindow.h"

#include <vtkRenderer.h>
#include <vtkLight.h>
#include <vtkLightKit.h>
#include <vtkRenderWindow.h>
#include <vtkTransform.h>

#include "PlaneGeometry.h"
#include "mitkProperties.h"
#include <queue>
#include <utility>

//##ModelId=3E33ECF301AD
mitk::OpenGLRenderer::OpenGLRenderer() : m_VtkMapperPresent(false)
{
  m_CameraController=NULL;
  m_CameraController = VtkInteractorCameraController::New();
  m_CameraController->AddRenderer(this);

  m_DataChangedCommand = itk::MemberCommand<mitk::OpenGLRenderer>::New();
#ifdef WIN32
  m_DataChangedCommand->SetCallbackFunction(this, mitk::OpenGLRenderer::DataChangedEvent);
#else
  m_DataChangedCommand->SetCallbackFunction(this, &mitk::OpenGLRenderer::DataChangedEvent);
#endif
}

//##ModelId=3E3D28AB0018
void mitk::OpenGLRenderer::SetData(mitk::DataTreeIterator* iterator)
{
  if(iterator!=GetData())
  {

    bool geometry_is_set=false;

    if(m_DataTreeIterator!=NULL)
    {
      //remove old connections
      mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
      while(it->hasNext())
      {
        it->next();
        BaseData::Pointer data=it->get()->GetData();
      }
      delete it;
    }

    BaseRenderer::SetData(iterator);

    if (iterator != NULL)
    {
      //initialize world geometry: use first slice of first node containing an image
      mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
      while(it->hasNext())
      {
        it->next();
        BaseData::Pointer data=it->get()->GetData();
        if(data.IsNotNull())
        {
          if(geometry_is_set==false)
          {
            Image::Pointer image = dynamic_cast<Image*>(data.GetPointer());
            if(image.IsNotNull())
            {
              SetWorldGeometry(image->GetGeometry2D(0, 0));
              geometry_is_set=true;
            }
          }
          //@todo add connections
          //data->AddObserver(itk::EndEvent(), m_DataChangedCommand);
        }
      }
      delete it;
    }

    //update the vtk-based mappers
    Update(); //this is only called to check, whether we have vtk-based mappers!
    UpdateVtkActors();

    Modified();
  }
}

//##ModelId=3ED91D060305
void mitk::OpenGLRenderer::UpdateVtkActors()
{
  VtkInteractorCameraController* vicc=dynamic_cast<VtkInteractorCameraController*>(m_CameraController.GetPointer());

  if (m_VtkMapperPresent == false)
  {
    if(vicc!=NULL)
      vicc->GetVtkInteractor()->Disable();
    return;
  }

  if(vicc!=NULL)
    vicc->GetVtkInteractor()->Enable();

  //    m_LightKit->RemoveLightsFromRenderer(this->m_VtkRenderer);

  //    m_MitkVtkRenderWindow->RemoveRenderer(m_VtkRenderer);
  //    m_VtkRenderer->Delete();

  if(m_VtkRenderer==NULL)
  {
    m_VtkRenderer = vtkRenderer::New();
    m_VtkRenderer->SetLayer(0);
    m_MitkVtkRenderWindow->AddRenderer( this->m_VtkRenderer );
  }

   m_VtkRenderer->RemoveAllProps();

  //strange: when using a simple light, the backface of the planes are not shown (regardless of SetNumberOfLayers)
  //m_Light->Delete();
  //m_Light = vtkLight::New();
  //m_VtkRenderer->AddLight( m_Light );
  if(m_LightKit!=NULL)
  {
    m_LightKit = vtkLightKit::New();
    m_LightKit->AddLightsToRenderer(m_VtkRenderer);
  }

  //    try
  if (m_DataTreeIterator != NULL)
  {
    mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
    while(it->hasNext())
    {
      it->next();
      mitk::Mapper::Pointer mapper = it->get()->GetMapper(m_MapperID);
      if(mapper.IsNotNull())
      {
        BaseVtkMapper2D* anVtkMapper2D;
        anVtkMapper2D=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
        if(anVtkMapper2D != NULL)
        {
          anVtkMapper2D->Update(this);
          m_VtkRenderer->AddProp(anVtkMapper2D->GetProp());
        }
        else
        {
          BaseVtkMapper3D* anVtkMapper3D;
          anVtkMapper3D=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
          if(anVtkMapper3D != NULL)
          {
            anVtkMapper3D->Update(this);
            m_VtkRenderer->AddProp(anVtkMapper3D->GetProp());
          }
        }
      }
    }
    delete it;
  }

  //    catch( ::itk::ExceptionObject ee)
  //    {
  //        printf("%s\n",ee.what());
  ////        itkGenericOutputMacro(ee->what());
  //    }
  //    catch( ...)
  //    {
  //            printf("test\n");
  //    }
}

//##ModelId=3E330D260255
void mitk::OpenGLRenderer::Update()
{
  if(m_DataTreeIterator == NULL) return;

  m_VtkMapperPresent=false;

  mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
  while(it->hasNext())
  {
    it->next();
    //      mitk::LevelWindow lw;
    //unsigned int dummy[] = {10,10,10};
    //Geometry3D geometry(3,dummy);
    mitk::Mapper::Pointer mapper = it->get()->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      Mapper2D* mapper2d=dynamic_cast<Mapper2D*>(mapper.GetPointer());
      if(mapper2d != NULL)
      {
        BaseVtkMapper2D* vtkmapper2d=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
        if(vtkmapper2d != NULL)
        {
          vtkmapper2d->Update(this);
          m_VtkMapperPresent=true;
        }
        else
          mapper2d->Update();
        //ImageMapper2D* imagemapper2d=dynamic_cast<ImageMapper2D*>(mapper.GetPointer());
      }
      else
      {
        BaseVtkMapper3D* vtkmapper3d=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
        if(vtkmapper3d != NULL)
        {
          vtkmapper3d->Update(this);
          m_VtkMapperPresent=true;
        }
      }
    }
  }

  delete it;
  Modified();
  m_LastUpdateTime=GetMTime();
}

//##ModelId=3E330D2903CC
void mitk::OpenGLRenderer::Render()
{
  //if we do not have any data, we do nothing else but clearing our window
  if(GetData() == NULL)
  {
    glClear(GL_COLOR_BUFFER_BIT);
    return;
  }

  //has someone transformed our worldgeometry-node? if so, incorporate this transform into
  //the worldgeometry itself and reset the transform of the node to identity
  /*	if(m_WorldGeometryTransformTime<m_WorldGeometryNode->GetVtkTransform()->GetMTime())
  {
  vtkTransform *i;
  m_WorldGeometry->TransformGeometry(m_WorldGeometryNode->GetVtkTransform());
  m_WorldGeometryNode->GetVtkTransform()->Identity();
  m_WorldGeometryTransformTime=GetWorldGeometryNode()->GetVtkTransform()->GetMTime();
  }
  */
  //has the data tree been changed?
  if(dynamic_cast<mitk::DataTree*>(GetData()->getTree()) == NULL ) return;
  //	if(m_LastUpdateTime<((mitk::DataTree*)GetData()->getTree())->GetMTime())
  if(m_LastUpdateTime < dynamic_cast<mitk::DataTree*>(GetData()->getTree())->GetMTime() )
  {
    //yes: update vtk-actors
    Update();
    UpdateVtkActors();
  }
  else
  //has anything else changed (geometry to display, etc.)?
  if (m_LastUpdateTime<GetMTime() ||
    m_LastUpdateTime<GetDisplayGeometry()->GetMTime() ||
    m_LastUpdateTime<GetDisplayGeometry()->GetWorldGeometry()->GetMTime())
  {
    //std::cout << "OpenGLRenderer calling its update..." << std::endl;
    Update();
  }
  else
  if(m_MapperID==2)
  { //@todo in 3D mode wird sonst nix geupdated, da z.Z. weder camera noch nderung des Baums beachtet wird!!!
    Update();
  }

  glClear(GL_COLOR_BUFFER_BIT);

  //PlaneGeometry* myPlaneGeom =
  //  dynamic_cast<PlaneGeometry *>((mitk::Geometry2D*)(GetWorldGeometry()));

  glViewport (0, 0, m_Size[0], m_Size[1]);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  gluOrtho2D( 0.0, m_Size[0], 0.0, m_Size[1] );
  glMatrixMode( GL_MODELVIEW );

  mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
  mitk::DataTree::Pointer tree = dynamic_cast <mitk::DataTree *> (it->getTree());
  //	std::cout << "Render:: tree: " <<  *tree << std::endl;

  typedef std::pair<int, GLMapper2D*> LayerMapperPair;
  std::priority_queue<LayerMapperPair> layers;
  int mapperNo = 0;
  while(it->hasNext())
  {
    it->next();

    mitk::DataTreeNode::Pointer node = it->get();
    mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      GLMapper2D* mapper2d=dynamic_cast<GLMapper2D*>(mapper.GetPointer());
      if(mapper2d!=NULL)
      {
        // mapper without a layer property are painted first
        int layer=-1;
        node->GetIntProperty("layer", layer, this);
        // pushing negative layer value, since default sort for
        // priority_queue is lessthan
        layers.push(LayerMapperPair(- (layer<<16) - mapperNo ,mapper2d));
        mapperNo++;
      }
    }
  }

  delete it;
  while (!layers.empty()) {
    layers.top().second->Paint(this);
    layers.pop();
  }
  if(m_VtkMapperPresent) {
    m_MitkVtkRenderWindow->MitkRender();
  }
  else
    m_RenderWindow->swapBuffers();
 }

/*!
\brief Initialize the OpenGLRenderer

This method is called from the two Constructors
*/
void mitk::OpenGLRenderer::InitRenderer(mitk::RenderWindow* renderwindow)
{
  BaseRenderer::InitRenderer(renderwindow);

  m_InitNeeded = true;
  m_ResizeNeeded = true;

  m_MitkVtkRenderWindow = mitk::VtkRenderWindow::New();
  m_MitkVtkRenderWindow->SetMitkRenderer(this);
  /**@todo SetNumberOfLayers commented out, because otherwise the backface of the planes are not shown (only, when a light is added).
  * But we need SetNumberOfLayers(2) later, when we want to prevent vtk to clear the widget before it renders (i.e., when we render something in the scene before vtk).
  */
  //m_MitkVtkRenderWindow->SetNumberOfLayers(2);

  m_VtkRenderer = vtkRenderer::New();
  m_MitkVtkRenderWindow->AddRenderer( m_VtkRenderer );

  //strange: when using a simple light, the backface of the planes are not shown (regardless of SetNumberOfLayers)
  //m_Light = vtkLight::New();
  //m_VtkRenderer->AddLight( m_Light );
  m_LightKit = vtkLightKit::New();
  m_LightKit->AddLightsToRenderer(m_VtkRenderer);

  if(m_CameraController)
    ((VtkInteractorCameraController*)m_CameraController.GetPointer())->SetRenderWindow(m_MitkVtkRenderWindow);

  //we should disable vtk doublebuffering, but then it doesn't work
  //m_MitkVtkRenderWindow->SwapBuffersOff();
}

/*!
\brief Destructs the OpenGLRenderer.
*/
//##ModelId=3E33ECF301B7
mitk::OpenGLRenderer::~OpenGLRenderer() {
  m_VtkRenderer->Delete();
  m_MitkVtkRenderWindow->Delete();
}

/*!
\brief Initialize the OpenGL Window
*/
//##ModelId=3E33145B0096
void mitk::OpenGLRenderer::Initialize( ) {
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glColor3f(1.0, 0.0, 0.0);
}

/*!
\brief Resize the OpenGL Window
*/
//##ModelId=3E33145B00D2
void mitk::OpenGLRenderer::Resize(int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  gluOrtho2D( 0.0, w, 0.0, h );
  glMatrixMode( GL_MODELVIEW );

  BaseRenderer::Resize(w, h);

  Update();
  //    m_MitkVtkRenderWindow->SetSize(w,h); //@FIXME?
}

/*!
\brief Render the scene
*/
//##ModelId=3E33145B005A
void mitk::OpenGLRenderer::Paint( )
{

//  glFlush();
//  m_RenderWindow->swapBuffers();
  Render();
}

//##ModelId=3E3314B0005C
void mitk::OpenGLRenderer::SetWindowId(void * id)
{
  m_MitkVtkRenderWindow->SetWindowId( id );
}

//##ModelId=3E3799420227
void mitk::OpenGLRenderer::InitSize(int w, int h)
{
  m_MitkVtkRenderWindow->SetSize(w,h);
  GetDisplayGeometry()->Fit();
  Modified();
  Update();
}

//##ModelId=3EF59AD20235
void mitk::OpenGLRenderer::SetMapperID(const MapperSlotId mapperId)
{
  Superclass::SetMapperID(mapperId);
  Update();
  UpdateVtkActors();
}

//##ModelId=3EF162760271
void mitk::OpenGLRenderer::MakeCurrent()
{
  if(m_RenderWindow!=NULL)
  {
    m_RenderWindow->MakeCurrent();
  }
}

void mitk::OpenGLRenderer::DataChangedEvent(const itk::Object *caller, const itk::EventObject &event)
{
  if(m_RenderWindow!=NULL)
  {
    m_RenderWindow->Update();
  }
}<commit_msg>correct initialization<commit_after>#include "mitkOpenGLRenderer.h"
#include "Mapper.h"
#include "mitkImageMapper2D.h"
#include "BaseVtkMapper2D.h"
#include "BaseVtkMapper3D.h"
#include "LevelWindow.h"
#include "mitkVtkInteractorCameraController.h"
#include "mitkVtkRenderWindow.h"
#include "mitkRenderWindow.h"

#include <vtkRenderer.h>
#include <vtkLight.h>
#include <vtkLightKit.h>
#include <vtkRenderWindow.h>
#include <vtkTransform.h>

#include "PlaneGeometry.h"
#include "mitkProperties.h"
#include <queue>
#include <utility>

//##ModelId=3E33ECF301AD
mitk::OpenGLRenderer::OpenGLRenderer() : m_VtkMapperPresent(false)
{
  m_CameraController=NULL;
  m_CameraController = VtkInteractorCameraController::New();
  m_CameraController->AddRenderer(this);

  m_DataChangedCommand = itk::MemberCommand<mitk::OpenGLRenderer>::New();
#ifdef WIN32
  m_DataChangedCommand->SetCallbackFunction(this, mitk::OpenGLRenderer::DataChangedEvent);
#else
  m_DataChangedCommand->SetCallbackFunction(this, &mitk::OpenGLRenderer::DataChangedEvent);
#endif
}

//##ModelId=3E3D28AB0018
void mitk::OpenGLRenderer::SetData(mitk::DataTreeIterator* iterator)
{
  if(iterator!=GetData())
  {

    bool geometry_is_set=false;

    if(m_DataTreeIterator!=NULL)
    {
      //remove old connections
      mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
      while(it->hasNext())
      {
        it->next();
        BaseData::Pointer data=it->get()->GetData();
      }
      delete it;
    }

    BaseRenderer::SetData(iterator);

    if (iterator != NULL)
    {
      //initialize world geometry: use first slice of first node containing an image
      mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
      while(it->hasNext())
      {
        it->next();
        BaseData::Pointer data=it->get()->GetData();
        if(data.IsNotNull())
        {
          if(geometry_is_set==false)
          {
            Image::Pointer image = dynamic_cast<Image*>(data.GetPointer());
            if(image.IsNotNull())
            {
              SetWorldGeometry(image->GetGeometry2D(0, 0));
              geometry_is_set=true;
            }
          }
          //@todo add connections
          //data->AddObserver(itk::EndEvent(), m_DataChangedCommand);
        }
      }
      delete it;
    }

    //update the vtk-based mappers
    Update(); //this is only called to check, whether we have vtk-based mappers!
    UpdateVtkActors();

    Modified();
  }
}

//##ModelId=3ED91D060305
void mitk::OpenGLRenderer::UpdateVtkActors()
{
  VtkInteractorCameraController* vicc=dynamic_cast<VtkInteractorCameraController*>(m_CameraController.GetPointer());

  if (m_VtkMapperPresent == false)
  {
    if(vicc!=NULL)
      vicc->GetVtkInteractor()->Disable();
    return;
  }

  if(vicc!=NULL)
    vicc->GetVtkInteractor()->Enable();

  //    m_LightKit->RemoveLightsFromRenderer(this->m_VtkRenderer);

  //    m_MitkVtkRenderWindow->RemoveRenderer(m_VtkRenderer);
  //    m_VtkRenderer->Delete();

  if(m_VtkRenderer==NULL)
  {
    m_VtkRenderer = vtkRenderer::New();
    m_VtkRenderer->SetLayer(0);
    m_MitkVtkRenderWindow->AddRenderer( this->m_VtkRenderer );
  }

   m_VtkRenderer->RemoveAllProps();

  //strange: when using a simple light, the backface of the planes are not shown (regardless of SetNumberOfLayers)
  //m_Light->Delete();
  //m_Light = vtkLight::New();
  //m_VtkRenderer->AddLight( m_Light );
  if(m_LightKit!=NULL)
  {
    m_LightKit = vtkLightKit::New();
    m_LightKit->AddLightsToRenderer(m_VtkRenderer);
  }

  //    try
  if (m_DataTreeIterator != NULL)
  {
    mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
    while(it->hasNext())
    {
      it->next();
      mitk::Mapper::Pointer mapper = it->get()->GetMapper(m_MapperID);
      if(mapper.IsNotNull())
      {
        BaseVtkMapper2D* anVtkMapper2D;
        anVtkMapper2D=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
        if(anVtkMapper2D != NULL)
        {
          anVtkMapper2D->Update(this);
          m_VtkRenderer->AddProp(anVtkMapper2D->GetProp());
        }
        else
        {
          BaseVtkMapper3D* anVtkMapper3D;
          anVtkMapper3D=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
          if(anVtkMapper3D != NULL)
          {
            anVtkMapper3D->Update(this);
            m_VtkRenderer->AddProp(anVtkMapper3D->GetProp());
          }
        }
      }
    }
    delete it;
  }

  //    catch( ::itk::ExceptionObject ee)
  //    {
  //        printf("%s\n",ee.what());
  ////        itkGenericOutputMacro(ee->what());
  //    }
  //    catch( ...)
  //    {
  //            printf("test\n");
  //    }
}

//##ModelId=3E330D260255
void mitk::OpenGLRenderer::Update()
{
  if(m_DataTreeIterator == NULL) return;

  m_VtkMapperPresent=false;

  mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
  while(it->hasNext())
  {
    it->next();
    //      mitk::LevelWindow lw;
    //unsigned int dummy[] = {10,10,10};
    //Geometry3D geometry(3,dummy);
    mitk::Mapper::Pointer mapper = it->get()->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      Mapper2D* mapper2d=dynamic_cast<Mapper2D*>(mapper.GetPointer());
      if(mapper2d != NULL)
      {
        BaseVtkMapper2D* vtkmapper2d=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
        if(vtkmapper2d != NULL)
        {
          vtkmapper2d->Update(this);
          m_VtkMapperPresent=true;
        }
        else
          mapper2d->Update();
        //ImageMapper2D* imagemapper2d=dynamic_cast<ImageMapper2D*>(mapper.GetPointer());
      }
      else
      {
        BaseVtkMapper3D* vtkmapper3d=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
        if(vtkmapper3d != NULL)
        {
          vtkmapper3d->Update(this);
          m_VtkMapperPresent=true;
        }
      }
    }
  }

  delete it;
  Modified();
  m_LastUpdateTime=GetMTime();
}

//##ModelId=3E330D2903CC
void mitk::OpenGLRenderer::Render()
{
  //if we do not have any data, we do nothing else but clearing our window
  if(GetData() == NULL)
  {
    glClear(GL_COLOR_BUFFER_BIT);
     if(m_VtkMapperPresent) {
      //    m_MitkVtkRenderWindow->MitkRender();
     } else
      m_RenderWindow->swapBuffers();

    return;
  }

  //has someone transformed our worldgeometry-node? if so, incorporate this transform into
  //the worldgeometry itself and reset the transform of the node to identity
  /*	if(m_WorldGeometryTransformTime<m_WorldGeometryNode->GetVtkTransform()->GetMTime())
  {
  vtkTransform *i;
  m_WorldGeometry->TransformGeometry(m_WorldGeometryNode->GetVtkTransform());
  m_WorldGeometryNode->GetVtkTransform()->Identity();
  m_WorldGeometryTransformTime=GetWorldGeometryNode()->GetVtkTransform()->GetMTime();
  }
  */
  //has the data tree been changed?
  if(dynamic_cast<mitk::DataTree*>(GetData()->getTree()) == NULL ) return;
  //	if(m_LastUpdateTime<((mitk::DataTree*)GetData()->getTree())->GetMTime())
  if(m_LastUpdateTime < dynamic_cast<mitk::DataTree*>(GetData()->getTree())->GetMTime() )
  {
    //yes: update vtk-actors
    Update();
    UpdateVtkActors();
  }
  else
  //has anything else changed (geometry to display, etc.)?
  if (m_LastUpdateTime<GetMTime() ||
    m_LastUpdateTime<GetDisplayGeometry()->GetMTime() ||
    m_LastUpdateTime<GetDisplayGeometry()->GetWorldGeometry()->GetMTime())
  {
    //std::cout << "OpenGLRenderer calling its update..." << std::endl;
    Update();
  }
  else
  if(m_MapperID==2)
  { //@todo in 3D mode wird sonst nix geupdated, da z.Z. weder camera noch nderung des Baums beachtet wird!!!
    Update();
  }

  glClear(GL_COLOR_BUFFER_BIT);

  //PlaneGeometry* myPlaneGeom =
  //  dynamic_cast<PlaneGeometry *>((mitk::Geometry2D*)(GetWorldGeometry()));

  glViewport (0, 0, m_Size[0], m_Size[1]);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  gluOrtho2D( 0.0, m_Size[0], 0.0, m_Size[1] );
  glMatrixMode( GL_MODELVIEW );

  mitk::DataTreeIterator* it=m_DataTreeIterator->clone();
  mitk::DataTree::Pointer tree = dynamic_cast <mitk::DataTree *> (it->getTree());
  //	std::cout << "Render:: tree: " <<  *tree << std::endl;

  typedef std::pair<int, GLMapper2D*> LayerMapperPair;
  std::priority_queue<LayerMapperPair> layers;
  int mapperNo = 0;
  while(it->hasNext())
  {
    it->next();

    mitk::DataTreeNode::Pointer node = it->get();
    mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      GLMapper2D* mapper2d=dynamic_cast<GLMapper2D*>(mapper.GetPointer());
      if(mapper2d!=NULL)
      {
        // mapper without a layer property are painted first
        int layer=-1;
        node->GetIntProperty("layer", layer, this);
        // pushing negative layer value, since default sort for
        // priority_queue is lessthan
        layers.push(LayerMapperPair(- (layer<<16) - mapperNo ,mapper2d));
        mapperNo++;
      }
    }
  }

  delete it;
  while (!layers.empty()) {
    layers.top().second->Paint(this);
    layers.pop();
  }
  if(m_VtkMapperPresent) {
    m_MitkVtkRenderWindow->MitkRender();
  }
  else
    m_RenderWindow->swapBuffers();
 }

/*!
\brief Initialize the OpenGLRenderer

This method is called from the two Constructors
*/
void mitk::OpenGLRenderer::InitRenderer(mitk::RenderWindow* renderwindow)
{
  BaseRenderer::InitRenderer(renderwindow);

  m_InitNeeded = true;
  m_ResizeNeeded = true;

  m_MitkVtkRenderWindow = mitk::VtkRenderWindow::New();
  m_MitkVtkRenderWindow->SetMitkRenderer(this);
  /**@todo SetNumberOfLayers commented out, because otherwise the backface of the planes are not shown (only, when a light is added).
  * But we need SetNumberOfLayers(2) later, when we want to prevent vtk to clear the widget before it renders (i.e., when we render something in the scene before vtk).
  */
  //m_MitkVtkRenderWindow->SetNumberOfLayers(2);

  m_VtkRenderer = vtkRenderer::New();
  m_MitkVtkRenderWindow->AddRenderer( m_VtkRenderer );

  //strange: when using a simple light, the backface of the planes are not shown (regardless of SetNumberOfLayers)
  //m_Light = vtkLight::New();
  //m_VtkRenderer->AddLight( m_Light );
  m_LightKit = vtkLightKit::New();
  m_LightKit->AddLightsToRenderer(m_VtkRenderer);

  if(m_CameraController)
    ((VtkInteractorCameraController*)m_CameraController.GetPointer())->SetRenderWindow(m_MitkVtkRenderWindow);

  //we should disable vtk doublebuffering, but then it doesn't work
  //m_MitkVtkRenderWindow->SwapBuffersOff();

}

/*!
\brief Destructs the OpenGLRenderer.
*/
//##ModelId=3E33ECF301B7
mitk::OpenGLRenderer::~OpenGLRenderer() {
  m_VtkRenderer->Delete();
  m_MitkVtkRenderWindow->Delete();
}

/*!
\brief Initialize the OpenGL Window
*/
//##ModelId=3E33145B0096
void mitk::OpenGLRenderer::Initialize( ) {

  glClearColor(0.0, 0.0, 0.0, 1.0);
  glColor3f(1.0, 0.0, 0.0);

}

/*!
\brief Resize the OpenGL Window
*/
//##ModelId=3E33145B00D2
void mitk::OpenGLRenderer::Resize(int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  gluOrtho2D( 0.0, w, 0.0, h );
  glMatrixMode( GL_MODELVIEW );

  BaseRenderer::Resize(w, h);

  Update();
  //    m_MitkVtkRenderWindow->SetSize(w,h); //@FIXME?
}

/*!
\brief Render the scene
*/
//##ModelId=3E33145B005A
void mitk::OpenGLRenderer::Paint( )
{

//  glFlush();
//  m_RenderWindow->swapBuffers();
  Render();
}

//##ModelId=3E3314B0005C
void mitk::OpenGLRenderer::SetWindowId(void * id)
{
  m_MitkVtkRenderWindow->SetWindowId( id );
}

//##ModelId=3E3799420227
void mitk::OpenGLRenderer::InitSize(int w, int h)
{
  m_MitkVtkRenderWindow->SetSize(w,h);
  GetDisplayGeometry()->Fit();
  Modified();
  Update();
}

//##ModelId=3EF59AD20235
void mitk::OpenGLRenderer::SetMapperID(const MapperSlotId mapperId)
{
  Superclass::SetMapperID(mapperId);
  Update();
  UpdateVtkActors();
}

//##ModelId=3EF162760271
void mitk::OpenGLRenderer::MakeCurrent()
{
  if(m_RenderWindow!=NULL)
  {
    m_RenderWindow->MakeCurrent();
  }
}

void mitk::OpenGLRenderer::DataChangedEvent(const itk::Object *caller, const itk::EventObject &event)
{
  if(m_RenderWindow!=NULL)
  {
    m_RenderWindow->Update();
  }
}<|endoftext|>


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

#include <LPC24.h>
#include "../../Drivers/AT49BV322DT_Flash/AT49BV322DT_Flash.h"

#define TOTAL_DEPLOYMENT_CONTROLLERS 1

static TinyCLR_Storage_Controller deploymentControllers[TOTAL_DEPLOYMENT_CONTROLLERS];
static TinyCLR_Api_Info deploymentApi[TOTAL_DEPLOYMENT_CONTROLLERS];

struct DeploymentState {
    uint32_t controllerIndex;

    size_t regionCount;
    const uint64_t* regionAddresses;
    const size_t* regionSizes;

    TinyCLR_Storage_Descriptor storageDescriptor;
    TinyCLR_Startup_DeploymentConfiguration deploymentConfiguration;

    bool isOpened = false;
};

static DeploymentState deploymentStates[TOTAL_DEPLOYMENT_CONTROLLERS];

void LPC24_Deployment_AddApi(const TinyCLR_Api_Manager* apiManager) {
    for (auto i = 0; i < TOTAL_DEPLOYMENT_CONTROLLERS; i++) {
        deploymentControllers[i].ApiInfo = &deploymentApi[i];
        deploymentControllers[i].Acquire = &LPC24_Deployment_Acquire;
        deploymentControllers[i].Release = &LPC24_Deployment_Release;
        deploymentControllers[i].Open = &LPC24_Deployment_Open;
        deploymentControllers[i].Close = &LPC24_Deployment_Close;
        deploymentControllers[i].Read = &LPC24_Deployment_Read;
        deploymentControllers[i].Write = &LPC24_Deployment_Write;
        deploymentControllers[i].Erase = &LPC24_Deployment_Erase;
        deploymentControllers[i].IsErased = &LPC24_Deployment_IsErased;
        deploymentControllers[i].GetDescriptor = &LPC24_Deployment_GetDescriptor;
        deploymentControllers[i].IsPresent = &LPC24_Deployment_IsPresent;
        deploymentControllers[i].SetPresenceChangedHandler = &LPC24_Deployment_SetPresenceChangedHandler;

        deploymentApi[i].Author = "GHI Electronics, LLC";
        deploymentApi[i].Name = "GHIElectronics.TinyCLR.NativeApis.LPC24.StorageController";
        deploymentApi[i].Type = TinyCLR_Api_Type::StorageController;
        deploymentApi[i].Version = 0;
        deploymentApi[i].Implementation = &deploymentControllers[i];
        deploymentApi[i].State = &deploymentStates[i];

        deploymentStates[i].controllerIndex = i;
        deploymentStates[i].regionCount = LPC24_DEPLOYMENT_SECTOR_NUM;
    }

    return (const TinyCLR_Api_Info*)&deploymentApi;
}

TinyCLR_Result LPC24_Deployment_Acquire(const TinyCLR_Storage_Controller* self) {
    return AT49BV322DT_Flash_Acquire();
}

TinyCLR_Result LPC24_Deployment_Release(const TinyCLR_Storage_Controller* self) {
    return AT49BV322DT_Flash_Release();
}

TinyCLR_Result LPC24_Deployment_Open(const TinyCLR_Storage_Controller* self) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    if (state->isOpened)
        return TinyCLR_Result::SharingViolation;

    state->storageDescriptor.CanReadDirect = true;
    state->storageDescriptor.CanWriteDirect = true;
    state->storageDescriptor.CanExecuteDirect = true;
    state->storageDescriptor.EraseBeforeWrite = true;
    state->storageDescriptor.Removable = false;
    state->storageDescriptor.RegionsRepeat = true;

    size_t regionCount;

    AT49BV322DT_Flash_GetSectorMap(state->regionAddresses, state->regionSizes, regionCount);

    if (regionCount < state->regionCount)
        return TinyCLR_Result::ArgumentOutOfRange;

    state->regionAddresses += LPC24_DEPLOYMENT_SECTOR_START;
    state->regionSizes += LPC24_DEPLOYMENT_SECTOR_START;

    state->storageDescriptor.RegionCount = state->regionCount;
    state->storageDescriptor.RegionAddresses = reinterpret_cast<const uint64_t*>(state->regionAddresses);
    state->storageDescriptor.RegionSizes = reinterpret_cast<const size_t*>(state->regionSizes);

    state->deploymentConfiguration.RegionCount = state->storageDescriptor.RegionCount;
    state->deploymentConfiguration.RegionAddresses = state->storageDescriptor.RegionAddresses;
    state->deploymentConfiguration.RegionSizes = state->storageDescriptor.RegionSizes;

    state->isOpened = true;

    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_Close(const TinyCLR_Storage_Controller* self) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    if (!state->isOpened)
        return TinyCLR_Result::NotFound;

    state->isOpened = false;

    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_Read(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, uint8_t* data, uint64_t timeout) {
    return AT49BV322DT_Flash_Read(address, count, data);
}

TinyCLR_Result LPC24_Deployment_Write(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, const uint8_t* data, uint64_t timeout) {
    return AT49BV322DT_Flash_Write(address, count, data);;
}

TinyCLR_Result LPC24_Deployment_Erase(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, uint64_t timeout) {
    auto sector = address;

    sector += LPC24_DEPLOYMENT_SECTOR_START;

    return AT49BV322DT_Flash_EraseBlock(sector);
}

TinyCLR_Result LPC24_Deployment_IsErased(const TinyCLR_Storage_Controller* self, uint64_t address, size_t count, bool& erased) {
    auto sector = address;

    sector += LPC24_DEPLOYMENT_SECTOR_START;

    return AT49BV322DT_Flash_IsBlockErased(sector, erased);
}

TinyCLR_Result LPC24_Deployment_GetBytesPerSector(const TinyCLR_Storage_Controller* self, uint32_t address, int32_t& size) {
    return AT49BV322DT_Flash_GetBytesPerSector(address, size);
}

TinyCLR_Result LPC24_Deployment_SetPresenceChangedHandler(const TinyCLR_Storage_Controller* self, TinyCLR_Storage_PresenceChangedHandler handler) {
    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_IsPresent(const TinyCLR_Storage_Controller* self, bool& present) {
    present = true;
    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_GetDescriptor(const TinyCLR_Storage_Controller* self, const TinyCLR_Storage_Descriptor*& descriptor) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    descriptor = &state->storageDescriptor;

    return descriptor->RegionCount > 0 ? TinyCLR_Result::Success : TinyCLR_Result::NotImplemented;
}

const TinyCLR_Startup_DeploymentConfiguration* LPC24_Deployment_GetDeploymentConfiguration() {
    auto state = &deploymentStates[0];

    return reinterpret_cast<const TinyCLR_Startup_DeploymentConfiguration*>(&state->deploymentConfiguration);
}

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

#include <LPC24.h>
#include "../../Drivers/AT49BV322DT_Flash/AT49BV322DT_Flash.h"

#define TOTAL_DEPLOYMENT_CONTROLLERS 1

const char* deploymentApiNames[TOTAL_DEPLOYMENT_CONTROLLERS] = {
    "GHIElectronics.TinyCLR.NativeApis.LPC24.StorageController\\0"
};

static TinyCLR_Storage_Controller deploymentControllers[TOTAL_DEPLOYMENT_CONTROLLERS];
static TinyCLR_Api_Info deploymentApi[TOTAL_DEPLOYMENT_CONTROLLERS];

struct DeploymentState {
    uint32_t controllerIndex;

    size_t regionCount;
    const uint64_t* regionAddresses;
    const size_t* regionSizes;

    TinyCLR_Storage_Descriptor storageDescriptor;
    TinyCLR_Startup_DeploymentConfiguration deploymentConfiguration;

    bool isOpened = false;
    bool tableInitialized = false;
};

static DeploymentState deploymentStates[TOTAL_DEPLOYMENT_CONTROLLERS];

void LPC24_Deployment_EnsureTableInitialized() {
    for (auto i = 0; i < TOTAL_DEPLOYMENT_CONTROLLERS; i++) {
        if (deploymentStates[i].tableInitialized)
            continue;

        deploymentControllers[i].ApiInfo = &deploymentApi[i];
        deploymentControllers[i].Acquire = &LPC24_Deployment_Acquire;
        deploymentControllers[i].Release = &LPC24_Deployment_Release;
        deploymentControllers[i].Open = &LPC24_Deployment_Open;
        deploymentControllers[i].Close = &LPC24_Deployment_Close;
        deploymentControllers[i].Read = &LPC24_Deployment_Read;
        deploymentControllers[i].Write = &LPC24_Deployment_Write;
        deploymentControllers[i].Erase = &LPC24_Deployment_Erase;
        deploymentControllers[i].IsErased = &LPC24_Deployment_IsErased;
        deploymentControllers[i].GetDescriptor = &LPC24_Deployment_GetDescriptor;
        deploymentControllers[i].IsPresent = &LPC24_Deployment_IsPresent;
        deploymentControllers[i].SetPresenceChangedHandler = &LPC24_Deployment_SetPresenceChangedHandler;

        deploymentApi[i].Author = "GHI Electronics, LLC";
        deploymentApi[i].Name = deploymentApiNames[i];
        deploymentApi[i].Type = TinyCLR_Api_Type::StorageController;
        deploymentApi[i].Version = 0;
        deploymentApi[i].Implementation = &deploymentControllers[i];
        deploymentApi[i].State = &deploymentStates[i];

        deploymentStates[i].controllerIndex = i;
        deploymentStates[i].regionCount = LPC24_DEPLOYMENT_SECTOR_NUM;

        deploymentStates[i].tableInitialized = true;
    }
}

void LPC24_Deployment_GetDeploymentApi(const TinyCLR_Api_Info*& api, const TinyCLR_Startup_DeploymentConfiguration*& configuration) {
    LPC24_Deployment_EnsureTableInitialized();

    auto state = &deploymentStates[0];

    api = &deploymentApi[0];
    configuration = &state->deploymentConfiguration;
}

void LPC24_Deployment_AddApi(const TinyCLR_Api_Manager* apiManager) {
    LPC24_Deployment_EnsureTableInitialized();

    for (auto i = 0; i < TOTAL_DEPLOYMENT_CONTROLLERS; i++) {
        apiManager->Add(apiManager, &deploymentApi[i]);
    }

    apiManager->SetDefaultName(apiManager, TinyCLR_Api_Type::StorageController, deploymentApi[0].Name);
}

TinyCLR_Result LPC24_Deployment_Acquire(const TinyCLR_Storage_Controller* self) {
    return AT49BV322DT_Flash_Acquire();
}

TinyCLR_Result LPC24_Deployment_Release(const TinyCLR_Storage_Controller* self) {
    return AT49BV322DT_Flash_Release();
}

TinyCLR_Result LPC24_Deployment_Open(const TinyCLR_Storage_Controller* self) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    if (state->isOpened)
        return TinyCLR_Result::SharingViolation;

    state->storageDescriptor.CanReadDirect = true;
    state->storageDescriptor.CanWriteDirect = true;
    state->storageDescriptor.CanExecuteDirect = true;
    state->storageDescriptor.EraseBeforeWrite = true;
    state->storageDescriptor.Removable = false;
    state->storageDescriptor.RegionsRepeat = true;

    size_t regionCount;

    AT49BV322DT_Flash_GetSectorMap(state->regionAddresses, state->regionSizes, regionCount);

    if (regionCount < state->regionCount)
        return TinyCLR_Result::ArgumentOutOfRange;

    state->regionAddresses += LPC24_DEPLOYMENT_SECTOR_START;
    state->regionSizes += LPC24_DEPLOYMENT_SECTOR_START;

    state->storageDescriptor.RegionCount = state->regionCount;
    state->storageDescriptor.RegionAddresses = reinterpret_cast<const uint64_t*>(state->regionAddresses);
    state->storageDescriptor.RegionSizes = reinterpret_cast<const size_t*>(state->regionSizes);

    state->deploymentConfiguration.RegionCount = state->storageDescriptor.RegionCount;
    state->deploymentConfiguration.RegionAddresses = state->storageDescriptor.RegionAddresses;
    state->deploymentConfiguration.RegionSizes = state->storageDescriptor.RegionSizes;

    state->isOpened = true;

    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_Close(const TinyCLR_Storage_Controller* self) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    if (!state->isOpened)
        return TinyCLR_Result::NotFound;

    state->isOpened = false;

    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_Read(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, uint8_t* data, uint64_t timeout) {
    return AT49BV322DT_Flash_Read(address, count, data);
}

TinyCLR_Result LPC24_Deployment_Write(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, const uint8_t* data, uint64_t timeout) {
    return AT49BV322DT_Flash_Write(address, count, data);;
}

TinyCLR_Result LPC24_Deployment_Erase(const TinyCLR_Storage_Controller* self, uint64_t address, size_t& count, uint64_t timeout) {
    auto sector = address;

    sector += LPC24_DEPLOYMENT_SECTOR_START;

    return AT49BV322DT_Flash_EraseBlock(sector);
}

TinyCLR_Result LPC24_Deployment_IsErased(const TinyCLR_Storage_Controller* self, uint64_t address, size_t count, bool& erased) {
    auto sector = address;

    sector += LPC24_DEPLOYMENT_SECTOR_START;

    return AT49BV322DT_Flash_IsBlockErased(sector, erased);
}

TinyCLR_Result LPC24_Deployment_GetBytesPerSector(const TinyCLR_Storage_Controller* self, uint32_t address, int32_t& size) {
    return AT49BV322DT_Flash_GetBytesPerSector(address, size);
}

TinyCLR_Result LPC24_Deployment_SetPresenceChangedHandler(const TinyCLR_Storage_Controller* self, TinyCLR_Storage_PresenceChangedHandler handler) {
    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_IsPresent(const TinyCLR_Storage_Controller* self, bool& present) {
    present = true;
    return TinyCLR_Result::Success;
}

TinyCLR_Result LPC24_Deployment_GetDescriptor(const TinyCLR_Storage_Controller* self, const TinyCLR_Storage_Descriptor*& descriptor) {
    auto state = reinterpret_cast<DeploymentState*>(self->ApiInfo->State);

    descriptor = &state->storageDescriptor;

    return descriptor->RegionCount > 0 ? TinyCLR_Result::Success : TinyCLR_Result::NotImplemented;
}

const TinyCLR_Startup_DeploymentConfiguration* LPC24_Deployment_GetDeploymentConfiguration() {
    auto state = &deploymentStates[0];

    return reinterpret_cast<const TinyCLR_Startup_DeploymentConfiguration*>(&state->deploymentConfiguration);
}

<|endoftext|>


<commit_before>#include "mpga.h"
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <iostream>
#include <argos3/core/simulator/simulator.h>
#include "mpga_loop_functions.h"

/****************************************/
/****************************************/

/* File name for shared memory area */
static const char* SHARED_MEMORY_FILE = "/MPGA_SHARED_MEMORY";

/****************************************/
/****************************************/

bool SortHighToLow(const CMPGA::SIndividual* pc_a,
                   const CMPGA::SIndividual* pc_b) {
   return pc_a->Score > pc_b->Score;
}

bool SortLowToHigh(const CMPGA::SIndividual* pc_a,
                   const CMPGA::SIndividual* pc_b) {
   return pc_b->Score > pc_a->Score;
}

/****************************************/
/****************************************/

CMPGA::CMPGA(const CRange<Real>& c_allele_range,
             UInt32 un_genome_size,
             UInt32 un_pop_size,
             Real f_mutation_prob,
             UInt32 un_num_trials,
             UInt32 un_generations,
             bool b_maximize,
             const std::string& str_argosconf,
             TScoreAggregator t_score_aggregator,
             UInt32 un_random_seed) :
   m_unCurrentGeneration(0),
   m_cAlleleRange(c_allele_range),
   m_unGenomeSize(un_genome_size),
   m_unPopSize(un_pop_size),
   m_fMutationProb(f_mutation_prob),
   m_unNumTrials(un_num_trials),
   m_unGenerations(un_generations),
   m_strARGoSConf(str_argosconf),
   m_tScoreAggregator(t_score_aggregator),
   MasterPID(::getpid()),
   m_cIndComparator(b_maximize ? SortHighToLow : SortLowToHigh) {
   /* Create shared memory manager */
   m_pcSharedMem = new CSharedMem(un_genome_size,
                                  un_pop_size);
   /* Create slave processes */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      /* Perform fork */
      SlavePIDs.push_back(::fork());
      if(SlavePIDs.back() == 0) {
         /* We're in a slave */
         LaunchARGoS(i);
      }
   }
   /* Create a random number generator */
   CRandom::CreateCategory("ga", un_random_seed);
   m_pcRNG = CRandom::CreateRNG("ga");
   /* Create initial population */
   SIndividual* psInd;
   for(size_t p = 0; p < m_unPopSize; ++p) {
      /* Create individual */
      psInd = new SIndividual;
      psInd->Score = -1.0;
      /* Create random genome */
      for(size_t g = 0; g < m_unGenomeSize; ++g) {
         psInd->Genome.push_back(m_pcRNG->Uniform(m_cAlleleRange));
      }
      /* Add individual to the population */
      m_tPopulation.push_back(psInd);
   }
   /* The master sleeps to give enough time to the slaves to
    * initialize and suspend properly. If not enough time is given
    * here, the master will hang later on. */
   ::sleep(3);
}

/****************************************/
/****************************************/

CMPGA::~CMPGA() {
   /* Terminate slaves */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      ::kill(SlavePIDs[i], SIGTERM);
   }
   /* Clean memory up */
   while(!m_tPopulation.empty()) {
      delete m_tPopulation.back();
      m_tPopulation.pop_back();
   }
   CRandom::RemoveCategory("ga");
   /* Other cleanup in common between master and slaves */
   Cleanup();
}

/****************************************/
/****************************************/

const CMPGA::TPopulation& CMPGA::GetPopulation() const {
   return m_tPopulation;
}

/****************************************/
/****************************************/

UInt32 CMPGA::GetGeneration() const {
   return m_unCurrentGeneration;
}

/****************************************/
/****************************************/

void CMPGA::Cleanup() {
   delete m_pcSharedMem;
}

/****************************************/
/****************************************/

void CMPGA::Evaluate() {
   /* Set parameters for the processes and resume them */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      /* Set genome */
      m_pcSharedMem->SetGenome(i, &(m_tPopulation[i]->Genome[0]));
      /* Resume process */
      ::kill(SlavePIDs[i], SIGCONT);
   }
   /* Wait for all the slaves to finish the run */
   UInt32 unTrialsLeft = m_unPopSize;
   int nSlaveInfo;
   pid_t tSlavePID;
   while(unTrialsLeft > 0) {
      /* Wait for next slave to finish */
      tSlavePID = ::waitpid(-1, &nSlaveInfo, WUNTRACED);
      /* Make sure the slave went back to sleep and didn't crash */
      if(!WIFSTOPPED(nSlaveInfo)) {
         LOGERR << "[FATAL] Slave process with PID " << tSlavePID << " exited, can't continue. Check file ARGoS_LOGERR_" << tSlavePID << " for more information." << std::endl;
         LOG.Flush();
         LOGERR.Flush();
         Cleanup();
         ::exit(1);
      }
      /* All OK, one less slave to wait for */
      --unTrialsLeft;
   }
   /* Copy the scores into the population data */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      m_tPopulation[i]->Score = m_pcSharedMem->GetScore(i);
   }
   /* Sort the population by score, from the best to the worst */
   std::sort(m_tPopulation.begin(),
             m_tPopulation.end(),
             m_cIndComparator);
}

/****************************************/
/****************************************/

void CMPGA::NextGen() {
   ++m_unCurrentGeneration;
   Selection();
   Crossover();
   Mutation();
}

/****************************************/
/****************************************/

bool CMPGA::Done() const {
   return m_unCurrentGeneration >= m_unGenerations;
}

/****************************************/
/****************************************/

/* Global pointer to the CMPGA object in the current slave, used by
 * SlaveHandleSIGTERM() to perform cleanup */
static CMPGA* GA_INSTANCE;

/* SIGTERM handler for slave processes */
void SlaveHandleSIGTERM(int) {
   argos::CSimulator::GetInstance().Destroy();
   argos::LOG.Flush();
   argos::LOGERR.Flush();
   GA_INSTANCE->Cleanup();
}

void CMPGA::LaunchARGoS(UInt32 un_slave_id) {
   /* Set the global GA instance pointer for signal handler */
   GA_INSTANCE = this;
   /* Install handler for SIGTERM */
   ::signal(SIGTERM, SlaveHandleSIGTERM);
   /* Initialize ARGoS */
   /* Redirect LOG and LOGERR to dedicated files to prevent clutter on the screen */
   std::ofstream cLOGFile("ARGoS_LOG_" + ToString(::getpid()), std::ios::out);
   LOG.DisableColoredOutput();
   LOG.GetStream().rdbuf(cLOGFile.rdbuf());
   std::ofstream cLOGERRFile("ARGoS_LOGERR_" + ToString(::getpid()), std::ios::out);
   LOGERR.DisableColoredOutput();
   LOGERR.GetStream().rdbuf(cLOGERRFile.rdbuf());
   /* The CSimulator class of ARGoS is a singleton. Therefore, to
    * manipulate an ARGoS experiment, it is enough to get its instance */
   argos::CSimulator& cSimulator = argos::CSimulator::GetInstance();
   try {
      /* Set the .argos configuration file
       * This is a relative path which assumed that you launch the executable
       * from argos3-examples (as said also in the README) */
      cSimulator.SetExperimentFileName(m_strARGoSConf);
      /* Load it to configure ARGoS */
      cSimulator.LoadExperiment();
      LOG.Flush();
      LOGERR.Flush();
   }
   catch(CARGoSException& ex) {
      LOGERR << ex.what() << std::endl;
      ::raise(SIGTERM);
   }
   /* Get a reference to the loop functions */
   CMPGALoopFunctions& cLoopFunctions = dynamic_cast<CMPGALoopFunctions&>(cSimulator.GetLoopFunctions());
   /* Create vector of scores */
   std::vector<Real> vecScores(m_unPopSize, 0.0);
   /* Continue working until killed by parent */
   while(1) {
      /* Suspend yourself, waiting for parent's resume signal */
      ::raise(SIGTSTP);
      /* Resumed */
      /* Configure the controller with the genome */
      cLoopFunctions.ConfigureFromGenome(m_pcSharedMem->GetGenome(un_slave_id));
      /* Run the trials */
      for(size_t i = 0; i < m_unNumTrials; ++i) {
         /* Tell the loop functions to get ready for the i-th trial */
         cLoopFunctions.SetTrial(i);
         /* Reset the experiment.
          * This internally calls also CMPGALoopFunctions::Reset(). */
         cSimulator.Reset();
         /* Run the experiment */
         cSimulator.Execute();
         /* Store score */
         vecScores[i] = cLoopFunctions.Score();
         LOG.Flush();
         LOGERR.Flush();
      }
      ;
      /* Put result in shared memory */
      m_pcSharedMem->SetScore(un_slave_id, m_tScoreAggregator(vecScores));
   }
}

/****************************************/
/****************************************/

void CMPGA::Selection() {
   /* Delete all individuals apart from the top two */
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      delete m_tPopulation[i];
      m_tPopulation.pop_back();
   }
}

/****************************************/
/****************************************/

void CMPGA::Crossover() {
   /*
    * This is a simple one-point crossover.
    */
   SIndividual* psParent1 = m_tPopulation[0];
   SIndividual* psParent2 = m_tPopulation[1];
   UInt32 unCut;
   SIndividual* psInd;
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      /* Pick a cutting point at random */
      unCut = m_pcRNG->Uniform(CRange<UInt32>(1, m_unGenomeSize-1));
      /* Make a new individual */
      psInd = new SIndividual;
      /* Copy alleles from parent 1 */
      for(UInt32 j = 0; j < unCut; ++j) {
         psInd->Genome.push_back(psParent1->Genome[j]);
      }
      /* Copy alleles from parent 2 */
      for(UInt32 j = unCut; j < m_unGenomeSize; ++j) {
         psInd->Genome.push_back(psParent2->Genome[j]);
      }
      /* Add individual to the new population */
      m_tPopulation.push_back(psInd);
   }
}

/****************************************/
/****************************************/

void CMPGA::Mutation() {
   /* Mutate the alleles of the newly added individuals by setting a
    * new random value from a uniform distribution */
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      for(UInt32 a = 0; a < m_unGenomeSize; ++a) {
         if(m_pcRNG->Bernoulli(m_fMutationProb))
            m_tPopulation[i]->Genome[a] = m_pcRNG->Uniform(m_cAlleleRange);
      }
   }
}

/****************************************/
/****************************************/

CMPGA::CSharedMem::CSharedMem(UInt32 un_genome_size,
                              UInt32 un_pop_size) :
   m_unGenomeSize(un_genome_size),
   m_unPopSize(un_pop_size) {
   /* Create shared memory area for master-slave communication */
   m_nSharedMemFD = ::shm_open(SHARED_MEMORY_FILE,
                               O_RDWR | O_CREAT,
                               S_IRUSR | S_IWUSR);
   if(m_nSharedMemFD < 0) {
      ::perror(SHARED_MEMORY_FILE);
      exit(1);
   }
   /* Resize shared memory area to contain the population data
    * - The area must contain m_unPopSize elements
    * - Each element must have space for the data of an individual
    *   - Genome: m_unGenomeSize * sizeof(Real)
    *   - Score: sizeof(Real)
    */
   size_t unShareMemSize = m_unPopSize * (m_unGenomeSize+1) * sizeof(Real);
   ::ftruncate(m_nSharedMemFD, unShareMemSize);
   /* Get pointer to shared memory area */
   m_pfSharedMem = reinterpret_cast<Real*>(
      ::mmap(NULL,
             unShareMemSize,
             PROT_READ | PROT_WRITE,
             MAP_SHARED,
             m_nSharedMemFD,
             0));
   if(m_pfSharedMem == MAP_FAILED) {
      ::perror("shared memory");
      exit(1);
   }
}

/****************************************/
/****************************************/

CMPGA::CSharedMem::~CSharedMem() {
   munmap(m_pfSharedMem, m_unPopSize * (m_unGenomeSize+1) * sizeof(Real));
   close(m_nSharedMemFD);
   shm_unlink(SHARED_MEMORY_FILE);
}

/****************************************/
/****************************************/

Real* CMPGA::CSharedMem::GetGenome(UInt32 un_individual) {
   return m_pfSharedMem + un_individual * (m_unGenomeSize+1);
}

/****************************************/
/****************************************/

void CMPGA::CSharedMem::SetGenome(UInt32 un_individual,
                                  const Real* pf_genome) {
   ::memcpy(m_pfSharedMem + un_individual * (m_unGenomeSize+1),
            pf_genome,
            m_unGenomeSize * sizeof(Real));
}

/****************************************/
/****************************************/

Real CMPGA::CSharedMem::GetScore(UInt32 un_individual) {
   return m_pfSharedMem[un_individual * (m_unGenomeSize+1) + m_unGenomeSize];
}

/****************************************/
/****************************************/

void CMPGA::CSharedMem::SetScore(UInt32 un_individual,
                                 Real f_score) {
   m_pfSharedMem[un_individual * (m_unGenomeSize+1) + m_unGenomeSize] = f_score;
}

/****************************************/
/****************************************/
<commit_msg>Fixed bug in MPGA. Wrong size for score vector.<commit_after>#include "mpga.h"
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <iostream>
#include <argos3/core/simulator/simulator.h>
#include "mpga_loop_functions.h"

/****************************************/
/****************************************/

/* File name for shared memory area */
static const char* SHARED_MEMORY_FILE = "/MPGA_SHARED_MEMORY";

/****************************************/
/****************************************/

bool SortHighToLow(const CMPGA::SIndividual* pc_a,
                   const CMPGA::SIndividual* pc_b) {
   return pc_a->Score > pc_b->Score;
}

bool SortLowToHigh(const CMPGA::SIndividual* pc_a,
                   const CMPGA::SIndividual* pc_b) {
   return pc_b->Score > pc_a->Score;
}

/****************************************/
/****************************************/

CMPGA::CMPGA(const CRange<Real>& c_allele_range,
             UInt32 un_genome_size,
             UInt32 un_pop_size,
             Real f_mutation_prob,
             UInt32 un_num_trials,
             UInt32 un_generations,
             bool b_maximize,
             const std::string& str_argosconf,
             TScoreAggregator t_score_aggregator,
             UInt32 un_random_seed) :
   m_unCurrentGeneration(0),
   m_cAlleleRange(c_allele_range),
   m_unGenomeSize(un_genome_size),
   m_unPopSize(un_pop_size),
   m_fMutationProb(f_mutation_prob),
   m_unNumTrials(un_num_trials),
   m_unGenerations(un_generations),
   m_strARGoSConf(str_argosconf),
   m_tScoreAggregator(t_score_aggregator),
   MasterPID(::getpid()),
   m_cIndComparator(b_maximize ? SortHighToLow : SortLowToHigh) {
   /* Create shared memory manager */
   m_pcSharedMem = new CSharedMem(un_genome_size,
                                  un_pop_size);
   /* Create slave processes */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      /* Perform fork */
      SlavePIDs.push_back(::fork());
      if(SlavePIDs.back() == 0) {
         /* We're in a slave */
         LaunchARGoS(i);
      }
   }
   /* Create a random number generator */
   CRandom::CreateCategory("ga", un_random_seed);
   m_pcRNG = CRandom::CreateRNG("ga");
   /* Create initial population */
   SIndividual* psInd;
   for(size_t p = 0; p < m_unPopSize; ++p) {
      /* Create individual */
      psInd = new SIndividual;
      psInd->Score = -1.0;
      /* Create random genome */
      for(size_t g = 0; g < m_unGenomeSize; ++g) {
         psInd->Genome.push_back(m_pcRNG->Uniform(m_cAlleleRange));
      }
      /* Add individual to the population */
      m_tPopulation.push_back(psInd);
   }
   /* The master sleeps to give enough time to the slaves to
    * initialize and suspend properly. If not enough time is given
    * here, the master will hang later on. */
   ::sleep(3);
}

/****************************************/
/****************************************/

CMPGA::~CMPGA() {
   /* Terminate slaves */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      ::kill(SlavePIDs[i], SIGTERM);
   }
   /* Clean memory up */
   while(!m_tPopulation.empty()) {
      delete m_tPopulation.back();
      m_tPopulation.pop_back();
   }
   CRandom::RemoveCategory("ga");
   /* Other cleanup in common between master and slaves */
   Cleanup();
}

/****************************************/
/****************************************/

const CMPGA::TPopulation& CMPGA::GetPopulation() const {
   return m_tPopulation;
}

/****************************************/
/****************************************/

UInt32 CMPGA::GetGeneration() const {
   return m_unCurrentGeneration;
}

/****************************************/
/****************************************/

void CMPGA::Cleanup() {
   delete m_pcSharedMem;
}

/****************************************/
/****************************************/

void CMPGA::Evaluate() {
   /* Set parameters for the processes and resume them */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      /* Set genome */
      m_pcSharedMem->SetGenome(i, &(m_tPopulation[i]->Genome[0]));
      /* Resume process */
      ::kill(SlavePIDs[i], SIGCONT);
   }
   /* Wait for all the slaves to finish the run */
   UInt32 unTrialsLeft = m_unPopSize;
   int nSlaveInfo;
   pid_t tSlavePID;
   while(unTrialsLeft > 0) {
      /* Wait for next slave to finish */
      tSlavePID = ::waitpid(-1, &nSlaveInfo, WUNTRACED);
      /* Make sure the slave went back to sleep and didn't crash */
      if(!WIFSTOPPED(nSlaveInfo)) {
         LOGERR << "[FATAL] Slave process with PID " << tSlavePID << " exited, can't continue. Check file ARGoS_LOGERR_" << tSlavePID << " for more information." << std::endl;
         LOG.Flush();
         LOGERR.Flush();
         Cleanup();
         ::exit(1);
      }
      /* All OK, one less slave to wait for */
      --unTrialsLeft;
   }
   /* Copy the scores into the population data */
   for(UInt32 i = 0; i < m_unPopSize; ++i) {
      m_tPopulation[i]->Score = m_pcSharedMem->GetScore(i);
   }
   /* Sort the population by score, from the best to the worst */
   std::sort(m_tPopulation.begin(),
             m_tPopulation.end(),
             m_cIndComparator);
}

/****************************************/
/****************************************/

void CMPGA::NextGen() {
   ++m_unCurrentGeneration;
   Selection();
   Crossover();
   Mutation();
}

/****************************************/
/****************************************/

bool CMPGA::Done() const {
   return m_unCurrentGeneration >= m_unGenerations;
}

/****************************************/
/****************************************/

/* Global pointer to the CMPGA object in the current slave, used by
 * SlaveHandleSIGTERM() to perform cleanup */
static CMPGA* GA_INSTANCE;

/* SIGTERM handler for slave processes */
void SlaveHandleSIGTERM(int) {
   argos::CSimulator::GetInstance().Destroy();
   argos::LOG.Flush();
   argos::LOGERR.Flush();
   GA_INSTANCE->Cleanup();
}

void CMPGA::LaunchARGoS(UInt32 un_slave_id) {
   /* Set the global GA instance pointer for signal handler */
   GA_INSTANCE = this;
   /* Install handler for SIGTERM */
   ::signal(SIGTERM, SlaveHandleSIGTERM);
   /* Initialize ARGoS */
   /* Redirect LOG and LOGERR to dedicated files to prevent clutter on the screen */
   std::ofstream cLOGFile("ARGoS_LOG_" + ToString(::getpid()), std::ios::out);
   LOG.DisableColoredOutput();
   LOG.GetStream().rdbuf(cLOGFile.rdbuf());
   std::ofstream cLOGERRFile("ARGoS_LOGERR_" + ToString(::getpid()), std::ios::out);
   LOGERR.DisableColoredOutput();
   LOGERR.GetStream().rdbuf(cLOGERRFile.rdbuf());
   /* The CSimulator class of ARGoS is a singleton. Therefore, to
    * manipulate an ARGoS experiment, it is enough to get its instance */
   argos::CSimulator& cSimulator = argos::CSimulator::GetInstance();
   try {
      /* Set the .argos configuration file
       * This is a relative path which assumed that you launch the executable
       * from argos3-examples (as said also in the README) */
      cSimulator.SetExperimentFileName(m_strARGoSConf);
      /* Load it to configure ARGoS */
      cSimulator.LoadExperiment();
      LOG.Flush();
      LOGERR.Flush();
   }
   catch(CARGoSException& ex) {
      LOGERR << ex.what() << std::endl;
      ::raise(SIGTERM);
   }
   /* Get a reference to the loop functions */
   CMPGALoopFunctions& cLoopFunctions = dynamic_cast<CMPGALoopFunctions&>(cSimulator.GetLoopFunctions());
   /* Create vector of scores */
   std::vector<Real> vecScores(m_unNumTrials, 0.0);
   /* Continue working until killed by parent */
   while(1) {
      /* Suspend yourself, waiting for parent's resume signal */
      ::raise(SIGTSTP);
      /* Resumed */
      /* Configure the controller with the genome */
      cLoopFunctions.ConfigureFromGenome(m_pcSharedMem->GetGenome(un_slave_id));
      /* Run the trials */
      for(size_t i = 0; i < m_unNumTrials; ++i) {
         /* Tell the loop functions to get ready for the i-th trial */
         cLoopFunctions.SetTrial(i);
         /* Reset the experiment.
          * This internally calls also CMPGALoopFunctions::Reset(). */
         cSimulator.Reset();
         /* Run the experiment */
         cSimulator.Execute();
         /* Store score */
         vecScores[i] = cLoopFunctions.Score();
         LOG.Flush();
         LOGERR.Flush();
      }
      ;
      /* Put result in shared memory */
      m_pcSharedMem->SetScore(un_slave_id, m_tScoreAggregator(vecScores));
   }
}

/****************************************/
/****************************************/

void CMPGA::Selection() {
   /* Delete all individuals apart from the top two */
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      delete m_tPopulation[i];
      m_tPopulation.pop_back();
   }
}

/****************************************/
/****************************************/

void CMPGA::Crossover() {
   /*
    * This is a simple one-point crossover.
    */
   SIndividual* psParent1 = m_tPopulation[0];
   SIndividual* psParent2 = m_tPopulation[1];
   UInt32 unCut;
   SIndividual* psInd;
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      /* Pick a cutting point at random */
      unCut = m_pcRNG->Uniform(CRange<UInt32>(1, m_unGenomeSize-1));
      /* Make a new individual */
      psInd = new SIndividual;
      /* Copy alleles from parent 1 */
      for(UInt32 j = 0; j < unCut; ++j) {
         psInd->Genome.push_back(psParent1->Genome[j]);
      }
      /* Copy alleles from parent 2 */
      for(UInt32 j = unCut; j < m_unGenomeSize; ++j) {
         psInd->Genome.push_back(psParent2->Genome[j]);
      }
      /* Add individual to the new population */
      m_tPopulation.push_back(psInd);
   }
}

/****************************************/
/****************************************/

void CMPGA::Mutation() {
   /* Mutate the alleles of the newly added individuals by setting a
    * new random value from a uniform distribution */
   for(UInt32 i = 2; i < m_unPopSize; ++i) {
      for(UInt32 a = 0; a < m_unGenomeSize; ++a) {
         if(m_pcRNG->Bernoulli(m_fMutationProb))
            m_tPopulation[i]->Genome[a] = m_pcRNG->Uniform(m_cAlleleRange);
      }
   }
}

/****************************************/
/****************************************/

CMPGA::CSharedMem::CSharedMem(UInt32 un_genome_size,
                              UInt32 un_pop_size) :
   m_unGenomeSize(un_genome_size),
   m_unPopSize(un_pop_size) {
   /* Create shared memory area for master-slave communication */
   m_nSharedMemFD = ::shm_open(SHARED_MEMORY_FILE,
                               O_RDWR | O_CREAT,
                               S_IRUSR | S_IWUSR);
   if(m_nSharedMemFD < 0) {
      ::perror(SHARED_MEMORY_FILE);
      exit(1);
   }
   /* Resize shared memory area to contain the population data
    * - The area must contain m_unPopSize elements
    * - Each element must have space for the data of an individual
    *   - Genome: m_unGenomeSize * sizeof(Real)
    *   - Score: sizeof(Real)
    */
   size_t unShareMemSize = m_unPopSize * (m_unGenomeSize+1) * sizeof(Real);
   ::ftruncate(m_nSharedMemFD, unShareMemSize);
   /* Get pointer to shared memory area */
   m_pfSharedMem = reinterpret_cast<Real*>(
      ::mmap(NULL,
             unShareMemSize,
             PROT_READ | PROT_WRITE,
             MAP_SHARED,
             m_nSharedMemFD,
             0));
   if(m_pfSharedMem == MAP_FAILED) {
      ::perror("shared memory");
      exit(1);
   }
}

/****************************************/
/****************************************/

CMPGA::CSharedMem::~CSharedMem() {
   munmap(m_pfSharedMem, m_unPopSize * (m_unGenomeSize+1) * sizeof(Real));
   close(m_nSharedMemFD);
   shm_unlink(SHARED_MEMORY_FILE);
}

/****************************************/
/****************************************/

Real* CMPGA::CSharedMem::GetGenome(UInt32 un_individual) {
   return m_pfSharedMem + un_individual * (m_unGenomeSize+1);
}

/****************************************/
/****************************************/

void CMPGA::CSharedMem::SetGenome(UInt32 un_individual,
                                  const Real* pf_genome) {
   ::memcpy(m_pfSharedMem + un_individual * (m_unGenomeSize+1),
            pf_genome,
            m_unGenomeSize * sizeof(Real));
}

/****************************************/
/****************************************/

Real CMPGA::CSharedMem::GetScore(UInt32 un_individual) {
   return m_pfSharedMem[un_individual * (m_unGenomeSize+1) + m_unGenomeSize];
}

/****************************************/
/****************************************/

void CMPGA::CSharedMem::SetScore(UInt32 un_individual,
                                 Real f_score) {
   m_pfSharedMem[un_individual * (m_unGenomeSize+1) + m_unGenomeSize] = f_score;
}

/****************************************/
/****************************************/
<|endoftext|>


<commit_before>/*
 * An istream which duplicates data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_tee.hxx"
#include "istream_oo.hxx"
#include "istream_pointer.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>

struct TeeIstream {
    struct {
        struct istream istream;

        /**
         * A weak output is one which is closed automatically when all
         * "strong" outputs have been closed - it will not keep up the
         * istream_tee object alone.
         */
        bool weak;

        bool enabled = true;
    } outputs[2];

    IstreamPointer input;

    /**
     * These flags control whether istream_tee_close[12]() may restart
     * reading for the other output.
     */
    bool reading = false, in_data = false;

#ifndef NDEBUG
    bool closed_while_reading = false, closed_while_data = false;
#endif

    /**
     * The number of bytes to skip for output 0.  The first output has
     * already consumed this many bytes, but the second output
     * blocked.
     */
    size_t skip = 0;

    TeeIstream(struct istream &_input,
               bool first_weak, bool second_weak)
        :input(_input, MakeIstreamHandler<TeeIstream>::handler, this)
    {
        outputs[0].weak = first_weak;
        outputs[1].weak = second_weak;
    }

    size_t Feed0(const char *data, size_t length);
    size_t Feed1(const void *data, size_t length);
    size_t Feed(const void *data, size_t length);

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        // TODO: implement that using sys_tee()
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
tee_quark(void)
{
    return g_quark_from_static_string("tee");
}

inline size_t
TeeIstream::Feed0(const char *data, size_t length)
{
    if (!outputs[0].enabled)
        return length;

    if (length <= skip)
        /* all of this has already been sent to the first input, but
           the second one didn't accept it yet */
        return length;

    /* skip the part which was already sent */
    data += skip;
    length -= skip;

    size_t nbytes = istream_invoke_data(&outputs[0].istream,
                                        data, length);
    if (nbytes > 0) {
        skip += nbytes;
        return skip;
    }

    if (outputs[0].enabled || !outputs[1].enabled)
        /* first output is blocking, or both closed: give up */
        return 0;

    /* the first output has been closed inside the data() callback,
       but the second is still alive: continue with the second
       output */
    return length;
}

inline size_t
TeeIstream::Feed1(const void *data, size_t length)
{
    if (!outputs[1].enabled)
        return length;

    size_t nbytes = istream_invoke_data(&outputs[1].istream, data, length);
    if (nbytes == 0 && !outputs[1].enabled &&
        outputs[0].enabled)
        /* during the data callback, outputs[1] has been closed,
           but outputs[0] continues; instead of returning 0 here,
           use outputs[0]'s result */
        return length;

    return nbytes;
}

inline size_t
TeeIstream::Feed(const void *data, size_t length)
{
    size_t nbytes0 = Feed0((const char *)data, length);
    if (nbytes0 == 0)
        return 0;

    size_t nbytes1 = Feed1(data, nbytes0);
    if (nbytes1 > 0 && outputs[0].enabled) {
        assert(nbytes1 <= skip);
        skip -= nbytes1;
    }

    return nbytes1;
}

/*
 * istream handler
 *
 */

inline size_t
TeeIstream::OnData(const void *data, size_t length)
{
    assert(input.IsDefined());
    assert(!in_data);

    const ScopePoolRef ref(*outputs[0].istream.pool TRACE_ARGS);
    in_data = true;
    size_t nbytes = Feed(data, length);
    in_data = false;
    return nbytes;
}

inline void
TeeIstream::OnEof()
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(*outputs[0].istream.pool TRACE_ARGS);

    /* clean up in reverse order */

    if (outputs[1].enabled) {
        outputs[1].enabled = false;
        istream_deinit_eof(&outputs[1].istream);
    }

    if (outputs[0].enabled) {
        outputs[0].enabled = false;
        istream_deinit_eof(&outputs[0].istream);
    }
}

inline void
TeeIstream::OnError(GError *error)
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(*outputs[0].istream.pool TRACE_ARGS);

    /* clean up in reverse order */

    if (outputs[1].enabled) {
        outputs[1].enabled = false;
        istream_deinit_abort(&outputs[1].istream, g_error_copy(error));
    }

    if (outputs[0].enabled) {
        outputs[0].enabled = false;
        istream_deinit_abort(&outputs[0].istream, g_error_copy(error));
    }

    g_error_free(error);
}

/*
 * istream implementation 0
 *
 */

#ifdef __clang__
#pragma GCC diagnostic ignored "-Wextended-offsetof"
#endif

static inline TeeIstream &
istream_to_tee0(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, outputs[0].istream);
}

static off_t
istream_tee_available0(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.outputs[0].enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.outputs[0].enabled);
    assert(!tee.reading);

    const ScopePoolRef ref(*tee.outputs[0].istream.pool TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.outputs[0].enabled);

    tee.outputs[0].enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.outputs[1].enabled)
            tee.input.ClearAndClose();
        else if (tee.outputs[1].weak) {
            const ScopePoolRef ref(*tee.outputs[0].istream.pool TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.outputs[1].enabled) {
                tee.outputs[1].enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak second output");
                istream_deinit_abort(&tee.outputs[1].istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.outputs[1].enabled &&
        istream_has_handler(&tee.outputs[1].istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.outputs[0].istream);
}

static const struct istream_class istream_tee0 = {
    .available = istream_tee_available0,
    .read = istream_tee_read0,
    .close = istream_tee_close0,
};

/*
 * istream implementation 2
 *
 */

static inline TeeIstream &
istream_to_tee1(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, outputs[1].istream);
}

static off_t
istream_tee_available1(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.outputs[1].enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(!tee.reading);

    const ScopePoolRef ref(*tee.outputs[0].istream.pool TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.outputs[1].enabled);

    tee.outputs[1].enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.outputs[0].enabled)
            tee.input.ClearAndClose();
        else if (tee.outputs[0].weak) {
            const ScopePoolRef ref(*tee.outputs[0].istream.pool TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.outputs[0].enabled) {
                tee.outputs[0].enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak first output");
                istream_deinit_abort(&tee.outputs[0].istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.outputs[0].enabled &&
        istream_has_handler(&tee.outputs[0].istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.outputs[1].istream);
}

static const struct istream_class istream_tee1 = {
    .available = istream_tee_available1,
    .read = istream_tee_read1,
    .close = istream_tee_close1,
};

/*
 * constructor
 *
 */

struct istream *
istream_tee_new(struct pool *pool, struct istream *input,
                bool first_weak, bool second_weak)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto tee = NewFromPool<TeeIstream>(*pool, *input,
                                       first_weak, second_weak);
    istream_init(&tee->outputs[0].istream, &istream_tee0, pool);
    istream_init(&tee->outputs[1].istream, &istream_tee1, pool);

    return &tee->outputs[0].istream;
}

struct istream *
istream_tee_second(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    return &tee.outputs[1].istream;
}

<commit_msg>istream_tee: rename outputs[2] to first_output, second_output<commit_after>/*
 * An istream which duplicates data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_tee.hxx"
#include "istream_oo.hxx"
#include "istream_pointer.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>

struct TeeIstream {
    struct {
        struct istream istream;

        /**
         * A weak output is one which is closed automatically when all
         * "strong" outputs have been closed - it will not keep up the
         * istream_tee object alone.
         */
        bool weak;

        bool enabled = true;
    } first_output, second_output;

    IstreamPointer input;

    /**
     * These flags control whether istream_tee_close[12]() may restart
     * reading for the other output.
     */
    bool reading = false, in_data = false;

#ifndef NDEBUG
    bool closed_while_reading = false, closed_while_data = false;
#endif

    /**
     * The number of bytes to skip for output 0.  The first output has
     * already consumed this many bytes, but the second output
     * blocked.
     */
    size_t skip = 0;

    TeeIstream(struct istream &_input,
               bool first_weak, bool second_weak)
        :input(_input, MakeIstreamHandler<TeeIstream>::handler, this)
    {
        first_output.weak = first_weak;
        second_output.weak = second_weak;
    }

    size_t Feed0(const char *data, size_t length);
    size_t Feed1(const void *data, size_t length);
    size_t Feed(const void *data, size_t length);

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        // TODO: implement that using sys_tee()
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
tee_quark(void)
{
    return g_quark_from_static_string("tee");
}

inline size_t
TeeIstream::Feed0(const char *data, size_t length)
{
    if (!first_output.enabled)
        return length;

    if (length <= skip)
        /* all of this has already been sent to the first input, but
           the second one didn't accept it yet */
        return length;

    /* skip the part which was already sent */
    data += skip;
    length -= skip;

    size_t nbytes = istream_invoke_data(&first_output.istream,
                                        data, length);
    if (nbytes > 0) {
        skip += nbytes;
        return skip;
    }

    if (first_output.enabled || !second_output.enabled)
        /* first output is blocking, or both closed: give up */
        return 0;

    /* the first output has been closed inside the data() callback,
       but the second is still alive: continue with the second
       output */
    return length;
}

inline size_t
TeeIstream::Feed1(const void *data, size_t length)
{
    if (!second_output.enabled)
        return length;

    size_t nbytes = istream_invoke_data(&second_output.istream, data, length);
    if (nbytes == 0 && !second_output.enabled &&
        first_output.enabled)
        /* during the data callback, second_output has been closed,
           but first_output continues; instead of returning 0 here,
           use first_output's result */
        return length;

    return nbytes;
}

inline size_t
TeeIstream::Feed(const void *data, size_t length)
{
    size_t nbytes0 = Feed0((const char *)data, length);
    if (nbytes0 == 0)
        return 0;

    size_t nbytes1 = Feed1(data, nbytes0);
    if (nbytes1 > 0 && first_output.enabled) {
        assert(nbytes1 <= skip);
        skip -= nbytes1;
    }

    return nbytes1;
}

/*
 * istream handler
 *
 */

inline size_t
TeeIstream::OnData(const void *data, size_t length)
{
    assert(input.IsDefined());
    assert(!in_data);

    const ScopePoolRef ref(*first_output.istream.pool TRACE_ARGS);
    in_data = true;
    size_t nbytes = Feed(data, length);
    in_data = false;
    return nbytes;
}

inline void
TeeIstream::OnEof()
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(*first_output.istream.pool TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        istream_deinit_eof(&second_output.istream);
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        istream_deinit_eof(&first_output.istream);
    }
}

inline void
TeeIstream::OnError(GError *error)
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(*first_output.istream.pool TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        istream_deinit_abort(&second_output.istream, g_error_copy(error));
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        istream_deinit_abort(&first_output.istream, g_error_copy(error));
    }

    g_error_free(error);
}

/*
 * istream implementation 0
 *
 */

#ifdef __clang__
#pragma GCC diagnostic ignored "-Wextended-offsetof"
#endif

static inline TeeIstream &
istream_to_tee0(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, first_output.istream);
}

static off_t
istream_tee_available0(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);
    assert(!tee.reading);

    const ScopePoolRef ref(*tee.first_output.istream.pool TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);

    tee.first_output.enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.second_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.second_output.weak) {
            const ScopePoolRef ref(*tee.first_output.istream.pool TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.second_output.enabled) {
                tee.second_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak second output");
                istream_deinit_abort(&tee.second_output.istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.second_output.enabled &&
        istream_has_handler(&tee.second_output.istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.first_output.istream);
}

static const struct istream_class istream_tee0 = {
    .available = istream_tee_available0,
    .read = istream_tee_read0,
    .close = istream_tee_close0,
};

/*
 * istream implementation 2
 *
 */

static inline TeeIstream &
istream_to_tee1(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, second_output.istream);
}

static off_t
istream_tee_available1(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.second_output.enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(!tee.reading);

    const ScopePoolRef ref(*tee.first_output.istream.pool TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.second_output.enabled);

    tee.second_output.enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.first_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.first_output.weak) {
            const ScopePoolRef ref(*tee.first_output.istream.pool TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.first_output.enabled) {
                tee.first_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak first output");
                istream_deinit_abort(&tee.first_output.istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.first_output.enabled &&
        istream_has_handler(&tee.first_output.istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.second_output.istream);
}

static const struct istream_class istream_tee1 = {
    .available = istream_tee_available1,
    .read = istream_tee_read1,
    .close = istream_tee_close1,
};

/*
 * constructor
 *
 */

struct istream *
istream_tee_new(struct pool *pool, struct istream *input,
                bool first_weak, bool second_weak)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto tee = NewFromPool<TeeIstream>(*pool, *input,
                                       first_weak, second_weak);
    istream_init(&tee->first_output.istream, &istream_tee0, pool);
    istream_init(&tee->second_output.istream, &istream_tee1, pool);

    return &tee->first_output.istream;
}

struct istream *
istream_tee_second(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    return &tee.second_output.istream;
}

<|endoftext|>


<commit_before>#include "sink_buffer.hxx"
#include "istream_oo.hxx"
#include "async.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <glib.h>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>

struct BufferSink {
    struct pool *pool;
    struct istream *input;

    unsigned char *buffer;
    size_t size, position;

    const struct sink_buffer_handler *handler;
    void *handler_ctx;

    struct async_operation async_operation;

    /* istream handler */

    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);;
    void OnEof();
    void OnError(GError *error);
};

static GQuark
sink_buffer_quark(void)
{
    return g_quark_from_static_string("sink_buffer");
}

/*
 * istream handler
 *
 */

inline size_t
BufferSink::OnData(const void *data, size_t length)
{
    assert(position < size);
    assert(length <= size - position);

    memcpy(buffer + position, data, length);
    position += length;

    return length;
}

inline ssize_t
BufferSink::OnDirect(FdType type, int fd, size_t max_length)
{
    size_t length = size - position;
    if (length > max_length)
        length = max_length;

    ssize_t nbytes = type == FdType::FD_SOCKET || type == FdType::FD_TCP
        ? recv(fd, buffer + position, length, MSG_DONTWAIT)
        : read(fd, buffer + position, length);
    if (nbytes > 0)
        position += (size_t)nbytes;

    return nbytes;
}

inline void
BufferSink::OnEof()
{
    assert(position == size);

    async_operation.Finished();
    handler->done(buffer, size, handler_ctx);
}

inline void
BufferSink::OnError(GError *error)
{
    async_operation.Finished();
    handler->error(error, handler_ctx);
}

/*
 * async operation
 *
 */

static BufferSink *
async_to_sink_buffer(struct async_operation *ao)
{
    return &ContainerCast2(*ao, &BufferSink::async_operation);
}

static void
sink_buffer_abort(struct async_operation *ao)
{
    BufferSink *buffer = async_to_sink_buffer(ao);

    const ScopePoolRef ref(*buffer->pool TRACE_ARGS);
    istream_close_handler(buffer->input);
}

static const struct async_operation_class sink_buffer_operation = {
    .abort = sink_buffer_abort,
};

/*
 * constructor
 *
 */

void
sink_buffer_new(struct pool *pool, struct istream *input,
                const struct sink_buffer_handler *handler, void *ctx,
                struct async_operation_ref *async_ref)
{
    off_t available;
    static char empty_buffer[1];

    assert(input != NULL);
    assert(!istream_has_handler(input));
    assert(handler != NULL);
    assert(handler->done != NULL);
    assert(handler->error != NULL);

    available = istream_available(input, false);
    if (available == -1 || available >= 0x10000000) {
        istream_close_unused(input);

        GError *error =
            g_error_new_literal(sink_buffer_quark(), 0,
                                available < 0
                                ? "unknown stream length"
                                : "stream is too large");
        handler->error(error, ctx);
        return;
    }

    if (available == 0) {
        istream_close_unused(input);
        handler->done(empty_buffer, 0, ctx);
        return;
    }

    auto buffer = NewFromPool<BufferSink>(*pool);
    buffer->pool = pool;

    istream_assign_handler(&buffer->input, input,
                           &MakeIstreamHandler<BufferSink>::handler, buffer,
                           FD_ANY);

    buffer->size = (size_t)available;
    buffer->position = 0;
    buffer->buffer = (unsigned char *)p_malloc(pool, buffer->size);
    buffer->handler = handler;
    buffer->handler_ctx = ctx;

    buffer->async_operation.Init(sink_buffer_operation);
    async_ref->Set(buffer->async_operation);
}
<commit_msg>sink_buffer: add constructor<commit_after>#include "sink_buffer.hxx"
#include "istream_oo.hxx"
#include "async.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <glib.h>

#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>

struct BufferSink {
    struct pool *pool;
    struct istream *input;

    unsigned char *const buffer;
    const size_t size;
    size_t position = 0;

    const struct sink_buffer_handler *const handler;
    void *handler_ctx;

    struct async_operation async_operation;

    BufferSink(struct pool &_pool, struct istream &_input, size_t available,
               const struct sink_buffer_handler &_handler, void *ctx)
        :pool(&_pool),
         buffer((unsigned char *)p_malloc(pool, available)),
         size(available),
         handler(&_handler), handler_ctx(ctx) {
        istream_assign_handler(&input, &_input,
                               &MakeIstreamHandler<BufferSink>::handler, this,
                               FD_ANY);
    }

    /* istream handler */

    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);;
    void OnEof();
    void OnError(GError *error);
};

static GQuark
sink_buffer_quark(void)
{
    return g_quark_from_static_string("sink_buffer");
}

/*
 * istream handler
 *
 */

inline size_t
BufferSink::OnData(const void *data, size_t length)
{
    assert(position < size);
    assert(length <= size - position);

    memcpy(buffer + position, data, length);
    position += length;

    return length;
}

inline ssize_t
BufferSink::OnDirect(FdType type, int fd, size_t max_length)
{
    size_t length = size - position;
    if (length > max_length)
        length = max_length;

    ssize_t nbytes = type == FdType::FD_SOCKET || type == FdType::FD_TCP
        ? recv(fd, buffer + position, length, MSG_DONTWAIT)
        : read(fd, buffer + position, length);
    if (nbytes > 0)
        position += (size_t)nbytes;

    return nbytes;
}

inline void
BufferSink::OnEof()
{
    assert(position == size);

    async_operation.Finished();
    handler->done(buffer, size, handler_ctx);
}

inline void
BufferSink::OnError(GError *error)
{
    async_operation.Finished();
    handler->error(error, handler_ctx);
}

/*
 * async operation
 *
 */

static BufferSink *
async_to_sink_buffer(struct async_operation *ao)
{
    return &ContainerCast2(*ao, &BufferSink::async_operation);
}

static void
sink_buffer_abort(struct async_operation *ao)
{
    BufferSink *buffer = async_to_sink_buffer(ao);

    const ScopePoolRef ref(*buffer->pool TRACE_ARGS);
    istream_close_handler(buffer->input);
}

static const struct async_operation_class sink_buffer_operation = {
    .abort = sink_buffer_abort,
};

/*
 * constructor
 *
 */

void
sink_buffer_new(struct pool *pool, struct istream *input,
                const struct sink_buffer_handler *handler, void *ctx,
                struct async_operation_ref *async_ref)
{
    off_t available;
    static char empty_buffer[1];

    assert(input != NULL);
    assert(!istream_has_handler(input));
    assert(handler != NULL);
    assert(handler->done != NULL);
    assert(handler->error != NULL);

    available = istream_available(input, false);
    if (available == -1 || available >= 0x10000000) {
        istream_close_unused(input);

        GError *error =
            g_error_new_literal(sink_buffer_quark(), 0,
                                available < 0
                                ? "unknown stream length"
                                : "stream is too large");
        handler->error(error, ctx);
        return;
    }

    if (available == 0) {
        istream_close_unused(input);
        handler->done(empty_buffer, 0, ctx);
        return;
    }

    auto buffer = NewFromPool<BufferSink>(*pool, *pool, *input, available,
                                          *handler, ctx);
    buffer->async_operation.Init(sink_buffer_operation);
    async_ref->Set(buffer->async_operation);
}
<|endoftext|>