<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __itkLocalAffineTransform_hxx
#define __itkLocalAffineTransform_hxx

#include "itkNumericTraits.h"
#include "vnl/algo/vnl_matrix_inverse.h"
#include "vnl_sd_matrix_tools.h"
#include "itkLocalAffineTransform.h"

namespace itk
{
/** Constructor with default arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform():Superclass(ParametersDimension)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/** Constructor with default arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform(unsigned int parametersDimension):
  Superclass(parametersDimension)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/** Constructor with explicit arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform(const MatrixType & matrix,
                                                             const OutputVectorType & offset):
  Superclass(matrix, offset)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/**  Destructor */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::
~LocalAffineTransform()
{
  return;
}

/** Compute the principal logarithm of an affine transform */
template< class TScalarType, unsigned int NDimensions >
vnl_matrix<TScalarType>
LocalAffineTransform< TScalarType, NDimensions >::ComputeLogarithmMatrix(
  AffineTransformPointer affineTransform)
{
  vnl_matrix<TScalarType> homoMat(NDimensions+1, NDimensions+1);
  this->GetHomogeneousMatrix(homoMat, affineTransform);

  vnl_matrix<TScalarType> logMat = sdtools::GetLogarithm(homoMat);

  return logMat;
}

/** Compute the exponential of an affine transform */
template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >::ComputeExponentialTransform(
  vnl_matrix<TScalarType> velocity)
{
  AffineTransformPointer expAffine = AffineTransformType::New();

  vnl_matrix<TScalarType> expMat = sdtools::GetExponential(velocity);
  this->SetHomogeneousTransform(expAffine, expMat);

  return expAffine;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::SetHomogeneousTransform(
  AffineTransformPointer &affineTransform,
  const vnl_matrix<TScalarType> &homoMatrix)
{
  MatrixType vmat;
  OutputVectorType voffset;
  TScalarType scale = homoMatrix[NDimensions][NDimensions];

  for (unsigned int i=0; i<NDimensions; i++)
    {
    for (unsigned int j=0; j<NDimensions; j++)
      {
        vmat[i][j] = homoMatrix[i][j] / scale;
      }
    voffset[i] = homoMatrix[i][NDimensions] / scale;
    }

  affineTransform->SetCenter(this->GetCenter());
  affineTransform->SetMatrix(vmat);
  affineTransform->SetOffset(voffset);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::GetHomogeneousMatrix(
  vnl_matrix<TScalarType> &homoMatrix,
  const AffineTransformPointer &affineTransform)
{
  MatrixType mat = affineTransform->GetMatrix();
  OutputVectorType offset = affineTransform->GetOffset();

  homoMatrix.fill(0.0);
  for (unsigned int i=0; i<NDimensions; i++)
    {
    for (unsigned int j=0; j<NDimensions; j++)
      {
      homoMatrix[i][j] = mat[i][j];
      }
    homoMatrix[i][NDimensions] = offset[i];
    }
  homoMatrix[NDimensions][NDimensions] = 1;
}

template< class TScalarType, unsigned int NDimensions >
vnl_matrix<TScalarType>
LocalAffineTransform< TScalarType, NDimensions >
::GetVelocityMatrix()
{
  if (this->m_VelocityMatrix.empty())
    {
    this->m_VelocityMatrix = this->ComputeLogarithmMatrix(this);
    }
  return this->m_VelocityMatrix;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::UpdatePartialVelocityMatrix()
{
  double timePeriod = (double)(m_StopTime - m_StartTime) / m_TimeStampMax;
  this->m_PartialVelocityMatrix = this->GetVelocityMatrix();
  this->m_PartialVelocityMatrix *= timePeriod;
}

template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::OutputVectorType
LocalAffineTransform< TScalarType, NDimensions >
::GetPartialVelocityAtPoint(const PointType &point)
{
  OutputVectorType velocity;

  for (unsigned int r=0; r<NDimensions; r++)
    {
    velocity[r] = this->m_PartialVelocityMatrix[r][NDimensions];
    for (unsigned int c=0; c<NDimensions; c++)
      {
      velocity[r] += this->m_PartialVelocityMatrix[r][c] * point[c];
      }
    }
  return velocity;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::AddFixedPoint(InputPointType point)
{
  if (this->m_FixedPointSet.IsNull())
    {
    this->m_FixedPointSet = PointSetType::New();
    }
  typename PointSetType::PointIndentifier id = this->m_FixedPointSet->GetNumberOfPoints();
  this->m_FixedPointSet.SetPoint(id, point);
}

template< class TScalarType, unsigned int NDimensions >
template< class TSpatialObject >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeFixedMaskImageFromSpatialObject(TSpatialObject *spatialObject, SizeType size)
{
  typedef itk::SpatialObjectToImageFilter<TSpatialObject,MaskImageType> SpatialObjectToImageFilterType;
  typename SpatialObjectToImageFilterType::Pointer imageFilter = SpatialObjectToImageFilterType::New();
  imageFilter->SetInput(spatialObject);
  imageFilter->SetInsideValue(1);
  imageFilter->SetOutsideValue(0);
  imageFilter->SetSize(size);
  imageFilter->Update();
  this->m_FixedMaskImage = imageFilter->GetOutput();
}

template< class TScalarType, unsigned int NDimensions >
template< class TSpatialObject >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeFixedMaskImageFromSpatialObject(TSpatialObject *spatialObject,
                                PointType origin,
                                DirectionType direction,
                                SpacingType spacing,
                                SizeType size)
{
  typedef itk::SpatialObjectToImageFilter<TSpatialObject,MaskImageType> SpatialObjectToImageFilterType;
  typename SpatialObjectToImageFilterType::Pointer imageFilter = SpatialObjectToImageFilterType::New();
  imageFilter->SetInput(spatialObject);
  imageFilter->SetInsideValue(1);
  imageFilter->SetOutsideValue(0);

  imageFilter->SetOrigin(origin);
  imageFilter->SetSpacing(spacing);
  imageFilter->SetDirection(direction);
  imageFilter->SetSize(size);

  imageFilter->Update();
  this->m_FixedMaskImage = imageFilter->GetOutput();
}

template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >
::GetPartialTransform(int startTime, int stopTime)
{
  AffineTransformPointer partialTransform = AffineTransform::New();
  int duration = stopTime - startTime;
  if (duration == 0)
    {
    partialTransform->SetCenter(this->GetCenter());
    partialTransform->SetIdentity();
    }
  else if (duration == this->m_TimeStampMax)
    {
    partialTransform->SetCenter(this->GetCenter());
    partialTransform->SetMatrix(this->GetMatrix());
    partialTransform->SetOffset(this->GetOffset());
    }
  else if (duration == -this->m_TimeStampMax)
    {
    partialTransform->SetCenter(this->GetCenter());
    bool invertible = this->GetInverse(partialTransform);
    if (!invertible)
      {
      itkWarningMacro("This LocalAffineTransform is not invertible.");
      }
    }
  else
    {
    double factor = (double)duration / this->m_TimeStampMax;
    vnl_matrix<TScalarType> partialVelocity = this->GetVelocityMatrix();
    partialVelocity *= factor;
    partialTransform = this->ComputeExponentialTransform(partialVelocity);
    }

  return partialTransform;
}

/**
 * The existing method AffineTransform::Scale(factor) scales around the center.
 * Instead, we scale around (0,0) in ScaleMatrixOffset().
 */
template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >
::ScaleMatrixOffset(AffineTransformPointer transform, double factor)
{
  AffineTransformPointer result = AffineTransformType::New();

  result->SetCenter(transform->GetCenter());

  AffineTransformType::MatrixType newMatrix = transform->GetMatrix();
  newMatrix *= factor;
  result->SetMatrix(newMatrix);

  AffineTransformType::OutputVectorType newOffset = transform->GetOffset();
  newOffset *= factor;
  result->SetOffset(newOffset);

  return result;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpMaskIntoPointSet(PointSetPointer &pointSet, const MaskImagePointer &mask,
                       const AffineTransformPointer &transform)
{
  typedef ImageRegionIteratorWithIndex< MaskImageType > IteratorType;
  IteratorType it( mask, mask->GetLargestPossibleRegion() );

  //fill the moving mask with values
  typename PointSetType::PointIdentifier pointId = pointSet->GetNumberOfPoints();
  PointType point, point2;

  for( it.GoToBegin(); !it.IsAtEnd(); ++it )
    {
      if (it.Get() != 0) //foreground
        {
        mask->TransformIndexToPhysicalPoint(it.GetIndex(), point);
        point2 = transform->TransformPoint(point);
        pointSet->SetPoint(pointId++, point2);
      }
    }
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpFixedMaskIntoPointSet(int timeStamp)
{
  AffineTransformPointer forwardTransform = this->GetPartialTransform(0, timeStamp);

  this->WarpMaskIntoPointSet(this->m_SamplePointSet,
    this->m_FixedMaskImage, forwardTransform);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpMovingMaskIntoPointSet(int timeStamp)
{
  AffineTransformPointer backwardTransform = this->GetPartialTransform(this->m_TimeStampMax, timeStamp);

  this->WarpMaskIntoPointSet(this->m_SamplePointSet,
    this->m_MovingMaskImage, backwardTransform);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeSamplePointSet(int timeStamp)
{
  //fill m_SamplePointSet with points
  this->m_SamplePointSet = PointSetType::New();
  this->WarpFixedMaskIntoPointSet(timeStamp);
  this->WarpMovingMaskIntoPointSet(timeStamp);
}

/**
 * Warp the fixed mask to the moving mask. The moving mask
 * uses the meta information from the fixed mask except its
 * region. Instead, the region will be expanded to contain
 * the warped mask.
 */
template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeMovingMaskImage()
{
  ContinuousIndexType mappedCorner, minIndex, maxIndex;

  //compute minIndex and maxIndex of the warped mask
  RegionType fixedRegion = this->m_FixedMaskImage->GetLargestPossibleRegion();
  minIndex = fixedRegion.GetIndex();
  maxIndex = fixedRegion.GetUpperIndex();

  typedef typename itk::VectorContainer<int, IndexType> IndexContainerType;
  typename IndexContainerType::Pointer corners =
    PicslImageHelper::GetCorners<RegionType>(fixedRegion);
  typename IndexContainerType::ConstIterator corner;
  for ( corner = corners->Begin(); corner != corners->End(); corner++)
    {
    IndexType cornerIndex = corner.Value();
    PointType cornerPoint, mappedPoint;
    //map the corner index into the physical point
    this->m_FixedMaskImage->TransformIndexToPhysicalPoint(cornerIndex, cornerPoint);
    //transform the point by this local affine transform
    mappedPoint = this->TransformPoint(cornerPoint);
    //map the transformed point to index
    this->m_FixedMaskImage->TransformPhysicalPointToContinuousIndex(mappedPoint, mappedCorner);

    PicslImageHelper::CopyWithMin<ContinuousIndexType>(minIndex, mappedCorner);
    PicslImageHelper::CopyWithMax<ContinuousIndexType>(maxIndex, mappedCorner);
    }

  //allocate the moving mask with the possible region
  IndexType index1, index2;
  index1.CopyWithRound(minIndex);
  index2.CopyWithRound(maxIndex);
  RegionType movingRegion;
  movingRegion.SetIndex(index1);
  movingRegion.SetUpperIndex(index2);

  MaskImagePointer movingMask = MaskImageType::New();
  movingMask->CopyInformation(this->m_FixedMaskImage);
  movingMask->SetRegions(movingRegion);
  movingMask->Allocate();

  //compute the inverse transform
  typename Superclass::Pointer inverse = Superclass::New();
  bool insideImage, invertible = this->GetInverse(inverse);
  if (!invertible)
    {
    itkWarningMacro("This LocalAffineTransform is not invertible.");
    return;
    }

  PointType point1, point2;
  typename MaskImageType::PixelType pixel;

  IndexType minMovingMaskIndex, maxMovingMaskIndex;
  minMovingMaskIndex = fixedRegion.GetIndex();
  maxMovingMaskIndex = fixedRegion.GetUpperIndex();

  //fill the moving mask with values
  typedef ImageRegionIteratorWithIndex< MaskImageType > IteratorType;
  IteratorType it( movingMask, movingMask->GetLargestPossibleRegion() );
  for( it.GoToBegin(); !it.IsAtEnd(); ++it )
    {
    index1 = it.GetIndex();
    movingMask->TransformIndexToPhysicalPoint(index1, point1);
    point2 = inverse->TransformPoint(point1);

    insideImage = this->m_FixedMaskImage->TransformPhysicalPointToIndex(point2, index2);
    pixel = 0;
    if (insideImage)
      {
      pixel = this->m_FixedMaskImage->GetPixel(index2);
      if (pixel != 0) //foreground
        {
        //update min and max indices
        PicslImageHelper::CopyWithMin<IndexType>(minMovingMaskIndex, index1);
        PicslImageHelper::CopyWithMax<IndexType>(maxMovingMaskIndex, index1);
        }
      }
    it.Set(pixel);
    } //for iterator of movingMask

  RegionType extractRegion;
  extractRegion.SetIndex(minMovingMaskIndex);
  extractRegion.SetUpperIndex(maxMovingMaskIndex);

  typedef itk::ExtractImageFilter< MaskImageType, MaskImageType > FilterType;
  typename FilterType::Pointer filter = FilterType::New();
  filter->SetExtractionRegion(extractRegion);
  filter->SetInput(movingMask);
#if ITK_VERSION_MAJOR >= 4
  filter->SetDirectionCollapseToIdentity(); // This is required.
#endif
  filter->Update();

  this->m_MovingMaskImage = filter->GetOutput();
}

/** Print self */
template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

} // namespace

#endif
<commit_msg>ENH: fixed a compiler error on linux<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __itkLocalAffineTransform_hxx
#define __itkLocalAffineTransform_hxx

#include "itkNumericTraits.h"
#include "vnl/algo/vnl_matrix_inverse.h"
#include "vnl_sd_matrix_tools.h"
#include "itkLocalAffineTransform.h"

namespace itk
{
/** Constructor with default arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform():Superclass(ParametersDimension)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/** Constructor with default arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform(unsigned int parametersDimension):
  Superclass(parametersDimension)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/** Constructor with explicit arguments */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::LocalAffineTransform(const MatrixType & matrix,
                                                             const OutputVectorType & offset):
  Superclass(matrix, offset)
{
  this->m_StartTime = 0.0;
  this->m_StopTime = 0.0;
}

/**  Destructor */
template< class TScalarType, unsigned int NDimensions >
LocalAffineTransform< TScalarType, NDimensions >::
~LocalAffineTransform()
{
  return;
}

/** Compute the principal logarithm of an affine transform */
template< class TScalarType, unsigned int NDimensions >
vnl_matrix<TScalarType>
LocalAffineTransform< TScalarType, NDimensions >::ComputeLogarithmMatrix(
  AffineTransformPointer affineTransform)
{
  vnl_matrix<TScalarType> homoMat(NDimensions+1, NDimensions+1);
  this->GetHomogeneousMatrix(homoMat, affineTransform);

  vnl_matrix<TScalarType> logMat = sdtools::GetLogarithm(homoMat);

  return logMat;
}

/** Compute the exponential of an affine transform */
template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >::ComputeExponentialTransform(
  vnl_matrix<TScalarType> velocity)
{
  AffineTransformPointer expAffine = AffineTransformType::New();

  vnl_matrix<TScalarType> expMat = sdtools::GetExponential(velocity);
  this->SetHomogeneousTransform(expAffine, expMat);

  return expAffine;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::SetHomogeneousTransform(
  AffineTransformPointer &affineTransform,
  const vnl_matrix<TScalarType> &homoMatrix)
{
  MatrixType vmat;
  OutputVectorType voffset;
  TScalarType scale = homoMatrix[NDimensions][NDimensions];

  for (unsigned int i=0; i<NDimensions; i++)
    {
    for (unsigned int j=0; j<NDimensions; j++)
      {
        vmat[i][j] = homoMatrix[i][j] / scale;
      }
    voffset[i] = homoMatrix[i][NDimensions] / scale;
    }

  affineTransform->SetCenter(this->GetCenter());
  affineTransform->SetMatrix(vmat);
  affineTransform->SetOffset(voffset);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::GetHomogeneousMatrix(
  vnl_matrix<TScalarType> &homoMatrix,
  const AffineTransformPointer &affineTransform)
{
  MatrixType mat = affineTransform->GetMatrix();
  OutputVectorType offset = affineTransform->GetOffset();

  homoMatrix.fill(0.0);
  for (unsigned int i=0; i<NDimensions; i++)
    {
    for (unsigned int j=0; j<NDimensions; j++)
      {
      homoMatrix[i][j] = mat[i][j];
      }
    homoMatrix[i][NDimensions] = offset[i];
    }
  homoMatrix[NDimensions][NDimensions] = 1;
}

template< class TScalarType, unsigned int NDimensions >
vnl_matrix<TScalarType>
LocalAffineTransform< TScalarType, NDimensions >
::GetVelocityMatrix()
{
  if (this->m_VelocityMatrix.empty())
    {
    this->m_VelocityMatrix = this->ComputeLogarithmMatrix(this);
    }
  return this->m_VelocityMatrix;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::UpdatePartialVelocityMatrix()
{
  double timePeriod = (double)(m_StopTime - m_StartTime) / m_TimeStampMax;
  this->m_PartialVelocityMatrix = this->GetVelocityMatrix();
  this->m_PartialVelocityMatrix *= timePeriod;
}

template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::OutputVectorType
LocalAffineTransform< TScalarType, NDimensions >
::GetPartialVelocityAtPoint(const PointType &point)
{
  OutputVectorType velocity;

  for (unsigned int r=0; r<NDimensions; r++)
    {
    velocity[r] = this->m_PartialVelocityMatrix[r][NDimensions];
    for (unsigned int c=0; c<NDimensions; c++)
      {
      velocity[r] += this->m_PartialVelocityMatrix[r][c] * point[c];
      }
    }
  return velocity;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::AddFixedPoint(InputPointType point)
{
  if (this->m_FixedPointSet.IsNull())
    {
    this->m_FixedPointSet = PointSetType::New();
    }
  typename PointSetType::PointIndentifier id = this->m_FixedPointSet->GetNumberOfPoints();
  this->m_FixedPointSet.SetPoint(id, point);
}

template< class TScalarType, unsigned int NDimensions >
template< class TSpatialObject >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeFixedMaskImageFromSpatialObject(TSpatialObject *spatialObject, SizeType size)
{
  typedef itk::SpatialObjectToImageFilter<TSpatialObject,MaskImageType> SpatialObjectToImageFilterType;
  typename SpatialObjectToImageFilterType::Pointer imageFilter = SpatialObjectToImageFilterType::New();
  imageFilter->SetInput(spatialObject);
  imageFilter->SetInsideValue(1);
  imageFilter->SetOutsideValue(0);
  imageFilter->SetSize(size);
  imageFilter->Update();
  this->m_FixedMaskImage = imageFilter->GetOutput();
}

template< class TScalarType, unsigned int NDimensions >
template< class TSpatialObject >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeFixedMaskImageFromSpatialObject(TSpatialObject *spatialObject,
                                PointType origin,
                                DirectionType direction,
                                SpacingType spacing,
                                SizeType size)
{
  typedef itk::SpatialObjectToImageFilter<TSpatialObject,MaskImageType> SpatialObjectToImageFilterType;
  typename SpatialObjectToImageFilterType::Pointer imageFilter = SpatialObjectToImageFilterType::New();
  imageFilter->SetInput(spatialObject);
  imageFilter->SetInsideValue(1);
  imageFilter->SetOutsideValue(0);

  imageFilter->SetOrigin(origin);
  imageFilter->SetSpacing(spacing);
  imageFilter->SetDirection(direction);
  imageFilter->SetSize(size);

  imageFilter->Update();
  this->m_FixedMaskImage = imageFilter->GetOutput();
}

template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >
::GetPartialTransform(int startTime, int stopTime)
{
  AffineTransformPointer partialTransform = AffineTransformType::New();
  int duration = stopTime - startTime;
  if (duration == 0)
    {
    partialTransform->SetCenter(this->GetCenter());
    partialTransform->SetIdentity();
    }
  else if (duration == this->m_TimeStampMax)
    {
    partialTransform->SetCenter(this->GetCenter());
    partialTransform->SetMatrix(this->GetMatrix());
    partialTransform->SetOffset(this->GetOffset());
    }
  else if (duration == -this->m_TimeStampMax)
    {
    partialTransform->SetCenter(this->GetCenter());
    bool invertible = this->GetInverse(partialTransform);
    if (!invertible)
      {
      itkWarningMacro("This LocalAffineTransform is not invertible.");
      }
    }
  else
    {
    double factor = (double)duration / this->m_TimeStampMax;
    vnl_matrix<TScalarType> partialVelocity = this->GetVelocityMatrix();
    partialVelocity *= factor;
    partialTransform = this->ComputeExponentialTransform(partialVelocity);
    }

  return partialTransform;
}

/**
 * The existing method AffineTransform::Scale(factor) scales around the center.
 * Instead, we scale around (0,0) in ScaleMatrixOffset().
 */
template< class TScalarType, unsigned int NDimensions >
typename LocalAffineTransform< TScalarType, NDimensions >::AffineTransformPointer
LocalAffineTransform< TScalarType, NDimensions >
::ScaleMatrixOffset(AffineTransformPointer transform, double factor)
{
  AffineTransformPointer result = AffineTransformType::New();

  result->SetCenter(transform->GetCenter());

  AffineTransformType::MatrixType newMatrix = transform->GetMatrix();
  newMatrix *= factor;
  result->SetMatrix(newMatrix);

  AffineTransformType::OutputVectorType newOffset = transform->GetOffset();
  newOffset *= factor;
  result->SetOffset(newOffset);

  return result;
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpMaskIntoPointSet(PointSetPointer &pointSet, const MaskImagePointer &mask,
                       const AffineTransformPointer &transform)
{
  typedef ImageRegionIteratorWithIndex< MaskImageType > IteratorType;
  IteratorType it( mask, mask->GetLargestPossibleRegion() );

  //fill the moving mask with values
  typename PointSetType::PointIdentifier pointId = pointSet->GetNumberOfPoints();
  PointType point, point2;

  for( it.GoToBegin(); !it.IsAtEnd(); ++it )
    {
      if (it.Get() != 0) //foreground
        {
        mask->TransformIndexToPhysicalPoint(it.GetIndex(), point);
        point2 = transform->TransformPoint(point);
        pointSet->SetPoint(pointId++, point2);
      }
    }
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpFixedMaskIntoPointSet(int timeStamp)
{
  AffineTransformPointer forwardTransform = this->GetPartialTransform(0, timeStamp);

  this->WarpMaskIntoPointSet(this->m_SamplePointSet,
    this->m_FixedMaskImage, forwardTransform);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::WarpMovingMaskIntoPointSet(int timeStamp)
{
  AffineTransformPointer backwardTransform = this->GetPartialTransform(this->m_TimeStampMax, timeStamp);

  this->WarpMaskIntoPointSet(this->m_SamplePointSet,
    this->m_MovingMaskImage, backwardTransform);
}

template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeSamplePointSet(int timeStamp)
{
  //fill m_SamplePointSet with points
  this->m_SamplePointSet = PointSetType::New();
  this->WarpFixedMaskIntoPointSet(timeStamp);
  this->WarpMovingMaskIntoPointSet(timeStamp);
}

/**
 * Warp the fixed mask to the moving mask. The moving mask
 * uses the meta information from the fixed mask except its
 * region. Instead, the region will be expanded to contain
 * the warped mask.
 */
template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >
::ComputeMovingMaskImage()
{
  ContinuousIndexType mappedCorner, minIndex, maxIndex;

  //compute minIndex and maxIndex of the warped mask
  RegionType fixedRegion = this->m_FixedMaskImage->GetLargestPossibleRegion();
  minIndex = fixedRegion.GetIndex();
  maxIndex = fixedRegion.GetUpperIndex();

  typedef typename itk::VectorContainer<int, IndexType> IndexContainerType;
  typename IndexContainerType::Pointer corners =
    PicslImageHelper::GetCorners<RegionType>(fixedRegion);
  typename IndexContainerType::ConstIterator corner;
  for ( corner = corners->Begin(); corner != corners->End(); corner++)
    {
    IndexType cornerIndex = corner.Value();
    PointType cornerPoint, mappedPoint;
    //map the corner index into the physical point
    this->m_FixedMaskImage->TransformIndexToPhysicalPoint(cornerIndex, cornerPoint);
    //transform the point by this local affine transform
    mappedPoint = this->TransformPoint(cornerPoint);
    //map the transformed point to index
    this->m_FixedMaskImage->TransformPhysicalPointToContinuousIndex(mappedPoint, mappedCorner);

    PicslImageHelper::CopyWithMin<ContinuousIndexType>(minIndex, mappedCorner);
    PicslImageHelper::CopyWithMax<ContinuousIndexType>(maxIndex, mappedCorner);
    }

  //allocate the moving mask with the possible region
  IndexType index1, index2;
  index1.CopyWithRound(minIndex);
  index2.CopyWithRound(maxIndex);
  RegionType movingRegion;
  movingRegion.SetIndex(index1);
  movingRegion.SetUpperIndex(index2);

  MaskImagePointer movingMask = MaskImageType::New();
  movingMask->CopyInformation(this->m_FixedMaskImage);
  movingMask->SetRegions(movingRegion);
  movingMask->Allocate();

  //compute the inverse transform
  typename Superclass::Pointer inverse = Superclass::New();
  bool insideImage, invertible = this->GetInverse(inverse);
  if (!invertible)
    {
    itkWarningMacro("This LocalAffineTransform is not invertible.");
    return;
    }

  PointType point1, point2;
  typename MaskImageType::PixelType pixel;

  IndexType minMovingMaskIndex, maxMovingMaskIndex;
  minMovingMaskIndex = fixedRegion.GetIndex();
  maxMovingMaskIndex = fixedRegion.GetUpperIndex();

  //fill the moving mask with values
  typedef ImageRegionIteratorWithIndex< MaskImageType > IteratorType;
  IteratorType it( movingMask, movingMask->GetLargestPossibleRegion() );
  for( it.GoToBegin(); !it.IsAtEnd(); ++it )
    {
    index1 = it.GetIndex();
    movingMask->TransformIndexToPhysicalPoint(index1, point1);
    point2 = inverse->TransformPoint(point1);

    insideImage = this->m_FixedMaskImage->TransformPhysicalPointToIndex(point2, index2);
    pixel = 0;
    if (insideImage)
      {
      pixel = this->m_FixedMaskImage->GetPixel(index2);
      if (pixel != 0) //foreground
        {
        //update min and max indices
        PicslImageHelper::CopyWithMin<IndexType>(minMovingMaskIndex, index1);
        PicslImageHelper::CopyWithMax<IndexType>(maxMovingMaskIndex, index1);
        }
      }
    it.Set(pixel);
    } //for iterator of movingMask

  RegionType extractRegion;
  extractRegion.SetIndex(minMovingMaskIndex);
  extractRegion.SetUpperIndex(maxMovingMaskIndex);

  typedef itk::ExtractImageFilter< MaskImageType, MaskImageType > FilterType;
  typename FilterType::Pointer filter = FilterType::New();
  filter->SetExtractionRegion(extractRegion);
  filter->SetInput(movingMask);
#if ITK_VERSION_MAJOR >= 4
  filter->SetDirectionCollapseToIdentity(); // This is required.
#endif
  filter->Update();

  this->m_MovingMaskImage = filter->GetOutput();
}

/** Print self */
template< class TScalarType, unsigned int NDimensions >
void
LocalAffineTransform< TScalarType, NDimensions >::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
}

} // namespace

#endif
<|endoftext|>


<commit_before>#include <iostream>

class MyClass
{
public:
  void DoThing() const & { std::cout << "Thing was done as const &" << std::endl; }
  void DoThing() const && { std::cout << "Thing was done as const &&" << std::endl; }

  void DoThing() & { std::cout << "Thing was done as &" << std::endl; }
  void DoThing() && { std::cout << "Thing was done as &&" << std::endl; }
};

int main(int argc, char* argv[])
{
	MyClass m;
	m.DoThing();

	MyClass().DoThing();

	const MyClass& crm = m;
	crm.DoThing();

	auto returnMyClass = []()->const MyClass{return MyClass();};
	returnMyClass().DoThing();
}

<commit_msg>Added stack overflow reference<commit_after>// http://stackoverflow.com/questions/17521238/what-are-rvalue-references-for-this-for

#include <iostream>

class MyClass
{
public:
  void DoThing() const & { std::cout << "Thing was done as const &" << std::endl; }
  void DoThing() const && { std::cout << "Thing was done as const &&" << std::endl; }

  void DoThing() & { std::cout << "Thing was done as &" << std::endl; }
  void DoThing() && { std::cout << "Thing was done as &&" << std::endl; }
};

int main(int argc, char* argv[])
{
	MyClass m;
	m.DoThing();

	MyClass().DoThing();

	const MyClass& crm = m;
	crm.DoThing();

	auto returnMyClass = []()->const MyClass{return MyClass();};
	returnMyClass().DoThing();
}

<|endoftext|>


<commit_before>#include "calc.h"
#include "sevensegment.h"
#include "pocketcalculator.h"

#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

#include <string>
#include <sstream>
#include <limits>
#include <algorithm>

namespace calc_tests {
	constexpr int max { std::numeric_limits<int>::max() },
				  min { std::numeric_limits<int>::min() };
	void multiplies_positive_numbers() {
		ASSERT_EQUAL(20, calc(4, 5, '*'));
	}
	void multiplies_negative_with_positive_number() {
		ASSERT_EQUAL(-30, calc(-6, 5, '*'));
	}
	void multiplies_negative_numbers() {
		ASSERT_EQUAL(20, calc(-4, -5, '*'));
	}
	void recognizes_overflows_when_multiplying() {
		ASSERT_THROWS(calc(4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(4, min/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, min/3, '*'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_multiplying() {
		calc(1, max, '*');
		calc(1, min, '*');
		calc(-1, max, '*');
		calc(-1, min+1, '*');
		calc(2, max/2, '*');
		calc(2, min/2, '*');
		calc(-2, max/2, '*');
		calc(-2, min/2+1, '*');
	}
	void divides() {
		ASSERT_EQUAL(5, calc(60, 12, '/'));
		ASSERT_EQUAL(-3, calc(9, -3, '/'));
	}
	void throws_when_dividing_by_zero() {
		ASSERT_THROWS(calc(1, 0, '/'), std::domain_error);
	}
	void adds() {
		ASSERT_EQUAL(5, calc(2, 3, '+'));
		ASSERT_EQUAL(-10, calc(-6, -4, '+'));
	}
	void recognizes_overflows_when_adding() {
		ASSERT_THROWS(calc(max, 1, '+'), std::overflow_error);
		ASSERT_THROWS(calc(min, -1, '+'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_adding() {
		calc(max, 0, '+');
		calc(min, 0, '+');
	}
	void subtracts() {
		ASSERT_EQUAL(17, calc(20, 3, '-'));
		ASSERT_EQUAL(-5, calc(-2, 3, '-'));
	}
	void recognizes_overflows_when_subtracting() {
		ASSERT_THROWS(calc(max, -1, '-'), std::overflow_error);
		ASSERT_THROWS(calc(min, 1, '-'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_subtracting() {
		calc(max, 0, '-');
		calc(min, 0, '-');
	}
	void knows_modulo() {
		ASSERT_EQUAL(5, calc(15, 10, '%'));
		ASSERT_EQUAL(-5, calc(-15, 10, '%'));
	}
	void throws_when_modulo_zero() {
		ASSERT_THROWS(calc(10, 0, '%'), std::domain_error);
	}
	void throws_when_given_invalid_operator() {
		ASSERT_THROWS(calc(1, 1, '^'), std::runtime_error);
	}

	void takes_term_from_istream() {
		std::istringstream term_stream { "1+1" };
		int result = calc(term_stream);
		ASSERT_EQUAL(2, result);
	}

	const std::vector<std::string> invalid_terms {
        "foobar",
        "3+2-",
        "1",
        "8--",
        "*",
        "4%%6",
        "3//7",
	};

    void throws_when_given_invalid_term() {
		for(auto const term : invalid_terms) {
			std::istringstream term_stream { term };
			ASSERT_THROWS(calc(term_stream), std::exception);
		}
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(multiplies_positive_numbers));
		s.push_back(CUTE(multiplies_negative_with_positive_number));
		s.push_back(CUTE(multiplies_negative_numbers));
		s.push_back(CUTE(recognizes_overflows_when_multiplying));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_multiplying));
		s.push_back(CUTE(divides));
		s.push_back(CUTE(throws_when_dividing_by_zero));
		s.push_back(CUTE(adds));
		s.push_back(CUTE(recognizes_overflows_when_adding));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_adding));
		s.push_back(CUTE(subtracts));
		s.push_back(CUTE(recognizes_overflows_when_subtracting));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_subtracting));
		s.push_back(CUTE(throws_when_given_invalid_operator));
		s.push_back(CUTE(knows_modulo));
		s.push_back(CUTE(throws_when_modulo_zero));
		s.push_back(CUTE(takes_term_from_istream));
		s.push_back(CUTE(throws_when_given_invalid_term));
	}
}

namespace sevensegment_tests {
	const std::string large_8 {
		" - \n"
		"| |\n"
		" - \n"
		"| |\n"
		" - \n"
	};
	const std::string large_1 {
		"   \n"
		"  |\n"
		"   \n"
		"  |\n"
		"   \n"
	};
	const std::string large_3_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
	};

	void prints_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(8, output, 1);
		ASSERT_EQUAL(large_8, output.str());
		output.str("");
		sevensegment::printLargeDigit(1, output, 1);
		ASSERT_EQUAL(large_1, output.str());
	}
	void prints_scaled_digit() {
		std::ostringstream output {};
		sevensegment::printLargeDigit(3, output, 2);
		ASSERT_EQUAL(large_3_scale2, output.str());
	}
	void throws_when_digit_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(10,output, 1),
				std::out_of_range);
	}
	void throws_when_scale_out_of_range() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeDigit(5,output, 0),
				std::range_error);
	}

	const std::string large_number {
		" -     -  -    \n"
		"|  | |  |  |  |\n"
		" -  -  -  -    \n"
		"  |  |  ||    |\n"
		" -     -  -    \n"
	};

	const std::string large_negative_number {
	"    -  - \n"
	"     |  |\n"
	" -  -  - \n"
	"     |  |\n"
	"    -  - \n"
	};

	void prints_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(54321, output, 1);
		ASSERT_EQUAL(large_number, output.str());
	}

	void prints_negative_number() {
		std::ostringstream output {};
		sevensegment::printLargeNumber(-33, output, 1);
		ASSERT_EQUAL(large_negative_number, output.str());
	}

	const std::string large_error {
		" -             \n"
		"|              \n"
		" -  -  -  -  - \n"
		"|  |  |  | ||  \n"
		" -        -    \n"
	};

	void prints_error() {
		std::ostringstream output {};
		sevensegment::printLargeError(output, 1);
		ASSERT_EQUAL(large_error, output.str());
	}

	void throws_when_too_many_digits_for_display() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeNumber(100000000, output, 1),
				std::overflow_error);
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(prints_digit));
		s.push_back(CUTE(prints_scaled_digit));
		s.push_back(CUTE(throws_when_digit_out_of_range));
		s.push_back(CUTE(throws_when_scale_out_of_range));
		s.push_back(CUTE(prints_number));
		s.push_back(CUTE(prints_negative_number));
		s.push_back(CUTE(prints_error));
		s.push_back(CUTE(throws_when_too_many_digits_for_display));
	}
}

namespace pocketcalculator_tests {
	const std::string large_22 {
		" -  - \n"
		"  |  |\n"
		" -  - \n"
		"|  |  \n"
		" -  - \n"
	};

	void gets_term_and_prints_result() {
		std::ostringstream output {};
		std::istringstream input { "2+20" };
		pocketcalculator::start(input, output, 1);
		ASSERT_EQUAL(large_22, output.str());
	}

	void prints_error_on_invalid_input() {
		for(auto const term : calc_tests::invalid_terms) {

			std::ostringstream output {};
			std::istringstream input { term };
			pocketcalculator::start(input, output, 1);
			ASSERT_EQUAL(sevensegment_tests::large_error, output.str());
		}
	}

	const std::string large_2_scale4 {
		" ---- \n"
		"     |\n"
		"     |\n"
		"     |\n"
		"     |\n"
		" ---- \n"
		"|     \n"
		"|     \n"
		"|     \n"
		"|     \n"
		" ---- \n"
	};

	void scales() {
		std::ostringstream output { };
		std::istringstream input { "1+1" };
		pocketcalculator::start(input, output, 4);
		ASSERT_EQUAL(large_2_scale4, output.str());
	}

	const std::string large_2 {
		" - \n"
		"  |\n"
		" - \n"
		"|  \n"
		" - \n"
	};

	void uses_default_scale_when_scale_omitted() {
		std::ostringstream output {};
		std::istringstream input {"1+1"};
		pocketcalculator::start(input, output);
		ASSERT_EQUAL(large_2, output.str());
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(gets_term_and_prints_result));
		s.push_back(CUTE(prints_error_on_invalid_input));
		s.push_back(CUTE(scales));
		s.push_back(CUTE(uses_default_scale_when_scale_omitted));
	}

	// TODO: add env scale test
	// TODO: test with and without env var set
}

void runAllTests(int argc, char const *argv[]){
	cute::suite s {};
	calc_tests::add_tests_to_suite(s);
	sevensegment_tests::add_tests_to_suite(s);
	pocketcalculator_tests::add_tests_to_suite(s);

	cute::xml_file_opener xmlfile(argc,argv);
	cute::xml_listener<cute::ide_listener<> >  lis(xmlfile.out);
	cute::makeRunner(lis,argc,argv)(s, "AllTests");
}

int main(int argc, char const *argv[]){
    runAllTests(argc,argv);
    return 0;
}

<commit_msg>style<commit_after>#include "calc.h"
#include "sevensegment.h"
#include "pocketcalculator.h"

#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

#include <string>
#include <sstream>
#include <limits>
#include <algorithm>

namespace calc_tests {
	constexpr int max { std::numeric_limits<int>::max() },
				  min { std::numeric_limits<int>::min() };
	void multiplies_positive_numbers() {
		ASSERT_EQUAL(20, calc(4, 5, '*'));
	}
	void multiplies_negative_with_positive_number() {
		ASSERT_EQUAL(-30, calc(-6, 5, '*'));
	}
	void multiplies_negative_numbers() {
		ASSERT_EQUAL(20, calc(-4, -5, '*'));
	}
	void recognizes_overflows_when_multiplying() {
		ASSERT_THROWS(calc(4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(4, min/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, max/3, '*'), std::overflow_error);
		ASSERT_THROWS(calc(-4, min/3, '*'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_multiplying() {
		calc(1, max, '*');
		calc(1, min, '*');
		calc(-1, max, '*');
		calc(-1, min+1, '*');
		calc(2, max/2, '*');
		calc(2, min/2, '*');
		calc(-2, max/2, '*');
		calc(-2, min/2+1, '*');
	}
	void divides() {
		ASSERT_EQUAL(5, calc(60, 12, '/'));
		ASSERT_EQUAL(-3, calc(9, -3, '/'));
	}
	void throws_when_dividing_by_zero() {
		ASSERT_THROWS(calc(1, 0, '/'), std::domain_error);
	}
	void adds() {
		ASSERT_EQUAL(5, calc(2, 3, '+'));
		ASSERT_EQUAL(-10, calc(-6, -4, '+'));
	}
	void recognizes_overflows_when_adding() {
		ASSERT_THROWS(calc(max, 1, '+'), std::overflow_error);
		ASSERT_THROWS(calc(min, -1, '+'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_adding() {
		calc(max, 0, '+');
		calc(min, 0, '+');
	}
	void subtracts() {
		ASSERT_EQUAL(17, calc(20, 3, '-'));
		ASSERT_EQUAL(-5, calc(-2, 3, '-'));
	}
	void recognizes_overflows_when_subtracting() {
		ASSERT_THROWS(calc(max, -1, '-'), std::overflow_error);
		ASSERT_THROWS(calc(min, 1, '-'), std::overflow_error);
	}
	void doesnt_overflow_near_limits_when_subtracting() {
		calc(max, 0, '-');
		calc(min, 0, '-');
	}
	void knows_modulo() {
		ASSERT_EQUAL(5, calc(15, 10, '%'));
		ASSERT_EQUAL(-5, calc(-15, 10, '%'));
	}
	void throws_when_modulo_zero() {
		ASSERT_THROWS(calc(10, 0, '%'), std::domain_error);
	}
	void throws_when_given_invalid_operator() {
		ASSERT_THROWS(calc(1, 1, '^'), std::runtime_error);
	}

	void takes_term_from_istream() {
		std::istringstream term_stream { "1+1" };
		int result = calc(term_stream);
		ASSERT_EQUAL(2, result);
	}

	const std::vector<std::string> invalid_terms {
        "foobar",
        "3+2-",
        "1",
        "8--",
        "*",
        "4%%6",
        "3//7",
	};

    void throws_when_given_invalid_term() {
		for(auto const term : invalid_terms) {
			std::istringstream term_stream { term };
			ASSERT_THROWS(calc(term_stream), std::exception);
		}
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(multiplies_positive_numbers));
		s.push_back(CUTE(multiplies_negative_with_positive_number));
		s.push_back(CUTE(multiplies_negative_numbers));
		s.push_back(CUTE(recognizes_overflows_when_multiplying));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_multiplying));
		s.push_back(CUTE(divides));
		s.push_back(CUTE(throws_when_dividing_by_zero));
		s.push_back(CUTE(adds));
		s.push_back(CUTE(recognizes_overflows_when_adding));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_adding));
		s.push_back(CUTE(subtracts));
		s.push_back(CUTE(recognizes_overflows_when_subtracting));
		s.push_back(CUTE(doesnt_overflow_near_limits_when_subtracting));
		s.push_back(CUTE(throws_when_given_invalid_operator));
		s.push_back(CUTE(knows_modulo));
		s.push_back(CUTE(throws_when_modulo_zero));
		s.push_back(CUTE(takes_term_from_istream));
		s.push_back(CUTE(throws_when_given_invalid_term));
	}
}

namespace sevensegment_tests {
	const std::string large_8 {
		" - \n"
		"| |\n"
		" - \n"
		"| |\n"
		" - \n"
	};
	const std::string large_1 {
		"   \n"
		"  |\n"
		"   \n"
		"  |\n"
		"   \n"
	};
	const std::string large_3_scale2 {
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
		"   |\n"
		"   |\n"
		" -- \n"
	};

	void prints_digit() {
		std::ostringstream output { };
		sevensegment::printLargeDigit(8, output, 1);
		ASSERT_EQUAL(large_8, output.str());
		output.str("");
		sevensegment::printLargeDigit(1, output, 1);
		ASSERT_EQUAL(large_1, output.str());
	}
	void prints_scaled_digit() {
		std::ostringstream output { };
		sevensegment::printLargeDigit(3, output, 2);
		ASSERT_EQUAL(large_3_scale2, output.str());
	}
	void throws_when_digit_out_of_range() {
		std::ostringstream output { };
		ASSERT_THROWS(sevensegment::printLargeDigit(10,output, 1),
				std::out_of_range);
	}
	void throws_when_scale_out_of_range() {
		std::ostringstream output { };
		ASSERT_THROWS(sevensegment::printLargeDigit(5,output, 0),
				std::range_error);
	}

	const std::string large_number {
		" -     -  -    \n"
		"|  | |  |  |  |\n"
		" -  -  -  -    \n"
		"  |  |  ||    |\n"
		" -     -  -    \n"
	};

	const std::string large_negative_number {
	"    -  - \n"
	"     |  |\n"
	" -  -  - \n"
	"     |  |\n"
	"    -  - \n"
	};

	void prints_number() {
		std::ostringstream output { };
		sevensegment::printLargeNumber(54321, output, 1);
		ASSERT_EQUAL(large_number, output.str());
	}

	void prints_negative_number() {
		std::ostringstream output { };
		sevensegment::printLargeNumber(-33, output, 1);
		ASSERT_EQUAL(large_negative_number, output.str());
	}

	const std::string large_error {
		" -             \n"
		"|              \n"
		" -  -  -  -  - \n"
		"|  |  |  | ||  \n"
		" -        -    \n"
	};

	void prints_error() {
		std::ostringstream output {};
		sevensegment::printLargeError(output, 1);
		ASSERT_EQUAL(large_error, output.str());
	}

	void throws_when_too_many_digits_for_display() {
		std::ostringstream output {};
		ASSERT_THROWS(sevensegment::printLargeNumber(100000000, output, 1),
				std::overflow_error);
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(prints_digit));
		s.push_back(CUTE(prints_scaled_digit));
		s.push_back(CUTE(throws_when_digit_out_of_range));
		s.push_back(CUTE(throws_when_scale_out_of_range));
		s.push_back(CUTE(prints_number));
		s.push_back(CUTE(prints_negative_number));
		s.push_back(CUTE(prints_error));
		s.push_back(CUTE(throws_when_too_many_digits_for_display));
	}
}

namespace pocketcalculator_tests {
	const std::string large_22 {
		" -  - \n"
		"  |  |\n"
		" -  - \n"
		"|  |  \n"
		" -  - \n"
	};

	void gets_term_and_prints_result() {
		std::ostringstream output { };
		std::istringstream input { "2+20" };
		pocketcalculator::start(input, output, 1);
		ASSERT_EQUAL(large_22, output.str());
	}

	void prints_error_on_invalid_input() {
		for(auto const term : calc_tests::invalid_terms) {

			std::ostringstream output { };
			std::istringstream input { term };
			pocketcalculator::start(input, output, 1);
			ASSERT_EQUAL(sevensegment_tests::large_error, output.str());
		}
	}

	const std::string large_2_scale4 {
		" ---- \n"
		"     |\n"
		"     |\n"
		"     |\n"
		"     |\n"
		" ---- \n"
		"|     \n"
		"|     \n"
		"|     \n"
		"|     \n"
		" ---- \n"
	};

	void scales() {
		std::ostringstream output { };
		std::istringstream input { "1+1" };
		pocketcalculator::start(input, output, 4);
		ASSERT_EQUAL(large_2_scale4, output.str());
	}

	const std::string large_2 {
		" - \n"
		"  |\n"
		" - \n"
		"|  \n"
		" - \n"
	};

	void uses_default_scale_when_scale_omitted() {
		std::ostringstream output { };
		std::istringstream input { "1+1" };
		pocketcalculator::start(input, output);
		ASSERT_EQUAL(large_2, output.str());
	}

	void add_tests_to_suite(cute::suite& s) {
		s.push_back(CUTE(gets_term_and_prints_result));
		s.push_back(CUTE(prints_error_on_invalid_input));
		s.push_back(CUTE(scales));
		s.push_back(CUTE(uses_default_scale_when_scale_omitted));
	}

	// TODO: add env scale test
	// TODO: test with and without env var set
}

void runAllTests(int argc, char const *argv[]){
	cute::suite s {};
	calc_tests::add_tests_to_suite(s);
	sevensegment_tests::add_tests_to_suite(s);
	pocketcalculator_tests::add_tests_to_suite(s);

	cute::xml_file_opener xmlfile(argc,argv);
	cute::xml_listener<cute::ide_listener<> >  lis(xmlfile.out);
	cute::makeRunner(lis,argc,argv)(s, "AllTests");
}

int main(int argc, char const *argv[]){
    runAllTests(argc,argv);
    return 0;
}

<|endoftext|>


<commit_before>/**
 * @file   ReuseQueueTest.cpp
 * @brief  ReuseQueue class tester.
 * @author zer0
 * @date   2016-08-03
 */

#include <gtest/gtest.h>
#include <libtbag/container/ReuseQueue.hpp>

using namespace libtbag;
using namespace libtbag::container;

TEST(ReuseQueueTest, Constructor)
{
    ReuseQueue<int> q1;
    ReuseQueue<int> q2;

    q1.push(1);
    ASSERT_EQ(1U, q1.size());

    q2 = q1;
    ASSERT_EQ(1U, q1.size());
    ASSERT_EQ(1U, q2.size());
}

TEST(ReuseQueueTest, MoveConstructor)
{
    ReuseQueue<int> q1;
    ReuseQueue<int> q2;

    ASSERT_EQ(0U, q1.size());
    ASSERT_EQ(0U, q2.size());

    q1.push(1);
    q2 = std::move(q1);
    ASSERT_EQ(1U, q2.size());
}

TEST(ReuseQueueTest, Default)
{
    ReuseQueue<int> queue;

    ASSERT_EQ(0U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    ASSERT_TRUE(queue.empty());
    ASSERT_TRUE(queue.emptyOfReady());

    queue.push(100);
    queue.push(200);
    ASSERT_EQ(2U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    int result;
    ASSERT_EQ(100, queue.front());

    queue.pop();
    ASSERT_EQ(200, queue.front());
    ASSERT_EQ(1U,  queue.size());
    ASSERT_EQ(1U,  queue.sizeOfReady());

    queue.push(300);
    ASSERT_EQ(2U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    queue.push(400);
    ASSERT_EQ(3U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    queue.clear();
    ASSERT_TRUE(queue.empty());
    ASSERT_TRUE(queue.emptyOfReady());
}

TEST(ReuseQueueTest, PushLambda)
{
    int const TEST_VALUE1 = 100;
    int const TEST_VALUE2 = 200;
    ReuseQueue<int> q1;

    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(0, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_TRUE(q1.emptyOfTotal());

    q1.push([&](int & v){ v = TEST_VALUE1; });
    ASSERT_EQ(TEST_VALUE1, q1.front());
    ASSERT_EQ(TEST_VALUE1, q1.back());

    q1.push([&](int & v){ v = TEST_VALUE2; });
    ASSERT_EQ(TEST_VALUE1, q1.front());
    ASSERT_EQ(TEST_VALUE2, q1.back());

    ASSERT_EQ(2, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_FALSE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    q1.pop();
    ASSERT_EQ(TEST_VALUE2, q1.front());
    ASSERT_EQ(TEST_VALUE2, q1.back());

    ASSERT_EQ(1, q1.size());
    ASSERT_EQ(1, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_FALSE(q1.empty());
    ASSERT_FALSE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    int result;
    ASSERT_TRUE(q1.frontAndPop(&result));
    ASSERT_EQ(TEST_VALUE2, result);

    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(2, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_FALSE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    q1.clear();
    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(0, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_TRUE(q1.emptyOfTotal());

    q1.push([&](int & v){ v = TEST_VALUE1; });
    q1.push([&](int & v){ v = TEST_VALUE2; });
    ASSERT_EQ(2, q1.size());

    q1.popAll();
    ASSERT_EQ(0, q1.size());
}

<commit_msg>Fixed bug in ReuseQueueTest.Default tester.<commit_after>/**
 * @file   ReuseQueueTest.cpp
 * @brief  ReuseQueue class tester.
 * @author zer0
 * @date   2016-08-03
 */

#include <gtest/gtest.h>
#include <libtbag/container/ReuseQueue.hpp>

using namespace libtbag;
using namespace libtbag::container;

TEST(ReuseQueueTest, Constructor)
{
    ReuseQueue<int> q1;
    ReuseQueue<int> q2;

    q1.push(1);
    ASSERT_EQ(1U, q1.size());

    q2 = q1;
    ASSERT_EQ(1U, q1.size());
    ASSERT_EQ(1U, q2.size());
}

TEST(ReuseQueueTest, MoveConstructor)
{
    ReuseQueue<int> q1;
    ReuseQueue<int> q2;

    ASSERT_EQ(0U, q1.size());
    ASSERT_EQ(0U, q2.size());

    q1.push(1);
    q2 = std::move(q1);
    ASSERT_EQ(1U, q2.size());
}

TEST(ReuseQueueTest, Default)
{
    ReuseQueue<int> queue;

    ASSERT_EQ(0U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    ASSERT_TRUE(queue.empty());
    ASSERT_TRUE(queue.emptyOfReady());

    queue.push(100);
    queue.push(200);
    ASSERT_EQ(2U, queue.size());
    ASSERT_EQ(0U, queue.sizeOfReady());

    int result;
    ASSERT_EQ(100, queue.front());

    queue.pop();
    ASSERT_EQ(200, queue.front());
    ASSERT_EQ(1U,  queue.size());
    ASSERT_EQ(1U,  queue.sizeOfReady());

    queue.push(300);
    ASSERT_EQ(2U, queue.size());
    ASSERT_EQ(1U, queue.sizeOfReady());

    queue.push(400);
    ASSERT_EQ(3U, queue.size());
    ASSERT_EQ(1U, queue.sizeOfReady());

    queue.clear();
    ASSERT_TRUE(queue.empty());
    ASSERT_TRUE(queue.emptyOfReady());
}

TEST(ReuseQueueTest, PushLambda)
{
    int const TEST_VALUE1 = 100;
    int const TEST_VALUE2 = 200;
    ReuseQueue<int> q1;

    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(0, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_TRUE(q1.emptyOfTotal());

    q1.push([&](int & v){ v = TEST_VALUE1; });
    ASSERT_EQ(TEST_VALUE1, q1.front());
    ASSERT_EQ(TEST_VALUE1, q1.back());

    q1.push([&](int & v){ v = TEST_VALUE2; });
    ASSERT_EQ(TEST_VALUE1, q1.front());
    ASSERT_EQ(TEST_VALUE2, q1.back());

    ASSERT_EQ(2, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_FALSE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    q1.pop();
    ASSERT_EQ(TEST_VALUE2, q1.front());
    ASSERT_EQ(TEST_VALUE2, q1.back());

    ASSERT_EQ(1, q1.size());
    ASSERT_EQ(1, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_FALSE(q1.empty());
    ASSERT_FALSE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    int result;
    ASSERT_TRUE(q1.frontAndPop(&result));
    ASSERT_EQ(TEST_VALUE2, result);

    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(2, q1.sizeOfReady());
    ASSERT_EQ(2, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_FALSE(q1.emptyOfReady());
    ASSERT_FALSE(q1.emptyOfTotal());

    q1.clear();
    ASSERT_EQ(0, q1.size());
    ASSERT_EQ(0, q1.sizeOfReady());
    ASSERT_EQ(0, q1.sizeOfTotal());
    ASSERT_TRUE(q1.empty());
    ASSERT_TRUE(q1.emptyOfReady());
    ASSERT_TRUE(q1.emptyOfTotal());

    q1.push([&](int & v){ v = TEST_VALUE1; });
    q1.push([&](int & v){ v = TEST_VALUE2; });
    ASSERT_EQ(2, q1.size());

    q1.popAll();
    ASSERT_EQ(0, q1.size());
}

<|endoftext|>


<commit_before>// ---------------------------------------------------------------------
// $Id$
//
// Copyright (C) 2008 - 2013 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

// Test interaction with p4est with 2d mesh with some 20 cells

#include "../tests.h"
#include "coarse_grid_common.h"
#include <deal.II/base/logstream.h>
#include <deal.II/base/tensor.h>
#include <deal.II/grid/tria.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/grid_in.h>

template<int dim>
void test(std::ostream & /*out*/)
{
  parallel::distributed::Triangulation<dim> tr(MPI_COMM_WORLD);

  GridIn<dim> gi;
  gi.attach_triangulation (tr);
  gi.read (SOURCE_DIR "../grid/grids/circle-grid.inp");

  write_vtk(tr, "1");
}

int main(int argc, char *argv[])
{
  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

  std::ofstream logfile("output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  deallog.push("2d");
  test<2>(logfile);
  deallog.pop();

}
<commit_msg>fix tests<commit_after>// ---------------------------------------------------------------------
// $Id$
//
// Copyright (C) 2008 - 2013 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

// Test interaction with p4est with 2d mesh with some 20 cells

#include "../tests.h"
#include "coarse_grid_common.h"
#include <deal.II/base/logstream.h>
#include <deal.II/base/tensor.h>
#include <deal.II/grid/tria.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/grid_in.h>

template<int dim>
void test(std::ostream & /*out*/)
{
  parallel::distributed::Triangulation<dim> tr(MPI_COMM_WORLD);

  GridIn<dim> gi;
  gi.attach_triangulation (tr);
  gi.read (SOURCE_DIR "/../grid/grids/circle-grid.inp");

  write_vtk(tr, "1");
}

int main(int argc, char *argv[])
{
  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

  std::ofstream logfile("output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  deallog.push("2d");
  test<2>(logfile);
  deallog.pop();

}
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//

//

#ifndef _HANDLETABLE_INL
#define _HANDLETABLE_INL

inline void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        SO_TOLERANT;
        MODE_COOPERATIVE;
    }
    CONTRACTL_END;

    // sanity
    _ASSERTE(handle);

#ifdef _DEBUG_IMPL
    // handle should not be in unloaded domain
    ValidateAppDomainForHandle(handle);

    // Make sure the objref is valid before it is assigned to a handle
    ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
#endif
    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);

    HndLogSetEvent(handle, value);

    // if we are doing a non-NULL pointer store then invoke the write-barrier
    if (value)
        HndWriteBarrier(handle, objref);

    // store the pointer
    *(_UNCHECKED_OBJECTREF *)handle = value;
}

inline void* HndInterlockedCompareExchangeHandle(OBJECTHANDLE handle, OBJECTREF objref, OBJECTREF oldObjref)
{
    WRAPPER_NO_CONTRACT;

    // sanity
    _ASSERTE(handle);

#ifdef _DEBUG_IMPL
    // handle should not be in unloaded domain
    ValidateAppDomainForHandle(handle);

    // Make sure the objref is valid before it is assigned to a handle
    ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
#endif
    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
    _UNCHECKED_OBJECTREF oldValue = OBJECTREF_TO_UNCHECKED_OBJECTREF(oldObjref);

    // if we are doing a non-NULL pointer store then invoke the write-barrier
    if (value)
        HndWriteBarrier(handle, objref);

    // store the pointer

    void* ret = Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), value, oldValue);

    if (ret == oldValue)
        HndLogSetEvent(handle, value);

    return ret;
}

inline BOOL HndFirstAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        SO_TOLERANT;
        MODE_COOPERATIVE;
    }
    CONTRACTL_END;

    // sanity
    _ASSERTE(handle);

#ifdef _DEBUG_IMPL
    // handle should not be in unloaded domain
    ValidateAppDomainForHandle(handle);

    // Make sure the objref is valid before it is assigned to a handle
    ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
#endif
    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
    _UNCHECKED_OBJECTREF null = NULL;

    // store the pointer if we are the first ones here
    BOOL success = (NULL == Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle),
                                                                value,
                                                                null));

    // if we successfully did a non-NULL pointer store then invoke the write-barrier
    if (success)
    {
        if (value)
            HndWriteBarrier(handle, objref);

        HndLogSetEvent(handle, value);
    }

    // return our result
    return success;
}

#endif // _HANDLETABLE_INL
<commit_msg>Remove handle assignment validation from GC side.<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//

//

#ifndef _HANDLETABLE_INL
#define _HANDLETABLE_INL

inline void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        SO_TOLERANT;
        MODE_COOPERATIVE;
    }
    CONTRACTL_END;

    // sanity
    _ASSERTE(handle);

    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);

    HndLogSetEvent(handle, value);

    // if we are doing a non-NULL pointer store then invoke the write-barrier
    if (value)
        HndWriteBarrier(handle, objref);

    // store the pointer
    *(_UNCHECKED_OBJECTREF *)handle = value;
}

inline void* HndInterlockedCompareExchangeHandle(OBJECTHANDLE handle, OBJECTREF objref, OBJECTREF oldObjref)
{
    WRAPPER_NO_CONTRACT;

    // sanity
    _ASSERTE(handle);

    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
    _UNCHECKED_OBJECTREF oldValue = OBJECTREF_TO_UNCHECKED_OBJECTREF(oldObjref);

    // if we are doing a non-NULL pointer store then invoke the write-barrier
    if (value)
        HndWriteBarrier(handle, objref);

    // store the pointer

    void* ret = Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), value, oldValue);

    if (ret == oldValue)
        HndLogSetEvent(handle, value);

    return ret;
}

inline BOOL HndFirstAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        SO_TOLERANT;
        MODE_COOPERATIVE;
    }
    CONTRACTL_END;

    // sanity
    _ASSERTE(handle);

    // unwrap the objectref we were given
    _UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
    _UNCHECKED_OBJECTREF null = NULL;

    // store the pointer if we are the first ones here
    BOOL success = (NULL == Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle),
                                                                value,
                                                                null));

    // if we successfully did a non-NULL pointer store then invoke the write-barrier
    if (success)
    {
        if (value)
            HndWriteBarrier(handle, objref);

        HndLogSetEvent(handle, value);
    }

    // return our result
    return success;
}

#endif // _HANDLETABLE_INL
<|endoftext|>


<commit_before>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * OTRadValve TempControl tests.
 */

#include <gtest/gtest.h>
#include <stdio.h>

#include "OTSIM900Link.h"

// Test for general sanity of OTSIM900Link.
// Make sure that an instance can be created and does not die horribly.
// Underlying simulated serial/SIM900 never accepts data or responds, eg like a dead card.
TEST(OTSIM900Link,basicsDeadCard)
{
    const bool verbose = false;

    class NULLSerialStream final : public Stream
      {
      public:
        void begin(unsigned long) { }
        void begin(unsigned long, uint8_t);
        void end();

        virtual size_t write(uint8_t c) override { if(verbose) { fprintf(stderr, "%c\n", (char) c); } return(0); }
        virtual int available() override { return(-1); }
        virtual int read() override { return(-1); }
        virtual int peek() override { return(-1); }
        virtual void flush() override { }
      };
    OTSIM900Link::OTSIM900Link<0, 0, 0, NULLSerialStream> l0;
    EXPECT_TRUE(l0.begin());
    EXPECT_EQ(OTSIM900Link::GET_STATE, l0._getState());
    // Try to hang just by calling poll() repeatedly.
    for(int i = 0; i < 100; ++i) { l0.poll(); }
    EXPECT_GE(OTSIM900Link::START_UP, l0._getState()) << "should keep trying to start with GET_STATE, RETRY_GET_STATE and START_UP";
    // ...
    l0.end();
}

// Test for general sanity of OTSIM900Link.
// Make sure that an instance can be created and does not die horribly.
// Underlying simulated serial/SIM900 accepts output, does not respond.
namespace B1
{
const bool verbose = true;

// Does a trivial simulation of SIM900, responding to start of 'A' of AT command.
class TrivialSimulator final : public Stream
  {
  public:
    // Events exposed.
    static bool haveSeenCommandStart;

  private:
    // Command being collected from OTSIM900Link.
    bool waitingForCommand = true;
    bool collectingCommand = false;
    // Entire request starting "AT"; no trailing CR or LF stored.
    std::string command;

    // Reply (postfix) being returned to OTSIM900Link: empty if none.
    std::string reply;

  public:
    void begin(unsigned long) { }
    void begin(unsigned long, uint8_t);
    void end();

    virtual size_t write(uint8_t uc) override
      {
      const char c = (char)uc;
      if(waitingForCommand)
        {
        // Look for leading 'A' of 'AT' to start a command.
        if('A' == c)
          {
          waitingForCommand = false;
          collectingCommand = true;
          command = 'A';
          haveSeenCommandStart = true; // Note at least one command start.
          }
        }
      else
        {
        // Look for CR (or LF) to terminate a command.
        if(('\r' == c) || ('\n' == c))
          {
          waitingForCommand = true;
          collectingCommand = false;
          if(verbose) { fprintf(stderr, "command received: %s\n", command.c_str()); }
          // Respond to particular commands...
          if("AT" == command) { reply = "AT\r"; }
          // DHD20161101: "No PIN" response (deliberately not typical SIM900 response) resulted in SIGSEGV from not checking getResponse() result for NULL.
          else if("AT+CPIN?" == command) { reply = "No PIN"; }
          }
        else if(collectingCommand) { command += c; }
        }
      if(verbose) { if(isprint(c)) { fprintf(stderr, "<%c\n", c); } else { fprintf(stderr, "< %d\n", (int)c); } }
      return(1);
      }
    virtual int read() override
        {
        if(0 == reply.size()) { return(-1); }
        const char c = reply[0];
        if(verbose) { if(isprint(c)) { fprintf(stderr, ">%c\n", c); } else { fprintf(stderr, "> %d\n", (int)c); } }
        reply.erase(0, 1);
        return(c);
        }
    virtual int available() override { return(-1); }
    virtual int peek() override { return(-1); }
    virtual void flush() override { }
  };
// Events exposed.
bool TrivialSimulator::haveSeenCommandStart;
}
TEST(OTSIM900Link,basics)
{
//    const bool verbose = true;

    ASSERT_FALSE(B1::TrivialSimulator::haveSeenCommandStart);
    OTSIM900Link::OTSIM900Link<0, 0, 0, B1::TrivialSimulator> l0;
    EXPECT_TRUE(l0.begin());
    EXPECT_EQ(OTSIM900Link::GET_STATE, l0._getState());
    // Try to hang just by calling poll() repeatedly.
    for(int i = 0; i < 100; ++i) { l0.poll(); }
    EXPECT_TRUE(B1::TrivialSimulator::haveSeenCommandStart) << "should see some attempt to communicate with SIM900";
    EXPECT_LE(OTSIM900Link::WAIT_FOR_REGISTRATION, l0._getState()) << "should make it to at least WAIT_FOR_REGISTRATION";
    // ...
    l0.end();
}

<commit_msg>TODO-1034: varying responses in simulator<commit_after>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * OTRadValve TempControl tests.
 */

#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>

#include "OTSIM900Link.h"

// Test for general sanity of OTSIM900Link.
// Make sure that an instance can be created and does not die horribly.
// Underlying simulated serial/SIM900 never accepts data or responds, eg like a dead card.
TEST(OTSIM900Link,basicsDeadCard)
{
    const bool verbose = false;

    class NULLSerialStream final : public Stream
      {
      public:
        void begin(unsigned long) { }
        void begin(unsigned long, uint8_t);
        void end();

        virtual size_t write(uint8_t c) override { if(verbose) { fprintf(stderr, "%c\n", (char) c); } return(0); }
        virtual int available() override { return(-1); }
        virtual int read() override { return(-1); }
        virtual int peek() override { return(-1); }
        virtual void flush() override { }
      };
    OTSIM900Link::OTSIM900Link<0, 0, 0, NULLSerialStream> l0;
    EXPECT_TRUE(l0.begin());
    EXPECT_EQ(OTSIM900Link::GET_STATE, l0._getState());
    // Try to hang just by calling poll() repeatedly.
    for(int i = 0; i < 100; ++i) { l0.poll(); }
    EXPECT_GE(OTSIM900Link::START_UP, l0._getState()) << "should keep trying to start with GET_STATE, RETRY_GET_STATE and START_UP";
    // ...
    l0.end();
}

// Test for general sanity of OTSIM900Link.
// Make sure that an instance can be created and does not die horribly.
// Underlying simulated serial/SIM900 accepts output, does not respond.
namespace B1
{
const bool verbose = true;

// Does a trivial simulation of SIM900, responding to start of 'A' of AT command.
class TrivialSimulator final : public Stream
  {
  public:
    // Events exposed.
    static bool haveSeenCommandStart;

  private:
    // Command being collected from OTSIM900Link.
    bool waitingForCommand = true;
    bool collectingCommand = false;
    // Entire request starting "AT"; no trailing CR or LF stored.
    std::string command;

    // Reply (postfix) being returned to OTSIM900Link: empty if none.
    std::string reply;

  public:
    void begin(unsigned long) { }
    void begin(unsigned long, uint8_t);
    void end();

    virtual size_t write(uint8_t uc) override
      {
      const char c = (char)uc;
      if(waitingForCommand)
        {
        // Look for leading 'A' of 'AT' to start a command.
        if('A' == c)
          {
          waitingForCommand = false;
          collectingCommand = true;
          command = 'A';
          haveSeenCommandStart = true; // Note at least one command start.
          }
        }
      else
        {
        // Look for CR (or LF) to terminate a command.
        if(('\r' == c) || ('\n' == c))
          {
          waitingForCommand = true;
          collectingCommand = false;
          if(verbose) { fprintf(stderr, "command received: %s\n", command.c_str()); }
          // Respond to particular commands...
          if("AT" == command) { reply = "AT\r"; }
          // DHD20161101: "No PIN" response (deliberately not typical SIM900 response) resulted in SIGSEGV from not checking getResponse() result for NULL.
          // Should futz/vary the response to check sensitivity.
          // TODO: have at least one response be expected SIM900 answer for no-PIN SIM.
          else if("AT+CPIN?" == command) { reply = (random() & 1) ? "No PIN" : "OK READY"; }
          }
        else if(collectingCommand) { command += c; }
        }
      if(verbose) { if(isprint(c)) { fprintf(stderr, "<%c\n", c); } else { fprintf(stderr, "< %d\n", (int)c); } }
      return(1);
      }
    virtual int read() override
        {
        if(0 == reply.size()) { return(-1); }
        const char c = reply[0];
        if(verbose) { if(isprint(c)) { fprintf(stderr, ">%c\n", c); } else { fprintf(stderr, "> %d\n", (int)c); } }
        reply.erase(0, 1);
        return(c);
        }
    virtual int available() override { return(-1); }
    virtual int peek() override { return(-1); }
    virtual void flush() override { }
  };
// Events exposed.
bool TrivialSimulator::haveSeenCommandStart;
}
TEST(OTSIM900Link,basicsSimpleSimulator)
{
//    const bool verbose = true;

    srandomdev(); // Seed random() for use in simulator.

    ASSERT_FALSE(B1::TrivialSimulator::haveSeenCommandStart);
    OTSIM900Link::OTSIM900Link<0, 0, 0, B1::TrivialSimulator> l0;
    EXPECT_TRUE(l0.begin());
    EXPECT_EQ(OTSIM900Link::GET_STATE, l0._getState());
    // Try to hang just by calling poll() repeatedly.
    for(int i = 0; i < 100; ++i) { l0.poll(); }
    EXPECT_TRUE(B1::TrivialSimulator::haveSeenCommandStart) << "should see some attempt to communicate with SIM900";
    EXPECT_LE(OTSIM900Link::WAIT_FOR_REGISTRATION, l0._getState()) << "should make it to at least WAIT_FOR_REGISTRATION";
    // ...
    l0.end();
}

<|endoftext|>


<commit_before>#include<iostream>
#include<vector>

using namespace std;

int main() {
  vector<int> v(10);     // Create vector of size 10

  v = {34, 23, 30, 19};

  // Display the size of the vector
  cout << "Vector size: " << v.size() << endl;
  cout << "Vector capacity: " << v.capacity() << endl;

  // Print vector with a for loop using array syntax (UNSAFE)
  for (unsigned int ii=0; ii<v.size(); ii++) {
    cout << v[ii] << " ";
  }
  cout << endl << endl;

  cout << "front: " << v.front() << endl;
  cout << " back: " << v.back() << endl;
  cout << endl;

  v.push_back(42);
  v.push_back(37);
  v.push_back(51);
  v.push_back(63);
  v.push_back(17);
  v.push_back(6);
  v.push_back(92);
  v.push_back(77);

  cout << "After push_back:" << endl;
  cout << "Vector size: " << v.size() << endl;
  cout << "Vector capacity: " << v.capacity() << endl;

  // Print vector using at()
  for (unsigned int ii=0; ii<v.size(); ii++) {
    cout << v.at(ii) << " ";
  }
  cout << endl << endl;;

  v[5] = 99;
  v.pop_back();
  cout << "After v[5]=99 & pop_back:" << endl;
  // Print vector using for-each
  for (auto& ii : v) {
    cout << ii << " ";
  }
  cout << endl;

  return 0;
}
<commit_msg>Changed loop variable names<commit_after>#include<iostream>
#include<vector>

using namespace std;

int main() {
  vector<int> v(10);     // Create vector of size 10

  v = {34, 23, 30, 19};

  // Display the size of the vector
  cout << "Vector size: " << v.size() << endl;
  cout << "Vector capacity: " << v.capacity() << endl;

  // Print vector with a for loop using array syntax (UNSAFE)
  for (unsigned int ii=0; ii<v.size(); ii++) {
    cout << v[ii] << " ";
  }
  cout << endl << endl;

  cout << "front: " << v.front() << endl;
  cout << " back: " << v.back() << endl;
  cout << endl;

  v.push_back(42);
  v.push_back(37);
  v.push_back(51);
  v.push_back(63);
  v.push_back(17);
  v.push_back(6);
  v.push_back(92);
  v.push_back(77);

  cout << "After push_back:" << endl;
  cout << "Vector size: " << v.size() << endl;
  cout << "Vector capacity: " << v.capacity() << endl;

  // Print vector using at()
  for (unsigned int jj=0; jj<v.size(); jj++) {
    cout << v.at(jj) << " ";
  }
  cout << endl << endl;;

  v[5] = 99;
  v.pop_back();
  cout << "After v[5]=99 & pop_back:" << endl;
  // Print vector using for-each
  for (auto& kk : v) {
    cout << kk << " ";
  }
  cout << endl;

  return 0;
}
<|endoftext|>


<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN set_intersection tests

#include <boost/test/unit_test.hpp>

#include <algorithm>
#include <cmath>
#include <functional>
#include <iterator>
#include <list>
#include <vector>

BOOST_AUTO_TEST_SUITE( set_intersection_test_suite )

BOOST_AUTO_TEST_CASE( empty_primary_input_default_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( empty_primary_input_custom_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{3, 2, 1};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), std::greater<int>());

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( empty_primary_input_conversion_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), std::less<double>());

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_default_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{1, 3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_custom_compare )
{
    const std::vector<int> primary{1, -3, -4, 5, -6};
    const std::list<int> secondary{1, -2, 3};
    std::vector<int> output;

    auto comp = [](int lhs, int rhs){ return std::less<int>()(std::abs(lhs), std::abs(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, -3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_conversion_compare )
{
    const std::vector<int> primary{1, -3, -4, 5, -6};
    const std::list<int> secondary{1, -2, 3};
    std::vector<int> output;

    auto comp = [](double lhs, double rhs){ return std::less<double>()(std::abs(lhs), std::abs(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, -3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_type_inputs_default_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<double> secondary{1.1, 2, 4.0, 4.6};
    std::vector<int> output;

    /*! For the default compare between an int and a double, the int will be
     * promoted to double first, so for example 1 will be considered different
     * to 1.1, in which case none of them will be reported to the output
     * iterator. */
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_type_inputs_custom_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<double> secondary{1.1, 2, 3.9, 4.6};
    std::vector<int> output;

    auto comp = [](int lhs, double rhs){ return std::less<double>()(static_cast<double>(lhs), std::floor(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, 3, 4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( repeated_elements_default_compare )
{
    const std::vector<int> primary{1, 1, 1, 1, 2, 3, 3, 3, 3, 4, 4, 5, 6};
    const std::list<int> secondary{1, 1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{1, 1, 2, 3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_SUITE_END( /* set_intersection_test_suite */ )
<commit_msg>Adds two interesting cases for set_intersection.<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN set_intersection tests

#include <boost/test/unit_test.hpp>

#include <algorithm>
#include <cmath>
#include <functional>
#include <iterator>
#include <list>
#include <vector>

BOOST_AUTO_TEST_SUITE( set_intersection_test_suite )

BOOST_AUTO_TEST_CASE( empty_primary_input_default_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( empty_primary_input_custom_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{3, 2, 1};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), std::greater<int>());

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( empty_primary_input_conversion_compare )
{
    const std::vector<int> primary;
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), std::less<double>());

    const std::vector<int> expected;
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_default_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<int> secondary{1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{1, 3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_custom_compare )
{
    const std::vector<int> primary{1, -3, -4, 5, -6};
    const std::list<int> secondary{1, -2, 3};
    std::vector<int> output;

    auto comp = [](int lhs, int rhs){ return std::less<int>()(std::abs(lhs), std::abs(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, -3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( same_type_inputs_conversion_compare )
{
    const std::vector<int> primary{1, -3, -4, 5, -6};
    const std::list<int> secondary{1, -2, 3};
    std::vector<int> output;

    auto comp = [](double lhs, double rhs){ return std::less<double>()(std::abs(lhs), std::abs(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, -3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_type_inputs_default_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<double> secondary{1.1, 2, 4.0, 4.6};
    std::vector<int> output;

    /*! For the default compare between an int and a double, the int will be
     * promoted to double first, so for example 1 will be considered different
     * to 1.1, in which case none of them will be reported to the output
     * iterator. */
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_type_inputs_custom_compare )
{
    const std::vector<int> primary{1, 3, 4, 5, 6};
    const std::list<double> secondary{1.1, 2, 3.9, 4.6};
    std::vector<int> output;

    auto comp = [](int lhs, double rhs){ return std::less<double>()(static_cast<double>(lhs), std::floor(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    const std::vector<int> expected{1, 3, 4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( repeated_elements_default_compare )
{
    const std::vector<int> primary{1, 1, 1, 1, 2, 3, 3, 3, 3, 4, 4, 5, 6};
    const std::list<int> secondary{1, 1, 2, 3};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{1, 1, 2, 3};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_output_type_default_compare )
{
    const std::vector<double> primary{1, 3, 4.6, 5, 6};
    const std::list<double> secondary{1.1, 2, 3.9, 4.6};
    std::vector<int> output;

    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output));

    const std::vector<int> expected{4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_CASE( different_output_type_custom_compare )
{
    const std::vector<double> primary{-1.1, 1, -1, 3, 4.6, 5, 6};
    const std::list<double> secondary{1.1, -2, 3.9, -4.6};
    std::vector<int> output;

    auto comp = [](double lhs, double rhs){ return std::less<double>()(std::abs(lhs), std::abs(rhs)); };
    std::set_intersection(std::begin(primary), std::end(primary), std::begin(secondary), std::end(secondary), std::back_inserter(output), comp);

    /*! Here is the interesting thing: -1.1 will be compared equal to 1.1 and
     * reported to an output iterator that accepts ints. As the algorithm
     * reports the element from the first collection, -1.1 will be cast to int,
     * so the number in the output collection will be negative as well. */
    const std::vector<int> expected{-1, 4};
    BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(output), std::end(output), std::begin(expected), std::end(expected));
}

BOOST_AUTO_TEST_SUITE_END( /* set_intersection_test_suite */ )
<|endoftext|>