<commit_before>#include "StdAfx.h"
#include "DngDecoderSlices.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can 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 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

void *DecodeThread(void *_this) {
  DngDecoderThread* me = (DngDecoderThread*)_this;
  DngDecoderSlices* parent = me->parent;
  try {
    parent->decodeSlice(me);
  } catch (...) {
    parent->setError("DNGDEcodeThread: Caught exception.");
  }
  pthread_exit(NULL);
  return NULL;
}

DngDecoderSlices::DngDecoderSlices(FileMap* file, RawImage img) :
    mFile(file), mRaw(img) {
  mFixLjpeg = false;
#ifdef WIN32
  nThreads = pthread_num_processors_np();
#else
  nThreads = 2; // FIXME: Port this to unix
#endif
}

DngDecoderSlices::~DngDecoderSlices(void) {
}

void DngDecoderSlices::addSlice(DngSliceElement slice) {
  slices.push(slice);
}

void DngDecoderSlices::startDecoding() {
  // Create threads

  int slicesPerThread = ((int)slices.size() + nThreads - 1) / nThreads;
//  decodedSlices = 0;
  pthread_attr_t attr;
  /* Initialize and set thread detached attribute */
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_mutex_init(&errMutex, NULL);

  for (guint i = 0; i < nThreads; i++) {
    DngDecoderThread* t = new DngDecoderThread();
    for (int j = 0; j < slicesPerThread ; j++) {
      if (!slices.empty()) {
        t->slices.push(slices.front());
        slices.pop();
      }
    }
    t->parent = this;
    pthread_create(&t->threadid, &attr, DecodeThread, t);
    threads.push_back(t);
  }
  pthread_attr_destroy(&attr);

  void *status;
  for (guint i = 0; i < nThreads; i++) {
    pthread_join(threads[i]->threadid, &status);
    delete(threads[i]);
  }
  pthread_mutex_destroy(&errMutex);

}

void DngDecoderSlices::decodeSlice(DngDecoderThread* t) {
  while (!t->slices.empty()) {
    LJpegPlain l(mFile, mRaw);
    l.mDNGCompatible = mFixLjpeg;
    l.mUseBigtable = false;
    DngSliceElement e = t->slices.front();
    t->slices.pop();
    try {
      l.startDecoder(e.byteOffset, e.byteCount, e.offX, e.offY);
    } catch (RawDecoderException err) {
      setError(err.what());
    } catch (IOException err) {
      setError("DngDecoderSlices::decodeSlice: IO error occurred.");
    }
  }
}

int DngDecoderSlices::size() {
  return (int)slices.size();
}

void DngDecoderSlices::setError( const char* err )
{
  pthread_mutex_lock(&errMutex);
  errors.push_back(_strdup(err));
  pthread_mutex_unlock(&errMutex);
}

} // namespace RawSpeed
<commit_msg>Properly propagate Bigtable usage on DNG Slices.<commit_after>#include "StdAfx.h"
#include "DngDecoderSlices.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can 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 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

void *DecodeThread(void *_this) {
  DngDecoderThread* me = (DngDecoderThread*)_this;
  DngDecoderSlices* parent = me->parent;
  try {
    parent->decodeSlice(me);
  } catch (...) {
    parent->setError("DNGDEcodeThread: Caught exception.");
  }
  pthread_exit(NULL);
  return NULL;
}

DngDecoderSlices::DngDecoderSlices(FileMap* file, RawImage img) :
    mFile(file), mRaw(img) {
  mFixLjpeg = false;
#ifdef WIN32
  nThreads = pthread_num_processors_np();
#else
  nThreads = 2; // FIXME: Port this to unix
#endif
}

DngDecoderSlices::~DngDecoderSlices(void) {
}

void DngDecoderSlices::addSlice(DngSliceElement slice) {
  slices.push(slice);
}

void DngDecoderSlices::startDecoding() {
  // Create threads

  int slicesPerThread = ((int)slices.size() + nThreads - 1) / nThreads;
//  decodedSlices = 0;
  pthread_attr_t attr;
  /* Initialize and set thread detached attribute */
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_mutex_init(&errMutex, NULL);

  for (guint i = 0; i < nThreads; i++) {
    DngDecoderThread* t = new DngDecoderThread();
    for (int j = 0; j < slicesPerThread ; j++) {
      if (!slices.empty()) {
        t->slices.push(slices.front());
        slices.pop();
      }
    }
    t->parent = this;
    pthread_create(&t->threadid, &attr, DecodeThread, t);
    threads.push_back(t);
  }
  pthread_attr_destroy(&attr);

  void *status;
  for (guint i = 0; i < nThreads; i++) {
    pthread_join(threads[i]->threadid, &status);
    delete(threads[i]);
  }
  pthread_mutex_destroy(&errMutex);

}

void DngDecoderSlices::decodeSlice(DngDecoderThread* t) {
  while (!t->slices.empty()) {
    LJpegPlain l(mFile, mRaw);
    l.mDNGCompatible = mFixLjpeg;
    DngSliceElement e = t->slices.front();
    l.mUseBigtable = e.mUseBigtable;
    t->slices.pop();
    try {
      l.startDecoder(e.byteOffset, e.byteCount, e.offX, e.offY);
    } catch (RawDecoderException err) {
      setError(err.what());
    } catch (IOException err) {
      setError("DngDecoderSlices::decodeSlice: IO error occurred.");
    }
  }
}

int DngDecoderSlices::size() {
  return (int)slices.size();
}

void DngDecoderSlices::setError( const char* err )
{
  pthread_mutex_lock(&errMutex);
  errors.push_back(_strdup(err));
  pthread_mutex_unlock(&errMutex);
}

} // namespace RawSpeed
<|endoftext|>


<commit_before>#include "itkCommandLineArgumentParser.h"

#include "itkImage.h"
#include "itkPoint.h"
#include "itkLandmarkBasedTransformInitializer.h"
#include "itkVersorRigid3DTransform.h"

#include "vnl/vnl_math.h"

#include <iostream>
#include <fstream>
#include <iomanip>

//-------------------------------------------------------------------------------------

void PrintHelp( void );

void ComputeClosestVersor(
  std::string fixedLandmarkFileName,
  std::string movingLandmarkFileName,
  std::vector<double> & parameters,
  std::vector<double> & centerOfRotation );

void ReadLandmarks(
  std::string landmarkFileName,
  std::vector< itk::Point<double,3> > & landmarkContainer );

void ConvertVersorToEuler(
  const std::vector<double> & parVersor,
  std::vector<double> & parEuler );

//-------------------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
  /** Check arguments for help. */
  if ( argc < 5 || argc > 5 )
  {
    PrintHelp();
    return 1;
  }

  /** Create a command line argument parser. */
  itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
  parser->SetCommandLineArguments( argc, argv );

  /** Get arguments. */
  std::string fixedLandmarkFileName = "";
  bool retf = parser->GetCommandLineArgument( "-f", fixedLandmarkFileName );

  std::string movingLandmarkFileName = "";
  bool retm = parser->GetCommandLineArgument( "-m", movingLandmarkFileName );

  /** Check if the required arguments are given. */
  if ( !retf )
  {
    std::cerr << "ERROR: You should specify \"-f\"." << std::endl;
    return 1;
  }

  if ( !retm )
  {
    std::cerr << "ERROR: You should specify \"-m\"." << std::endl;
    return 1;
  }

  /** Compute the closest rigid transformation. */
  std::vector<double> parVersor, centerOfRotation;
  try
  {
    ComputeClosestVersor(
      fixedLandmarkFileName, movingLandmarkFileName,
      parVersor, centerOfRotation );
  }
  catch( itk::ExceptionObject &excp )
  {
    std::cerr << "Caught ITK exception: " << excp << std::endl;
    return 1;
  }

  /** Convert from versor to Euler angles. */
  std::vector<double> parEuler;
  ConvertVersorToEuler( parVersor, parEuler );

  /** Print. */
  std::cout << std::fixed;
  std::cout << std::showpoint;
  std::cout << std::setprecision( 6 );
  unsigned int nop = parVersor.size();

  std::cout << "versor: ";
  for ( unsigned int i = 0; i < nop - 1; i++ )
  {
    std::cout << parVersor[ i ] << " ";
  }
  std::cout << parVersor[ nop - 1 ] << std::endl;

  std::cout << "Euler: ";
  for ( unsigned int i = 0; i < nop - 1; i++ )
  {
    std::cout << parEuler[ i ] << " ";
  }
  std::cout << parEuler[ nop - 1 ] << std::endl;

  std::cout << "center of rotation: ";
  for ( unsigned int i = 0; i < 2; i++ )
  {
    std::cout << centerOfRotation[ i ] << " ";
  }
  std::cout << centerOfRotation[ 2 ] << std::endl;

  /** End program. */
  return 0;

} // end main

