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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    DerivativeImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

//  Software Guide : BeginLatex
//
//  The \doxygen{DerivativeImageFilter} is used for computing the derivative
//  of an image along a particular direction.
//
//  \index{itk::DerivativeImageFilter|textbf}
//
//  Software Guide : EndLatex

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

//  Software Guide : BeginLatex
//
//  The header file corresponding to this filter should be included first.
//
//  \index{itk::DerivativeImageFilter!header|textbf}
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkDerivativeImageFilter.h"
// Software Guide : EndCodeSnippet

int main( int argc, char * argv[] )
{

  if( argc < 5 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile  derivativeOrder direction" << std::endl;
    return 1;
    }

  //  Software Guide : BeginLatex
  //
  //  Then the pixel types for input and output image must be defined and with
  //  them the image types can be instantiated. Note that it is important to
  //  select a signed type for the image, since the values of the derivatives
  //  will be positive as well as negative.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef   float  InputPixelType;
  typedef   float  OutputPixelType;

  typedef itk::Image< InputPixelType,  2 >   InputImageType;
  typedef itk::Image< OutputPixelType, 2 >   OutputImageType;
  // Software Guide : EndCodeSnippet

  typedef itk::ImageFileReader< InputImageType  >  ReaderType;
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();

  reader->SetFileName( argv[1] );
  writer->SetFileName( argv[2] );

  //  Software Guide : BeginLatex
  //
  //  Using the image types it is now possible to instantiate the filter type
  //  and create the filter object.
  //
  //  \index{itk::DerivativeImageFilter!instantiation}
  //  \index{itk::DerivativeImageFilter!New()}
  //  \index{itk::DerivativeImageFilter!Pointer}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::DerivativeImageFilter<
               InputImageType, OutputImageType >  FilterType;

  FilterType::Pointer filter = FilterType::New();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The order of the derivative is selected with the \code{SetOrder()} method.
  //  The direction along which the derivative will be computed is selected with
  //  the \code{SetDirection()} method.
  //
  //  \index{itk::DerivativeImageFilter!SetOrder()}
  //  \index{itk::DerivativeImageFilter!SetDirection()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetOrder(     atoi( argv[3] ) );
  filter->SetDirection( atoi( argv[4] ) );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The input to the filter can be taken from any other filter, for example a
  //  reader. The output can be passed down the pipeline to other filters, for
  //  example a writer. An update call on any downstream filter will trigger
  //  the execution of the mean filter.
  //
  //  \index{itk::DerivativeImageFilter!SetInput()}
  //  \index{itk::DerivativeImageFilter!GetOutput()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetInput( reader->GetOutput() );
  writer->SetInput( filter->GetOutput() );
  writer->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // \begin{figure}
  // \center
  // \includegraphics[width=6cm]{BrainProtonDensitySlice.eps}
  // \includegraphics[width=6cm]{DerivativeImageFilterOutput.eps}
  // \caption{Effect of the Derivative filter on a slice from a MRI
  // Proton Density brain image.}
  // \label{fig:DerivativeImageFilterOutput}
  // \end{figure}
  //
  //  Figure \ref{fig:DerivativeImageFilterOutput} illustrate the effect of this
  //  filter on a slice of MRI brain image. The derivative is taken along the X direction.
  //  The sensibility to noise present in the image is evident from this result.
  //
  //  Software Guide : EndLatex

  return 0;

}

<commit_msg>ENH: Normalized output added. This permits to obtain PNG images with      unsigned char pixel reascaling the intensities of the derivative.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    DerivativeImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

//  Software Guide : BeginLatex
//
//  The \doxygen{DerivativeImageFilter} is used for computing the derivative
//  of an image along a particular direction.
//
//  \index{itk::DerivativeImageFilter|textbf}
//
//  Software Guide : EndLatex

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"

//  Software Guide : BeginLatex
//
//  The header file corresponding to this filter should be included first.
//
//  \index{itk::DerivativeImageFilter!header|textbf}
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkDerivativeImageFilter.h"
// Software Guide : EndCodeSnippet

int main( int argc, char * argv[] )
{

  if( argc < 6 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << "  inputImageFile   outputImageFile  normalizedOutputImageFile ";
    std::cerr << " derivativeOrder direction" << std::endl;
    return 1;
    }

  //  Software Guide : BeginLatex
  //
  //  Then the pixel types for input and output image must be defined and with
  //  them the image types can be instantiated. Note that it is important to
  //  select a signed type for the image, since the values of the derivatives
  //  will be positive as well as negative.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef   float  InputPixelType;
  typedef   float  OutputPixelType;

  const unsigned int Dimension = 2;

  typedef itk::Image< InputPixelType,  Dimension >   InputImageType;
  typedef itk::Image< OutputPixelType, Dimension >   OutputImageType;
  // Software Guide : EndCodeSnippet

  typedef itk::ImageFileReader< InputImageType  >  ReaderType;
  typedef itk::ImageFileWriter< OutputImageType >  WriterType;

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();

  reader->SetFileName( argv[1] );
  writer->SetFileName( argv[2] );

  //  Software Guide : BeginLatex
  //
  //  Using the image types it is now possible to instantiate the filter type
  //  and create the filter object.
  //
  //  \index{itk::DerivativeImageFilter!instantiation}
  //  \index{itk::DerivativeImageFilter!New()}
  //  \index{itk::DerivativeImageFilter!Pointer}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::DerivativeImageFilter<
               InputImageType, OutputImageType >  FilterType;

  FilterType::Pointer filter = FilterType::New();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The order of the derivative is selected with the \code{SetOrder()} method.
  //  The direction along which the derivative will be computed is selected with
  //  the \code{SetDirection()} method.
  //
  //  \index{itk::DerivativeImageFilter!SetOrder()}
  //  \index{itk::DerivativeImageFilter!SetDirection()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetOrder(     atoi( argv[4] ) );
  filter->SetDirection( atoi( argv[5] ) );
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  The input to the filter can be taken from any other filter, for example a
  //  reader. The output can be passed down the pipeline to other filters, for
  //  example a writer. An update call on any downstream filter will trigger
  //  the execution of the derivative filter.
  //
  //  \index{itk::DerivativeImageFilter!SetInput()}
  //  \index{itk::DerivativeImageFilter!GetOutput()}
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  filter->SetInput( reader->GetOutput() );
  writer->SetInput( filter->GetOutput() );
  writer->Update();
  // Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  // \begin{figure}
  // \center
  // \includegraphics[width=6cm]{BrainProtonDensitySlice.eps}
  // \includegraphics[width=6cm]{DerivativeImageFilterOutput.eps}
  // \caption{Effect of the Derivative filter on a slice from a MRI
  // Proton Density brain image.}
  // \label{fig:DerivativeImageFilterOutput}
  // \end{figure}
  //
  //  Figure \ref{fig:DerivativeImageFilterOutput} illustrate the effect of this
  //  filter on a slice of MRI brain image. The derivative is taken along the X direction.
  //  The sensibility to noise present in the image is evident from this result.
  //
  //  Software Guide : EndLatex

  typedef itk::Image< unsigned char, Dimension >  WriteImageType;

  typedef itk::RescaleIntensityImageFilter<
                                  OutputImageType,
                                  WriteImageType >    NormalizeFilterType;

  typedef itk::ImageFileWriter< WriteImageType >       NormalizedWriterType;

  NormalizeFilterType::Pointer normalizer = NormalizeFilterType::New();
  NormalizedWriterType::Pointer normalizedWriter = NormalizedWriterType::New();

  normalizer->SetInput( filter->GetOutput() );
  normalizedWriter->SetInput( normalizer->GetOutput() );

  normalizer->SetOutputMinimum(   0 );
  normalizer->SetOutputMaximum( 255 );

  normalizedWriter->SetFileName( argv[3] );
  normalizedWriter->Update();

  return 0;

}

<|endoftext|>


<commit_before>// @(#)root/cont:$Name:  $:$Id: THashTable.cxx,v 1.12 2006/05/24 14:34:00 brun Exp $
// Author: Fons Rademakers   27/09/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THashTable                                                           //
//                                                                      //
// THashTable implements a hash table to store TObject's. The hash      //
// value is calculated using the value returned by the TObject's        //
// Hash() function. Each class inheriting from TObject can override     //
// Hash() as it sees fit.                                               //
// THashTable does not preserve the insertion order of the objects.     //
// If the insertion order is important AND fast retrieval is needed     //
// use THashList instead.                                               //
//Begin_Html
/*

*/
//End_Html
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "THashTable.h"
#include "TObjectTable.h"
#include "TList.h"
#include "TMath.h"
#include "TError.h"

ClassImp(THashTable)

