<commit_before>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Linear;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  if (!m_modifySourceMatrix) {
    registration->SetTransformTypeToScaleTargetAxes();
  }
  else {
    registration->SetTransformTypeToRigid();
  }

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // two stages for each resolution:
  // first without interpolation, and then with interpolation
  int stage = 0;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (stage == 0)
    {
      registration->SetInterpolatorTypeToNearest();
      registration->SetTransformTolerance(minSpacing);
    }
    else
    {
      registration->SetInterpolatorType(interpolatorType);
      registration->SetTransformTolerance(transformTolerance);
    }
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " stage " << stage << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    if (stage == 1)
    {
      blurFactor /= 2.0;
      if (blurFactor < 0.9)
      {
        break;
      }
    }
    stage = (stage + 1) % 2;
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<commit_msg>Use Affine registration for secondary.<commit_after>/*=========================================================================
  Program: Cerebra
  Module:  cbMRIRegistration.cxx

  Copyright (c) 2011-2013 Qian Lu, David Adair
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

  * Neither the name of the Calgary Image Processing and Analysis Centre
    (CIPAC), the University of Calgary, nor the names of any authors nor
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/

/*=========================================================================
 Copyright (c) 2005 Atamai, Inc.
 All rights reserved.

 Use, modification and redistribution of the software, in source or
 binary forms, are permitted provided that the following terms and
 conditions are met:

 1) Redistribution of the source code, in verbatim or modified
 form, must retain the above copyright notice, this license,
 the following disclaimer, and any notices that refer to this
 license and/or the following disclaimer.

 2) Redistribution in binary form must include the above copyright
 notice, a copy of this license and the following disclaimer
 in the documentation or with other materials provided with the
 distribution.

 3) Modified copies of the source code must be clearly marked as such,
 and must not be misrepresented as verbatim copies of the source code.

 THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS"
 WITHOUT EXPRESSED OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE.  IN NO EVENT SHALL ANY COPYRIGHT HOLDER OR OTHER PARTY WHO MAY
 MODIFY AND/OR REDISTRIBUTE THE SOFTWARE UNDER THE TERMS OF THIS LICENSE
 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA OR DATA BECOMING INACCURATE
 OR LOSS OF PROFIT OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF
 THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGES.

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

#include "cbMRIRegistration.h"

#include <vtkSmartPointer.h>
#include <vtkMath.h>
#include <vtkImageResize.h>
#include <vtkImageReslice.h>
#include <vtkImageSincInterpolator.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageSlice.h>
#include <vtkImageStack.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageProperty.h>
#include <vtkTimerLog.h>
#include <vtkErrorCode.h>

#include <vtkImageRegistration.h>
#include <vtkProgressAccumulator.h>

//----------------------------------------------------------------------------
cbMRIRegistration::cbMRIRegistration()
{
  this->m_sourceImage = NULL;
  this->m_targetImage = NULL;
  this->m_sourceMatrix = NULL;
  this->m_targetMatrix = NULL;
  this->m_renderWindow = NULL;
  this->m_progressAccumulate = NULL;
  this->m_modifySourceMatrix = true;
  this->m_registrationMethod = MUTUAL_INFORMATION;
}

//----------------------------------------------------------------------------
cbMRIRegistration::~cbMRIRegistration()
{
  if (m_sourceImage) {
    this->m_sourceImage->Delete();
  }
  if (m_targetImage) {
    this->m_targetImage->Delete();
  }
  if (m_sourceMatrix) {
    this->m_sourceMatrix->Delete();
  }
  if (m_targetMatrix) {
    this->m_targetMatrix->Delete();
  }
  if (m_renderWindow) {
    this->m_renderWindow->Delete();
  }
  if (m_progressAccumulate) {
    this->m_progressAccumulate->Delete();
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRenderWindow(vtkRenderWindow *renderwindow)
{
  m_renderWindow = renderwindow;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSource(vtkImageData *inputSource)
{
  this->m_sourceImage = inputSource;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputSource()
{
  return this->m_sourceImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTarget(vtkImageData *inputTarget)
{
  this->m_targetImage = inputTarget;
}

//----------------------------------------------------------------------------
vtkImageData *cbMRIRegistration::GetInputTarget()
{
  return this->m_targetImage;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputSourceMatrix(vtkMatrix4x4 *inputSourceMatrix)
{
  this->m_sourceMatrix = inputSourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetInputTargetMatrix(vtkMatrix4x4 *inputTargetMatrix)
{
  this->m_targetMatrix = inputTargetMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetInputTargetMatrix()
{
  return this->m_targetMatrix;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetRegistrationMethod(int method)
{
  if (method == 0) {
    this->m_registrationMethod = MUTUAL_INFORMATION;
  }
  else if (method == 1) {
    this->m_registrationMethod = CROSS_CORRELATION;
  }
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToSource()
{
  this->m_modifySourceMatrix = true;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetModifyMatrixToTarget()
{
  this->m_modifySourceMatrix = false;
}

//----------------------------------------------------------------------------
void cbMRIRegistration::SetProgressAccumulator(
  vtkProgressAccumulator *progressAccumulate)
{
  this->m_progressAccumulate = progressAccumulate;
}

//----------------------------------------------------------------------------
vtkProgressAccumulator *cbMRIRegistration::GetProgressAccumulator()
{
  return this->m_progressAccumulate;
}

//----------------------------------------------------------------------------
int cbMRIRegistration::Execute()
{
  if (this->m_sourceImage == NULL || this->m_targetImage == NULL ||
      this->m_sourceMatrix == NULL || this->m_targetMatrix == NULL)
  {
    cout << "Execute: Input source image & matrix and"
            "target image & matrix are not set " << endl;
    return 0;
  }

  // parameters for registration
  int interpolatorType = vtkImageRegistration::Linear;
  double transformTolerance = 0.1; // tolerance on transformation result
  int numberOfBins = 64; // for Mattes' mutual information
  double initialBlurFactor = 4.0;

  // get information about the images
  double targetSpacing[3], sourceSpacing[3];
  this->m_targetImage->GetSpacing(targetSpacing);
  this->m_sourceImage->GetSpacing(sourceSpacing);

  for (int jj = 0; jj < 3; jj++)
  {
    targetSpacing[jj] = fabs(targetSpacing[jj]);
    sourceSpacing[jj] = fabs(sourceSpacing[jj]);
  }

  double minSpacing = sourceSpacing[0];
  if (minSpacing > sourceSpacing[1])
  {
    minSpacing = sourceSpacing[1];
  }
  if (minSpacing > sourceSpacing[2])
  {
    minSpacing = sourceSpacing[2];
  }

  // blur source image with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> sourceBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  sourceBlurKernel->SetWindowFunctionToHamming();

  // reduce the source resolution
  vtkSmartPointer<vtkImageResize> sourceBlur =
  vtkSmartPointer<vtkImageResize>::New();
  sourceBlur->SetInput(this->m_sourceImage);
  sourceBlur->SetResizeMethodToOutputSpacing();
  sourceBlur->SetInterpolator(sourceBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(sourceBlur,0.07f);
  }

  // blur target with Hamming-windowed sinc
  vtkSmartPointer<vtkImageSincInterpolator> targetBlurKernel =
  vtkSmartPointer<vtkImageSincInterpolator>::New();
  targetBlurKernel->SetWindowFunctionToHamming();

  // keep target at full resolution
  vtkSmartPointer<vtkImageResize> targetBlur =
  vtkSmartPointer<vtkImageResize>::New();
  targetBlur->SetInput(this->m_targetImage);
  targetBlur->SetResizeMethodToOutputSpacing();
  targetBlur->SetInterpolator(targetBlurKernel);

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(targetBlur,0.07f);
  }

  // get the initial transformation
  vtkSmartPointer<vtkMatrix4x4> matrix =
  vtkSmartPointer<vtkMatrix4x4>::New();
  matrix->DeepCopy(this->m_targetMatrix);
  matrix->Invert();
  vtkMatrix4x4::Multiply4x4(matrix, this->m_sourceMatrix, matrix);

  // set up the registration
  vtkSmartPointer<vtkImageRegistration> registration =
  vtkSmartPointer<vtkImageRegistration>::New();
  registration->SetTargetImageInputConnection(targetBlur->GetOutputPort());
  registration->SetSourceImageInputConnection(sourceBlur->GetOutputPort());
  registration->SetInitializerTypeToCentered();

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterFilter(registration,0.05f);
  }

  registration->SetTransformTypeToAffine();

  if (this->m_registrationMethod == MUTUAL_INFORMATION) {
    registration->SetMetricTypeToNormalizedMutualInformation();
  }
  else if (this->m_registrationMethod == CROSS_CORRELATION) {
    registration->SetMetricTypeToNormalizedCrossCorrelation();
  }
  registration->SetInterpolatorType(interpolatorType);
  registration->SetJointHistogramSize(numberOfBins,numberOfBins);
  registration->SetMetricTolerance(1e-4);
  registration->SetTransformTolerance(transformTolerance);
  registration->SetMaximumNumberOfIterations(500);

  // make a timer
  vtkSmartPointer<vtkTimerLog> timer =
  vtkSmartPointer<vtkTimerLog>::New();
  double startTime = timer->GetUniversalTime();
  double lastTime = startTime;

  // do the registration
  // the registration starts at low-resolution
  double blurFactor = initialBlurFactor;
  // two stages for each resolution:
  // first without interpolation, and then with interpolation
  int stage = 0;
  // will be set to "true" when registration is initialized
  bool initialized = false;

  for (;;)
  {
    if (stage == 0)
    {
      registration->SetInterpolatorTypeToNearest();
      registration->SetTransformTolerance(minSpacing);
    }
    else
    {
      registration->SetInterpolatorType(interpolatorType);
      registration->SetTransformTolerance(transformTolerance);
    }
    if (blurFactor < 1.1)
    {
      // full resolution: no blurring or resampling
      sourceBlur->InterpolateOff();
      sourceBlur->SetOutputSpacing(sourceSpacing);
      sourceBlur->Update();

      targetBlur->InterpolateOff();
      targetBlur->SetOutputSpacing(targetSpacing);
      targetBlur->Update();
    }
    else
    {
      // reduced resolution: set the blurring
      double spacing[3];
      for (int j = 0; j < 3; j++)
      {
        spacing[j] = blurFactor*minSpacing;
        if (spacing[j] < sourceSpacing[j])
        {
          spacing[j] = sourceSpacing[j];
        }
      }

      sourceBlurKernel->SetBlurFactors(
                                       spacing[0]/sourceSpacing[0],
                                       spacing[1]/sourceSpacing[1],
                                       spacing[2]/sourceSpacing[2]);

      sourceBlur->SetOutputSpacing(spacing);
      sourceBlur->Update();

      targetBlurKernel->SetBlurFactors(
                                       blurFactor*minSpacing/targetSpacing[0],
                                       blurFactor*minSpacing/targetSpacing[1],
                                       blurFactor*minSpacing/targetSpacing[2]);

      targetBlur->Update();
    }

    if (initialized)
    {
      // re-initialize with the matrix from the previous step
      registration->SetInitializerTypeToNone();
      matrix->DeepCopy(registration->GetTransform()->GetMatrix());
    }

    registration->Initialize(matrix);

    initialized = true;

    while (registration->Iterate())
    {
      //registration->UpdateRegistration();
      // will iterate until convergence or failure
      if (m_modifySourceMatrix) {
        vtkMatrix4x4::Multiply4x4(this->m_targetMatrix,
                                  registration->GetTransform()->GetMatrix(),
                                  this->m_sourceMatrix);
        this->m_sourceMatrix->Modified();
      }
      else {
        vtkMatrix4x4::Multiply4x4(
                                  this->m_sourceMatrix,
                                  registration->GetTransform()->GetLinearInverse()->GetMatrix(),
                                  this->m_targetMatrix);
        this->m_targetMatrix->Modified();
      }

      if (m_renderWindow) {
        m_renderWindow->Render();
      }
    }

    double newTime = timer->GetUniversalTime();
    cout << "blur " << blurFactor << " stage " << stage << " took "
    << (newTime - lastTime) << "s and "
    << registration->GetNumberOfEvaluations() << " evaluations" << endl;
    lastTime = newTime;

    // prepare for next iteration
    if (stage == 1)
    {
      blurFactor /= 2.0;
      if (blurFactor < 0.9)
      {
        break;
      }
    }
    stage = (stage + 1) % 2;
  }

  if (m_progressAccumulate) {
    m_progressAccumulate->RegisterEndEvent();
  }

  cout << "registration took " << (lastTime - startTime) << "s" << endl;

  return 1;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedSourceMatrix()
{
  return this->m_sourceMatrix;
}

//----------------------------------------------------------------------------
vtkMatrix4x4 *cbMRIRegistration::GetModifiedTargetMatrix()
{
  return this->m_targetMatrix;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, Tolga HOŞGÖR
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/

#include <cstdio>

#include <algorithm>
#include <array>
#include <iostream>
#include <mutex>
#include <thread>

#include "threadpool11/threadpool11.h"

std::mutex coutMutex;

void test1Func()
{
  coutMutex.lock();
  //heavy job that takes 1 second
  std::cout << "Waiting thread id: " << std::this_thread::get_id() << std::endl;
  coutMutex.unlock();
  std::this_thread::sleep_for(std::chrono::seconds(1));
}

void test2Func()
{
  volatile int i = std::min(5, rand());
}

std::atomic<uint64_t> test3Var(0);
void test3Func()
{
    volatile uint16_t var = 0;
    while(++var < (std::numeric_limits<uint16_t>::max()));
    ++test3Var;
}

int main()
{
  threadpool11::Pool pool;

  std::cout << "Your machine's hardware concurrency is " << std::thread::hardware_concurrency() << std::endl << std::endl;

  /**
  * Demo #1.
  */
  {
    std::cout << "This demo is about showing how parallelization increases the performance. "
      << "In this test case, work is simulated by making the threads inactive by sleeping for 1 second. "
      << "It will seem like all jobs complete in ~1 second even in a single core machine. "
      << "However, in real life cases, work would keep CPU busy so you would not get any real benefit using "
      << "thread numbers that are higher than your machine's hardware concurrency (threads that are executed "
      << "concurrently) except in some cases like doing file IO." << std::endl << std::endl;
    {
      std::cout << "Demo 1\n";
      std::cout << "Executing 5 test1Func() WITHOUT posting to thread pool:\n";
      auto begin = std::chrono::high_resolution_clock::now();
      test1Func();
      test1Func();
      test1Func();
      test1Func();
      test1Func();
      auto end = std::chrono::high_resolution_clock::now();
      std::cout << "\texecution took "
        << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " milliseconds.\n\n";
    }

    {
      std::cout << "Executing 5 test1Func() WITH posting to thread pool:" << std::endl;
      std::vector<std::future<void>> futures;
      auto begin = std::chrono::high_resolution_clock::now();
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      for(auto& it : futures)
        it.get();
      auto end = std::chrono::high_resolution_clock::now();
      std::cout << "\tDemo 1 took "
        << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " milliseconds."
    << std::endl << std::endl;
    }
  }

  /*!
    Helper function tests
  */
  {
    std::cout << "Increasing worker count by 5." << std::endl;
    pool.increaseWorkerCountBy(5);
    std::cout << "Current worker count is " << pool.getWorkerCount()
              << ". Setting worker count to " << std::thread::hardware_concurrency() << "... " << std::flush;
    pool.setWorkerCount(std::thread::hardware_concurrency());
    std::cout << "The new worker count is (may be still) " << pool.getWorkerCount() << "." << std::endl;
    std::cout << "Waiting 1 second..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "The new worker count is " << pool.getWorkerCount() << "." << std::endl << std::endl;
  }

  /**
  * Demo #2
  */
  {
    std::cout << "Demo 2" << std::endl;
    std::cout << "Posting 1.000.000 jobs." << std::endl;

    std::vector<std::future<void>> futures;
    auto begin = std::chrono::high_resolution_clock::now();
    for(int i = 0; i < 1000000; ++i)
    {
      futures.emplace_back(pool.postWork<void>(test2Func));
    }
    auto end = std::chrono::high_resolution_clock::now();
    for(auto& it : futures)
      it.get();
    auto end2 = std::chrono::high_resolution_clock::now();

    std::cout << "Demo 2 took " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - begin).count()
              << " milliseconds. (Posting: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " ms, getting: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - end).count() << " ms)"
              << std::endl << std::endl;
  }

  /**
  * Demo #3
  * You should always capture by value or use appropriate mutexes for reference access.
  */
  {
    std::cout << "Demo 3" << std::endl;
    std::cout << "Testing work queue flow." << std::endl;
#define th11_demo_iterations 30000
	pool.increaseWorkerCountBy(th11_demo_iterations - 2);
	std::array<std::future<void>, th11_demo_iterations> futures;
    auto begin = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < th11_demo_iterations; ++i)
      futures[i] = pool.postWork<void>([=]() { test3Func(); });
	for (int i = 0; i < th11_demo_iterations; ++i)
      futures[i].get();
    auto end = std::chrono::high_resolution_clock::now();
	std::cout << "Variable is: " << test3Var << ", expected: " << th11_demo_iterations << std::endl;
    std::cout << "Demo 3 took "
              << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " milliseconds." << std::endl << std::endl;
  }

  /**
  * Demo #4
  * Using futures.
  */
  {
    std::cout << "Demo 4\n";
    std::cout << "WARNING: This test's output may be distorted because no synchronization on std::cout is done.\n";
    std::array<std::future<float>, 20> futures;

    auto begin = std::chrono::high_resolution_clock::now();
    for (int i=0; i<20; i++) {
      futures[i] = pool.postWork<float>([=]() {
        std::cout << "\tExecuted pow(" << i << ", 2) by thread id "
                  << std::this_thread::get_id() << std::endl;
        return pow(i, 2);
      });
    }

    for (int i=0; i < 20; i++) {
      std::cout << "\tfuture[" << i << "] value: " << futures[i].get() << std::endl;
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Demo 4 took "
              << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " milliseconds." << std::endl << std::endl;
  }

  /**
  * Test case for Issue #1 (fixed): Pool::postWork waiting forever, due to posting work before all threads in pool
  * are properly initialized and waiting.
  */
  /*{
    while(true)
    {
      std::cout << "Loop begin" << std::endl;

      std::vector<std::future<void>> futures;
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo1" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo2" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo3" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo4" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo5" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo6" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo7" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo8" << std::endl;}));

      //pool[0].setWork([]{});
      std::cout << "waiting 1" << std::endl;
      for(auto& it : futures)
        it.get();
      std::cout << "wait 1 end" << std::endl;
      futures.clear();

      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo1" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo2" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo3" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo4" << std::endl;}));

      std::cout << "waiting 2" << std::endl;
      for(auto& it : futures)
        it.get();
      std::cout << "wait 2 end" << std::endl;
      futures.clear();

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << "Increasing thread count by 4." << std::endl;
      pool.increaseWorkerCountBy(4);

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << "Decreasing thread count by 4." << std::endl;
      pool.decreaseWorkerCountBy(4);

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << std::endl << std::endl << std::endl << std::endl << std::endl << std::endl;

      std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
  }*/

  std::cout << std::endl << std::endl;

  std::cout << "Demos completed." << std::endl;

  pool.joinAll();

  //std::cin.get();
  return 0;
}
<commit_msg>some fixes for msvc 12<commit_after>/*
Copyright (c) 2013, Tolga HOŞGÖR
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/

#include <cstdio>

#include <algorithm>
#include <array>
#include <iostream>
#include <mutex>
#include <thread>

#include "threadpool11/threadpool11.h"

std::mutex coutMutex;

void test1Func()
{
  coutMutex.lock();
  //heavy job that takes 1 second
  std::cout << "Waiting thread id: " << std::this_thread::get_id() << std::endl;
  coutMutex.unlock();
  std::this_thread::sleep_for(std::chrono::seconds(1));
}

void test2Func()
{
  volatile int i = std::min(5, rand());
}

std::atomic<uint64_t> test3Var(0);
void test3Func()
{
    volatile uint16_t var = 0;
    while(++var < (std::numeric_limits<uint16_t>::max()));
    ++test3Var;
}

int main()
{
  threadpool11::Pool pool;

  std::cout << "Your machine's hardware concurrency is " << std::thread::hardware_concurrency() << std::endl << std::endl;

  /**
  * Demo #1.
  */
  {
    std::cout << "This demo is about showing how parallelization increases the performance. "
      << "In this test case, work is simulated by making the threads inactive by sleeping for 1 second. "
      << "It will seem like all jobs complete in ~1 second even in a single core machine. "
      << "However, in real life cases, work would keep CPU busy so you would not get any real benefit using "
      << "thread numbers that are higher than your machine's hardware concurrency (threads that are executed "
      << "concurrently) except in some cases like doing file IO." << std::endl << std::endl;
    {
      std::cout << "Demo 1\n";
      std::cout << "Executing 5 test1Func() WITHOUT posting to thread pool:\n";
      auto begin = std::chrono::high_resolution_clock::now();
      test1Func();
      test1Func();
      test1Func();
      test1Func();
      test1Func();
      auto end = std::chrono::high_resolution_clock::now();
      std::cout << "\texecution took "
        << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " milliseconds.\n\n";
    }

    {
      std::cout << "Executing 5 test1Func() WITH posting to thread pool:" << std::endl;
      std::vector<std::future<void>> futures;
      auto begin = std::chrono::high_resolution_clock::now();
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      futures.emplace_back(pool.postWork<void>(test1Func));
      for(auto& it : futures)
        it.get();
      auto end = std::chrono::high_resolution_clock::now();
      std::cout << "\tDemo 1 took "
        << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " milliseconds."
    << std::endl << std::endl;
    }
  }

  /*!
    Helper function tests
  */
  {
    std::cout << "Increasing worker count by 5." << std::endl;
    pool.increaseWorkerCountBy(5);
    std::cout << "Current worker count is " << pool.getWorkerCount()
              << ". Setting worker count to " << std::thread::hardware_concurrency() << "... " << std::flush;
    pool.setWorkerCount(std::thread::hardware_concurrency());
    std::cout << "The new worker count is (may be still) " << pool.getWorkerCount() << "." << std::endl;
    std::cout << "Waiting 1 second..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "The new worker count is " << pool.getWorkerCount() << "." << std::endl << std::endl;
  }

  /**
  * Demo #2
  */
  {
    std::cout << "Demo 2" << std::endl;
    std::cout << "Posting 1.000.000 jobs." << std::endl;

    std::vector<std::future<void>> futures;
    auto begin = std::chrono::high_resolution_clock::now();
    for(int i = 0; i < 1000000; ++i)
    {
      futures.emplace_back(pool.postWork<void>(test2Func));
    }
    auto end = std::chrono::high_resolution_clock::now();
    for(auto& it : futures)
      it.get();
    auto end2 = std::chrono::high_resolution_clock::now();

    std::cout << "Demo 2 took " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - begin).count()
              << " milliseconds. (Posting: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " ms, getting: " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - end).count() << " ms)"
              << std::endl << std::endl;
  }

  /**
  * Demo #3
  * You should always capture by value or use appropriate mutexes for reference access.
  */
  {
    std::cout << "Demo 3" << std::endl;
    std::cout << "Testing work queue flow." << std::endl;
#define th11_demo_iterations 30000
	//pool.increaseWorkerCountBy(th11_demo_iterations - 2);
	std::array<std::future<void>, th11_demo_iterations> futures;
    auto begin = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < th11_demo_iterations; ++i)
      futures[i] = pool.postWork<void>([=]() { test3Func(); });
	for (int i = 0; i < th11_demo_iterations; ++i)
      futures[i].get();
    auto end = std::chrono::high_resolution_clock::now();
	std::cout << "Variable is: " << test3Var << ", expected: " << th11_demo_iterations << std::endl;
    std::cout << "Demo 3 took "
              << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " milliseconds." << std::endl << std::endl;
  }

  /**
  * Demo #4
  * Using futures.
  */
  {
    std::cout << "Demo 4\n";
    std::cout << "WARNING: This test's output may be distorted because no synchronization on std::cout is done.\n";
    std::array<std::future<float>, 20> futures;

    auto begin = std::chrono::high_resolution_clock::now();
    for (int i=0; i<20; i++) {
      futures[i] = pool.postWork<float>([=]() {
        std::cout << "\tExecuted pow(" << i << ", 2) by thread id "
                  << std::this_thread::get_id() << std::endl;
        return pow(i, 2);
      });
    }

    for (int i=0; i < 20; i++) {
      std::cout << "\tfuture[" << i << "] value: " << futures[i].get() << std::endl;
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Demo 4 took "
              << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
              << " milliseconds." << std::endl << std::endl;
  }

  /**
  * Test case for Issue #1 (fixed): Pool::postWork waiting forever, due to posting work before all threads in pool
  * are properly initialized and waiting.
  */
  /*{
    while(true)
    {
      std::cout << "Loop begin" << std::endl;

      std::vector<std::future<void>> futures;
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo1" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo2" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo3" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo4" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo5" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo6" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo7" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " heyyo8" << std::endl;}));

      //pool[0].setWork([]{});
      std::cout << "waiting 1" << std::endl;
      for(auto& it : futures)
        it.get();
      std::cout << "wait 1 end" << std::endl;
      futures.clear();

      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo1" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo2" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo3" << std::endl;}));
      futures.emplace_back(pool.postWork<void>([]{std::cout << std::this_thread::get_id() << " 2heyyo4" << std::endl;}));

      std::cout << "waiting 2" << std::endl;
      for(auto& it : futures)
        it.get();
      std::cout << "wait 2 end" << std::endl;
      futures.clear();

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << "Increasing thread count by 4." << std::endl;
      pool.increaseWorkerCountBy(4);

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << "Decreasing thread count by 4." << std::endl;
      pool.decreaseWorkerCountBy(4);

      std::cout << "Active thread count: " << pool.getActiveWorkerCount() << std::endl;
      std::cout << "Inactive thread count: " << pool.getInactiveWorkerCount() << std::endl;

      std::cout << std::endl << std::endl << std::endl << std::endl << std::endl << std::endl;

      std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
  }*/

  std::cout << std::endl << std::endl;

  std::cout << "Demos completed." << std::endl;

  pool.joinAll();

  //std::cin.get();
  return 0;
}
<|endoftext|>