/**
 * ******************* ComputeClosestVersor *******************
 */

void ComputeClosestVersor(
  std::string fixedLandmarkFileName,
  std::string movingLandmarkFileName,
  std::vector<double> & parameters,
  std::vector<double> & centerOfRotation )
{
  /** Some consts. */
  const unsigned int  Dimension = 3;
  typedef short PixelType;

  /** Typedefs. */
  typedef itk::Image< PixelType, Dimension >          ImageType;
  typedef itk::VersorRigid3DTransform< double >       TransformType;
  typedef TransformType::ParametersType               ParametersType;
  typedef TransformType::CenterType                   CenterType;
  typedef itk::LandmarkBasedTransformInitializer<
    TransformType, ImageType, ImageType >             EstimatorType;
  typedef EstimatorType::LandmarkPointType            LandmarkType;
  typedef EstimatorType::LandmarkPointContainer       LandmarkContainer;

  /** Read the fixed landmark points. */
  LandmarkContainer fixedLandmarkContainer;
  ReadLandmarks( fixedLandmarkFileName, fixedLandmarkContainer );

  /** Read the moving landmark points. */
  LandmarkContainer movingLandmarkContainer;
  ReadLandmarks( movingLandmarkFileName, movingLandmarkContainer );

  /** Check the sizes. */
  if ( fixedLandmarkContainer.size() != movingLandmarkContainer.size() )
  {
    std::cerr << "ERROR: the two sets of landmarks are not of the same size." << std::endl;
    return;
  }

  /** Create transform. */
  TransformType::Pointer transform = TransformType::New();
  transform->SetIdentity();

  /** Create estimator. */
  EstimatorType::Pointer estimator = EstimatorType::New();
  estimator->SetTransform( transform );
  estimator->SetFixedLandmarks(  fixedLandmarkContainer );
  estimator->SetMovingLandmarks( movingLandmarkContainer );

  /** Run. */
  estimator->InitializeTransform();

  /** Get the parameters of the estimated closest rigid transformation. */
  ParametersType params = transform->GetParameters();
  unsigned int nop = transform->GetNumberOfParameters();
  parameters.resize( nop, 0.0 );
  for ( unsigned int i = 0; i < nop; ++i )
  {
    parameters[ i ] = params[ i ];
  }

  /** Get the estimated center of rotation. */
  CenterType center = transform->GetCenter();
  centerOfRotation.resize( Dimension, 0.0 );
  for ( unsigned int i = 0; i < Dimension; ++i )
  {
    centerOfRotation[ i ] = center[ i ];
  }

} // end ComputeClosestVersor()

/**
 * ******************* ReadLandmarks *******************
 */

void ReadLandmarks(
  std::string landmarkFileName,
  std::vector< itk::Point<double,3> > & landmarkContainer )
{
  /** Typedef's. */
  const unsigned int Dimension = 3;
  typedef itk::Image< short, Dimension >              ImageType;
  typedef itk::VersorRigid3DTransform< double >       TransformType;
  typedef TransformType::ParametersType               ParametersType;
  typedef itk::LandmarkBasedTransformInitializer<
    TransformType, ImageType, ImageType >             EstimatorType;
  typedef EstimatorType::LandmarkPointType            LandmarkType;
  typedef EstimatorType::LandmarkPointContainer       LandmarkContainer;

  /** Open file for reading and read landmarks. */
  std::ifstream landmarkFile( landmarkFileName.c_str() );
  if ( landmarkFile.is_open() )
  {
    LandmarkType landmark;
    while ( !landmarkFile.eof() )
    {
      for ( unsigned int i = 0; i < Dimension; i++ )
      {
        landmarkFile >> landmark[ i ];
      }
      landmarkContainer.push_back( landmark );
    }
  }
  landmarkFile.close();
  landmarkContainer.pop_back();

} // end ReadLandMarks()

/**
 * ******************* ConvertVersorToEuler *******************
 */

void ConvertVersorToEuler(
  const std::vector<double> & parVersor,
  std::vector<double> & parEuler )
{
  /** Create an Euler parameter vector. */
  unsigned int nop = parVersor.size();
  if ( nop != 6 ) return;
  parEuler.resize( nop, 0.0 );

  /** Easy notation. */
  double q0 = vcl_sqrt( 1.0 - parVersor[ 0 ] * parVersor[ 0 ]
    - parVersor[ 1 ] * parVersor[ 1 ] - parVersor[ 2 ] * parVersor[ 2 ] );
  double q1 = parVersor[ 0 ];
  double q2 = parVersor[ 1 ];
  double q3 = parVersor[ 2 ];

  /** Computer Euler angles. */
  parEuler[ 0 ] = vcl_atan2( 2.0 * ( q0 * q1 + q2 * q3 ), 1.0 - 2.0 * ( q1 * q1 + q2 * q2 ) );
  parEuler[ 1 ] = vcl_asin( 2.0 * ( q0 * q2 - q3 * q1 ) );
  parEuler[ 2 ] = vcl_atan2( 2.0 * ( q0 * q3 + q1 * q2 ), 1.0 - 2.0 * ( q2 * q2 + q3 * q3 ) );
  parEuler[ 3 ] = parVersor[ 3 ];
  parEuler[ 4 ] = parVersor[ 4 ];
  parEuler[ 5 ] = parVersor[ 5 ];

} // end ConvertVersorToEuler()

/**
 * ******************* PrintHelp *******************
 */

void PrintHelp( void )
{
  std::cout << "Calculates the closest rigid transform (VersorRigid3D) between" << std::endl;
  std::cout << "two sets of landmarks. The two sets should be of equal size." << std::endl;
  std::cout << "Usage:" << std::endl << "pxclosestversor3Dtransform" << std::endl;
  std::cout << "  -f       the file containing the fixed landmarks" << std::endl;
  std::cout << "  -m       the file containing the moving landmarks" << std::endl;

} // end PrintHelp()
<commit_msg>New style arguments for closestversor3Dtransform<commit_after>#include "itkCommandLineArgumentParser.h"

#include "itkImage.h"
#include "itkPoint.h"
#include "itkLandmarkBasedTransformInitializer.h"
#include "itkVersorRigid3DTransform.h"

#include "vnl/vnl_math.h"

#include <iostream>
#include <fstream>
#include <iomanip>

//-------------------------------------------------------------------------------------

std::string PrintHelp( void );

void ComputeClosestVersor(
  std::string fixedLandmarkFileName,
  std::string movingLandmarkFileName,
  std::vector<double> & parameters,
  std::vector<double> & centerOfRotation );

void ReadLandmarks(
  std::string landmarkFileName,
  std::vector< itk::Point<double,3> > & landmarkContainer );

void ConvertVersorToEuler(
  const std::vector<double> & parVersor,
  std::vector<double> & parEuler );

//-------------------------------------------------------------------------------------

int main( int argc, char *argv[] )
{
  /** Create a command line argument parser. */
  itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
  parser->SetCommandLineArguments( argc, argv );
  parser->SetProgramHelpText(PrintHelp());

  parser->MarkArgumentAsRequired( "-f", "The fixed landmark filename." );
  parser->MarkArgumentAsRequired( "-m", "The moving landmark filename." );

  /** Get arguments. */
  std::string fixedLandmarkFileName = "";
  parser->GetCommandLineArgument( "-f", fixedLandmarkFileName );

  std::string movingLandmarkFileName = "";
  parser->GetCommandLineArgument( "-m", movingLandmarkFileName );

  bool validateArguments = parser->CheckForRequiredArguments();

  if(!validateArguments)
  {
    return EXIT_FAILURE;
  }

  /** Compute the closest rigid transformation. */
  std::vector<double> parVersor, centerOfRotation;
  try
  {
    ComputeClosestVersor(
      fixedLandmarkFileName, movingLandmarkFileName,
      parVersor, centerOfRotation );
  }
  catch( itk::ExceptionObject &excp )
  {
    std::cerr << "Caught ITK exception: " << excp << std::endl;
    return 1;
  }

  /** Convert from versor to Euler angles. */
  std::vector<double> parEuler;
  ConvertVersorToEuler( parVersor, parEuler );

  /** Print. */
  std::cout << std::fixed;
  std::cout << std::showpoint;
  std::cout << std::setprecision( 6 );
  unsigned int nop = parVersor.size();

  std::cout << "versor: ";
  for ( unsigned int i = 0; i < nop - 1; i++ )
  {
    std::cout << parVersor[ i ] << " ";
  }
  std::cout << parVersor[ nop - 1 ] << std::endl;

  std::cout << "Euler: ";
  for ( unsigned int i = 0; i < nop - 1; i++ )
  {
    std::cout << parEuler[ i ] << " ";
  }
  std::cout << parEuler[ nop - 1 ] << std::endl;

  std::cout << "center of rotation: ";
  for ( unsigned int i = 0; i < 2; i++ )
  {
    std::cout << centerOfRotation[ i ] << " ";
  }
  std::cout << centerOfRotation[ 2 ] << std::endl;

  /** End program. */
  return 0;

} // end main