//______________________________________________________________________________
THashTable::THashTable(Int_t capacity, Int_t rehashlevel)
{
   // Create a THashTable object. Capacity is the initial hashtable capacity
   // (i.e. number of slots), by default kInitHashTableCapacity = 17, and
   // rehashlevel is the value at which a rehash will be triggered. I.e. when
   // the average size of the linked lists at a slot becomes longer than
   // rehashlevel then the hashtable will be resized and refilled to reduce
   // the collision rate to about 1. The higher the collision rate, i.e. the
   // longer the linked lists, the longer lookup will take. If rehashlevel=0
   // the table will NOT automatically be rehashed. Use Rehash() for manual
   // rehashing.

   if (capacity < 0) {
      Warning("THashTable", "capacity (%d) < 0", capacity);
      capacity = TCollection::kInitHashTableCapacity;
   } else if (capacity == 0)
      capacity = TCollection::kInitHashTableCapacity;

   fSize = (Int_t)TMath::NextPrime(TMath::Max(capacity,(int)TCollection::kInitHashTableCapacity));
   fCont = new TList* [fSize];
   memset(fCont, 0, fSize*sizeof(TList*));

   fEntries   = 0;
   fUsedSlots = 0;
   if (rehashlevel < 2) rehashlevel = 0;
   fRehashLevel = rehashlevel;
}

//______________________________________________________________________________
THashTable::~THashTable()
{
   // Delete a hashtable. Objects are not deleted unless the THashTable is the
   // owner (set via SetOwner()).

   if (fCont) Clear();
   delete [] fCont;
   fCont = 0;
   fSize = 0;
}

//______________________________________________________________________________
void THashTable::Add(TObject *obj)
{
   // Add object to the hash table. Its position in the table will be
   // determined by the value returned by its Hash() function.

   if (IsArgNull("Add", obj)) return;

   Int_t slot = GetHashValue(obj);
   if (!fCont[slot]) {
      fCont[slot] = new TList;
      fUsedSlots++;
   }
   fCont[slot]->Add(obj);
   fEntries++;

   if (fRehashLevel && AverageCollisions() > fRehashLevel)
      Rehash(fEntries);
}

//______________________________________________________________________________
void THashTable::AddAll(const TCollection *col)
{
   // Add all objects from collection col to this collection.
   // Implemented for more efficient rehashing.

   // Hashing after AddAll can be much more expensive than
   // hashing before, as we need to add more elements.
   // We assume an ideal hash, i.e. fUsedSlots==fSize.
   Int_t sumEntries=fEntries+col->GetEntries();
   Bool_t rehashBefore=fRehashLevel && (sumEntries > fSize*fRehashLevel);
   if (rehashBefore)
      Rehash(sumEntries);

   // prevent Add from Rehashing
   Int_t saveRehashLevel=fRehashLevel;
   fRehashLevel=0;

   TCollection::AddAll(col);

   fRehashLevel=saveRehashLevel;
   // If we didn't Rehash before, we might have to do it
   // now, due to a non-perfect hash function.
   if (!rehashBefore && fRehashLevel && AverageCollisions() > fRehashLevel)
      Rehash(fEntries);
}

//______________________________________________________________________________
void THashTable::Clear(Option_t *option)
{
   // Remove all objects from the table. Does not delete the objects
   // unless the THashTable is the owner (set via SetOwner()).

   for (int i = 0; i < fSize; i++) {
      // option "nodelete" is passed when Clear is called from
      // THashList::Clear() or THashList::Delete() or Rehash().
      if (fCont[i]) {
         if (IsOwner())
            fCont[i]->SetOwner();
         fCont[i]->Clear(option);
      }
      SafeDelete(fCont[i]);
   }

   fEntries   = 0;
   fUsedSlots = 0;
}

//______________________________________________________________________________
Int_t THashTable::Collisions(const char *name) const
{
   // Returns the number of collisions for an object with a certain name
   // (i.e. number of objects in same slot in the hash table, i.e. length
   // of linked list).

   Int_t slot = GetHashValue(name);
   if (fCont[slot]) return fCont[slot]->GetSize();
   return 0;
}