<commit_before>//
// C++ Implementation: PresetLoader
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "PresetLoader.hpp"
#include "Preset.hpp"
#include <iostream>
#include <sstream>
extern "C"
{
#include <errno.h>
#include <dirent.h>
}
#include <cassert>
#include "projectM.hpp"

const std::string PresetLoader::PROJECTM_FILE_EXTENSION(".prjm");
const std::string PresetLoader::MILKDROP_FILE_EXTENSION(".milk");

PresetLoader::PresetLoader(std::string dirname) :m_dirname(dirname), m_dir(0)
{
  // Do one scan
  rescan();
}

PresetLoader::~PresetLoader()
{
  if (m_dir)
    closedir(m_dir);
}

void PresetLoader::setScanDirectory(std::string dirname)
{
  m_dirname = dirname;
}

void PresetLoader::rescan()
{
  std::cerr << "Rescanning..." << std::endl;

  // Clear the directory entry collection
  m_entries.clear();

  std::cerr << "cleared!" << std::endl;

  // If directory already opened, close it first
  if (m_dir)
  {
  std::cerr << "m_dir" << std::endl;
    closedir(m_dir);
    m_dir = 0;
  }

  std::cerr << "opening " << m_dirname << std::endl;
  // Allocate a new a stream given the current directory name
  if ((m_dir = opendir(m_dirname.c_str())) == NULL)
  {
    handleDirectoryError();
    abort();
  }

  struct dirent * dir_entry;

  while ((dir_entry = readdir(m_dir)) != NULL)
  {

    std::ostringstream out;
    // Convert char * to friendly string
    std::string filename(dir_entry->d_name);

    // Verify extension is projectm or milkdrop
    if ((filename.rfind(PROJECTM_FILE_EXTENSION) != (filename.length() - PROJECTM_FILE_EXTENSION.length()))
        && (filename.rfind(MILKDROP_FILE_EXTENSION) != (filename.length() - MILKDROP_FILE_EXTENSION.length())))
      continue;

    // Create full path name
    out << m_dirname << PATH_SEPARATOR << filename;

   // std::cerr << "[PresetLoader]" << filename << std::endl;
    // Add to our directory entry collection
    m_entries.push_back(out.str());

    // the directory entry struct is freed elsewhere
  }

}