/**
 * ******************* ComputeClosestVersor *******************
 */

void ComputeClosestVersor(
  std::string fixedLandmarkFileName,
  std::string movingLandmarkFileName,
  std::vector<double> & parameters,
  std::vector<double> & centerOfRotation )
{
  /** Some consts. */
  const unsigned int  Dimension = 3;
  typedef short PixelType;

  /** Typedefs. */
  typedef itk::Image< PixelType, Dimension >          ImageType;
  typedef itk::VersorRigid3DTransform< double >       TransformType;
  typedef TransformType::ParametersType               ParametersType;
  typedef TransformType::CenterType                   CenterType;
  typedef itk::LandmarkBasedTransformInitializer<
    TransformType, ImageType, ImageType >             EstimatorType;
  typedef EstimatorType::LandmarkPointType            LandmarkType;
  typedef EstimatorType::LandmarkPointContainer       LandmarkContainer;

  /** Read the fixed landmark points. */
  LandmarkContainer fixedLandmarkContainer;
  ReadLandmarks( fixedLandmarkFileName, fixedLandmarkContainer );

  /** Read the moving landmark points. */
  LandmarkContainer movingLandmarkContainer;
  ReadLandmarks( movingLandmarkFileName, movingLandmarkContainer );

  /** Check the sizes. */
  if ( fixedLandmarkContainer.size() != movingLandmarkContainer.size() )
  {
    std::cerr << "ERROR: the two sets of landmarks are not of the same size." << std::endl;
    return;
  }

  /** Create transform. */
  TransformType::Pointer transform = TransformType::New();
  transform->SetIdentity();

  /** Create estimator. */
  EstimatorType::Pointer estimator = EstimatorType::New();
  estimator->SetTransform( transform );
  estimator->SetFixedLandmarks(  fixedLandmarkContainer );
  estimator->SetMovingLandmarks( movingLandmarkContainer );

  /** Run. */
  estimator->InitializeTransform();

  /** Get the parameters of the estimated closest rigid transformation. */
  ParametersType params = transform->GetParameters();
  unsigned int nop = transform->GetNumberOfParameters();
  parameters.resize( nop, 0.0 );
  for ( unsigned int i = 0; i < nop; ++i )
  {
    parameters[ i ] = params[ i ];
  }

  /** Get the estimated center of rotation. */
  CenterType center = transform->GetCenter();
  centerOfRotation.resize( Dimension, 0.0 );
  for ( unsigned int i = 0; i < Dimension; ++i )
  {
    centerOfRotation[ i ] = center[ i ];
  }

} // end ComputeClosestVersor()

/**
 * ******************* ReadLandmarks *******************
 */

void ReadLandmarks(
  std::string landmarkFileName,
  std::vector< itk::Point<double,3> > & landmarkContainer )
{
  /** Typedef's. */
  const unsigned int Dimension = 3;
  typedef itk::Image< short, Dimension >              ImageType;
  typedef itk::VersorRigid3DTransform< double >       TransformType;
  typedef TransformType::ParametersType               ParametersType;
  typedef itk::LandmarkBasedTransformInitializer<
    TransformType, ImageType, ImageType >             EstimatorType;
  typedef EstimatorType::LandmarkPointType            LandmarkType;
  typedef EstimatorType::LandmarkPointContainer       LandmarkContainer;

  /** Open file for reading and read landmarks. */
  std::ifstream landmarkFile( landmarkFileName.c_str() );
  if ( landmarkFile.is_open() )
  {
    LandmarkType landmark;
    while ( !landmarkFile.eof() )
    {
      for ( unsigned int i = 0; i < Dimension; i++ )
      {
        landmarkFile >> landmark[ i ];
      }
      landmarkContainer.push_back( landmark );
    }
  }
  landmarkFile.close();
  landmarkContainer.pop_back();

} // end ReadLandMarks()

/**
 * ******************* ConvertVersorToEuler *******************
 */

void ConvertVersorToEuler(
  const std::vector<double> & parVersor,
  std::vector<double> & parEuler )
{
  /** Create an Euler parameter vector. */
  unsigned int nop = parVersor.size();
  if ( nop != 6 ) return;
  parEuler.resize( nop, 0.0 );

  /** Easy notation. */
  double q0 = vcl_sqrt( 1.0 - parVersor[ 0 ] * parVersor[ 0 ]
    - parVersor[ 1 ] * parVersor[ 1 ] - parVersor[ 2 ] * parVersor[ 2 ] );
  double q1 = parVersor[ 0 ];
  double q2 = parVersor[ 1 ];
  double q3 = parVersor[ 2 ];

  /** Computer Euler angles. */
  parEuler[ 0 ] = vcl_atan2( 2.0 * ( q0 * q1 + q2 * q3 ), 1.0 - 2.0 * ( q1 * q1 + q2 * q2 ) );
  parEuler[ 1 ] = vcl_asin( 2.0 * ( q0 * q2 - q3 * q1 ) );
  parEuler[ 2 ] = vcl_atan2( 2.0 * ( q0 * q3 + q1 * q2 ), 1.0 - 2.0 * ( q2 * q2 + q3 * q3 ) );
  parEuler[ 3 ] = parVersor[ 3 ];
  parEuler[ 4 ] = parVersor[ 4 ];
  parEuler[ 5 ] = parVersor[ 5 ];

} // end ConvertVersorToEuler()

/**
 * ******************* PrintHelp *******************
 */

std::string PrintHelp( void )
{
  std::string helpString = "Calculates the closest rigid transform (VersorRigid3D) between \
  two sets of landmarks. The two sets should be of equal size. \
  Usage:\n \
  pxclosestversor3Dtransform \
    -f       the file containing the fixed landmarks \
    -m       the file containing the moving landmarks";
  return helpString;
} // end PrintHelp()
<|endoftext|>


<commit_before>#include "errors.hpp"
#include <boost/variant.hpp>

#include "clustering/immediate_consistency/branch/backfillee.hpp"
#include "clustering/immediate_consistency/branch/history.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/promise.hpp"
#include "concurrency/queue/unlimited_fifo.hpp"
#include "containers/death_runner.hpp"

template<class protocol_t>
void on_receive_backfill_chunk(
        store_view_t<protocol_t> *store,
        signal_t *dont_go_until,
        typename protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, typename protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue
        )
        THROWS_NOTHING
{
    {
        wait_any_t waiter(dont_go_until, interruptor);
        waiter.wait_lazily_unordered();
        if (interruptor->is_pulsed()) {
            return;
        }
    }

    try {
        boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
        store->new_write_token(write_token);
        queue->finish_write(tok);
        store->receive_backfill(chunk, write_token, interruptor);
    } catch (interrupted_exc_t) {
        return;
    }
};

template <class backfill_chunk_t>
void push_on_queue(fifo_enforcer_queue_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue, backfill_chunk_t chunk, fifo_enforcer_write_token_t token) {
    queue->push(token, std::make_pair(std::make_pair(true, chunk), token));
}