//______________________________________________________________________________
Int_t THashTable::Collisions(TObject *obj) const
{
   // Returns the number of collisions for an object (i.e. number of objects
   // in same slot in the hash table, i.e. length of linked list).

   if (IsArgNull("Collisions", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->GetSize();
   return 0;
}

//______________________________________________________________________________
void THashTable::Delete(Option_t *)
{
   // Remove all objects from the table AND delete all heap based objects.

   for (int i = 0; i < fSize; i++)
      if (fCont[i]) {
         fCont[i]->Delete();
         SafeDelete(fCont[i]);
      }

   fEntries   = 0;
   fUsedSlots = 0;
}

//______________________________________________________________________________
TObject *THashTable::FindObject(const char *name) const
{
   // Find object using its name. Uses the hash value returned by the
   // TString::Hash() after converting name to a TString.

   Int_t slot = GetHashValue(name);
   if (fCont[slot]) return fCont[slot]->FindObject(name);
   return 0;
}

//______________________________________________________________________________
TObject *THashTable::FindObject(const TObject *obj) const
{
   // Find object using its hash value (returned by its Hash() member).

   if (IsArgNull("FindObject", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->FindObject(obj);
   return 0;
}

//______________________________________________________________________________
TList *THashTable::GetListForObject(const char *name) const
{
   // Return the TList corresponding to object's name based hash value.
   // One can iterate this list "manually" to find, e.g. objects with
   // the same name.

   return fCont[GetHashValue(name)];
}

//______________________________________________________________________________
TList *THashTable::GetListForObject(const TObject *obj) const
{
   // Return the TList corresponding to object's hash value.
   // One can iterate this list "manually" to find, e.g. identical
   // objects.

   if (IsArgNull("GetListForObject", obj)) return 0;
   return fCont[GetHashValue(obj)];
}

//______________________________________________________________________________
TObject **THashTable::GetObjectRef(const TObject *obj) const
{
   // Return address of pointer to obj

   if (IsArgNull("GetObjectRef", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->GetObjectRef(obj);
   return 0;
}

//______________________________________________________________________________
TIterator *THashTable::MakeIterator(Bool_t dir) const
{
   // Returns a hash table iterator.

   return new THashTableIter(this, dir);
}

//______________________________________________________________________________
void THashTable::Rehash(Int_t newCapacity, Bool_t checkObjValidity)
{
   // Rehash the hashtable. If the collision rate becomes too high (i.e.
   // the average size of the linked lists become too long) then lookup
   // efficiency decreases since relatively long lists have to be searched
   // every time. To improve performance rehash the hashtable. This resizes
   // the table to newCapacity slots and refills the table. Use
   // AverageCollisions() to check if you need to rehash. Set checkObjValidity
   // to kFALSE if you know that all objects in the table are still valid
   // (i.e. have not been deleted from the system in the meanwhile).

   THashTable *ht = new THashTable(newCapacity);

   TIter next(this);
   TObject *obj;

   if (checkObjValidity && TObject::GetObjectStat() && gObjectTable) {
      while ((obj = next()))
         if (gObjectTable->PtrIsValid(obj)) ht->Add(obj);
   } else {
      while ((obj = next()))
         ht->Add(obj);
   }

   Clear("nodelete");
   delete [] fCont;
   fCont = ht->fCont;
   ht->fCont = 0;

   fSize      = ht->fSize;     // idem
   fEntries   = ht->fEntries;
   fUsedSlots = ht->fUsedSlots;

   // this should not happen, but it will prevent an endless loop
   // in case of a very bad hash function
   if (fRehashLevel && AverageCollisions() > fRehashLevel)
      fRehashLevel = (int)AverageCollisions() + 1;

   delete ht;
}

//______________________________________________________________________________
TObject *THashTable::Remove(TObject *obj)
{
   // Remove object from the hashtable.

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) {
      TObject *ob = fCont[slot]->Remove(obj);
      if (ob) {
         fEntries--;
         if (fCont[slot]->GetSize() == 0) {
            SafeDelete(fCont[slot]);
            fUsedSlots--;
         }
         return ob;
      }
   }
   return 0;
}

//______________________________________________________________________________
TObject *THashTable::RemoveSlow(TObject *obj)
{
   // Remove object from the hashtable without using the hash value.

   for (int i = 0; i < fSize; i++) {
      if (fCont[i]) {
         TObject *ob = fCont[i]->Remove(obj);
         if (ob) {
            fEntries--;
            if (fCont[i]->GetSize() == 0) {
               SafeDelete(fCont[i]);
               fUsedSlots--;
            }
            return ob;
         }
      }
   }
   return 0;
}

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THashTableIter                                                       //
//                                                                      //
// Iterator of hash table.                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(THashTableIter)

//______________________________________________________________________________
THashTableIter::THashTableIter(const THashTable *ht, Bool_t dir)
{
   // Create a hashtable iterator. By default the iteration direction
   // is kIterForward. To go backward use kIterBackward.

   fTable      = ht;
   fDirection  = dir;
   fListCursor = 0;
   Reset();
}

//______________________________________________________________________________
THashTableIter::THashTableIter(const THashTableIter &iter) : TIterator(iter)
{
   // Copy ctor.

   fTable      = iter.fTable;
   fDirection  = iter.fDirection;
   fCursor     = iter.fCursor;
   if (iter.fListCursor) {
      fListCursor = (TListIter *)iter.fListCursor->GetCollection()->MakeIterator();
      fListCursor->operator=(*iter.fListCursor);
   }
}

//______________________________________________________________________________
TIterator &THashTableIter::operator=(const TIterator &rhs)
{
   // Overridden assignment operator.

   if (this != &rhs && rhs.IsA() == THashTableIter::Class()) {
      const THashTableIter &rhs1 = (const THashTableIter &)rhs;
      fTable     = rhs1.fTable;
      fDirection = rhs1.fDirection;
      fCursor    = rhs1.fCursor;
      if (rhs1.fListCursor) {
         fListCursor = (TListIter *)rhs1.fListCursor->GetCollection()->MakeIterator();
         fListCursor->operator=(*rhs1.fListCursor);
      }
   }
   return *this;
}

//______________________________________________________________________________
THashTableIter &THashTableIter::operator=(const THashTableIter &rhs)
{
   // Overloaded assignment operator.

   if (this != &rhs) {
      fTable     = rhs.fTable;
      fDirection = rhs.fDirection;
      fCursor    = rhs.fCursor;
      if (rhs.fListCursor) {
         fListCursor = (TListIter *)rhs.fListCursor->GetCollection()->MakeIterator();
         fListCursor->operator=(*rhs.fListCursor);
      }
   }
   return *this;
}

//______________________________________________________________________________
THashTableIter::~THashTableIter()
{
   // Delete hashtable iterator.

   delete fListCursor;
}

//______________________________________________________________________________
TObject *THashTableIter::Next()
{
   // Return next object in hashtable. Returns 0 when no more objects in table.

   if (!fListCursor) {
      int slot = NextSlot();
      if (slot == -1) return 0;
      fListCursor = new TListIter(fTable->fCont[slot], fDirection);
   }

   TObject *obj = fListCursor->Next();

   if (!obj) {
      SafeDelete(fListCursor);
      return Next();
   }
   return obj;
}

//______________________________________________________________________________
Int_t THashTableIter::NextSlot()
{
   // Returns index of next slot in table containing list to be iterated.

   if (fDirection == kIterForward) {
      for ( ; fCursor < fTable->Capacity() && fTable->fCont[fCursor] == 0;
              fCursor++) { }

      if (fCursor < fTable->Capacity())
         return fCursor++;

   } else {
      for ( ; fCursor >= 0 && fTable->fCont[fCursor] == 0;
              fCursor--) { }

      if (fCursor >= 0)
         return fCursor--;
   }
   return -1;
}

//______________________________________________________________________________
void THashTableIter::Reset()
{
   // Reset the hashtable iterator. Either to beginning or end, depending on
   // the initial iteration direction.

   if (fDirection == kIterForward)
      fCursor = 0;
   else
      fCursor = fTable->Capacity() - 1;
   SafeDelete(fListCursor);
}
<commit_msg>From Maarten: avoid a potentially very deep recursion.<commit_after>// @(#)root/cont:$Name:  $:$Id: THashTable.cxx,v 1.13 2006/07/26 13:36:42 rdm Exp $
// Author: Fons Rademakers   27/09/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THashTable                                                           //
//                                                                      //
// THashTable implements a hash table to store TObject's. The hash      //
// value is calculated using the value returned by the TObject's        //
// Hash() function. Each class inheriting from TObject can override     //
// Hash() as it sees fit.                                               //
// THashTable does not preserve the insertion order of the objects.     //
// If the insertion order is important AND fast retrieval is needed     //
// use THashList instead.                                               //
//Begin_Html
/*

*/
//End_Html
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "THashTable.h"
#include "TObjectTable.h"
#include "TList.h"
#include "TMath.h"
#include "TError.h"

ClassImp(THashTable)

//______________________________________________________________________________
THashTable::THashTable(Int_t capacity, Int_t rehashlevel)
{
   // Create a THashTable object. Capacity is the initial hashtable capacity
   // (i.e. number of slots), by default kInitHashTableCapacity = 17, and
   // rehashlevel is the value at which a rehash will be triggered. I.e. when
   // the average size of the linked lists at a slot becomes longer than
   // rehashlevel then the hashtable will be resized and refilled to reduce
   // the collision rate to about 1. The higher the collision rate, i.e. the
   // longer the linked lists, the longer lookup will take. If rehashlevel=0
   // the table will NOT automatically be rehashed. Use Rehash() for manual
   // rehashing.

   if (capacity < 0) {
      Warning("THashTable", "capacity (%d) < 0", capacity);
      capacity = TCollection::kInitHashTableCapacity;
   } else if (capacity == 0)
      capacity = TCollection::kInitHashTableCapacity;

   fSize = (Int_t)TMath::NextPrime(TMath::Max(capacity,(int)TCollection::kInitHashTableCapacity));
   fCont = new TList* [fSize];
   memset(fCont, 0, fSize*sizeof(TList*));

   fEntries   = 0;
   fUsedSlots = 0;
   if (rehashlevel < 2) rehashlevel = 0;
   fRehashLevel = rehashlevel;
}

//______________________________________________________________________________
THashTable::~THashTable()
{
   // Delete a hashtable. Objects are not deleted unless the THashTable is the
   // owner (set via SetOwner()).

   if (fCont) Clear();
   delete [] fCont;
   fCont = 0;
   fSize = 0;
}

//______________________________________________________________________________
void THashTable::Add(TObject *obj)
{
   // Add object to the hash table. Its position in the table will be
   // determined by the value returned by its Hash() function.

   if (IsArgNull("Add", obj)) return;

   Int_t slot = GetHashValue(obj);
   if (!fCont[slot]) {
      fCont[slot] = new TList;
      fUsedSlots++;
   }
   fCont[slot]->Add(obj);
   fEntries++;

   if (fRehashLevel && AverageCollisions() > fRehashLevel)
      Rehash(fEntries);
}

//______________________________________________________________________________
void THashTable::AddAll(const TCollection *col)
{
   // Add all objects from collection col to this collection.
   // Implemented for more efficient rehashing.

   // Hashing after AddAll can be much more expensive than
   // hashing before, as we need to add more elements.
   // We assume an ideal hash, i.e. fUsedSlots==fSize.
   Int_t sumEntries=fEntries+col->GetEntries();
   Bool_t rehashBefore=fRehashLevel && (sumEntries > fSize*fRehashLevel);
   if (rehashBefore)
      Rehash(sumEntries);

   // prevent Add from Rehashing
   Int_t saveRehashLevel=fRehashLevel;
   fRehashLevel=0;

   TCollection::AddAll(col);

   fRehashLevel=saveRehashLevel;
   // If we didn't Rehash before, we might have to do it
   // now, due to a non-perfect hash function.
   if (!rehashBefore && fRehashLevel && AverageCollisions() > fRehashLevel)
      Rehash(fEntries);
}

//______________________________________________________________________________
void THashTable::Clear(Option_t *option)
{
   // Remove all objects from the table. Does not delete the objects
   // unless the THashTable is the owner (set via SetOwner()).

   for (int i = 0; i < fSize; i++) {
      // option "nodelete" is passed when Clear is called from
      // THashList::Clear() or THashList::Delete() or Rehash().
      if (fCont[i]) {
         if (IsOwner())
            fCont[i]->SetOwner();
         fCont[i]->Clear(option);
      }
      SafeDelete(fCont[i]);
   }

   fEntries   = 0;
   fUsedSlots = 0;
}

//______________________________________________________________________________
Int_t THashTable::Collisions(const char *name) const
{
   // Returns the number of collisions for an object with a certain name
   // (i.e. number of objects in same slot in the hash table, i.e. length
   // of linked list).

   Int_t slot = GetHashValue(name);
   if (fCont[slot]) return fCont[slot]->GetSize();
   return 0;
}

//______________________________________________________________________________
Int_t THashTable::Collisions(TObject *obj) const
{
   // Returns the number of collisions for an object (i.e. number of objects
   // in same slot in the hash table, i.e. length of linked list).

   if (IsArgNull("Collisions", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->GetSize();
   return 0;
}

//______________________________________________________________________________
void THashTable::Delete(Option_t *)
{
   // Remove all objects from the table AND delete all heap based objects.

   for (int i = 0; i < fSize; i++)
      if (fCont[i]) {
         fCont[i]->Delete();
         SafeDelete(fCont[i]);
      }

   fEntries   = 0;
   fUsedSlots = 0;
}

//______________________________________________________________________________
TObject *THashTable::FindObject(const char *name) const
{
   // Find object using its name. Uses the hash value returned by the
   // TString::Hash() after converting name to a TString.

   Int_t slot = GetHashValue(name);
   if (fCont[slot]) return fCont[slot]->FindObject(name);
   return 0;
}

//______________________________________________________________________________
TObject *THashTable::FindObject(const TObject *obj) const
{
   // Find object using its hash value (returned by its Hash() member).

   if (IsArgNull("FindObject", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->FindObject(obj);
   return 0;
}

//______________________________________________________________________________
TList *THashTable::GetListForObject(const char *name) const
{
   // Return the TList corresponding to object's name based hash value.
   // One can iterate this list "manually" to find, e.g. objects with
   // the same name.

   return fCont[GetHashValue(name)];
}

//______________________________________________________________________________
TList *THashTable::GetListForObject(const TObject *obj) const
{
   // Return the TList corresponding to object's hash value.
   // One can iterate this list "manually" to find, e.g. identical
   // objects.

   if (IsArgNull("GetListForObject", obj)) return 0;
   return fCont[GetHashValue(obj)];
}

//______________________________________________________________________________
TObject **THashTable::GetObjectRef(const TObject *obj) const
{
   // Return address of pointer to obj

   if (IsArgNull("GetObjectRef", obj)) return 0;

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) return fCont[slot]->GetObjectRef(obj);
   return 0;
}

//______________________________________________________________________________
TIterator *THashTable::MakeIterator(Bool_t dir) const
{
   // Returns a hash table iterator.

   return new THashTableIter(this, dir);
}

//______________________________________________________________________________
void THashTable::Rehash(Int_t newCapacity, Bool_t checkObjValidity)
{
   // Rehash the hashtable. If the collision rate becomes too high (i.e.
   // the average size of the linked lists become too long) then lookup
   // efficiency decreases since relatively long lists have to be searched
   // every time. To improve performance rehash the hashtable. This resizes
   // the table to newCapacity slots and refills the table. Use
   // AverageCollisions() to check if you need to rehash. Set checkObjValidity
   // to kFALSE if you know that all objects in the table are still valid
   // (i.e. have not been deleted from the system in the meanwhile).

   THashTable *ht = new THashTable(newCapacity);

   TIter next(this);
   TObject *obj;

   if (checkObjValidity && TObject::GetObjectStat() && gObjectTable) {
      while ((obj = next()))
         if (gObjectTable->PtrIsValid(obj)) ht->Add(obj);
   } else {
      while ((obj = next()))
         ht->Add(obj);
   }

   Clear("nodelete");
   delete [] fCont;
   fCont = ht->fCont;
   ht->fCont = 0;

   fSize      = ht->fSize;     // idem
   fEntries   = ht->fEntries;
   fUsedSlots = ht->fUsedSlots;

   // this should not happen, but it will prevent an endless loop
   // in case of a very bad hash function
   if (fRehashLevel && AverageCollisions() > fRehashLevel)
      fRehashLevel = (int)AverageCollisions() + 1;

   delete ht;
}

//______________________________________________________________________________
TObject *THashTable::Remove(TObject *obj)
{
   // Remove object from the hashtable.

   Int_t slot = GetHashValue(obj);
   if (fCont[slot]) {
      TObject *ob = fCont[slot]->Remove(obj);
      if (ob) {
         fEntries--;
         if (fCont[slot]->GetSize() == 0) {
            SafeDelete(fCont[slot]);
            fUsedSlots--;
         }
         return ob;
      }
   }
   return 0;
}

//______________________________________________________________________________
TObject *THashTable::RemoveSlow(TObject *obj)
{
   // Remove object from the hashtable without using the hash value.

   for (int i = 0; i < fSize; i++) {
      if (fCont[i]) {
         TObject *ob = fCont[i]->Remove(obj);
         if (ob) {
            fEntries--;
            if (fCont[i]->GetSize() == 0) {
               SafeDelete(fCont[i]);
               fUsedSlots--;
            }
            return ob;
         }
      }
   }
   return 0;
}

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THashTableIter                                                       //
//                                                                      //
// Iterator of hash table.                                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(THashTableIter)

//______________________________________________________________________________
THashTableIter::THashTableIter(const THashTable *ht, Bool_t dir)
{
   // Create a hashtable iterator. By default the iteration direction
   // is kIterForward. To go backward use kIterBackward.

   fTable      = ht;
   fDirection  = dir;
   fListCursor = 0;
   Reset();
}

//______________________________________________________________________________
THashTableIter::THashTableIter(const THashTableIter &iter) : TIterator(iter)
{
   // Copy ctor.

   fTable      = iter.fTable;
   fDirection  = iter.fDirection;
   fCursor     = iter.fCursor;
   if (iter.fListCursor) {
      fListCursor = (TListIter *)iter.fListCursor->GetCollection()->MakeIterator();
      fListCursor->operator=(*iter.fListCursor);
   }
}

//______________________________________________________________________________
TIterator &THashTableIter::operator=(const TIterator &rhs)
{
   // Overridden assignment operator.

   if (this != &rhs && rhs.IsA() == THashTableIter::Class()) {
      const THashTableIter &rhs1 = (const THashTableIter &)rhs;
      fTable     = rhs1.fTable;
      fDirection = rhs1.fDirection;
      fCursor    = rhs1.fCursor;
      if (rhs1.fListCursor) {
         fListCursor = (TListIter *)rhs1.fListCursor->GetCollection()->MakeIterator();
         fListCursor->operator=(*rhs1.fListCursor);
      }
   }
   return *this;
}

//______________________________________________________________________________
THashTableIter &THashTableIter::operator=(const THashTableIter &rhs)
{
   // Overloaded assignment operator.

   if (this != &rhs) {
      fTable     = rhs.fTable;
      fDirection = rhs.fDirection;
      fCursor    = rhs.fCursor;
      if (rhs.fListCursor) {
         fListCursor = (TListIter *)rhs.fListCursor->GetCollection()->MakeIterator();
         fListCursor->operator=(*rhs.fListCursor);
      }
   }
   return *this;
}

//______________________________________________________________________________
THashTableIter::~THashTableIter()
{
   // Delete hashtable iterator.

   delete fListCursor;
}

//______________________________________________________________________________
TObject *THashTableIter::Next()
{
   // Return next object in hashtable. Returns 0 when no more objects in table.

   while (kTRUE) {
      if (!fListCursor) {
         int slot = NextSlot();
         if (slot == -1) return 0;
         fListCursor = new TListIter(fTable->fCont[slot], fDirection);
      }

      TObject *obj = fListCursor->Next();
      if (obj) return obj;

      SafeDelete(fListCursor);
   }
}

//______________________________________________________________________________
Int_t THashTableIter::NextSlot()
{
   // Returns index of next slot in table containing list to be iterated.

   if (fDirection == kIterForward) {
      for ( ; fCursor < fTable->Capacity() && fTable->fCont[fCursor] == 0;
              fCursor++) { }

      if (fCursor < fTable->Capacity())
         return fCursor++;

   } else {
      for ( ; fCursor >= 0 && fTable->fCont[fCursor] == 0;
              fCursor--) { }

      if (fCursor >= 0)
         return fCursor--;
   }
   return -1;
}

//______________________________________________________________________________
void THashTableIter::Reset()
{
   // Reset the hashtable iterator. Either to beginning or end, depending on
   // the initial iteration direction.

   if (fDirection == kIterForward)
      fCursor = 0;
   else
      fCursor = fTable->Capacity() - 1;
   SafeDelete(fListCursor);
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.
 *
 *=========================================================================*/

// First include the header file to be tested:
#include "elxConversion.h"

#include <gtest/gtest.h>

#include <limits>
#include <string>
#include <vector>

#include <itkImageBase.h>
#include <itkIndex.h>
#include <itkOptimizerParameters.h>
#include <itkPoint.h>
#include <itkSize.h>
#include <itkVector.h>

// The class to be tested.
using elastix::Conversion;

namespace
{
template <typename TContainer>
void
Expect_GetNumberOfElements_returns_size(const TContainer & container)
{
  EXPECT_EQ(Conversion::GetNumberOfElements(container), container.size());
}
} // namespace

GTEST_TEST(Conversion, GetNumberOfParameters)
{
  Expect_GetNumberOfElements_returns_size(itk::Size<>{});
  Expect_GetNumberOfElements_returns_size(itk::Index<>{});

  // Note: Currently we still support ITK 5.1.1, which does not yet have a
  // size() member function for itk::Point and itk::Vector.
  EXPECT_EQ(Conversion::GetNumberOfElements(itk::Point<double>{}), 3);
  EXPECT_EQ(Conversion::GetNumberOfElements(itk::Vector<double>{}), 3);

  for (std::size_t i{}; i <= 2; ++i)
  {
    Expect_GetNumberOfElements_returns_size(itk::OptimizerParameters<double>(i));
  }
}

GTEST_TEST(Conversion, BoolToString)
{
  // Tests that BoolToString can be evaluated at compile-time.
  static_assert((Conversion::BoolToString(false) != nullptr) && (Conversion::BoolToString(true) != nullptr),
                "BoolToString(bool) does not return nullptr");

  EXPECT_EQ(Conversion::BoolToString(false), std::string{ "false" });
  EXPECT_EQ(Conversion::BoolToString(true), std::string{ "true" });
}

GTEST_TEST(Conversion, ParameterMapToString)
{
  EXPECT_EQ(Conversion::ParameterMapToString({}), std::string{});
  EXPECT_EQ(Conversion::ParameterMapToString({ { "A", {} } }), "(A)\n");
  EXPECT_EQ(Conversion::ParameterMapToString({ { "Numbers", { "0", "1" } } }), "(Numbers 0 1)\n");
  EXPECT_EQ(Conversion::ParameterMapToString({ { "Letters", { "a", "z" } } }), "(Letters \"a\" \"z\")\n");

  // A realistic example:
  const std::string expectedString = R"((Direction 0 0 0 0)
(FixedImageDimension 2)
(FixedInternalImagePixelType "float")
(HowToCombineTransforms "Compose")
(Index 0 0)
(InitialTransformParametersFileName "NoInitialTransform")
(MovingImageDimension 2)
(MovingInternalImagePixelType "float")
(NumberOfParameters 2)
(Origin 0 0)
(Size 0 0)
(Spacing 1 1)
(Transform "TranslationTransform")
(TransformParameters 0 0)
(UseBinaryFormatForTransformationParameters "false")
(UseDirectionCosines "true")
)";

  EXPECT_EQ(Conversion::ParameterMapToString({ { "Direction", { "0", "0", "0", "0" } },
                                               { "FixedImageDimension", { "2" } },
                                               { "FixedInternalImagePixelType", { "float" } },
                                               { "HowToCombineTransforms", { "Compose" } },
                                               { "Index", { "0", "0" } },
                                               { "InitialTransformParametersFileName", { "NoInitialTransform" } },
                                               { "MovingImageDimension", { "2" } },
                                               { "MovingInternalImagePixelType", { "float" } },
                                               { "NumberOfParameters", { "2" } },
                                               { "Origin", { "0", "0" } },
                                               { "Size", { "0", "0" } },
                                               { "Spacing", { "1", "1" } },
                                               { "Transform", { "TranslationTransform" } },
                                               { "TransformParameters", { "0", "0" } },
                                               { "UseBinaryFormatForTransformationParameters", { "false" } },
                                               { "UseDirectionCosines", { "true" } } }),
            expectedString);
}

GTEST_TEST(Conversion, ToString)
{
  // Note that this is different from std::to_string(false) and
  // std::to_string(true), which return "0" and "1", respecively.
  EXPECT_EQ(Conversion::ToString(false), "false");
  EXPECT_EQ(Conversion::ToString(true), "true");

  EXPECT_EQ(Conversion::ToString(0), "0");
  EXPECT_EQ(Conversion::ToString(1), "1");
  EXPECT_EQ(Conversion::ToString(-1), "-1");

  EXPECT_EQ(Conversion::ToString(std::numeric_limits<std::int64_t>::min()), "-9223372036854775808");
  EXPECT_EQ(Conversion::ToString(std::numeric_limits<std::uint64_t>::max()), "18446744073709551615");

  // Extensive tests of conversion from double to string:

  using DoubleLimits = std::numeric_limits<double>;

  // Note that this is different from std::to_string(0.5), which returns "0.500000"
  EXPECT_EQ(Conversion::ToString(0.5), "0.5");

  constexpr auto expectedPrecision = 16;
  static_assert(expectedPrecision == std::numeric_limits<double>::digits10 + 1,
                "The expected precision for double floating point numbers");
  const auto expectedString = "0." + std::string(expectedPrecision, '3');

  EXPECT_EQ(Conversion::ToString(+0.0), "0");
  EXPECT_EQ(Conversion::ToString(-0.0), "0");
  EXPECT_EQ(Conversion::ToString(+1.0), "1");
  EXPECT_EQ(Conversion::ToString(-1.0), "-1");
  EXPECT_EQ(Conversion::ToString(0.1), "0.1");
  EXPECT_EQ(Conversion::ToString(1.0 / 3.0), "0." + std::string(expectedPrecision, '3'));

  for (std::uint8_t exponent{ 20 }; exponent > 0; --exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 1000...000
    EXPECT_EQ(Conversion::ToString(power_of_ten), '1' + std::string(exponent, '0'));
    EXPECT_EQ(Conversion::ToString(-power_of_ten), "-1" + std::string(exponent, '0'));
  }

  for (std::uint8_t exponent{ 15 }; exponent > 0; --exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 999...999
    EXPECT_EQ(Conversion::ToString(power_of_ten - 1), std::string(exponent, '9'));
    EXPECT_EQ(Conversion::ToString(1 - power_of_ten), '-' + std::string(exponent, '9'));
  }

  for (std::int8_t exponent{ -6 }; exponent < 0; ++exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 0.000...001
    EXPECT_EQ(Conversion::ToString(power_of_ten), "0." + std::string(-1 - exponent, '0') + '1');
    EXPECT_EQ(Conversion::ToString(-power_of_ten), "-0." + std::string(-1 - exponent, '0') + '1');
  }

  for (std::int8_t exponent{ -16 }; exponent < 0; ++exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 0.999...999
    EXPECT_EQ(Conversion::ToString(1 - power_of_ten), "0." + std::string(-exponent, '9'));
    EXPECT_EQ(Conversion::ToString(power_of_ten - 1), "-0." + std::string(-exponent, '9'));
  }

  // The first powers of ten that are represented by scientific "e" notation:
  EXPECT_EQ(Conversion::ToString(1e+21), "1e+21");
  EXPECT_EQ(Conversion::ToString(1e-7), "1e-7");

  // Test the most relevant constants from <limits>:
  EXPECT_EQ(Conversion::ToString(DoubleLimits::epsilon()), "2.220446049250313e-16");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::min()), "2.2250738585072014e-308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::lowest()), "-1.7976931348623157e+308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::max()), "1.7976931348623157e+308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::quiet_NaN()), "NaN");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::quiet_NaN()), "NaN");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::infinity()), "Infinity");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::infinity()), "-Infinity");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::denorm_min()), "5e-324");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::denorm_min()), "-5e-324");
}

GTEST_TEST(Conversion, ToVectorOfStrings)
{
  using VectorOfStrings = std::vector<std::string>;
  using ArrayOfDoubles = std::array<double, 3>;

  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Size<>{ 1, 2 }), VectorOfStrings({ "1", "2" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Index<>{ 1, 2 }), VectorOfStrings({ "1", "2" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Point<double>(ArrayOfDoubles{ -0.5, 0.0, 0.25 })),
            VectorOfStrings({ "-0.5", "0", "0.25" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Vector<double>(ArrayOfDoubles{ -0.5, 0.0, 0.25 }.data())),
            VectorOfStrings({ "-0.5", "0", "0.25" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::OptimizerParameters<double>{}), VectorOfStrings{});
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::ImageBase<>::DirectionType{}), VectorOfStrings({ "0", "0", "0", "0" }));
}

GTEST_TEST(Conversion, ConcatenateVectors)
{
  using VectorType = std::vector<std::string>;

  const auto expectConcatenation = [](const VectorType & vector1, const VectorType & vector2) {
    auto expectedResult = vector1;

    for (const auto & element : vector2)
    {
      expectedResult.push_back(element);
    }
    EXPECT_EQ(Conversion::ConcatenateVectors(vector1, vector2), expectedResult);
  };

  expectConcatenation({}, {});
  expectConcatenation({ "1" }, {});
  expectConcatenation({}, { "1" });
  expectConcatenation({ "1" }, { "2", "3" });
}

GTEST_TEST(Conversion, IsNumberReturnsFalseOnNonNumericString)
{
  const auto expect_IsNumber_returns_false = [](const std::string & str) {
    SCOPED_TRACE(str);
    EXPECT_FALSE(Conversion::IsNumber(str));
  };

  for (const auto str : { "", " ", "a", "A B C", "true", "false", "nan", "NaN" })
  {
    expect_IsNumber_returns_false(str);
  }

  for (const auto transformName : { "AffineDTITransform",
                                    "AffineLogStackTransform",
                                    "AffineLogTransform",
                                    "AffineTransform",
                                    "BSplineStackTransform",
                                    "BSplineTransform",
                                    "BSplineTransformWithDiffusion",
                                    "DeformationFieldTransform",
                                    "EulerStackTransform",
                                    "EulerTransform",
                                    "MultiBSplineTransformWithNormal",
                                    "RecursiveBSplineTransform",
                                    "SimilarityTransform",
                                    "SplineKernelTransform",
                                    "TranslationStackTransform",
                                    "TranslationTransform",
                                    "WeightedCombinationTransform" })
  {
    expect_IsNumber_returns_false(transformName);
  }
}

GTEST_TEST(Conversion, IsNumberReturnsTrueOnNumericString)
{
  const auto expect_IsNumber_returns_true = [](const std::string & str) {
    SCOPED_TRACE(str);
    EXPECT_TRUE(Conversion::IsNumber(str));
  };

  for (int i{ -10 }; i < 10; ++i)
  {
    expect_IsNumber_returns_true(Conversion::ToString(i));
  }

  expect_IsNumber_returns_true("1e+21");
  expect_IsNumber_returns_true("1e-7");

  for (double d{ -1.0 }; d < 1.0; d += 0.1)
  {
    expect_IsNumber_returns_true(Conversion::ToString(d));
  }

  using limits = std::numeric_limits<double>;

  for (const auto limit : { limits::min(), limits::max(), limits::epsilon(), limits::lowest(), limits::denorm_min() })
  {
    expect_IsNumber_returns_true(Conversion::ToString(limit));
  }
}
<commit_msg>ENH: Add Conversion.LosslessRoundTripOfParameterValue GTest unit test<commit_after>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.
 *
 *=========================================================================*/

// First include the header file to be tested:
#include "elxConversion.h"

#include "itkParameterMapInterface.h"

#include <gtest/gtest.h>

#include <initializer_list>
#include <limits>
#include <string>
#include <type_traits> // For is_floating_point.
#include <vector>

#include <itkImageBase.h>
#include <itkIndex.h>
#include <itkOptimizerParameters.h>
#include <itkPoint.h>
#include <itkSize.h>
#include <itkVector.h>

// The class to be tested.
using elastix::Conversion;

namespace
{
template <typename TContainer>
void
Expect_GetNumberOfElements_returns_size(const TContainer & container)
{
  EXPECT_EQ(Conversion::GetNumberOfElements(container), container.size());
}

template <typename TParameterValue>
void
Expect_lossless_round_trip_of_parameter_value(const TParameterValue & parameterValue)
{
  const std::string                                  parameterName("Key");
  const itk::ParameterMapInterface::ParameterMapType parameterMap{ { parameterName,
                                                                     { Conversion::ToString(parameterValue) } } };
  const auto                                         parameterMapInterface = itk::ParameterMapInterface::New();

  parameterMapInterface->SetParameterMap(parameterMap);

  TParameterValue actualParameterValue{};

  std::string errorMessage;
  try
  {
    parameterMapInterface->ReadParameter(actualParameterValue, parameterName, 0, errorMessage);
  }
  catch (const itk::ExceptionObject & exceptionObject)
  {
    EXPECT_EQ(exceptionObject.what(), std::string{});
  }
  EXPECT_EQ(errorMessage, std::string{});
  EXPECT_EQ(actualParameterValue, parameterValue);
}

template <typename TParameterValue>
void
Expect_lossless_round_trip_of_parameter_values(const std::initializer_list<TParameterValue> & parameterValues)
{
  for (const auto parameterValue : parameterValues)
  {
    Expect_lossless_round_trip_of_parameter_value(parameterValue);
  }
}

template <typename TUnsignedInteger>
void
Expect_lossless_round_trip_of_unsigned_parameter_values()
{
  using NumericLimits = std::numeric_limits<TUnsignedInteger>;
  static_assert(!NumericLimits::is_signed, "This function is only meant to test unsigned types!");

  // Note: the static_cast for `NumericLimits::max() - 1` is a workaround for
  // the following compile error from Visual C++ 2017:
  // > error C2398: Element '3': conversion from 'int' to 'TUnsignedInteger' requires a narrowing conversion
  Expect_lossless_round_trip_of_parameter_values<TUnsignedInteger>(
    { 0, 1, static_cast<TUnsignedInteger>(NumericLimits::max() - 1), NumericLimits::max() });
}

template <typename TSignedInteger>
void
Expect_lossless_round_trip_of_signed_integer_parameter_values()
{
  using NumericLimits = std::numeric_limits<TSignedInteger>;

  static_assert(NumericLimits::is_signed && NumericLimits::is_integer,
                "This function is only meant to test signed integer types!");

  const auto minValue = NumericLimits::min();
  const auto maxValue = NumericLimits::max();

  Expect_lossless_round_trip_of_parameter_values<TSignedInteger>(
    { minValue, minValue + 1, -1, 0, 1, maxValue - 1, maxValue });
}

template <typename TFloatingPoint>
void
Expect_lossless_round_trip_of_floating_point_parameter_values()
{
  static_assert(std::is_floating_point<TFloatingPoint>::value,
                "This function is only meant to test floating point types!");

  using NumericLimits = std::numeric_limits<TFloatingPoint>;

  Expect_lossless_round_trip_of_parameter_values<TFloatingPoint>({ NumericLimits::lowest(),
                                                                   -1,
                                                                   -NumericLimits::epsilon(),
                                                                   -NumericLimits::min(),
                                                                   -NumericLimits::denorm_min(),
                                                                   -TFloatingPoint{}, // Minus zero
                                                                   0,
                                                                   NumericLimits::denorm_min(),
                                                                   NumericLimits::min(),
                                                                   NumericLimits::epsilon(),
                                                                   1,
                                                                   NumericLimits::max() });
}

} // namespace

GTEST_TEST(Conversion, GetNumberOfParameters)
{
  Expect_GetNumberOfElements_returns_size(itk::Size<>{});
  Expect_GetNumberOfElements_returns_size(itk::Index<>{});

  // Note: Currently we still support ITK 5.1.1, which does not yet have a
  // size() member function for itk::Point and itk::Vector.
  EXPECT_EQ(Conversion::GetNumberOfElements(itk::Point<double>{}), 3);
  EXPECT_EQ(Conversion::GetNumberOfElements(itk::Vector<double>{}), 3);

  for (std::size_t i{}; i <= 2; ++i)
  {
    Expect_GetNumberOfElements_returns_size(itk::OptimizerParameters<double>(i));
  }
}

GTEST_TEST(Conversion, BoolToString)
{
  // Tests that BoolToString can be evaluated at compile-time.
  static_assert((Conversion::BoolToString(false) != nullptr) && (Conversion::BoolToString(true) != nullptr),
                "BoolToString(bool) does not return nullptr");

  EXPECT_EQ(Conversion::BoolToString(false), std::string{ "false" });
  EXPECT_EQ(Conversion::BoolToString(true), std::string{ "true" });
}

GTEST_TEST(Conversion, ParameterMapToString)
{
  EXPECT_EQ(Conversion::ParameterMapToString({}), std::string{});
  EXPECT_EQ(Conversion::ParameterMapToString({ { "A", {} } }), "(A)\n");
  EXPECT_EQ(Conversion::ParameterMapToString({ { "Numbers", { "0", "1" } } }), "(Numbers 0 1)\n");
  EXPECT_EQ(Conversion::ParameterMapToString({ { "Letters", { "a", "z" } } }), "(Letters \"a\" \"z\")\n");

  // A realistic example:
  const std::string expectedString = R"((Direction 0 0 0 0)
(FixedImageDimension 2)
(FixedInternalImagePixelType "float")
(HowToCombineTransforms "Compose")
(Index 0 0)
(InitialTransformParametersFileName "NoInitialTransform")
(MovingImageDimension 2)
(MovingInternalImagePixelType "float")
(NumberOfParameters 2)
(Origin 0 0)
(Size 0 0)
(Spacing 1 1)
(Transform "TranslationTransform")
(TransformParameters 0 0)
(UseBinaryFormatForTransformationParameters "false")
(UseDirectionCosines "true")
)";

  EXPECT_EQ(Conversion::ParameterMapToString({ { "Direction", { "0", "0", "0", "0" } },
                                               { "FixedImageDimension", { "2" } },
                                               { "FixedInternalImagePixelType", { "float" } },
                                               { "HowToCombineTransforms", { "Compose" } },
                                               { "Index", { "0", "0" } },
                                               { "InitialTransformParametersFileName", { "NoInitialTransform" } },
                                               { "MovingImageDimension", { "2" } },
                                               { "MovingInternalImagePixelType", { "float" } },
                                               { "NumberOfParameters", { "2" } },
                                               { "Origin", { "0", "0" } },
                                               { "Size", { "0", "0" } },
                                               { "Spacing", { "1", "1" } },
                                               { "Transform", { "TranslationTransform" } },
                                               { "TransformParameters", { "0", "0" } },
                                               { "UseBinaryFormatForTransformationParameters", { "false" } },
                                               { "UseDirectionCosines", { "true" } } }),
            expectedString);
}

GTEST_TEST(Conversion, ToString)
{
  // Note that this is different from std::to_string(false) and
  // std::to_string(true), which return "0" and "1", respecively.
  EXPECT_EQ(Conversion::ToString(false), "false");
  EXPECT_EQ(Conversion::ToString(true), "true");

  EXPECT_EQ(Conversion::ToString(0), "0");
  EXPECT_EQ(Conversion::ToString(1), "1");
  EXPECT_EQ(Conversion::ToString(-1), "-1");

  EXPECT_EQ(Conversion::ToString(std::numeric_limits<std::int64_t>::min()), "-9223372036854775808");
  EXPECT_EQ(Conversion::ToString(std::numeric_limits<std::uint64_t>::max()), "18446744073709551615");

  // Extensive tests of conversion from double to string:

  using DoubleLimits = std::numeric_limits<double>;

  // Note that this is different from std::to_string(0.5), which returns "0.500000"
  EXPECT_EQ(Conversion::ToString(0.5), "0.5");

  constexpr auto expectedPrecision = 16;
  static_assert(expectedPrecision == std::numeric_limits<double>::digits10 + 1,
                "The expected precision for double floating point numbers");
  const auto expectedString = "0." + std::string(expectedPrecision, '3');

  EXPECT_EQ(Conversion::ToString(+0.0), "0");
  EXPECT_EQ(Conversion::ToString(-0.0), "0");
  EXPECT_EQ(Conversion::ToString(+1.0), "1");
  EXPECT_EQ(Conversion::ToString(-1.0), "-1");
  EXPECT_EQ(Conversion::ToString(0.1), "0.1");
  EXPECT_EQ(Conversion::ToString(1.0 / 3.0), "0." + std::string(expectedPrecision, '3'));

  for (std::uint8_t exponent{ 20 }; exponent > 0; --exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 1000...000
    EXPECT_EQ(Conversion::ToString(power_of_ten), '1' + std::string(exponent, '0'));
    EXPECT_EQ(Conversion::ToString(-power_of_ten), "-1" + std::string(exponent, '0'));
  }

  for (std::uint8_t exponent{ 15 }; exponent > 0; --exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 999...999
    EXPECT_EQ(Conversion::ToString(power_of_ten - 1), std::string(exponent, '9'));
    EXPECT_EQ(Conversion::ToString(1 - power_of_ten), '-' + std::string(exponent, '9'));
  }

  for (std::int8_t exponent{ -6 }; exponent < 0; ++exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 0.000...001
    EXPECT_EQ(Conversion::ToString(power_of_ten), "0." + std::string(-1 - exponent, '0') + '1');
    EXPECT_EQ(Conversion::ToString(-power_of_ten), "-0." + std::string(-1 - exponent, '0') + '1');
  }

  for (std::int8_t exponent{ -16 }; exponent < 0; ++exponent)
  {
    const auto power_of_ten = std::pow(10.0, exponent);

    // Test +/- 0.999...999
    EXPECT_EQ(Conversion::ToString(1 - power_of_ten), "0." + std::string(-exponent, '9'));
    EXPECT_EQ(Conversion::ToString(power_of_ten - 1), "-0." + std::string(-exponent, '9'));
  }

  // The first powers of ten that are represented by scientific "e" notation:
  EXPECT_EQ(Conversion::ToString(1e+21), "1e+21");
  EXPECT_EQ(Conversion::ToString(1e-7), "1e-7");

  // Test the most relevant constants from <limits>:
  EXPECT_EQ(Conversion::ToString(DoubleLimits::epsilon()), "2.220446049250313e-16");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::min()), "2.2250738585072014e-308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::lowest()), "-1.7976931348623157e+308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::max()), "1.7976931348623157e+308");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::quiet_NaN()), "NaN");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::quiet_NaN()), "NaN");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::infinity()), "Infinity");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::infinity()), "-Infinity");
  EXPECT_EQ(Conversion::ToString(DoubleLimits::denorm_min()), "5e-324");
  EXPECT_EQ(Conversion::ToString(-DoubleLimits::denorm_min()), "-5e-324");
}