std::auto_ptr<Preset> PresetLoader::loadPreset(unsigned int index, const PresetInputs & presetInputs, PresetOutputs & presetOutputs) const
{

  // Check that index isn't insane
  assert(index >= 0);
  assert(index < m_entries.size());

  // Return a new pointer to a present
  return std::auto_ptr<Preset>(new Preset(m_entries[index], presetInputs, presetOutputs));
}

void PresetLoader::handleDirectoryError()
{
  switch (errno)
  {
  case ENOENT:
    std::cerr << "[PresetLoader] ENOENT error. \"man fopen\" for more info." << std::endl;
    break;
  case ENOMEM:
    std::cerr << "[PresetLoader] out of memory! Are you running Windows?" << std::endl;
    abort();
 case ENOTDIR:
    std::cerr << "[PresetLoader] directory specified is not a preset directory! Cannot continue." << std::endl;
    break;
  case ENFILE:
    std::cerr << "[PresetLoader] Your system has reached its open file limit. Giving up..." << std::endl;
    abort();
  case EMFILE:
    std::cerr << "[PresetLoader] too many files in use by projectM! Bailing!" << std::endl;
    abort();
  case EACCES:
    std::cerr << "[PresetLoader] permissions issue reading the specified preset directory." << std::endl;
    break;
  default:
    break;
  }
}
<commit_msg>more useful error message added when preset dir is invalid<commit_after>//
// C++ Implementation: PresetLoader
//
// Description:
//
//
// Author: Carmelo Piccione <carmelo.piccione@gmail.com>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "PresetLoader.hpp"
#include "Preset.hpp"
#include <iostream>
#include <sstream>
extern "C"
{
#include <errno.h>
#include <dirent.h>
}
#include <cassert>
#include "projectM.hpp"