template<class protocol_t>
void backfillee(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<protocol_t> > > branch_history,
        store_view_t<protocol_t> *store,
        typename protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t)
{
    rassert(region_is_superset(store->get_region(), region));
    resource_access_t<backfiller_business_card_t<protocol_t> > backfiller(backfiller_metadata);

    /* Read the metadata to determine where we're starting from */
    boost::scoped_ptr<fifo_enforcer_sink_t::exit_read_t> read_token;
    store->new_read_token(read_token);
    region_map_t<protocol_t, version_range_t> start_point =
        region_map_transform<protocol_t, binary_blob_t, version_range_t>(
            store->get_metainfo(read_token, interruptor),
            &binary_blob_t::get<version_range_t>
            );

    start_point = start_point.mask(region);

    /* The backfiller will send a message to `end_point_mailbox` before it sends
    any other messages; that message will tell us what the version will be when
    the backfill is over. */
    promise_t<region_map_t<protocol_t, version_range_t> > end_point_cond;
    mailbox_t<void(region_map_t<protocol_t, version_range_t>)> end_point_mailbox(
        mailbox_manager,
        boost::bind(&promise_t<region_map_t<protocol_t, version_range_t> >::pulse, &end_point_cond, _1),
        mailbox_callback_mode_inline);

    /* `dont_go_until` prevents any backfill chunks from being applied before we
    update the store metadata to indicate that the backfill is in progress. */
    cond_t dont_go_until;

    /* The backfiller will notify `done_mailbox` when the backfill is all over
    and the version described in `end_point_mailbox` has been achieved. */
    promise_t<fifo_enforcer_write_token_t> done_cond;
    mailbox_t<void(fifo_enforcer_write_token_t)> done_mailbox(
        mailbox_manager,
        boost::bind(&promise_t<fifo_enforcer_write_token_t>::pulse, &done_cond, _1),
        mailbox_callback_mode_inline);

    {
        /* A queue of the requests the backfill chunk mailbox receives, a coro
         * pool services these requests and poops them off one at a time to
         * perform them. */

        typedef typename protocol_t::backfill_chunk_t backfill_chunk_t;
        typedef fifo_enforcer_queue_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > chunk_queue_t;
        chunk_queue_t chunk_queue;

        struct chunk_callback_t : public coro_pool_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> >::callback_t {
            chunk_callback_t(store_view_t<protocol_t> *_store, signal_t *_dont_go_until,
                             signal_t *_interruptor, chunk_queue_t *_chunk_queue)
                : store(_store), dont_go_until(_dont_go_until), interruptor(_interruptor), chunk_queue(_chunk_queue)
            { }
            void coro_pool_callback(std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> chunk) {
                on_receive_backfill_chunk(store, dont_go_until, chunk.first.second, interruptor, chunk.second, chunk_queue);
            }
            store_view_t<protocol_t> *store;
            signal_t *dont_go_until;
            signal_t *interruptor;
            chunk_queue_t *chunk_queue;
        };

        chunk_callback_t chunk_callback(store, &dont_go_until, interruptor, &chunk_queue);
        /* A callback, this function will be called on backfill_chunk_ts as
         * they are popped off the queue. */
        //typename coro_pool_t<std::pair<backfill_chunk_t, auto_drainer_t::lock_t> >::boost_function_callback_t
        //    chunk_callback(boost::bind(&on_receive_backfill_chunk<protocol_t>,
        //        store, &dont_go_until, boost::bind(&std::pair::first, _1), interruptor, boost::bind(&std::pair::second, _1)
        //        ));

        coro_pool_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > backfill_workers(10, &chunk_queue, &chunk_callback);

        /* Use an `auto_drainer_t` to wait for all the bits of the backfill to
        finish being applied. Construct it before `chunk_mailbox` so that we
        don't get any chunks after `drainer` is destroyed. */
        auto_drainer_t drainer;

        /* The backfiller will send individual chunks of the backfill to
        `chunk_mailbox`. */
        mailbox_t<void(backfill_chunk_t, fifo_enforcer_write_token_t)> chunk_mailbox(
            mailbox_manager, boost::bind(&push_on_queue<backfill_chunk_t>, &chunk_queue, _1, _2));

        /* Send off the backfill request */
        send(mailbox_manager,
            backfiller.access().backfill_mailbox,
            backfill_session_id,
            start_point,
            end_point_mailbox.get_address(),
            chunk_mailbox.get_address(),
            done_mailbox.get_address()
            );

        /* If something goes wrong, we'd like to inform the backfiller that it
        it has gone wrong, so it doesn't just keep blindly sending us chunks.
        `backfiller_notifier` notifies the backfiller in its destructor. If
        everything goes right, we'll explicitly disarm it. */
        death_runner_t backfiller_notifier;
        {
            /* We have to cast `send()` to the correct type before we pass
            it to `boost::bind()`, or else C++ can't figure out which
            overload to use. */
            void (*send_cast_to_correct_type)(
                mailbox_manager_t *,
                typename backfiller_business_card_t<protocol_t>::cancel_backfill_mailbox_t::address_t,
                const backfill_session_id_t &) = &send;
            backfiller_notifier.fun = boost::bind(
                send_cast_to_correct_type, mailbox_manager,
                backfiller.access().cancel_backfill_mailbox,
                backfill_session_id);
        }

        /* Wait until we get a message in `end_point_mailbox`. */
        {
            wait_any_t waiter(end_point_cond.get_ready_signal(), backfiller.get_failed_signal());
            wait_interruptible(&waiter, interruptor);

            /* Throw an exception if backfiller died */
            backfiller.access();
            rassert(end_point_cond.get_ready_signal()->is_pulsed());
        }

        /* Indicate in the metadata that a backfill is happening. We do this by
        marking every region as indeterminate between the current state and the
        backfill end state, since we don't know whether the backfill has reached
        that region yet. */

        typedef region_map_t<protocol_t, version_range_t> version_map_t;

        version_map_t end_point = end_point_cond.get_value();

        std::vector<std::pair<typename protocol_t::region_t, version_range_t> > span_parts;

        for (typename version_map_t::const_iterator it  = start_point.begin();
                                                    it != start_point.end();
                                                    it++) {
            for (typename version_map_t::const_iterator jt  = end_point.begin();
                                                        jt != end_point.end();
                                                        jt++) {
                typename protocol_t::region_t ixn = region_intersection(it->first, jt->first);
                if (!region_is_empty(ixn)) {
                    rassert(version_is_ancestor(branch_history->get(),
                        it->second.earliest,
                        jt->second.latest,
                        ixn),
                        "We're on a different timeline than the backfiller, "
                        "but it somehow failed to notice.");
                    span_parts.push_back(std::make_pair(
                        ixn,
                        version_range_t(it->second.earliest, jt->second.latest)
                        ));
                }
            }
        }
        boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
        store->new_write_token(write_token);
        store->set_metainfo(
            region_map_transform<protocol_t, version_range_t, binary_blob_t>(
                region_map_t<protocol_t, version_range_t>(span_parts.begin(), span_parts.end()),
                &binary_blob_t::make<version_range_t>
                ),
            write_token,
            interruptor
            );

        /* Now that the metadata indicates that the backfill is happening, it's
        OK for backfill chunks to be applied */
        dont_go_until.pulse();

        /* Now wait for the backfill to be over */
        {
            wait_any_t waiter(done_cond.get_ready_signal(), backfiller.get_failed_signal());
            wait_interruptible(&waiter, interruptor);

            /* Throw an exception if backfiller died */
            backfiller.access();
            rassert(done_cond.get_ready_signal()->is_pulsed());
        }

        /* All went well, so don't send a cancel message to the backfiller */
        backfiller_notifier.fun = 0;

        /* `drainer` destructor is run here; we block until all the chunks are
        done being applied. */
    }

    /* Update the metadata to indicate that the backfill occurred */
    boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
    store->new_write_token(write_token);
    store->set_metainfo(
        region_map_transform<protocol_t, version_range_t, binary_blob_t>(
            end_point_cond.get_value(),
            &binary_blob_t::make<version_range_t>
            ),
        write_token,
        interruptor
        );
}

#include "memcached/protocol.hpp"
#include "mock/dummy_protocol.hpp"

template void backfillee<mock::dummy_protocol_t>(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<mock::dummy_protocol_t> > > branch_history,
        store_view_t<mock::dummy_protocol_t> *store,
        mock::dummy_protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<mock::dummy_protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t);

template void on_receive_backfill_chunk<mock::dummy_protocol_t>(
        store_view_t<mock::dummy_protocol_t> *store,
        signal_t *dont_go_until,
        mock::dummy_protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, mock::dummy_protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue)
    THROWS_NOTHING;

template void backfillee<memcached_protocol_t>(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<memcached_protocol_t> > > branch_history,
        store_view_t<memcached_protocol_t> *store,
        memcached_protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<memcached_protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t);

template void on_receive_backfill_chunk<memcached_protocol_t>(
        store_view_t<memcached_protocol_t> *store,
        signal_t *dont_go_until,
        memcached_protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, memcached_protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue)
    THROWS_NOTHING;
<commit_msg>Completes the backfill ordering fix.<commit_after>#include "errors.hpp"
#include <boost/variant.hpp>

#include "clustering/immediate_consistency/branch/backfillee.hpp"
#include "clustering/immediate_consistency/branch/history.hpp"
#include "concurrency/coro_pool.hpp"
#include "concurrency/promise.hpp"
#include "concurrency/queue/unlimited_fifo.hpp"
#include "containers/death_runner.hpp"

template<class protocol_t>
void on_receive_backfill_chunk(
        store_view_t<protocol_t> *store,
        signal_t *dont_go_until,
        typename protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, typename protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue
        )
        THROWS_NOTHING
{
    {
        wait_any_t waiter(dont_go_until, interruptor);
        waiter.wait_lazily_unordered();
        if (interruptor->is_pulsed()) {
            return;
        }
    }

    try {
        boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
        store->new_write_token(write_token);
        queue->finish_write(tok);
        store->receive_backfill(chunk, write_token, interruptor);
    } catch (interrupted_exc_t) {
        return;
    }
};

template <class backfill_chunk_t>
void push_chunk_on_queue(fifo_enforcer_queue_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue, backfill_chunk_t chunk, fifo_enforcer_write_token_t token) {
    queue->push(token, std::make_pair(std::make_pair(true, chunk), token));
}