GTEST_TEST(Conversion, ToVectorOfStrings)
{
  using VectorOfStrings = std::vector<std::string>;
  using ArrayOfDoubles = std::array<double, 3>;

  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Size<>{ 1, 2 }), VectorOfStrings({ "1", "2" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Index<>{ 1, 2 }), VectorOfStrings({ "1", "2" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Point<double>(ArrayOfDoubles{ -0.5, 0.0, 0.25 })),
            VectorOfStrings({ "-0.5", "0", "0.25" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::Vector<double>(ArrayOfDoubles{ -0.5, 0.0, 0.25 }.data())),
            VectorOfStrings({ "-0.5", "0", "0.25" }));
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::OptimizerParameters<double>{}), VectorOfStrings{});
  EXPECT_EQ(Conversion::ToVectorOfStrings(itk::ImageBase<>::DirectionType{}), VectorOfStrings({ "0", "0", "0", "0" }));
}

GTEST_TEST(Conversion, ConcatenateVectors)
{
  using VectorType = std::vector<std::string>;

  const auto expectConcatenation = [](const VectorType & vector1, const VectorType & vector2) {
    auto expectedResult = vector1;

    for (const auto & element : vector2)
    {
      expectedResult.push_back(element);
    }
    EXPECT_EQ(Conversion::ConcatenateVectors(vector1, vector2), expectedResult);
  };

  expectConcatenation({}, {});
  expectConcatenation({ "1" }, {});
  expectConcatenation({}, { "1" });
  expectConcatenation({ "1" }, { "2", "3" });
}