const std::string PresetLoader::PROJECTM_FILE_EXTENSION(".prjm");
const std::string PresetLoader::MILKDROP_FILE_EXTENSION(".milk");

PresetLoader::PresetLoader(std::string dirname) :m_dirname(dirname), m_dir(0)
{
  // Do one scan
  rescan();
}

PresetLoader::~PresetLoader()
{
  if (m_dir)
    closedir(m_dir);
}

void PresetLoader::setScanDirectory(std::string dirname)
{
  m_dirname = dirname;
}

void PresetLoader::rescan()
{
  std::cerr << "Rescanning..." << std::endl;

  // Clear the directory entry collection
  m_entries.clear();

  std::cerr << "cleared!" << std::endl;

  // If directory already opened, close it first
  if (m_dir)
  {
  std::cerr << "m_dir" << std::endl;
    closedir(m_dir);
    m_dir = 0;
  }

  std::cerr << "opening " << m_dirname << std::endl;
  // Allocate a new a stream given the current directory name
  if ((m_dir = opendir(m_dirname.c_str())) == NULL)
  {
    handleDirectoryError();
    abort();
  }

  struct dirent * dir_entry;

  while ((dir_entry = readdir(m_dir)) != NULL)
  {

    std::ostringstream out;
    // Convert char * to friendly string
    std::string filename(dir_entry->d_name);

    // Verify extension is projectm or milkdrop
    if ((filename.rfind(PROJECTM_FILE_EXTENSION) != (filename.length() - PROJECTM_FILE_EXTENSION.length()))
        && (filename.rfind(MILKDROP_FILE_EXTENSION) != (filename.length() - MILKDROP_FILE_EXTENSION.length())))
      continue;

    // Create full path name
    out << m_dirname << PATH_SEPARATOR << filename;

   // std::cerr << "[PresetLoader]" << filename << std::endl;
    // Add to our directory entry collection
    m_entries.push_back(out.str());

    // the directory entry struct is freed elsewhere
  }

}