template <class backfill_chunk_t>
void push_finish_on_queue(fifo_enforcer_queue_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue, fifo_enforcer_write_token_t token) {
    queue->push(token, std::make_pair(std::make_pair(false, backfill_chunk_t()), token));
}

template<class protocol_t>
void backfillee(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<protocol_t> > > branch_history,
        store_view_t<protocol_t> *store,
        typename protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
        THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t)
{
    rassert(region_is_superset(store->get_region(), region));
    resource_access_t<backfiller_business_card_t<protocol_t> > backfiller(backfiller_metadata);

    /* Read the metadata to determine where we're starting from */
    boost::scoped_ptr<fifo_enforcer_sink_t::exit_read_t> read_token;
    store->new_read_token(read_token);
    region_map_t<protocol_t, version_range_t> start_point =
        region_map_transform<protocol_t, binary_blob_t, version_range_t>(
            store->get_metainfo(read_token, interruptor),
            &binary_blob_t::get<version_range_t>
            );

    start_point = start_point.mask(region);

    /* The backfiller will send a message to `end_point_mailbox` before it sends
    any other messages; that message will tell us what the version will be when
    the backfill is over. */
    promise_t<region_map_t<protocol_t, version_range_t> > end_point_cond;
    mailbox_t<void(region_map_t<protocol_t, version_range_t>)> end_point_mailbox(
        mailbox_manager,
        boost::bind(&promise_t<region_map_t<protocol_t, version_range_t> >::pulse, &end_point_cond, _1),
        mailbox_callback_mode_inline);

    /* `dont_go_until` prevents any backfill chunks from being applied before we
    update the store metadata to indicate that the backfill is in progress. */
    cond_t dont_go_until;

    {
        typedef typename protocol_t::backfill_chunk_t backfill_chunk_t;

        /* A queue of the requests the backfill chunk mailbox receives, a coro
         * pool services these requests and poops them off one at a time to
         * perform them. */

        typedef fifo_enforcer_queue_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > chunk_queue_t;
        chunk_queue_t chunk_queue;

        /* The backfiller will notify `done_mailbox` when the backfill is all over
        and the version described in `end_point_mailbox` has been achieved. */
        cond_t done_cond;
        mailbox_t<void(fifo_enforcer_write_token_t)> done_mailbox(
            mailbox_manager,
            boost::bind(&push_finish_on_queue<backfill_chunk_t>, &chunk_queue, _1),
            mailbox_callback_mode_inline);

        struct chunk_callback_t : public coro_pool_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> >::callback_t {
            chunk_callback_t(store_view_t<protocol_t> *_store, signal_t *_dont_go_until,
                             signal_t *_interruptor, chunk_queue_t *_chunk_queue,
                             cond_t *_done_cond)
                : store(_store), dont_go_until(_dont_go_until), interruptor(_interruptor),
                  chunk_queue(_chunk_queue), done_cond(_done_cond)
            { }
            void coro_pool_callback(std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> chunk) {
                if (chunk.first.first) {
                    on_receive_backfill_chunk(store, dont_go_until, chunk.first.second, interruptor, chunk.second, chunk_queue);
                } else {
                    rassert(!done_cond->is_pulsed());
                    done_cond->pulse();
                }
            }
            store_view_t<protocol_t> *store;
            signal_t *dont_go_until;
            signal_t *interruptor;
            chunk_queue_t *chunk_queue;
            cond_t *done_cond;
        };

        chunk_callback_t chunk_callback(store, &dont_go_until, interruptor, &chunk_queue, &done_cond);
        /* A callback, this function will be called on backfill_chunk_ts as
         * they are popped off the queue. */
        //typename coro_pool_t<std::pair<backfill_chunk_t, auto_drainer_t::lock_t> >::boost_function_callback_t
        //    chunk_callback(boost::bind(&on_receive_backfill_chunk<protocol_t>,
        //        store, &dont_go_until, boost::bind(&std::pair::first, _1), interruptor, boost::bind(&std::pair::second, _1)
        //        ));

        coro_pool_t<std::pair<std::pair<bool, backfill_chunk_t>, fifo_enforcer_write_token_t> > backfill_workers(10, &chunk_queue, &chunk_callback);

        /* Use an `auto_drainer_t` to wait for all the bits of the backfill to
        finish being applied. Construct it before `chunk_mailbox` so that we
        don't get any chunks after `drainer` is destroyed. */
        auto_drainer_t drainer;

        /* The backfiller will send individual chunks of the backfill to
        `chunk_mailbox`. */
        mailbox_t<void(backfill_chunk_t, fifo_enforcer_write_token_t)> chunk_mailbox(
            mailbox_manager, boost::bind(&push_chunk_on_queue<backfill_chunk_t>, &chunk_queue, _1, _2));

        /* Send off the backfill request */
        send(mailbox_manager,
            backfiller.access().backfill_mailbox,
            backfill_session_id,
            start_point,
            end_point_mailbox.get_address(),
            chunk_mailbox.get_address(),
            done_mailbox.get_address()
            );

        /* If something goes wrong, we'd like to inform the backfiller that it
        it has gone wrong, so it doesn't just keep blindly sending us chunks.
        `backfiller_notifier` notifies the backfiller in its destructor. If
        everything goes right, we'll explicitly disarm it. */
        death_runner_t backfiller_notifier;
        {
            /* We have to cast `send()` to the correct type before we pass
            it to `boost::bind()`, or else C++ can't figure out which
            overload to use. */
            void (*send_cast_to_correct_type)(
                mailbox_manager_t *,
                typename backfiller_business_card_t<protocol_t>::cancel_backfill_mailbox_t::address_t,
                const backfill_session_id_t &) = &send;
            backfiller_notifier.fun = boost::bind(
                send_cast_to_correct_type, mailbox_manager,
                backfiller.access().cancel_backfill_mailbox,
                backfill_session_id);
        }

        /* Wait until we get a message in `end_point_mailbox`. */
        {
            wait_any_t waiter(end_point_cond.get_ready_signal(), backfiller.get_failed_signal());
            wait_interruptible(&waiter, interruptor);

            /* Throw an exception if backfiller died */
            backfiller.access();
            rassert(end_point_cond.get_ready_signal()->is_pulsed());
        }

        /* Indicate in the metadata that a backfill is happening. We do this by
        marking every region as indeterminate between the current state and the
        backfill end state, since we don't know whether the backfill has reached
        that region yet. */

        typedef region_map_t<protocol_t, version_range_t> version_map_t;

        version_map_t end_point = end_point_cond.get_value();

        std::vector<std::pair<typename protocol_t::region_t, version_range_t> > span_parts;

        for (typename version_map_t::const_iterator it  = start_point.begin();
                                                    it != start_point.end();
                                                    it++) {
            for (typename version_map_t::const_iterator jt  = end_point.begin();
                                                        jt != end_point.end();
                                                        jt++) {
                typename protocol_t::region_t ixn = region_intersection(it->first, jt->first);
                if (!region_is_empty(ixn)) {
                    rassert(version_is_ancestor(branch_history->get(),
                        it->second.earliest,
                        jt->second.latest,
                        ixn),
                        "We're on a different timeline than the backfiller, "
                        "but it somehow failed to notice.");
                    span_parts.push_back(std::make_pair(
                        ixn,
                        version_range_t(it->second.earliest, jt->second.latest)
                        ));
                }
            }
        }
        boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
        store->new_write_token(write_token);
        store->set_metainfo(
            region_map_transform<protocol_t, version_range_t, binary_blob_t>(
                region_map_t<protocol_t, version_range_t>(span_parts.begin(), span_parts.end()),
                &binary_blob_t::make<version_range_t>
                ),
            write_token,
            interruptor
            );

        /* Now that the metadata indicates that the backfill is happening, it's
        OK for backfill chunks to be applied */
        dont_go_until.pulse();

        /* Now wait for the backfill to be over */
        {
            wait_any_t waiter(&done_cond, backfiller.get_failed_signal());
            wait_interruptible(&waiter, interruptor);

            /* Throw an exception if backfiller died */
            backfiller.access();
            rassert(done_cond.is_pulsed());
        }

        /* All went well, so don't send a cancel message to the backfiller */
        backfiller_notifier.fun = 0;

        /* `drainer` destructor is run here; we block until all the chunks are
        done being applied. */
    }

    /* Update the metadata to indicate that the backfill occurred */
    boost::scoped_ptr<fifo_enforcer_sink_t::exit_write_t> write_token;
    store->new_write_token(write_token);
    store->set_metainfo(
        region_map_transform<protocol_t, version_range_t, binary_blob_t>(
            end_point_cond.get_value(),
            &binary_blob_t::make<version_range_t>
            ),
        write_token,
        interruptor
        );
}

#include "memcached/protocol.hpp"
#include "mock/dummy_protocol.hpp"

template void backfillee<mock::dummy_protocol_t>(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<mock::dummy_protocol_t> > > branch_history,
        store_view_t<mock::dummy_protocol_t> *store,
        mock::dummy_protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<mock::dummy_protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t);