GTEST_TEST(Conversion, IsNumberReturnsFalseOnNonNumericString)
{
  const auto expect_IsNumber_returns_false = [](const std::string & str) {
    SCOPED_TRACE(str);
    EXPECT_FALSE(Conversion::IsNumber(str));
  };

  for (const auto str : { "", " ", "a", "A B C", "true", "false", "nan", "NaN" })
  {
    expect_IsNumber_returns_false(str);
  }

  for (const auto transformName : { "AffineDTITransform",
                                    "AffineLogStackTransform",
                                    "AffineLogTransform",
                                    "AffineTransform",
                                    "BSplineStackTransform",
                                    "BSplineTransform",
                                    "BSplineTransformWithDiffusion",
                                    "DeformationFieldTransform",
                                    "EulerStackTransform",
                                    "EulerTransform",
                                    "MultiBSplineTransformWithNormal",
                                    "RecursiveBSplineTransform",
                                    "SimilarityTransform",
                                    "SplineKernelTransform",
                                    "TranslationStackTransform",
                                    "TranslationTransform",
                                    "WeightedCombinationTransform" })
  {
    expect_IsNumber_returns_false(transformName);
  }
}

GTEST_TEST(Conversion, IsNumberReturnsTrueOnNumericString)
{
  const auto expect_IsNumber_returns_true = [](const std::string & str) {
    SCOPED_TRACE(str);
    EXPECT_TRUE(Conversion::IsNumber(str));
  };

  for (int i{ -10 }; i < 10; ++i)
  {
    expect_IsNumber_returns_true(Conversion::ToString(i));
  }

  expect_IsNumber_returns_true("1e+21");
  expect_IsNumber_returns_true("1e-7");

  for (double d{ -1.0 }; d < 1.0; d += 0.1)
  {
    expect_IsNumber_returns_true(Conversion::ToString(d));
  }

  using limits = std::numeric_limits<double>;

  for (const auto limit : { limits::min(), limits::max(), limits::epsilon(), limits::lowest(), limits::denorm_min() })
  {
    expect_IsNumber_returns_true(Conversion::ToString(limit));
  }
}