std::auto_ptr<Preset> PresetLoader::loadPreset(unsigned int index, const PresetInputs & presetInputs, PresetOutputs & presetOutputs) const
{

  // Check that index isn't insane
  assert(index >= 0);
  assert(index < m_entries.size());

  // Return a new pointer to a present
  return std::auto_ptr<Preset>(new Preset(m_entries[index], presetInputs, presetOutputs));
}

void PresetLoader::handleDirectoryError()
{
  switch (errno)
  {
  case ENOENT:
    std::cerr << "[PresetLoader] ENOENT error. The path \"" << this->m_dirname << "\" probably does not exist. \"man open\" for more info." << std::endl;
    break;
  case ENOMEM:
    std::cerr << "[PresetLoader] out of memory! Are you running Windows?" << std::endl;
    abort();
 case ENOTDIR:
    std::cerr << "[PresetLoader] directory specified is not a preset directory! Cannot continue." << std::endl;
    break;
  case ENFILE:
    std::cerr << "[PresetLoader] Your system has reached its open file limit. Giving up..." << std::endl;
    abort();
  case EMFILE:
    std::cerr << "[PresetLoader] too many files in use by projectM! Bailing!" << std::endl;
    abort();
  case EACCES:
    std::cerr << "[PresetLoader] permissions issue reading the specified preset directory." << std::endl;
    break;
  default:
    break;
  }
}
<|endoftext|>