template void on_receive_backfill_chunk<mock::dummy_protocol_t>(
        store_view_t<mock::dummy_protocol_t> *store,
        signal_t *dont_go_until,
        mock::dummy_protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, mock::dummy_protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue)
    THROWS_NOTHING;

template void backfillee<memcached_protocol_t>(
        mailbox_manager_t *mailbox_manager,
        UNUSED boost::shared_ptr<semilattice_read_view_t<branch_history_t<memcached_protocol_t> > > branch_history,
        store_view_t<memcached_protocol_t> *store,
        memcached_protocol_t::region_t region,
        clone_ptr_t<watchable_t<boost::optional<boost::optional<backfiller_business_card_t<memcached_protocol_t> > > > > backfiller_metadata,
        backfill_session_id_t backfill_session_id,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t, resource_lost_exc_t);

template void on_receive_backfill_chunk<memcached_protocol_t>(
        store_view_t<memcached_protocol_t> *store,
        signal_t *dont_go_until,
        memcached_protocol_t::backfill_chunk_t chunk,
        signal_t *interruptor,
        fifo_enforcer_write_token_t tok,
        fifo_enforcer_queue_t<std::pair<std::pair<bool, memcached_protocol_t::backfill_chunk_t>, fifo_enforcer_write_token_t> > *queue)
    THROWS_NOTHING;
<|endoftext|>