GTEST_TEST(Conversion, LosslessRoundTripOfParameterValue)
{
  Expect_lossless_round_trip_of_unsigned_parameter_values<unsigned>();
  Expect_lossless_round_trip_of_unsigned_parameter_values<std::uint16_t>();
  Expect_lossless_round_trip_of_unsigned_parameter_values<std::uintmax_t>();

  Expect_lossless_round_trip_of_signed_integer_parameter_values<int>();
  Expect_lossless_round_trip_of_signed_integer_parameter_values<std::int16_t>();
  Expect_lossless_round_trip_of_signed_integer_parameter_values<std::intmax_t>();

  Expect_lossless_round_trip_of_floating_point_parameter_values<float>();
  Expect_lossless_round_trip_of_floating_point_parameter_values<double>();

  for (const bool parameterValue : { false, true })
  {
    Expect_lossless_round_trip_of_parameter_value<bool>(parameterValue);
  }
}
<|endoftext|>


<commit_before>// This file is part of BlueSky
//
// BlueSky 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 3
// of the License, or (at your option) any later version.
//
// BlueSky 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with BlueSky; if not, see <http://www.gnu.org/licenses/>.

#include "py_array_converter.h"
#include "py_bs_exports.h"
#include "py_smart_ptr.h"

using namespace std;