<commit_before>/*
   Filename: JSFS.cpp
   Purpose:  Javascript bindings for Engine::Filesystem

   Part of Engine2D

   Copyright (C) 2014 Vbitz

   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 "JSFS.hpp"

#include "Util.hpp"
#include "Filesystem.hpp"

namespace Engine {
    namespace JsFS {
        ENGINE_JS_METHOD(ReadFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file to read");

            std::string path = ENGINE_GET_ARG_CPPSTRING_VALUE(0);

            if (!Filesystem::FileExists(path)) {
                ENGINE_THROW_ARGERROR("File does not exist");
                ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
            }

            if (args.Length() == 2) {
                ENGINE_CHECK_ARG_BOOLEAN(1, "Set Arg1 if you need a raw byte array");
                long fileLength = 0;
                char* file = Filesystem::GetFileContent(path, fileLength);
                v8::Handle<v8::Array> arr = v8::Array::New();
                for (int i = 0; i < fileLength; i++) {
                    arr->Set(i, v8::Number::New((unsigned char) file[i]));
                }
                ENGINE_JS_SCOPE_CLOSE(arr);
            } else {
                ENGINE_JS_SCOPE_CLOSE(v8::String::New(Filesystem::GetFileContent(path)));
            }
        }

        ENGINE_JS_METHOD(WriteFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file to write");
            ENGINE_CHECK_ARG_STRING(1, "Arg1 is the content to write to the file");

            Filesystem::WriteFile(ENGINE_GET_ARG_CPPSTRING_VALUE(0), *ENGINE_GET_ARG_CSTRING_VALUE(1), args[1]->ToString()->Length());

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

        ENGINE_JS_METHOD(FileExists) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file");

            ENGINE_JS_SCOPE_CLOSE(v8::Boolean::New(Filesystem::FileExists(ENGINE_GET_ARG_CPPSTRING_VALUE(0))));
        }

        ENGINE_JS_METHOD(FileSize) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file");

            ENGINE_JS_SCOPE_CLOSE(v8::Integer::New((int) Filesystem::FileSize(ENGINE_GET_ARG_CPPSTRING_VALUE(0))));
        }

        ENGINE_JS_METHOD(MountFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(2);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the archivefile");
            ENGINE_CHECK_ARG_STRING(1, "Arg1 is the path to mount the archive to");

            std::string path = ENGINE_GET_ARG_CPPSTRING_VALUE(0);

            if (!Filesystem::FileExists(path)) {
                ENGINE_THROW_ARGERROR("File does not exist");
                ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
            }

            bool result = Filesystem::Mount(Filesystem::GetRealPath(path), ENGINE_GET_ARG_CPPSTRING_VALUE(1));

            ENGINE_JS_SCOPE_CLOSE(v8::Boolean::New(result));
        }

        ENGINE_JS_METHOD(ConfigDir) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the application name");

            Filesystem::SetupUserDir(ENGINE_GET_ARG_CPPSTRING_VALUE(0));

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

        ENGINE_JS_METHOD(Mkdir) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the directory to create");

            Filesystem::Mkdir(ENGINE_GET_ARG_CPPSTRING_VALUE(0));

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

#define addItem(table, js_name, funct) table->Set(js_name, v8::FunctionTemplate::New(funct))

        void InitFS(v8::Handle<v8::ObjectTemplate> fsTable) {
            addItem(fsTable, "readFile", ReadFile);
            addItem(fsTable, "writeFile", WriteFile);
            addItem(fsTable, "fileExists", FileExists);
            addItem(fsTable, "fileSize", FileSize);
            addItem(fsTable, "mountFile", MountFile);
            addItem(fsTable, "configDir", ConfigDir);
            addItem(fsTable, "mkdir", Mkdir);
        }

#undef addItem

    }
}<commit_msg>Added fs.lsdir<commit_after>/*
   Filename: JSFS.cpp
   Purpose:  Javascript bindings for Engine::Filesystem

   Part of Engine2D

   Copyright (C) 2014 Vbitz

   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 "JSFS.hpp"

#include "Util.hpp"
#include "Filesystem.hpp"

namespace Engine {
    namespace JsFS {
        ENGINE_JS_METHOD(ReadFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file to read");

            std::string path = ENGINE_GET_ARG_CPPSTRING_VALUE(0);

            if (!Filesystem::FileExists(path)) {
                ENGINE_THROW_ARGERROR("File does not exist");
                ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
            }

            if (args.Length() == 2) {
                ENGINE_CHECK_ARG_BOOLEAN(1, "Set Arg1 if you need a raw byte array");
                long fileLength = 0;
                char* file = Filesystem::GetFileContent(path, fileLength);
                v8::Handle<v8::Array> arr = v8::Array::New();
                for (int i = 0; i < fileLength; i++) {
                    arr->Set(i, v8::Number::New((unsigned char) file[i]));
                }
                ENGINE_JS_SCOPE_CLOSE(arr);
            } else {
                ENGINE_JS_SCOPE_CLOSE(v8::String::New(Filesystem::GetFileContent(path)));
            }
        }

        ENGINE_JS_METHOD(WriteFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file to write");
            ENGINE_CHECK_ARG_STRING(1, "Arg1 is the content to write to the file");

            Filesystem::WriteFile(ENGINE_GET_ARG_CPPSTRING_VALUE(0), *ENGINE_GET_ARG_CSTRING_VALUE(1), args[1]->ToString()->Length());

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

        ENGINE_JS_METHOD(FileExists) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file");

            ENGINE_JS_SCOPE_CLOSE(v8::Boolean::New(Filesystem::FileExists(ENGINE_GET_ARG_CPPSTRING_VALUE(0))));
        }

        ENGINE_JS_METHOD(FileSize) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the file");

            ENGINE_JS_SCOPE_CLOSE(v8::Integer::New((int) Filesystem::FileSize(ENGINE_GET_ARG_CPPSTRING_VALUE(0))));
        }

        ENGINE_JS_METHOD(MountFile) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(2);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the archivefile");
            ENGINE_CHECK_ARG_STRING(1, "Arg1 is the path to mount the archive to");

            std::string path = ENGINE_GET_ARG_CPPSTRING_VALUE(0);

            if (!Filesystem::FileExists(path)) {
                ENGINE_THROW_ARGERROR("File does not exist");
                ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
            }

            bool result = Filesystem::Mount(Filesystem::GetRealPath(path), ENGINE_GET_ARG_CPPSTRING_VALUE(1));

            ENGINE_JS_SCOPE_CLOSE(v8::Boolean::New(result));
        }

        ENGINE_JS_METHOD(ConfigDir) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the application name");

            Filesystem::SetupUserDir(ENGINE_GET_ARG_CPPSTRING_VALUE(0));

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

        ENGINE_JS_METHOD(Mkdir) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path to the directory to create");

            Filesystem::Mkdir(ENGINE_GET_ARG_CPPSTRING_VALUE(0));

            ENGINE_JS_SCOPE_CLOSE_UNDEFINED;
        }

        ENGINE_JS_METHOD(Lsdir) {
            ENGINE_JS_SCOPE_OPEN;

            ENGINE_CHECK_ARGS_LENGTH(1);

            ENGINE_CHECK_ARG_STRING(0, "Arg0 is the path of the directory to list");

            v8::Handle<v8::Array> ret = v8::Array::New();

            std::vector<std::string> files = Filesystem::GetDirectoryContent(ENGINE_GET_ARG_CPPSTRING_VALUE(0));

            for (size_t i = 0; i < files.size(); i++) {
                ret->Set(i, v8::String::New(files[i].c_str()));
            }

            ENGINE_JS_SCOPE_CLOSE(ret);
        }

#define addItem(table, js_name, funct) table->Set(js_name, v8::FunctionTemplate::New(funct))

        void InitFS(v8::Handle<v8::ObjectTemplate> fsTable) {
            addItem(fsTable, "readFile", ReadFile);
            addItem(fsTable, "writeFile", WriteFile);
            addItem(fsTable, "fileExists", FileExists);
            addItem(fsTable, "fileSize", FileSize);
            addItem(fsTable, "mountFile", MountFile);
            addItem(fsTable, "configDir", ConfigDir);
            addItem(fsTable, "mkdir", Mkdir);
            addItem(fsTable, "lsdir", Lsdir);
        }

#undef addItem

    }
}<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_
#define _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Execution/Exceptions.h"

#include    "BadFormatException.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             ******************* ObjectVariantMapper::StructureFieldInfo ********************
             ********************************************************************************
             */
            inline  ObjectVariantMapper::StructureFieldInfo::StructureFieldInfo (size_t fieldOffset, type_index typeInfo, const String& serializedFieldName)
                : fOffset (fieldOffset)
                , fTypeInfo (typeInfo)
                , fSerializedFieldName (serializedFieldName)
            {
            }

            /*
             ********************************************************************************
             ******************************** ObjectVariantMapper ***************************
             ********************************************************************************
             */
            inline  Set<ObjectVariantMapper::TypeMappingDetails>    ObjectVariantMapper::GetTypeMappingRegistry () const
            {
                return fSerializers_;
            }
            inline  void    ObjectVariantMapper::SetTypeMappingRegistry (const Set<TypeMappingDetails>& s)
            {
                fSerializers_ = s;
            }
            template    <typename CLASS>
            inline  void    ObjectVariantMapper::RegisterClass (const Sequence<StructureFieldInfo>& fieldDescriptions)
            {
                RegisterTypeMapper (TypeMappingDetails (typeid (CLASS), sizeof (CLASS), fieldDescriptions));
            }
            template    <typename CLASS>
            inline  void    ObjectVariantMapper::ToObject (const Memory::VariantValue& v, CLASS* into) const
            {
                ToObject  (typeid (CLASS), v, reinterpret_cast<Byte*> (into));
            }
            template    <typename CLASS>
            inline  CLASS    ObjectVariantMapper::ToObject (const Memory::VariantValue& v) const
            {
                CLASS tmp;
                ToObject (v, &tmp);
                return tmp;
            }
            template    <typename CLASS>
            inline  VariantValue    ObjectVariantMapper::FromObject (const CLASS& from) const
            {
                return FromObject  (typeid (CLASS), reinterpret_cast<const Byte*> (&from));
            }
            template <typename T, size_t SZ>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Array ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const T*  actualMember    =   reinterpret_cast<const T*> (fromObjOfTypeT);
                    for (auto i = actualMember; i < actualMember + SZ; ++i) {
                        s.Append (mapper->FromObject<T> (*i));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue> s  =   d.As<Sequence<T>> ();
                    T*  actualMember    =   reinterpret_cast<T*> (intoObjOfTypeT);
                    if (s.size () > SZ) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    size_t idx = 0;
                    for (auto i : s) {
                        actualMember[idx++] = mapper->ToObject<T> (i);
                    }
                    while (idx < SZ) {
                        actualMember[idx++] = T ();
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Sequence<T>), toVariantMapper, fromVariantMapper);
            }
            template    <typename T>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Sequence ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const Sequence<T>*  actualMember    =   reinterpret_cast<const Sequence<T>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        s.Append (mapper->FromObject<T> (i));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue> s  =   d.As<Sequence<T>> ();
                    Sequence<T>*    actualInto  =   reinterpret_cast<Sequence<T>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (auto i : s) {
                        actualInto->Append (mapper->ToObject<T> (i));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Sequence<T>), toVariantMapper, fromVariantMapper);
            }
            template    <typename KEY_TYPE, typename VALUE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Mapping ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const Mapping<KEY_TYPE, VALUE_TYPE>*  actualMember    =   reinterpret_cast<const Mapping<KEY_TYPE, VALUE_TYPE>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        Sequence<VariantValue>  encodedPair;
                        encodedPair.Append (mapper->FromObject<KEY_TYPE> (i.first));
                        encodedPair.Append (mapper->FromObject<VALUE_TYPE> (i.second));
                        s.Append (VariantValue (encodedPair));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue>          s  =   d.As<Sequence<VariantValue>> ();
                    Mapping<KEY_TYPE, VALUE_TYPE>*  actualInto  =   reinterpret_cast<Mapping<KEY_TYPE, VALUE_TYPE>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (VariantValue encodedPair : s) {
                        Sequence<VariantValue>  p   =   p.As<Sequence<VariantValue>> ();
                        if (p.size () != 2) {
                            Execution::DoThrow<BadFormatException> (BadFormatException ());
                        }
                        actualInto->Add (mapper->ToObject<KEY_TYPE> (p[0]), mapper->ToObject<VALUE_TYPE> (p[1]));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Mapping<KEY_TYPE, VALUE_TYPE>), toVariantMapper, fromVariantMapper);
            }
            template    <typename KEY_TYPE, typename VALUE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_MappingWithStringishKey ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Mapping<String, VariantValue> m;
                    const Mapping<KEY_TYPE, VALUE_TYPE>*  actualMember    =   reinterpret_cast<const Mapping<KEY_TYPE, VALUE_TYPE>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        m.Add (mapper->FromObject<String> (i.first), mapper->FromObject<VALUE_TYPE> (i.second));
                    }
                    return VariantValue (m);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Mapping<String, VariantValue>    m  =   d.As<Mapping<String, VariantValue>> ();
                    Mapping<KEY_TYPE, VALUE_TYPE>*  actualInto  =   reinterpret_cast<Mapping<KEY_TYPE, VALUE_TYPE>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (pair<String, VariantValue> : m) {
                        actualInto->Add (mapper->ToObject<String> (p.first), mapper->ToObject<VALUE_TYPE> (p.second));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Mapping<KEY_TYPE, VALUE_TYPE>), toVariantMapper, fromVariantMapper);
            }
            template <typename RANGE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Range ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    typedef typename RANGE_TYPE::ElementType    ElementType;
                    Mapping<String, VariantValue> m;
                    const RANGE_TYPE*  actualMember    =   reinterpret_cast<const RANGE_TYPE*> (fromObjOfTypeT);
                    m.Add (L"Begin", mapper->FromObject<ElementType> (actualMember->begin ()));
                    m.Add (L"End", mapper->FromObject<ElementType> (actualMember->end ()));
                    return VariantValue (m);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    typedef typename RANGE_TYPE::ElementType    ElementType;
                    Mapping<String, VariantValue>          m  =   d.As<Mapping<String, VariantValue>> ();
                    RANGE_TYPE*  actualInto  =   reinterpret_cast<RANGE_TYPE*> (intoObjOfTypeT);
                    if (m.size () != 2) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    if (not m.ContainsKey (L"Begin") or not m.ContainsKey (L"End")) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    ElementType from    =   mapper->ToObject<ElementType> (*m.Lookup (L"Begin"));
                    ElementType to      =   mapper->ToObject<ElementType> (*m.Lookup (L"End"));
                    if (not (RANGE_TYPE::TraitsType::kMin <= from and from < RANGE_TYPE::TraitsType::kMax)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    if (not (RANGE_TYPE::TraitsType::kMin <= to and to < RANGE_TYPE::TraitsType::kMax)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    * actualInto = RANGE_TYPE (from, to);
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (RANGE_TYPE), toVariantMapper, fromVariantMapper);
            }
            template <typename ENUM_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Enumeration ()
            {
                /*
                 *  Note: we cannot get the enumeration print names - in general. That would be nicer to read, but we dont have
                 *  the data, and this is simple and efficient.
                 */
                Require (std::is_enum<ENUM_TYPE>::value);
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                typedef typename std::underlying_type<ENUM_TYPE>::type SerializeAsType;
#else
                typedef long long SerializeAsType;
#endif
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    const ENUM_TYPE*  actualMember    =   reinterpret_cast<const ENUM_TYPE*> (fromObjOfTypeT);
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                    Assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE));
#endif
                    Assert (static_cast<ENUM_TYPE> (static_cast<SerializeAsType> (*actualMember)) == *actualMember);    // no round-trip loss
                    return VariantValue (static_cast<SerializeAsType> (*actualMember));
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    ENUM_TYPE*  actualInto  =   reinterpret_cast<ENUM_TYPE*> (intoObjOfTypeT);
                    * actualInto = static_cast<ENUM_TYPE> (d.As<SerializeAsType> ());
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                    Assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE));
#endif
                    Assert (static_cast<SerializeAsType> (*actualInto) == d.As<SerializeAsType> ());  // no round-trip loss
                    if (not (ENUM_TYPE::eSTART <= *actualInto and * actualInto <= ENUM_TYPE::eEND)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (ENUM_TYPE), toVariantMapper, fromVariantMapper);
            }