<commit_before>/*
 Copyright (c) 2010, The Barbarian Group
 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.

 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.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#if defined( CINDER_MSW )
#include "cinder/dx/dx.h"
#include "cinder/app/AppImplMswRendererDx.h"
#endif

#include "AntTweakBar.h"

#include <boost/assign/list_of.hpp>

using namespace std;

namespace cinder { namespace params {

namespace {

#undef DELETE

#define SYNONYM(ck,ak) ((int)cinder::app::KeyEvent::KEY_ ## ck, TW_KEY_ ## ak)
#define HOMONYM(k) SYNONYM(k,k)
    std::map<int,TwKeySpecial> specialKeys = boost::assign::map_list_of
        HOMONYM(RIGHT)
        HOMONYM(LEFT)
        HOMONYM(BACKSPACE)
        HOMONYM(DELETE)
        HOMONYM(TAB)
        HOMONYM(F1)
        HOMONYM(F2)
        HOMONYM(F3)
        HOMONYM(F4)
        HOMONYM(F5)
        HOMONYM(F6)
        HOMONYM(F7)
        HOMONYM(F8)
        HOMONYM(F9)
        HOMONYM(F10)
        HOMONYM(F11)
        HOMONYM(F12)
        HOMONYM(F13)
        HOMONYM(F14)
        HOMONYM(F15)
        HOMONYM(HOME)
        HOMONYM(END)
        SYNONYM(PAGEUP,PAGE_UP)
        SYNONYM(PAGEDOWN,PAGE_DOWN)
        ;
#undef SYNONYM
#undef HOMONYM

void mouseDown( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_PRESSED, button ) != 0 );
}

void mouseUp( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_RELEASED, button ) != 0 );
}

void mouseWheel( app::MouseEvent &event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	event.setHandled( TwMouseWheel( (int)(sWheelPos) ) != 0 );
}

void mouseMove( app::MouseEvent &event )
{
	event.setHandled( TwMouseMotion( event.getX(), event.getY() ) != 0 );
}

void keyDown( app::KeyEvent &event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	event.setHandled( TwKeyPressed(
            (specialKeys.count( event.getCode() ) > 0)
                ? specialKeys[event.getCode()]
                : event.getChar(),
            kmod ) != 0 );
}

void resize( cinder::app::WindowRef window )
{
	TwWindowSize( window->getWidth(), window->getHeight() );
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
#if defined( CINDER_MSW )
		app::Renderer::RendererType rendererType = app::App::get()->getRenderer()->getRendererType();
		if( ! TwInit( (rendererType == app::Renderer::RENDERER_GL) ? TW_OPENGL : TW_DIRECT3D11, (rendererType == app::Renderer::RENDERER_GL) ? NULL : dx::getDxRenderer()->md3dDevice ) )
			throw Exception();
#else
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}
#endif
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	init( app::App::get()->getWindow(), title, size, color );
}

InterfaceGl::InterfaceGl( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	init( window, title, size, color );
}

void InterfaceGl::init( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();

	mWindow = window;

	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );

	mWindow->getSignalMouseDown().connect( mouseDown );
	mWindow->getSignalMouseUp().connect( mouseUp );
	mWindow->getSignalMouseWheel().connect( mouseWheel );
	mWindow->getSignalMouseMove().connect( mouseMove );
	mWindow->getSignalMouseDrag().connect( mouseMove );
	mWindow->getSignalKeyDown().connect( keyDown );
	mWindow->getSignalResize().connect( std::bind( resize, mWindow ) );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, double *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DOUBLE, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::removeParam( const std::string &name )
{
	TwRemoveVar( mBar.get(), name.c_str() );
}

void InterfaceGl::clear()
{
	TwRemoveAllVars( mBar.get() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<commit_msg>Added USE_DIRECTX define to prevent DirectX dependency when building for OpenGL<commit_after>/*
 Copyright (c) 2010, The Barbarian Group
 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.

 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.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#if (defined( CINDER_MSW ) && defined( USE_DIRECTX ))
#include "cinder/dx/dx.h"
#include "cinder/app/AppImplMswRendererDx.h"
#endif

#include "AntTweakBar.h"

#include <boost/assign/list_of.hpp>

using namespace std;

namespace cinder { namespace params {

namespace {

#undef DELETE

#define SYNONYM(ck,ak) ((int)cinder::app::KeyEvent::KEY_ ## ck, TW_KEY_ ## ak)
#define HOMONYM(k) SYNONYM(k,k)
    std::map<int,TwKeySpecial> specialKeys = boost::assign::map_list_of
        HOMONYM(RIGHT)
        HOMONYM(LEFT)
        HOMONYM(BACKSPACE)
        HOMONYM(DELETE)
        HOMONYM(TAB)
        HOMONYM(F1)
        HOMONYM(F2)
        HOMONYM(F3)
        HOMONYM(F4)
        HOMONYM(F5)
        HOMONYM(F6)
        HOMONYM(F7)
        HOMONYM(F8)
        HOMONYM(F9)
        HOMONYM(F10)
        HOMONYM(F11)
        HOMONYM(F12)
        HOMONYM(F13)
        HOMONYM(F14)
        HOMONYM(F15)
        HOMONYM(HOME)
        HOMONYM(END)
        SYNONYM(PAGEUP,PAGE_UP)
        SYNONYM(PAGEDOWN,PAGE_DOWN)
        ;
#undef SYNONYM
#undef HOMONYM

void mouseDown( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_PRESSED, button ) != 0 );
}

void mouseUp( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_RELEASED, button ) != 0 );
}

void mouseWheel( app::MouseEvent &event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	event.setHandled( TwMouseWheel( (int)(sWheelPos) ) != 0 );
}

void mouseMove( app::MouseEvent &event )
{
	event.setHandled( TwMouseMotion( event.getX(), event.getY() ) != 0 );
}

void keyDown( app::KeyEvent &event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	event.setHandled( TwKeyPressed(
            (specialKeys.count( event.getCode() ) > 0)
                ? specialKeys[event.getCode()]
                : event.getChar(),
            kmod ) != 0 );
}

void resize( cinder::app::WindowRef window )
{
	TwWindowSize( window->getWidth(), window->getHeight() );
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
#if defined( USE_DIRECTX )
		if( ! TwInit( TW_DIRECT3D11, dx::getDxRenderer()->md3dDevice ) ) {
			throw Exception();
		}
#else
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}
#endif
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	init( app::App::get()->getWindow(), title, size, color );
}

InterfaceGl::InterfaceGl( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	init( window, title, size, color );
}

void InterfaceGl::init( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();

	mWindow = window;

	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );

	mWindow->getSignalMouseDown().connect( mouseDown );
	mWindow->getSignalMouseUp().connect( mouseUp );
	mWindow->getSignalMouseWheel().connect( mouseWheel );
	mWindow->getSignalMouseMove().connect( mouseMove );
	mWindow->getSignalMouseDrag().connect( mouseMove );
	mWindow->getSignalKeyDown().connect( keyDown );
	mWindow->getSignalResize().connect( std::bind( resize, mWindow ) );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, double *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DOUBLE, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::removeParam( const std::string &name )
{
	TwRemoveVar( mBar.get(), name.c_str() );
}

void InterfaceGl::clear()
{
	TwRemoveAllVars( mBar.get() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include <boost/algorithm/string.hpp>

#ifndef unix
#include <float.h>
#else
#include "CoreTypes.h"
#endif

#include "RexNetworkUtils.h"
#include "QuatUtils.h"
#include <QStringList>

namespace RexTypes
{
    bool ParseBool(const std::string &value)
    {
        std::string testedvalue = value;
        boost::algorithm::to_lower(testedvalue);
        return (boost::algorithm::starts_with(testedvalue,"true") || boost::algorithm::starts_with(testedvalue,"1"));
    }

    Quaternion GetProcessedQuaternion(const uint8_t* bytes)
    {
        uint16_t *rot = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);
        Quaternion rotation = UnpackQuaternionFromU16_4(rot);
        rotation.normalize();
        return rotation;
    }

    Vector3df GetProcessedScaledVectorFromUint16(const uint8_t* bytes, float scale)
    {
        uint16_t *vec = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);

        Vector3df resultvector;
        resultvector.x = scale * ((vec[0] / 32768.0f) - 1.0f);
        resultvector.y = scale * ((vec[1] / 32768.0f) - 1.0f);
        resultvector.z = scale * ((vec[2] / 32768.0f) - 1.0f);

        return resultvector;
    }

    Vector3df GetProcessedVectorFromUint16(const uint8_t* bytes)
    {
        uint16_t *vec = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);
        return Vector3df(vec[0],vec[1],vec[2]);
    }

    Vector3df GetProcessedVector(const uint8_t* bytes)
    {
        Vector3df resultvector = *reinterpret_cast<Vector3df*>((Vector3df*)&bytes[0]);
        return resultvector;
    }

    bool IsValidPositionVector(const Vector3df &pos)
    {
        // This is a heuristic check to guard against the OpenSim server sending us stupid positions.
        if (fabs(pos.x) > 1e6f || fabs(pos.y) > 1e6f || fabs(pos.z) > 1e6f)
            return false;
        if (_isnan(pos.x) || _isnan(pos.y) || _isnan(pos.z))
            return false;
        if (!_finite(pos.x) || !_finite(pos.y) || !_finite(pos.z))
            return false;

        return true;
    }

    bool IsValidVelocityVector(const Vector3df &pos)
    {
        // This is a heuristic check to guard against the OpenSim server sending us stupid velocity vectors.
        if (fabs(pos.x) > 1e3f || fabs(pos.y) > 1e3f || fabs(pos.z) > 1e3f)
            return false;
        if (_isnan(pos.x) || _isnan(pos.y) || _isnan(pos.z))
            return false;
        if (!_finite(pos.x) || !_finite(pos.y) || !_finite(pos.z))
            return false;

        return true;
    }

    bool ReadBoolFromBytes(const uint8_t* bytes, int& idx)
    {
        bool result = *(bool*)(&bytes[idx]);
        idx += sizeof(bool);

        return result;
    }

    uint8_t ReadUInt8FromBytes(const uint8_t* bytes, int& idx)
    {
        uint8_t result = bytes[idx];
        idx++;

        return result;
    }

    uint16_t ReadUInt16FromBytes(const uint8_t* bytes, int& idx)
    {
        uint16_t result = *(uint16_t*)(&bytes[idx]);
        idx += sizeof(uint16_t);

        return result;
    }

    uint32_t ReadUInt32FromBytes(const uint8_t* bytes, int& idx)
    {
        uint32_t result = *(uint32_t*)(&bytes[idx]);
        idx += sizeof(uint32_t);

        return result;
    }

    int16_t ReadSInt16FromBytes(const uint8_t* bytes, int& idx)
    {
        int16_t result = *(int16_t*)(&bytes[idx]);
        idx += sizeof(int16_t);

        return result;
    }

    int32_t ReadSInt32FromBytes(const uint8_t* bytes, int& idx)
    {
        int32_t result = *(int32_t*)(&bytes[idx]);
        idx += sizeof(int32_t);

        return result;
    }

    float ReadFloatFromBytes(const uint8_t* bytes, int& idx)
    {
        float result = *(float*)(&bytes[idx]);
        idx += sizeof(float);

        return result;
    }

    RexUUID ReadUUIDFromBytes(const uint8_t* bytes, int& idx)
    {
        RexUUID result = *(RexUUID*)(&bytes[idx]);
        idx += sizeof(RexUUID);

        return result;
    }

    Color ReadColorFromBytes(const uint8_t* bytes, int& idx)
    {
        uint8_t r = bytes[idx++];
        uint8_t g = bytes[idx++];
        uint8_t b = bytes[idx++];
        uint8_t a = bytes[idx++];

        return Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
    }

    Color ReadColorFromBytesInverted(const uint8_t* bytes, int& idx)
    {
        uint8_t r = 255 - bytes[idx++];
        uint8_t g = 255 - bytes[idx++];
        uint8_t b = 255 - bytes[idx++];
        uint8_t a = 255 - bytes[idx++];

        return Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
    }

    std::string ReadNullTerminatedStringFromBytes(const uint8_t* bytes, int& idx)
    {
        std::string result = "";

        uint8_t readbyte = bytes[idx];
        idx++;
        while(readbyte != 0)
        {
            result.push_back((char)readbyte);
            readbyte = bytes[idx];
            idx++;
        }

        return result;
    }

    void WriteBoolToBytes(bool value, uint8_t* bytes, int& idx)
    {
        bytes[idx] = (uint8_t)value;
        idx++;
    }

    void WriteUInt8ToBytes(uint8_t value, uint8_t* bytes, int& idx)
    {
        bytes[idx] = value;
        idx++;
    }

    void WriteUInt16ToBytes(uint16_t value, uint8_t* bytes, int& idx)
    {
        *(uint16_t*)(&bytes[idx]) = value;
        idx += sizeof(uint16_t);
    }

    void WriteUInt32ToBytes(uint32_t value, uint8_t* bytes, int& idx)
    {
        *(uint32_t*)(&bytes[idx]) = value;
        idx += sizeof(uint32_t);
    }

    void WriteFloatToBytes(float value, uint8_t* bytes, int& idx)
    {
        *(float*)(&bytes[idx]) = value;
        idx += sizeof(float);
    }

    void WriteUUIDToBytes(const RexUUID &value, uint8_t* bytes, int& idx)
    {
        *(RexUUID*)(&bytes[idx]) = value;
        idx += sizeof(RexUUID);
    }

    void WriteNullTerminatedStringToBytes(const std::string& value, uint8_t* bytes, int& idx)
    {
        const char* c_str = value.c_str();

        memcpy(&bytes[idx], c_str, value.length() + 1);
        idx += value.length() + 1;
    }

    NameValueMap ParseNameValueMap(const std::string& namevalue)
    {
        // NameValue contains: "FirstName STRING RW SV <firstName>\nLastName STRING RW SV <lastName>"
        // When using rex auth <firstName> contains both first and last name and <lastName> contains the auth server address

        // Split into lines
        NameValueMap map;
        StringVector lines = SplitString(namevalue, '\n');
        for (unsigned i = 0; i < lines.size(); ++i)
        {
            StringVector line = SplitString(lines[i], ' ');
            if (line.size() > 4)
            {
                // First element is the name
                const std::string& name = line[0];
                std::string value;
                // Skip over the STRING RW SV etc. (3 values)
                // Concatenate the rest of the values
                for (unsigned j = 4; j < line.size(); ++j)
                {
                    value += line[j];
                    if (j != line.size()-1)
                        value += " ";
                }
                map[name] = value;
            }
        }

        // Parse auth server address out from the NameValue if it exists
        QString fullname = QString(map["FirstName"].c_str()) + " " + QString(map["LastName"].c_str());

        // Rex auth has: <First Last> <rex auth url>
        if (fullname.count('@') == 1)
        {
            QStringList names;
            if (fullname.contains('@'))
            {
                names = fullname.split(" ");
                foreach(QString name, names)
                {
                    if (name.contains('@'))
                    {
                        map["RexAuth"] = name.toStdString();
                        names.removeOne(name);
                    }
                }
            }
            assert(names[0].size() >= 2);
            map["FirstName"] = names[0].toStdString();
            map["LastName"] = names[1].toStdString();
        }
        // Web auth has: <url> <url>
        else if (fullname.count('@') == 2)
        {
            QStringList names = fullname.split(" ");
            map["FirstName"] = names[0].toStdString();
            map["LastName"] = "";
        }

        return map;
    }

    bool ReadTextureEntryBits(uint32_t& bits, int& num_bits, const uint8_t* bytes, int& idx)
    {
        bits = 0;
        num_bits = 0;
        uint8_t byte;

        do
        {
            byte = bytes[idx++];
            bits <<= 7;
            bits |= byte & 0x7f;
            num_bits += 7;
        }
        while (byte & 0x80);

        return bits != 0;
    }
}
<commit_msg>Avoid crash on missing last name<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include <boost/algorithm/string.hpp>

#ifndef unix
#include <float.h>
#else
#include "CoreTypes.h"
#endif

#include "RexNetworkUtils.h"
#include "QuatUtils.h"
#include <QStringList>

namespace RexTypes
{
    bool ParseBool(const std::string &value)
    {
        std::string testedvalue = value;
        boost::algorithm::to_lower(testedvalue);
        return (boost::algorithm::starts_with(testedvalue,"true") || boost::algorithm::starts_with(testedvalue,"1"));
    }

    Quaternion GetProcessedQuaternion(const uint8_t* bytes)
    {
        uint16_t *rot = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);
        Quaternion rotation = UnpackQuaternionFromU16_4(rot);
        rotation.normalize();
        return rotation;
    }

    Vector3df GetProcessedScaledVectorFromUint16(const uint8_t* bytes, float scale)
    {
        uint16_t *vec = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);

        Vector3df resultvector;
        resultvector.x = scale * ((vec[0] / 32768.0f) - 1.0f);
        resultvector.y = scale * ((vec[1] / 32768.0f) - 1.0f);
        resultvector.z = scale * ((vec[2] / 32768.0f) - 1.0f);

        return resultvector;
    }

    Vector3df GetProcessedVectorFromUint16(const uint8_t* bytes)
    {
        uint16_t *vec = reinterpret_cast<uint16_t*>((uint16_t*)&bytes[0]);
        return Vector3df(vec[0],vec[1],vec[2]);
    }

    Vector3df GetProcessedVector(const uint8_t* bytes)
    {
        Vector3df resultvector = *reinterpret_cast<Vector3df*>((Vector3df*)&bytes[0]);
        return resultvector;
    }

    bool IsValidPositionVector(const Vector3df &pos)
    {
        // This is a heuristic check to guard against the OpenSim server sending us stupid positions.
        if (fabs(pos.x) > 1e6f || fabs(pos.y) > 1e6f || fabs(pos.z) > 1e6f)
            return false;
        if (_isnan(pos.x) || _isnan(pos.y) || _isnan(pos.z))
            return false;
        if (!_finite(pos.x) || !_finite(pos.y) || !_finite(pos.z))
            return false;

        return true;
    }

    bool IsValidVelocityVector(const Vector3df &pos)
    {
        // This is a heuristic check to guard against the OpenSim server sending us stupid velocity vectors.
        if (fabs(pos.x) > 1e3f || fabs(pos.y) > 1e3f || fabs(pos.z) > 1e3f)
            return false;
        if (_isnan(pos.x) || _isnan(pos.y) || _isnan(pos.z))
            return false;
        if (!_finite(pos.x) || !_finite(pos.y) || !_finite(pos.z))
            return false;

        return true;
    }

    bool ReadBoolFromBytes(const uint8_t* bytes, int& idx)
    {
        bool result = *(bool*)(&bytes[idx]);
        idx += sizeof(bool);

        return result;
    }

    uint8_t ReadUInt8FromBytes(const uint8_t* bytes, int& idx)
    {
        uint8_t result = bytes[idx];
        idx++;

        return result;
    }

    uint16_t ReadUInt16FromBytes(const uint8_t* bytes, int& idx)
    {
        uint16_t result = *(uint16_t*)(&bytes[idx]);
        idx += sizeof(uint16_t);

        return result;
    }

    uint32_t ReadUInt32FromBytes(const uint8_t* bytes, int& idx)
    {
        uint32_t result = *(uint32_t*)(&bytes[idx]);
        idx += sizeof(uint32_t);

        return result;
    }

    int16_t ReadSInt16FromBytes(const uint8_t* bytes, int& idx)
    {
        int16_t result = *(int16_t*)(&bytes[idx]);
        idx += sizeof(int16_t);

        return result;
    }

    int32_t ReadSInt32FromBytes(const uint8_t* bytes, int& idx)
    {
        int32_t result = *(int32_t*)(&bytes[idx]);
        idx += sizeof(int32_t);

        return result;
    }

    float ReadFloatFromBytes(const uint8_t* bytes, int& idx)
    {
        float result = *(float*)(&bytes[idx]);
        idx += sizeof(float);

        return result;
    }

    RexUUID ReadUUIDFromBytes(const uint8_t* bytes, int& idx)
    {
        RexUUID result = *(RexUUID*)(&bytes[idx]);
        idx += sizeof(RexUUID);

        return result;
    }

    Color ReadColorFromBytes(const uint8_t* bytes, int& idx)
    {
        uint8_t r = bytes[idx++];
        uint8_t g = bytes[idx++];
        uint8_t b = bytes[idx++];
        uint8_t a = bytes[idx++];

        return Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
    }

    Color ReadColorFromBytesInverted(const uint8_t* bytes, int& idx)
    {
        uint8_t r = 255 - bytes[idx++];
        uint8_t g = 255 - bytes[idx++];
        uint8_t b = 255 - bytes[idx++];
        uint8_t a = 255 - bytes[idx++];

        return Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
    }

    std::string ReadNullTerminatedStringFromBytes(const uint8_t* bytes, int& idx)
    {
        std::string result = "";

        uint8_t readbyte = bytes[idx];
        idx++;
        while(readbyte != 0)
        {
            result.push_back((char)readbyte);
            readbyte = bytes[idx];
            idx++;
        }

        return result;
    }

    void WriteBoolToBytes(bool value, uint8_t* bytes, int& idx)
    {
        bytes[idx] = (uint8_t)value;
        idx++;
    }

    void WriteUInt8ToBytes(uint8_t value, uint8_t* bytes, int& idx)
    {
        bytes[idx] = value;
        idx++;
    }

    void WriteUInt16ToBytes(uint16_t value, uint8_t* bytes, int& idx)
    {
        *(uint16_t*)(&bytes[idx]) = value;
        idx += sizeof(uint16_t);
    }

    void WriteUInt32ToBytes(uint32_t value, uint8_t* bytes, int& idx)
    {
        *(uint32_t*)(&bytes[idx]) = value;
        idx += sizeof(uint32_t);
    }

    void WriteFloatToBytes(float value, uint8_t* bytes, int& idx)
    {
        *(float*)(&bytes[idx]) = value;
        idx += sizeof(float);
    }

    void WriteUUIDToBytes(const RexUUID &value, uint8_t* bytes, int& idx)
    {
        *(RexUUID*)(&bytes[idx]) = value;
        idx += sizeof(RexUUID);
    }

    void WriteNullTerminatedStringToBytes(const std::string& value, uint8_t* bytes, int& idx)
    {
        const char* c_str = value.c_str();

        memcpy(&bytes[idx], c_str, value.length() + 1);
        idx += value.length() + 1;
    }

    NameValueMap ParseNameValueMap(const std::string& namevalue)
    {
        // NameValue contains: "FirstName STRING RW SV <firstName>\nLastName STRING RW SV <lastName>"
        // When using rex auth <firstName> contains both first and last name and <lastName> contains the auth server address

        // Split into lines
        NameValueMap map;
        StringVector lines = SplitString(namevalue, '\n');
        for (unsigned i = 0; i < lines.size(); ++i)
        {
            StringVector line = SplitString(lines[i], ' ');
            if (line.size() > 4)
            {
                // First element is the name
                const std::string& name = line[0];
                std::string value;
                // Skip over the STRING RW SV etc. (3 values)
                // Concatenate the rest of the values
                for (unsigned j = 4; j < line.size(); ++j)
                {
                    value += line[j];
                    if (j != line.size()-1)
                        value += " ";
                }
                map[name] = value;
            }
        }

        // Parse auth server address out from the NameValue if it exists
        QString fullname = QString(map["FirstName"].c_str()) + " " + QString(map["LastName"].c_str());

        // Rex auth has: <First Last> <rex auth url>
        if (fullname.count('@') == 1)
        {
            QStringList names;
            if (fullname.contains('@'))
            {
                names = fullname.split(" ");
                foreach(QString name, names)
                {
                    if (name.contains('@'))
                    {
                        map["RexAuth"] = name.toStdString();
                        names.removeOne(name);
                    }
                }
            }
            assert(names[0].size() >= 2);
            if (names.length() >= 1)
                map["FirstName"] = names[0].toStdString();
            if (names.length() >= 2)
                map["LastName"] = names[1].toStdString();
        }
        // Web auth has: <url> <url>
        else if (fullname.count('@') == 2)
        {
            QStringList names = fullname.split(" ");
            map["FirstName"] = names[0].toStdString();
            map["LastName"] = "";
        }

        return map;
    }

    bool ReadTextureEntryBits(uint32_t& bits, int& num_bits, const uint8_t* bytes, int& idx)
    {
        bits = 0;
        num_bits = 0;
        uint8_t byte;

        do
        {
            byte = bytes[idx++];
            bits <<= 7;
            bits |= byte & 0x7f;
            num_bits += 7;
        }
        while (byte & 0x80);

        return bits != 0;
    }
}
<|endoftext|>