namespace blue_sky {
// usefull typedefs
typedef bs_array< int, bs_nparray > bs_nparray_i;
typedef bs_array< long, bs_nparray > bs_nparray_l;
typedef bs_array< float, bs_nparray > bs_nparray_f;
typedef bs_array< double, bs_nparray > bs_nparray_d;

// bs_array< T, bs_nparray > instantiations
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (int, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (unsigned int, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (long, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (unsigned long, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (float, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (double, bs_nparray));

kernel::types_enum register_nparray() {
	kernel::types_enum te;
	te.push_back(bs_nparray_i::bs_type());
	te.push_back(bs_nparray_l::bs_type());
	te.push_back(bs_nparray_f::bs_type());
	te.push_back(bs_nparray_d::bs_type());
	return te;
}

namespace python {

// bs_nparray test function
template< class inp_array_t, class ret_array_t >
smart_ptr< ret_array_t > test_nparray(smart_ptr< inp_array_t > a, smart_ptr< inp_array_t > b) {
	// a little test on nparray resize
	smart_ptr< bs_nparray_d > tmp = BS_KERNEL.create_object(bs_nparray_d::bs_type());
	tmp->resize(10);
	tmp->resize(11);

	ulong sz = (ulong) std::min(a->size(), b->size());
	smart_ptr< ret_array_t > res = BS_KERNEL.create_object(ret_array_t::bs_type());
	*res = *a;
	res->assign(*a);
	res->assign(a->begin(), a->end());
	//*res = *a->clone();
	res->resize(sz + 1);
	for(ulong i = 0; i < sz; ++i)
		(*res)[i] = (*a)[i] + (*b)[i];
	(*res)[res->size() - 1] = 12345;
	//res->insert(1.);
	return res;
}

void py_export_nparray() {
	// export converters
	array_converters< int >           :: make_known();
	array_converters< unsigned int >  :: make_known();
	array_converters< long >          :: make_known();
	array_converters< unsigned long > :: make_known();
	array_converters< float >         :: make_known();
	array_converters< double >        :: make_known();

	// export test functions
	def("test_nparray_i", &test_nparray< bs_nparray_i, bs_array< int > >);
	def("test_nparray_l", &test_nparray< bs_nparray_i, bs_array< long > >);
	def("test_nparray_f", &test_nparray< bs_nparray_f, bs_array< float > >);
	def("test_nparray_d", &test_nparray< bs_array< double, bs_npvec_shared >,
		bs_array< double, bs_npvec_shared > >);
	//def("test_nparray_d", &test_nparray< bs_array< double, vector_traits >, bs_array< double, vector_traits > >);
	//def("test_nparray_d", &test_nparray< bs_nparray< double >, bs_array< double, vector_traits > >);
	//def("test_nparray_d", &test_nparray< double, bs_arrbase >);
}

}}

<commit_msg>ARRAY: add Python converters for bs_array with long long & unsigned long long types (fix 64-bit Windows version)<commit_after>// This file is part of BlueSky
//
// BlueSky 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 3
// of the License, or (at your option) any later version.
//
// BlueSky 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with BlueSky; if not, see <http://www.gnu.org/licenses/>.

#include "py_array_converter.h"
#include "py_bs_exports.h"
#include "py_smart_ptr.h"

using namespace std;

namespace blue_sky {
// usefull typedefs
typedef bs_array< int, bs_nparray > bs_nparray_i;
typedef bs_array< long, bs_nparray > bs_nparray_l;
typedef bs_array< float, bs_nparray > bs_nparray_f;
typedef bs_array< double, bs_nparray > bs_nparray_d;

// bs_array< T, bs_nparray > instantiations
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (int, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (unsigned int, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (long, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (unsigned long, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (float, bs_nparray));
BS_TYPE_IMPL_T_EXT_MEM(bs_array, 2, (double, bs_nparray));

kernel::types_enum register_nparray() {
	kernel::types_enum te;
	te.push_back(bs_nparray_i::bs_type());
	te.push_back(bs_nparray_l::bs_type());
	te.push_back(bs_nparray_f::bs_type());
	te.push_back(bs_nparray_d::bs_type());
	return te;
}

namespace python {

// bs_nparray test function
template< class inp_array_t, class ret_array_t >
smart_ptr< ret_array_t > test_nparray(smart_ptr< inp_array_t > a, smart_ptr< inp_array_t > b) {
	// a little test on nparray resize
	smart_ptr< bs_nparray_d > tmp = BS_KERNEL.create_object(bs_nparray_d::bs_type());
	tmp->resize(10);
	tmp->resize(11);

	ulong sz = (ulong) std::min(a->size(), b->size());
	smart_ptr< ret_array_t > res = BS_KERNEL.create_object(ret_array_t::bs_type());
	*res = *a;
	res->assign(*a);
	res->assign(a->begin(), a->end());
	//*res = *a->clone();
	res->resize(sz + 1);
	for(ulong i = 0; i < sz; ++i)
		(*res)[i] = (*a)[i] + (*b)[i];
	(*res)[res->size() - 1] = 12345;
	//res->insert(1.);
	return res;
}

void py_export_nparray() {
	// export converters
	array_converters< int >               :: make_known();
	array_converters< unsigned int >      :: make_known();
	array_converters< long >              :: make_known();
	array_converters< long long >         :: make_known();
	array_converters< unsigned long >     :: make_known();
	array_converters< unsigned long long> :: make_known();
	array_converters< float >             :: make_known();
	array_converters< double >            :: make_known();

	// export test functions
	def("test_nparray_i", &test_nparray< bs_nparray_i, bs_array< int > >);
	def("test_nparray_l", &test_nparray< bs_nparray_i, bs_array< long > >);
	def("test_nparray_f", &test_nparray< bs_nparray_f, bs_array< float > >);
	def("test_nparray_d", &test_nparray< bs_array< double, bs_npvec_shared >,
		bs_array< double, bs_npvec_shared > >);
	//def("test_nparray_d", &test_nparray< bs_array< double, vector_traits >, bs_array< double, vector_traits > >);
	//def("test_nparray_d", &test_nparray< bs_nparray< double >, bs_array< double, vector_traits > >);
	//def("test_nparray_d", &test_nparray< double, bs_arrbase >);
}

}}

<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include "TokenStream.hpp"
#include <memory>

namespace calc
{
class Evaluator
{
public:
    Evaluator(TokenStream&);
    Evaluator(TokenStream&& tsInitVal);

    double calculate();
    double expression();
    double primary();
    double term();
private:
    std::unique_ptr<TokenStream> tsVal;
    TokenStream& ts;
};
};
<commit_msg>[ch06] fix a very pedantic error<commit_after>#pragma once
#include <vector>
#include "TokenStream.hpp"
#include <memory>

namespace calc
{
class Evaluator
{
public:
    Evaluator(TokenStream&);
    Evaluator(TokenStream&& tsInitVal);

    double calculate();
    double expression();
    double primary();
    double term();
private:
    std::unique_ptr<TokenStream> tsVal;
    TokenStream& ts;
};
}
<|endoftext|>


<commit_before>#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}<commit_msg>add code to test if compile succeeds.<commit_after>#include <iostream>

#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
#include <glm/ext.hpp>

glm::mat4 camera(float Translate, glm::vec2 const &Rotate) {
    glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.f);
    glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
    View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
    View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
    glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
    return Projection * View * Model;
}

int main() {
    std::cout << "Hello, World!" << std::endl;
    glm::tmat4x4<float> tesetMatrix
            (-0.0046, -0.9997, 0.0227, -2.0922,
             -0.9998, 0.0041, -0.0197, -6.3851,
             0.0196, -0.0228, -0.9995, -5.9063,
             0, 0, 0, 1);
    std::cout << glm::to_string(tesetMatrix) << std::endl;
    return 0;
}<|endoftext|>


<commit_before>AliAnalysisTaskSEBkgLikeSignJPSI *AddTaskBkgLikeSign()
{
  //
  // Test macro for the AliAnalysisTaskSEBkgLikeSignJPSI
  // starting from AliAOD.root file with HF + Like Sign candidates.
  // C.Di Giglio, carmelo.digiglio@ba.infn.it
  //

  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskBkgLikeSign", "No analysis manager to connect to.");
    return NULL;
  }

  // Like-sign background analysis task
  AliAnalysisTaskSEBkgLikeSignJPSI *lsTask = new AliAnalysisTaskSEBkgLikeSignJPSI("CmpLikeSignAnalysis");
  lsTask->SetDebugLevel(2);

  mgr->AddTask(lsTask);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cinputLS = mgr->CreateContainer("cinputLikeSignJPSI",TChain::Class(),
							  AliAnalysisManager::kInputContainer);
  AliAnalysisDataContainer *coutputLS = mgr->CreateContainer("coutputLikeSignJPSI",TList::Class(),
                                                           AliAnalysisManager::kOutputContainer,
                                                           "CmpLikeSignJPSI.root");

  mgr->ConnectInput(lsTask,0,mgr->GetCommonInputContainer());
  mgr->ConnectOutput(lsTask,1,coutputLS);

  return lsTask;
}
<commit_msg>Renamed AddTaskBkgLikeSign.C -> AddTaskBkgLikeSignJPSI.C<commit_after>AliAnalysisTaskSEBkgLikeSignJPSI *AddTaskBkgLikeSignJPSI()
{
  //
  // Test macro for the AliAnalysisTaskSEBkgLikeSignJPSI
  // starting from AliAOD.root file with HF + Like Sign candidates.
  // C.Di Giglio, carmelo.digiglio@ba.infn.it
  //

  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskBkgLikeSignJPSI", "No analysis manager to connect to.");
    return NULL;
  }

  // Like-sign background analysis task
  AliAnalysisTaskSEBkgLikeSignJPSI *lsTask = new AliAnalysisTaskSEBkgLikeSignJPSI("CmpLikeSignAnalysis");
  lsTask->SetDebugLevel(2);

  mgr->AddTask(lsTask);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cinputLS = mgr->CreateContainer("cinputLikeSignJPSI",TChain::Class(),
							  AliAnalysisManager::kInputContainer);
  AliAnalysisDataContainer *coutputLS = mgr->CreateContainer("coutputLikeSignJPSI",TList::Class(),
                                                           AliAnalysisManager::kOutputContainer,
                                                           "CmpLikeSignJPSI.root");

  mgr->ConnectInput(lsTask,0,mgr->GetCommonInputContainer());
  mgr->ConnectOutput(lsTask,1,coutputLS);

  return lsTask;
}
<|endoftext|>


<commit_before><commit_msg>PWGGA/GammaConv: Simplification of bad channel rejection for background rotation method<commit_after><|endoftext|>