#if 0
            template    <typename T>
            inline  ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Sequence<T>> ()
            {
                return mkSerializerInfoFor_Sequence_<T> ();
            }
#endif

        }
    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_*/
<commit_msg>fixed typo<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_
#define _Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Execution/Exceptions.h"

#include    "BadFormatException.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchangeFormat {

            /*
             ********************************************************************************
             ******************* ObjectVariantMapper::StructureFieldInfo ********************
             ********************************************************************************
             */
            inline  ObjectVariantMapper::StructureFieldInfo::StructureFieldInfo (size_t fieldOffset, type_index typeInfo, const String& serializedFieldName)
                : fOffset (fieldOffset)
                , fTypeInfo (typeInfo)
                , fSerializedFieldName (serializedFieldName)
            {
            }

            /*
             ********************************************************************************
             ******************************** ObjectVariantMapper ***************************
             ********************************************************************************
             */
            inline  Set<ObjectVariantMapper::TypeMappingDetails>    ObjectVariantMapper::GetTypeMappingRegistry () const
            {
                return fSerializers_;
            }
            inline  void    ObjectVariantMapper::SetTypeMappingRegistry (const Set<TypeMappingDetails>& s)
            {
                fSerializers_ = s;
            }
            template    <typename CLASS>
            inline  void    ObjectVariantMapper::RegisterClass (const Sequence<StructureFieldInfo>& fieldDescriptions)
            {
                RegisterTypeMapper (TypeMappingDetails (typeid (CLASS), sizeof (CLASS), fieldDescriptions));
            }
            template    <typename CLASS>
            inline  void    ObjectVariantMapper::ToObject (const Memory::VariantValue& v, CLASS* into) const
            {
                ToObject  (typeid (CLASS), v, reinterpret_cast<Byte*> (into));
            }
            template    <typename CLASS>
            inline  CLASS    ObjectVariantMapper::ToObject (const Memory::VariantValue& v) const
            {
                CLASS tmp;
                ToObject (v, &tmp);
                return tmp;
            }
            template    <typename CLASS>
            inline  VariantValue    ObjectVariantMapper::FromObject (const CLASS& from) const
            {
                return FromObject  (typeid (CLASS), reinterpret_cast<const Byte*> (&from));
            }
            template <typename T, size_t SZ>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Array ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const T*  actualMember    =   reinterpret_cast<const T*> (fromObjOfTypeT);
                    for (auto i = actualMember; i < actualMember + SZ; ++i) {
                        s.Append (mapper->FromObject<T> (*i));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue> s  =   d.As<Sequence<T>> ();
                    T*  actualMember    =   reinterpret_cast<T*> (intoObjOfTypeT);
                    if (s.size () > SZ) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    size_t idx = 0;
                    for (auto i : s) {
                        actualMember[idx++] = mapper->ToObject<T> (i);
                    }
                    while (idx < SZ) {
                        actualMember[idx++] = T ();
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Sequence<T>), toVariantMapper, fromVariantMapper);
            }
            template    <typename T>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Sequence ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const Sequence<T>*  actualMember    =   reinterpret_cast<const Sequence<T>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        s.Append (mapper->FromObject<T> (i));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue> s  =   d.As<Sequence<T>> ();
                    Sequence<T>*    actualInto  =   reinterpret_cast<Sequence<T>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (auto i : s) {
                        actualInto->Append (mapper->ToObject<T> (i));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Sequence<T>), toVariantMapper, fromVariantMapper);
            }
            template    <typename KEY_TYPE, typename VALUE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Mapping ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Sequence<VariantValue> s;
                    const Mapping<KEY_TYPE, VALUE_TYPE>*  actualMember    =   reinterpret_cast<const Mapping<KEY_TYPE, VALUE_TYPE>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        Sequence<VariantValue>  encodedPair;
                        encodedPair.Append (mapper->FromObject<KEY_TYPE> (i.first));
                        encodedPair.Append (mapper->FromObject<VALUE_TYPE> (i.second));
                        s.Append (VariantValue (encodedPair));
                    }
                    return VariantValue (s);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Sequence<VariantValue>          s  =   d.As<Sequence<VariantValue>> ();
                    Mapping<KEY_TYPE, VALUE_TYPE>*  actualInto  =   reinterpret_cast<Mapping<KEY_TYPE, VALUE_TYPE>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (VariantValue encodedPair : s) {
                        Sequence<VariantValue>  p   =   p.As<Sequence<VariantValue>> ();
                        if (p.size () != 2) {
                            Execution::DoThrow<BadFormatException> (BadFormatException ());
                        }
                        actualInto->Add (mapper->ToObject<KEY_TYPE> (p[0]), mapper->ToObject<VALUE_TYPE> (p[1]));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Mapping<KEY_TYPE, VALUE_TYPE>), toVariantMapper, fromVariantMapper);
            }
            template    <typename KEY_TYPE, typename VALUE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_MappingWithStringishKey ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    Mapping<String, VariantValue> m;
                    const Mapping<KEY_TYPE, VALUE_TYPE>*  actualMember    =   reinterpret_cast<const Mapping<KEY_TYPE, VALUE_TYPE>*> (fromObjOfTypeT);
                    for (auto i : *actualMember) {
                        m.Add (mapper->FromObject<String> (i.first), mapper->FromObject<VALUE_TYPE> (i.second));
                    }
                    return VariantValue (m);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    Mapping<String, VariantValue>    m  =   d.As<Mapping<String, VariantValue>> ();
                    Mapping<KEY_TYPE, VALUE_TYPE>*  actualInto  =   reinterpret_cast<Mapping<KEY_TYPE, VALUE_TYPE>*> (intoObjOfTypeT);
                    actualInto->clear ();
                    for (pair<String, VariantValue> p : m) {
                        actualInto->Add (mapper->ToObject<String> (p.first), mapper->ToObject<VALUE_TYPE> (p.second));
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (Mapping<KEY_TYPE, VALUE_TYPE>), toVariantMapper, fromVariantMapper);
            }
            template <typename RANGE_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Range ()
            {
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    typedef typename RANGE_TYPE::ElementType    ElementType;
                    Mapping<String, VariantValue> m;
                    const RANGE_TYPE*  actualMember    =   reinterpret_cast<const RANGE_TYPE*> (fromObjOfTypeT);
                    m.Add (L"Begin", mapper->FromObject<ElementType> (actualMember->begin ()));
                    m.Add (L"End", mapper->FromObject<ElementType> (actualMember->end ()));
                    return VariantValue (m);
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    typedef typename RANGE_TYPE::ElementType    ElementType;
                    Mapping<String, VariantValue>          m  =   d.As<Mapping<String, VariantValue>> ();
                    RANGE_TYPE*  actualInto  =   reinterpret_cast<RANGE_TYPE*> (intoObjOfTypeT);
                    if (m.size () != 2) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    if (not m.ContainsKey (L"Begin") or not m.ContainsKey (L"End")) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    ElementType from    =   mapper->ToObject<ElementType> (*m.Lookup (L"Begin"));
                    ElementType to      =   mapper->ToObject<ElementType> (*m.Lookup (L"End"));
                    if (not (RANGE_TYPE::TraitsType::kMin <= from and from < RANGE_TYPE::TraitsType::kMax)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    if (not (RANGE_TYPE::TraitsType::kMin <= to and to < RANGE_TYPE::TraitsType::kMax)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                    * actualInto = RANGE_TYPE (from, to);
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (RANGE_TYPE), toVariantMapper, fromVariantMapper);
            }
            template <typename ENUM_TYPE>
            ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer_Enumeration ()
            {
                /*
                 *  Note: we cannot get the enumeration print names - in general. That would be nicer to read, but we dont have
                 *  the data, and this is simple and efficient.
                 */
                Require (std::is_enum<ENUM_TYPE>::value);
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                typedef typename std::underlying_type<ENUM_TYPE>::type SerializeAsType;
#else
                typedef long long SerializeAsType;
#endif
                auto toVariantMapper = [] (const ObjectVariantMapper * mapper, const Byte * fromObjOfTypeT) -> VariantValue {
                    const ENUM_TYPE*  actualMember    =   reinterpret_cast<const ENUM_TYPE*> (fromObjOfTypeT);
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                    Assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE));
#endif
                    Assert (static_cast<ENUM_TYPE> (static_cast<SerializeAsType> (*actualMember)) == *actualMember);    // no round-trip loss
                    return VariantValue (static_cast<SerializeAsType> (*actualMember));
                };
                auto fromVariantMapper = [] (const ObjectVariantMapper * mapper, const VariantValue & d, Byte * intoObjOfTypeT) -> void {
                    ENUM_TYPE*  actualInto  =   reinterpret_cast<ENUM_TYPE*> (intoObjOfTypeT);
                    * actualInto = static_cast<ENUM_TYPE> (d.As<SerializeAsType> ());
#if     qCompilerAndStdLib_Supports_TypeTraits_underlying_type
                    Assert (sizeof (SerializeAsType) == sizeof (ENUM_TYPE));
#endif
                    Assert (static_cast<SerializeAsType> (*actualInto) == d.As<SerializeAsType> ());  // no round-trip loss
                    if (not (ENUM_TYPE::eSTART <= *actualInto and * actualInto <= ENUM_TYPE::eEND)) {
                        Execution::DoThrow<BadFormatException> (BadFormatException ());
                    }
                };
                return ObjectVariantMapper::TypeMappingDetails (typeid (ENUM_TYPE), toVariantMapper, fromVariantMapper);
            }

#if 0
            template    <typename T>
            inline  ObjectVariantMapper::TypeMappingDetails ObjectVariantMapper::MakeCommonSerializer<Sequence<T>> ()
            {
                return mkSerializerInfoFor_Sequence_<T> ();
            }
#endif

        }
    }
}
#endif  /*_Stroika_Foundation_DataExchangeFormat_ObjectVariantMapper_inl_*/
<|endoftext|>