<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
/**
 *
 * @author Scott Boag (scott_boag@lotus.com)
 * @author David N. Bertoni (david_n_bertoni@lotus.com)
 */

// Class header file.
#include "NodeSorter.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>

#include <XPath/XPath.hpp>

NodeSorter::NodeSorter(XPathExecutionContext&	executionContext) :
	m_executionContext(executionContext),
	m_keys()
{
}

NodeSorter::~NodeSorter()
{
}

void
NodeSorter::sort(
				NodeVectorType&					v,
				const NodeSortKeyVectorType&	keys)
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::stable_sort;
#endif

	m_keys = keys;

	NodeSortKeyCompare	theComparer(m_executionContext,
									v,
									keys);

	// Use the stl sort algorithm, which will use our compare functor,
	// which returns true if first less than second
	stable_sort(v.begin(),
			    v.end(),
			    theComparer);
}

void
NodeSorter::sort(
			MutableNodeRefList&				theList,
			const NodeSortKeyVectorType&	keys)
{
	const unsigned int	theLength = theList.getLength();

	// Copy the nodes to a vector...
	NodeVectorType	theNodes(theLength);

	unsigned int		i = 0;

	for (; i < theLength; ++i)
	{
		theNodes[i] = theList.item(i);
	}

	sort(theNodes,
		 keys);
	assert(theNodes.size() ==
				static_cast<NodeVectorType::size_type>(theLength));

	theList.clear();

	for (i = 0; i < theLength; ++i)
	{
		theList.addNode(theNodes[i]);
	}

	assert(theList.getLength() == theLength);
}

NodeSorter::NodeSortKeyCompare::result_type
NodeSorter::NodeSortKeyCompare::operator()(
			first_argument_type		theLHS,
			second_argument_type	theRHS,
			unsigned int			theKeyIndex) const
{
	assert(theKeyIndex < UINT_MAX);
	result_type			theResult = false;

	const NodeSortKey&	theKey = m_nodeSortKeys[theKeyIndex];

	const XPath&		xpath = theKey.getSelectPattern();

	XObject* r1 = xpath.execute(theLHS, theKey.getPrefixResolver(), NodeRefList(), m_executionContext);
	XObject* r2 = xpath.execute(theRHS, theKey.getPrefixResolver(), NodeRefList(), m_executionContext);

	// Compare as numbers
	if(theKey.getTreatAsNumbers() == true)
	{
		double	n1Num = r1->num();
		double	n2Num = r2->num();

		if (DoubleSupport::isNaN(n1Num))
			n1Num = 0.0;

		if (DoubleSupport::isNaN(n2Num))
			n2Num = 0.0;

		if(n1Num == n2Num &&
		  (theKeyIndex + 1 ) < m_nodeSortKeys.size())
		{
			theResult = operator()(theLHS, theRHS, theKeyIndex + 1);
		}
		else
		{
			const double	diff = n1Num - n2Num;

			theResult =  diff < 0.0 ? true : false;

			if (theKey.getDescending() == true)
			{
				theResult = !theResult;
			}
		}
	}
	// Compare as strings
	else
	{
		const int	theCompareResult = compare(r1->str(), r2->str());

		if(0 == theCompareResult)
		{
			if ((theKeyIndex + 1 ) < m_nodeSortKeys.size())
			{
				theResult = operator()(theLHS, theRHS, theKeyIndex + 1);
			}
		}
		else
		{
			theResult = theCompareResult < 0 ? true : false;

			if (theKey.getDescending() == true)
			{
				theResult = !theResult;
			}
		}
	}

	return theResult;
}
<commit_msg>Compare strings according to collation sequence.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
/**
 *
 * @author Scott Boag (scott_boag@lotus.com)
 * @author David N. Bertoni (david_n_bertoni@lotus.com)
 */

// Class header file.
#include "NodeSorter.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>

#include <XPath/XPath.hpp>

NodeSorter::NodeSorter(XPathExecutionContext&	executionContext) :
	m_executionContext(executionContext),
	m_keys()
{
}

NodeSorter::~NodeSorter()
{
}

void
NodeSorter::sort(
				NodeVectorType&					v,
				const NodeSortKeyVectorType&	keys)
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::stable_sort;
#endif

	m_keys = keys;

	NodeSortKeyCompare	theComparer(m_executionContext,
									v,
									keys);

	// Use the stl sort algorithm, which will use our compare functor,
	// which returns true if first less than second
	stable_sort(v.begin(),
			    v.end(),
			    theComparer);
}

void
NodeSorter::sort(
			MutableNodeRefList&				theList,
			const NodeSortKeyVectorType&	keys)
{
	const unsigned int	theLength = theList.getLength();

	// Copy the nodes to a vector...
	NodeVectorType	theNodes(theLength);

	unsigned int		i = 0;

	for (; i < theLength; ++i)
	{
		theNodes[i] = theList.item(i);
	}

	sort(theNodes,
		 keys);
	assert(theNodes.size() ==
				static_cast<NodeVectorType::size_type>(theLength));

	theList.clear();

	for (i = 0; i < theLength; ++i)
	{
		theList.addNode(theNodes[i]);
	}

	assert(theList.getLength() == theLength);
}

NodeSorter::NodeSortKeyCompare::result_type
NodeSorter::NodeSortKeyCompare::operator()(
			first_argument_type		theLHS,
			second_argument_type	theRHS,
			unsigned int			theKeyIndex) const
{
	assert(theKeyIndex < UINT_MAX);
	result_type			theResult = false;

	const NodeSortKey&	theKey = m_nodeSortKeys[theKeyIndex];

	const XPath&		xpath = theKey.getSelectPattern();

	XObject* r1 = xpath.execute(theLHS, theKey.getPrefixResolver(), NodeRefList(), m_executionContext);
	XObject* r2 = xpath.execute(theRHS, theKey.getPrefixResolver(), NodeRefList(), m_executionContext);

	// Compare as numbers
	if(theKey.getTreatAsNumbers() == true)
	{
		double	n1Num = r1->num();
		double	n2Num = r2->num();

		if (DoubleSupport::isNaN(n1Num))
			n1Num = 0.0;

		if (DoubleSupport::isNaN(n2Num))
			n2Num = 0.0;

		if(n1Num == n2Num &&
		  (theKeyIndex + 1 ) < m_nodeSortKeys.size())
		{
			theResult = operator()(theLHS, theRHS, theKeyIndex + 1);
		}
		else
		{
			const double	diff = n1Num - n2Num;

			theResult =  diff < 0.0 ? true : false;

			if (theKey.getDescending() == true)
			{
				theResult = !theResult;
			}
		}
	}
	// Compare as strings
	else
	{
		const int	theCompareResult = collationCompare(r1->str(), r2->str());

		if(0 == theCompareResult)
		{
			if ((theKeyIndex + 1 ) < m_nodeSortKeys.size())
			{
				theResult = operator()(theLHS, theRHS, theKeyIndex + 1);
			}
		}
		else
		{
			theResult = theCompareResult < 0 ? true : false;

			if (theKey.getDescending() == true)
			{
				theResult = !theResult;
			}
		}
	}

	return theResult;
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkImageAccumulate.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

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

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

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

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkImageAccumulate.h"
#include <math.h>
#include <stdlib.h>
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageAccumulate* vtkImageAccumulate::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageAccumulate");
  if(ret)
    {
    return (vtkImageAccumulate*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageAccumulate;
}

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageAccumulate::vtkImageAccumulate()
{
  int idx;

  for (idx = 0; idx < 3; ++idx)
    {
    this->ComponentSpacing[idx] = 1.0;
    this->ComponentOrigin[idx] = 0.0;
    this->ComponentExtent[idx*2] = 0;
    this->ComponentExtent[idx*2+1] = 0;
    }
  this->ComponentExtent[1] = 255;

  this->StencilFunction = NULL;
  this->ClippingExtents = NULL;

  this->ReverseStencil = 0;

  this->Min[0] = this->Min[1] = this->Min[2] = 0.0;
  this->Max[0] = this->Max[1] = this->Max[2] = 0.0;
  this->Mean[0] = this->Mean[1] = this->Mean[2] = 0.0;
  this->PixelCount = 0;
}

//----------------------------------------------------------------------------
vtkImageAccumulate::~vtkImageAccumulate()
{
  this->SetStencilFunction(NULL);
  this->SetClippingExtents(NULL);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->ComponentExtent[idx] != extent[idx])
      {
      this->ComponentExtent[idx] = extent[idx];
      this->Modified();
      }
    }
  if (modified)
    {
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int minX, int maxX,
                                            int minY, int maxY,
                                            int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetComponentExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::GetComponentExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->ComponentExtent[idx];
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class T>
static void vtkImageAccumulateExecute(vtkImageAccumulate *self,
				      vtkImageData *inData, T *inPtr,
				      vtkImageData *outData, int *outPtr,
				      double Min[3],
				      double Max[3],
				      double Mean[3],
				      long int *PixelCount)
{
  int idX, idY, idZ, idxC;
  int r1, r2, cr1, cr2, iter, rval;
  int min0, max0, min1, max1, min2, max2;
  int inInc0, inInc1, inInc2;
  T *tempPtr;
  int *outPtrC;
  int numC, outIdx, *outExtent, *outIncs;
  float *origin, *spacing;
  unsigned long count = 0;
  unsigned long target;

  // variables used to compute statistics (filter handles max 3 components)
  double sum[3];
  sum[0] = sum[1] = sum[2] = 0.0;
  Min[0] = Min[1] = Min[2] = VTK_DOUBLE_MAX;
  Max[0] = Max[1] = Max[2] = VTK_DOUBLE_MIN;
  *PixelCount = 0;

  vtkImageClippingExtents *clippingExtents = self->GetClippingExtents();

  // Zero count in every bin
  outData->GetExtent(min0, max0, min1, max1, min2, max2);
  memset((void *)outPtr, 0,
         (max0-min0+1)*(max1-min1+1)*(max2-min2+1)*sizeof(int));

  // Get information to march through data
  numC = inData->GetNumberOfScalarComponents();
  inData->GetUpdateExtent(min0, max0, min1, max1, min2, max2);
  inData->GetIncrements(inInc0, inInc1, inInc2);
  outExtent = outData->GetExtent();
  outIncs = outData->GetIncrements();
  origin = outData->GetOrigin();
  spacing = outData->GetSpacing();

  target = (unsigned long)((max2 - min2 + 1)*(max1 - min1 +1)/50.0);
  target++;

  // Loop through input pixels
  for (idZ = min2; idZ <= max2; idZ++)
    {
    for (idY = min1; idY <= max1; idY++)
      {
      if (!(count%target))
	{
        self->UpdateProgress(count/(50.0*target));
	}
      count++;

      if (clippingExtents == NULL)
        {
        tempPtr = inPtr + (inInc2*(idZ - min2) +
                           inInc1*(idY - min1));
        for (idX = min0; idX <= max0; idX++)
          {
	  // find the bin for this pixel.
	  outPtrC = outPtr;
	  for (idxC = 0; idxC < numC; ++idxC)
	    {
	    // Gather statistics
	    sum[idxC]+= *tempPtr;
	    if (*tempPtr > Max[idxC])
	      Max[idxC] = *tempPtr;
	    else if (*tempPtr < Min[idxC])
	      Min[idxC] = *tempPtr;
	    (*PixelCount)++;
	    // compute the index
	    outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
	    if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
	      {
	      // Out of bin range
	      outPtrC = NULL;
	      break;
	      }
	    outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
	    }
	  if (outPtrC)
	    {
	    ++(*outPtrC);
	    }

          }
        }
      else
        {
        iter = 0;
        cr1 = min0;
        for (;;)
          {
          rval = clippingExtents->GetNextExtent(r1, r2, min0, max0,
                                                idY, idZ, iter);
          cr2 = r1 - 1;
          if (!self->GetReverseStencil())
            {
            tempPtr = inPtr + (inInc2*(idZ - min2) +
                               inInc1*(idY - min1) +
                               numC*(cr1 - min0));

            for (idX = cr1; idX <= cr2; idX++)
              {
	      // find the bin for this pixel.
	      outPtrC = outPtr;
	      for (idxC = 0; idxC < numC; ++idxC)
		{
		// Gather statistics
		sum[idxC]+= *tempPtr;
		if (*tempPtr > Max[idxC])
		  Max[idxC] = *tempPtr;
		else if (*tempPtr < Min[idxC])
		  Min[idxC] = *tempPtr;
		(*PixelCount)++;
		// compute the index
		outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
		if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
		  {
		  // Out of bin range
		  outPtrC = NULL;
		  break;
		  }
		outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
		}
	      if (outPtrC)
		{
		++(*outPtrC);
		}

	      }
            }
          cr1 = r2 + 1;

          // break if no foreground extents left
          if (rval == 0)
            {
            break;
            }

          if (self->GetReverseStencil())
            {
            // do unchanged portion
            tempPtr = inPtr + (inInc2*(idZ - min2) +
                               inInc1*(idY - min1) +
                               numC*(r1 - min0));

            for (idX = r1; idX <= r2; idX++)
              {
	      // find the bin for this pixel.
	      outPtrC = outPtr;
	      for (idxC = 0; idxC < numC; ++idxC)
		{
		// Gather statistics
		sum[idxC]+= *tempPtr;
		if (*tempPtr > Max[idxC])
		  Max[idxC] = *tempPtr;
		else if (*tempPtr < Min[idxC])
		  Min[idxC] = *tempPtr;
		(*PixelCount)++;
		// compute the index
		outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
		if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
		  {
		  // Out of bin range
		  outPtrC = NULL;
		  break;
		  }
		outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
		}
	      if (outPtrC)
		{
		++(*outPtrC);
		}

              }
            }
          }
        }
      }
    }

  if (*PixelCount) // avoid the div0
    {
    Mean[0] = sum[0] / (double)*PixelCount;
    Mean[1] = sum[1] / (double)*PixelCount;
    Mean[2] = sum[2] / (double)*PixelCount;
    }
  else
    {
    Mean[0]=Mean[1]=Mean[2] = 0.0;
    }

}

//----------------------------------------------------------------------------
// This method is passed a input and output Data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the Datas data types.
void vtkImageAccumulate::ExecuteData(vtkDataObject *vtkNotUsed(out))
{
  void *inPtr;
  void *outPtr;
  vtkImageData *inData = this->GetInput();
  vtkImageData *outData = this->GetOutput();

  vtkDebugMacro(<<"Executing image accumulate");

  // We need to allocate our own scalars since we are overriding
  // the superclasses "Execute()" method.
  outData->SetExtent(outData->GetWholeExtent());
  outData->AllocateScalars();

  inPtr = inData->GetScalarPointerForExtent(inData->GetUpdateExtent());
  outPtr = outData->GetScalarPointer();

  // Components turned into x, y and z
  if (this->GetInput()->GetNumberOfScalarComponents() > 3)
    {
    vtkErrorMacro("This filter can handle upto 3 components");
    return;
    }

  // this filter expects that output is type int.
  if (outData->GetScalarType() != VTK_INT)
    {
    vtkErrorMacro(<< "Execute: out ScalarType " << outData->GetScalarType()
                  << " must be int\n");
    return;
    }

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro9(vtkImageAccumulateExecute, this,
                      inData, (VTK_TT *)(inPtr),
                      outData, (int *)(outPtr),
		      this->Min, this->Max,
		      this->Mean, &this->PixelCount);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::ExecuteInformation(vtkImageData *input,
                                            vtkImageData *output)
{
  output->SetWholeExtent(this->ComponentExtent);
  output->SetOrigin(this->ComponentOrigin);
  output->SetSpacing(this->ComponentSpacing);
  output->SetNumberOfScalarComponents(1);
  output->SetScalarType(VTK_INT);

  // See if we should be setting up some clipping extents
  if (this->StencilFunction)
    {
    if (!this->ClippingExtents)
      {
      this->ClippingExtents = vtkImageClippingExtents::New();
      }
    this->ClippingExtents->SetClippingObject(this->StencilFunction);
    }
  if (this->ClippingExtents)
    {
    this->ClippingExtents->BuildExtents(input);
    }
}

//----------------------------------------------------------------------------
// Get ALL of the input.
void vtkImageAccumulate::ComputeInputUpdateExtent(int inExt[6],
                                                  int outExt[6])
{
  int *wholeExtent;

  outExt = outExt;
  wholeExtent = this->GetInput()->GetWholeExtent();
  memcpy(inExt, wholeExtent, 6*sizeof(int));
}

void vtkImageAccumulate::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageToImageFilter::PrintSelf(os,indent);

  os << indent << "ComponentOrigin: ( "
     << this->ComponentOrigin[0] << ", "
     << this->ComponentOrigin[1] << ", "
     << this->ComponentOrigin[2] << " )\n";

  os << indent << "ComponentSpacing: ( "
     << this->ComponentSpacing[0] << ", "
     << this->ComponentSpacing[1] << ", "
     << this->ComponentSpacing[2] << " )\n";

  os << indent << "ComponentExtent: ( "
     << this->ComponentExtent[0] << "," << this->ComponentExtent[1] << " "
     << this->ComponentExtent[2] << "," << this->ComponentExtent[3] << " "
     << this->ComponentExtent[4] << "," << this->ComponentExtent[5] << " }\n";
}

<commit_msg><commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageAccumulate.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$
  Thanks:    Thanks to C. Charles Law who developed this class.

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

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

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

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

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkImageAccumulate.h"
#include <math.h>
#include <stdlib.h>
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkImageAccumulate* vtkImageAccumulate::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkImageAccumulate");
  if(ret)
    {
    return (vtkImageAccumulate*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkImageAccumulate;
}

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageAccumulate::vtkImageAccumulate()
{
  int idx;

  for (idx = 0; idx < 3; ++idx)
    {
    this->ComponentSpacing[idx] = 1.0;
    this->ComponentOrigin[idx] = 0.0;
    this->ComponentExtent[idx*2] = 0;
    this->ComponentExtent[idx*2+1] = 0;
    }
  this->ComponentExtent[1] = 255;

  this->StencilFunction = NULL;
  this->ClippingExtents = NULL;

  this->ReverseStencil = 0;

  this->Min[0] = this->Min[1] = this->Min[2] = 0.0;
  this->Max[0] = this->Max[1] = this->Max[2] = 0.0;
  this->Mean[0] = this->Mean[1] = this->Mean[2] = 0.0;
  this->PixelCount = 0;
}

//----------------------------------------------------------------------------
vtkImageAccumulate::~vtkImageAccumulate()
{
  this->SetStencilFunction(NULL);
  this->SetClippingExtents(NULL);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int extent[6])
{
  int idx, modified = 0;

  for (idx = 0; idx < 6; ++idx)
    {
    if (this->ComponentExtent[idx] != extent[idx])
      {
      this->ComponentExtent[idx] = extent[idx];
      this->Modified();
      }
    }
  if (modified)
    {
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::SetComponentExtent(int minX, int maxX,
                                            int minY, int maxY,
                                            int minZ, int maxZ)
{
  int extent[6];

  extent[0] = minX;  extent[1] = maxX;
  extent[2] = minY;  extent[3] = maxY;
  extent[4] = minZ;  extent[5] = maxZ;
  this->SetComponentExtent(extent);
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::GetComponentExtent(int extent[6])
{
  int idx;

  for (idx = 0; idx < 6; ++idx)
    {
    extent[idx] = this->ComponentExtent[idx];
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class T>
static void vtkImageAccumulateExecute(vtkImageAccumulate *self,
				      vtkImageData *inData, T *inPtr,
				      vtkImageData *outData, int *outPtr,
				      double Min[3],
				      double Max[3],
				      double Mean[3],
				      long int *PixelCount)
{
  int idX, idY, idZ, idxC;
  int r1, r2, cr1, cr2, iter, rval;
  int min0, max0, min1, max1, min2, max2;
  int inInc0, inInc1, inInc2;
  T *tempPtr;
  int *outPtrC;
  int numC, outIdx, *outExtent, *outIncs;
  float *origin, *spacing;
  unsigned long count = 0;
  unsigned long target;

  // variables used to compute statistics (filter handles max 3 components)
  double sum[3];
  sum[0] = sum[1] = sum[2] = 0.0;
  Min[0] = Min[1] = Min[2] = VTK_DOUBLE_MAX;
  Max[0] = Max[1] = Max[2] = VTK_DOUBLE_MIN;
  *PixelCount = 0;

  vtkImageClippingExtents *clippingExtents = self->GetClippingExtents();

  // Zero count in every bin
  outData->GetExtent(min0, max0, min1, max1, min2, max2);
  memset((void *)outPtr, 0,
         (max0-min0+1)*(max1-min1+1)*(max2-min2+1)*sizeof(int));

  // Get information to march through data
  numC = inData->GetNumberOfScalarComponents();
  inData->GetUpdateExtent(min0, max0, min1, max1, min2, max2);
  inData->GetIncrements(inInc0, inInc1, inInc2);
  outExtent = outData->GetExtent();
  outIncs = outData->GetIncrements();
  origin = outData->GetOrigin();
  spacing = outData->GetSpacing();

  target = (unsigned long)((max2 - min2 + 1)*(max1 - min1 +1)/50.0);
  target++;

  // Loop through input pixels
  for (idZ = min2; idZ <= max2; idZ++)
    {
    for (idY = min1; idY <= max1; idY++)
      {
      if (!(count%target))
	{
        self->UpdateProgress(count/(50.0*target));
	}
      count++;

      if (clippingExtents == NULL)
        {
        tempPtr = inPtr + (inInc2*(idZ - min2) +
                           inInc1*(idY - min1));
        for (idX = min0; idX <= max0; idX++)
          {
	  // find the bin for this pixel.
	  outPtrC = outPtr;
	  for (idxC = 0; idxC < numC; ++idxC)
	    {
	    // Gather statistics
	    sum[idxC]+= *tempPtr;
	    if (*tempPtr > Max[idxC])
	      Max[idxC] = *tempPtr;
	    else if (*tempPtr < Min[idxC])
	      Min[idxC] = *tempPtr;
	    (*PixelCount)++;
	    // compute the index
	    outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
	    if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
	      {
	      // Out of bin range
	      outPtrC = NULL;
	      break;
	      }
	    outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
	    }
	  if (outPtrC)
	    {
	    ++(*outPtrC);
	    }

          }
        }
      else
        {
        iter = 0;
        cr1 = min0;
        for (;;)
          {
          rval = clippingExtents->GetNextExtent(r1, r2, min0, max0,
                                                idY, idZ, iter);
          cr2 = r1 - 1;
          if (!self->GetReverseStencil())
            {
            tempPtr = inPtr + (inInc2*(idZ - min2) +
                               inInc1*(idY - min1) +
                               numC*(cr1 - min0));

            for (idX = cr1; idX <= cr2; idX++)
              {
	      // find the bin for this pixel.
	      outPtrC = outPtr;
	      for (idxC = 0; idxC < numC; ++idxC)
		{
		// Gather statistics
		sum[idxC]+= *tempPtr;
		if (*tempPtr > Max[idxC])
		  Max[idxC] = *tempPtr;
		else if (*tempPtr < Min[idxC])
		  Min[idxC] = *tempPtr;
		(*PixelCount)++;
		// compute the index
		outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
		if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
		  {
		  // Out of bin range
		  outPtrC = NULL;
		  break;
		  }
		outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
		}
	      if (outPtrC)
		{
		++(*outPtrC);
		}

	      }
            }
          cr1 = r2 + 1;

          // break if no foreground extents left
          if (rval == 0)
            {
            break;
            }

          if (self->GetReverseStencil())
            {
            // do unchanged portion
            tempPtr = inPtr + (inInc2*(idZ - min2) +
                               inInc1*(idY - min1) +
                               numC*(r1 - min0));

            for (idX = r1; idX <= r2; idX++)
              {
	      // find the bin for this pixel.
	      outPtrC = outPtr;
	      for (idxC = 0; idxC < numC; ++idxC)
		{
		// Gather statistics
		sum[idxC]+= *tempPtr;
		if (*tempPtr > Max[idxC])
		  Max[idxC] = *tempPtr;
		else if (*tempPtr < Min[idxC])
		  Min[idxC] = *tempPtr;
		(*PixelCount)++;
		// compute the index
		outIdx = (int) floor((((double)*tempPtr++ - origin[idxC]) / spacing[idxC]));
		if (outIdx < outExtent[idxC*2] || outIdx > outExtent[idxC*2+1])
		  {
		  // Out of bin range
		  outPtrC = NULL;
		  break;
		  }
		outPtrC += (outIdx - outExtent[idxC*2]) * outIncs[idxC];
		}
	      if (outPtrC)
		{
		++(*outPtrC);
		}

              }
            }
          }
        }
      }
    }

  if (*PixelCount) // avoid the div0
    {
    Mean[0] = sum[0] / (double)*PixelCount;
    Mean[1] = sum[1] / (double)*PixelCount;
    Mean[2] = sum[2] / (double)*PixelCount;
    }
  else
    {
    Mean[0]=Mean[1]=Mean[2] = 0.0;
    }

}

//----------------------------------------------------------------------------
// This method is passed a input and output Data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the Datas data types.
void vtkImageAccumulate::ExecuteData(vtkDataObject *vtkNotUsed(out))
{
  void *inPtr;
  void *outPtr;
  vtkImageData *inData = this->GetInput();
  vtkImageData *outData = this->GetOutput();

  vtkDebugMacro(<<"Executing image accumulate");

  // We need to allocate our own scalars since we are overriding
  // the superclasses "Execute()" method.
  outData->SetExtent(outData->GetWholeExtent());
  outData->AllocateScalars();

  inPtr = inData->GetScalarPointerForExtent(inData->GetUpdateExtent());
  outPtr = outData->GetScalarPointer();

  // Components turned into x, y and z
  if (this->GetInput()->GetNumberOfScalarComponents() > 3)
    {
    vtkErrorMacro("This filter can handle upto 3 components");
    return;
    }

  // this filter expects that output is type int.
  if (outData->GetScalarType() != VTK_INT)
    {
    vtkErrorMacro(<< "Execute: out ScalarType " << outData->GetScalarType()
                  << " must be int\n");
    return;
    }

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro9(vtkImageAccumulateExecute, this,
                      inData, (VTK_TT *)(inPtr),
                      outData, (int *)(outPtr),
		      this->Min, this->Max,
		      this->Mean, &this->PixelCount);
    default:
      vtkErrorMacro(<< "Execute: Unknown ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
void vtkImageAccumulate::ExecuteInformation(vtkImageData *input,
                                            vtkImageData *output)
{
  output->SetWholeExtent(this->ComponentExtent);
  output->SetOrigin(this->ComponentOrigin);
  output->SetSpacing(this->ComponentSpacing);
  output->SetNumberOfScalarComponents(1);
  output->SetScalarType(VTK_INT);

  // See if we should be setting up some clipping extents
  if (this->StencilFunction)
    {
    if (!this->ClippingExtents)
      {
      this->ClippingExtents = vtkImageClippingExtents::New();
      }
    this->ClippingExtents->SetClippingObject(this->StencilFunction);
    }
  if (this->ClippingExtents)
    {
    this->ClippingExtents->BuildExtents(input);
    }
}

//----------------------------------------------------------------------------
// Get ALL of the input.
void vtkImageAccumulate::ComputeInputUpdateExtent(int inExt[6],
                                                  int outExt[6])
{
  int *wholeExtent;

  outExt = outExt;
  wholeExtent = this->GetInput()->GetWholeExtent();
  memcpy(inExt, wholeExtent, 6*sizeof(int));
}

void vtkImageAccumulate::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageToImageFilter::PrintSelf(os,indent);

  os << indent << "ComponentOrigin: ( "
     << this->ComponentOrigin[0] << ", "
     << this->ComponentOrigin[1] << ", "
     << this->ComponentOrigin[2] << " )\n";

  os << indent << "ComponentSpacing: ( "
     << this->ComponentSpacing[0] << ", "
     << this->ComponentSpacing[1] << ", "
     << this->ComponentSpacing[2] << " )\n";

  os << indent << "ComponentExtent: ( "
     << this->ComponentExtent[0] << "," << this->ComponentExtent[1] << " "
     << this->ComponentExtent[2] << "," << this->ComponentExtent[3] << " "
     << this->ComponentExtent[4] << "," << this->ComponentExtent[5] << " }\n";

  os << indent << "StencilFunction: " << this->StencilFunction << "\n";
  os << indent << "ReverseStencil: " << (this->ReverseStencil ?
		                         "On\n" : "Off\n");

  os << indent << "ClippingExtents: " << this->ClippingExtents << "\n";
}

<|endoftext|>


<commit_before>#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

#include "nifty/graph/optimization/mincut/mincut_base.hxx"
#include "nifty/graph/optimization/mincut/mincut_visitor_base.hxx"

#include "nifty/python/graph/undirected_list_graph.hxx"
#include "nifty/python/graph/edge_contraction_graph.hxx"
#include "nifty/python/graph/optimization/mincut/mincut_objective.hxx"
#include "nifty/python/graph/optimization/mincut/py_mincut_visitor_base.hxx"

#include "nifty/python/converter.hxx"

namespace py = pybind11;

namespace nifty{
namespace graph{

    using namespace py;
    //PYBIND11_DECLARE_HOLDER_TYPE(McBase, std::shared_ptr<McBase>);

    template<class OBJECTIVE>
    void exportMincutVisitorBaseT(py::module & mincutModule) {

        typedef OBJECTIVE ObjectiveType;
        typedef PyMincutVisitorBase<ObjectiveType> PyMcVisitorBase;
        typedef MincutVisitorBase<ObjectiveType> McVisitorBase;

        const auto objName = MincutObjectiveName<ObjectiveType>::name();
        const auto mcVisitorBaseClsName = std::string("MincutVisitorBase") + objName;
        const auto mcVerboseVisitorClsName = std::string("MincutVerboseVisitor") + objName;

        // base factory
        py::class_<
            McVisitorBase,
            std::unique_ptr<McVisitorBase>,
            PyMcVisitorBase
        > mcVisitorBase(mincutModule, mcVisitorBaseClsName.c_str());

        //mcVisitorBase
        //;

        // concrete visitors

        typedef MincutVerboseVisitor<ObjectiveType> McVerboseVisitor;

        py::class_<McVerboseVisitor, std::unique_ptr<McVerboseVisitor> >(mincutModule, mcVerboseVisitorClsName.c_str(),  mcVisitorBase)
            .def(py::init<const int, const double>(),
                py::arg_t<int>("printNth",1),
                py::arg_t<double>("timeLimit",std::numeric_limits<double>::infinity())
            )
            .def("stopOptimize",&McVerboseVisitor::stopOptimize)
        ;
    }

    void exportMincutVisitorBase(py::module & mincutModule) {

        {
            typedef PyUndirectedGraph GraphType;
            typedef MincutObjective<GraphType, double> ObjectiveType;
            exportMincutVisitorBaseT<ObjectiveType>(mincutModule);
        }
        {
            typedef PyContractionGraph<PyUndirectedGraph> GraphType;
            typedef MincutObjective<GraphType, double> ObjectiveType;
            exportMincutVisitorBaseT<ObjectiveType>(mincutModule);
        }
    }

}
}

<commit_msg>minor changes<commit_after>#include <memory>

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

#include "nifty/graph/optimization/mincut/mincut_base.hxx"
#include "nifty/graph/optimization/mincut/mincut_visitor_base.hxx"

#include "nifty/python/graph/undirected_list_graph.hxx"
#include "nifty/python/graph/edge_contraction_graph.hxx"
#include "nifty/python/graph/optimization/mincut/mincut_objective.hxx"
#include "nifty/python/graph/optimization/mincut/py_mincut_visitor_base.hxx"

#include "nifty/python/converter.hxx"

namespace py = pybind11;

namespace nifty{
namespace graph{

    using namespace py;
    //PYBIND11_DECLARE_HOLDER_TYPE(McBase, std::shared_ptr<McBase>);

    template<class OBJECTIVE>
    void exportMincutVisitorBaseT(py::module & module) {

        typedef OBJECTIVE ObjectiveType;
        typedef PyMincutVisitorBase<ObjectiveType> PyVisitorBase;
        typedef MincutVisitorBase<ObjectiveType> VisitorBase;

        const auto objName = MincutObjectiveName<ObjectiveType>::name();
        const auto visitorBaseClsName = std::string("MincutVisitorBase") + objName;
        const auto mcVerboseVisitorClsName = std::string("MincutVerboseVisitor") + objName;

        // base factory
        py::class_<
            VisitorBase,
            std::unique_ptr<VisitorBase>,
            PyVisitorBase
        > visitorBase(module, visitorBaseClsName.c_str());

        //visitorBase
        //;

        // concrete visitors

        {
            const auto visitorClsName = std::string("VerboseVisitor") + objName;
            typedef MincutVerboseVisitor<ObjectiveType> VisitorType;
            py::class_<VisitorType, std::unique_ptr<VisitorType> >(module, visitorClsName.c_str(),  visitorBase)
                .def(py::init<const int, const double , const double>(),
                    py::arg_t<int>("visitNth",1),
                    py::arg_t<double>("timeLimitSolver",std::numeric_limits<double>::infinity()),
                    py::arg_t<double>("timeLimitTotal",std::numeric_limits<double>::infinity())
                )
                .def("stopOptimize",&VisitorType::stopOptimize)
                .def_property_readonly("timeLimitSolver", &VisitorType::timeLimitSolver)
                .def_property_readonly("timeLimitTotal", &VisitorType::timeLimitTotal)
                .def_property_readonly("runtimeSolver", &VisitorType::runtimeSolver)
                .def_property_readonly("runtimeTotal", &VisitorType::runtimeTotal)
            ;
        }

    }

    void exportMincutVisitorBase(py::module & module) {

        {
            typedef PyUndirectedGraph GraphType;
            typedef MincutObjective<GraphType, double> ObjectiveType;
            exportMincutVisitorBaseT<ObjectiveType>(module);
        }
        {
            typedef PyContractionGraph<PyUndirectedGraph> GraphType;
            typedef MincutObjective<GraphType, double> ObjectiveType;
            exportMincutVisitorBaseT<ObjectiveType>(module);
        }
    }

}
}

<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include "coroutine-scheduler.hxx"

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <errno.h> // EINVAL errno
   #include <time.h> // nanosleep()
   #if ABC_HOST_API_DARWIN
      #include <dispatch/dispatch.h>
   #else
      #include <semaphore.h>
      #if ABC_HOST_API_FREEBSD
         #include <pthread_np.h> // pthread_getthreadid_np()
      #elif ABC_HOST_API_LINUX
         #include <sys/syscall.h> // SYS_*
         #include <unistd.h> // syscall()
      #endif
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::thread

namespace abc {

class thread::impl {
private:
   friend class thread;

public:
   /*! Constructor

   @param fnMain
      Initial value for m_fnInnerMain.
   */
   impl(std::function<void ()> fnMain) :
#if ABC_HOST_API_POSIX
      m_id(0),
#elif ABC_HOST_API_WIN32
      m_h(nullptr),
#else
   #error "TODO: HOST_API"
#endif
      m_fnInnerMain(std::move(fnMain)) {
   }

   //! Destructor.
   ~impl() {
#if ABC_HOST_API_WIN32
      ::CloseHandle(m_h);
#endif
   }

   //! Creates a thread to run outer_main().
   void start(std::shared_ptr<impl> * ppimplThis) {
      ABC_TRACE_FUNC(this);

#if ABC_HOST_API_DARWIN
      m_dsemStarted = ::dispatch_semaphore_create(0);
      if (!m_dsemStarted) {
         exception::throw_os_error();
      }
      try {
         if (int iErr = ::pthread_create(&m_h, nullptr, &outer_main, ppimplThis)) {
            exception::throw_os_error(iErr);
         }
         // Block until the new thread is finished updating *this.
         ::dispatch_semaphore_wait(m_dsemStarted, DISPATCH_TIME_FOREVER);
      } catch (...) {
         // TODO: move this code to a “defer” lambda.
         ::dispatch_release(m_dsemStarted);
         throw;
      }
      // TODO: move this code to a “defer” lambda.
      ::dispatch_release(m_dsemStarted);
#elif ABC_HOST_API_POSIX
      if (::sem_init(&m_semStarted, 0, 0)) {
         exception::throw_os_error();
      }
      try {
         if (int iErr = ::pthread_create(&m_h, nullptr, &outer_main, ppimplThis)) {
            exception::throw_os_error(iErr);
         }
         /* Block until the new thread is finished updating *this. The only possible failure is
         EINTR, so we just keep on retrying. */
         while (::sem_wait(&m_semStarted)) {
            ;
         }
      } catch (...) {
         // TODO: move this code to a “defer” lambda.
         ::sem_destroy(&m_semStarted);
         throw;
      }
      // TODO: move this code to a “defer” lambda.
      ::sem_destroy(&m_semStarted);
#elif ABC_HOST_API_WIN32
      m_hStartedEvent = ::CreateEvent(nullptr, true, false, nullptr);
      try {
         m_h = ::CreateThread(nullptr, 0, &outer_main, ppimplThis, 0, nullptr);
         if (!m_h) {
            exception::throw_os_error();
         }
         // Block until the new thread is finished updating *this. Must not fail.
         ::WaitForSingleObject(m_hStartedEvent, INFINITE);
      } catch (...) {
         // TODO: move this code to a “defer” lambda.
         ::CloseHandle(m_hStartedEvent);
         throw;
      }
      // TODO: move this code to a “defer” lambda.
      ::CloseHandle(m_hStartedEvent);
#else
   #error "TODO: HOST_API"
#endif
   }

private:
   /*! Lower-level wrapper for the thread function passed to the constructor. Under POSIX, this is
   also needed to assign the thread ID to the owning abc::thread instance.

   @param p
      *this.
   @return
      Unused.
   */
#if ABC_HOST_API_POSIX
   static void * outer_main(void * p) {
#elif ABC_HOST_API_WIN32
   static DWORD WINAPI outer_main(void * p) {
#else
   #error "TODO: HOST_API"
#endif
      /* Get a copy of the shared_ptr owning *this, so that members will be guaranteed to be
      accessible even after start() returns, in the creating thread.
      Dereferencing p is safe because the creating thread, which owns *p, is blocked, waiting for
      this thread to signal that it’s finished starting. */
      std::shared_ptr<impl> pimplThis(*static_cast<std::shared_ptr<impl> *>(p));
#if ABC_HOST_API_POSIX
      pimplThis->m_id = this_thread::id();
   #if ABC_HOST_API_DARWIN
      ::dispatch_semaphore_signal(pimplThis->m_dsemStarted);
   #else
      // Report that this thread is done with writing to *pthr.
      ::sem_post(&pimplThis->m_semStarted);
   #endif
#elif ABC_HOST_API_WIN32
      // Report that this thread is done with writing to *pthr.
      ::SetEvent(pimplThis->m_hStartedEvent);
#else
   #error "TODO: HOST_API"
#endif
      try {
         pimplThis->m_fnInnerMain();
      } catch (std::exception const & x) {
         exception::write_with_scope_trace(nullptr, &x);
         // TODO: kill every other thread.
      } catch (...) {
         exception::write_with_scope_trace();
         // TODO: kill every other thread.
      }
#if ABC_HOST_API_POSIX
      return nullptr;
#elif ABC_HOST_API_WIN32
      return 0;
#else
   #error "TODO: HOST_API"
#endif
   }

private:
   //! OS-dependent ID/handle.
   native_handle_type m_h;
#if ABC_HOST_API_DARWIN
   //! Dispatch semaphore used by the new thread to report to its parent that it has started.
   ::dispatch_semaphore_t m_dsemStarted;
#elif ABC_HOST_API_POSIX
   //! OS-dependent ID for use with OS-specific API (pthread_*_np() functions and other native API).
   id_type m_id;
   //! Semaphore used by the new thread to report to its parent that it has started.
   ::sem_t m_semStarted;
#elif ABC_HOST_API_WIN32
   //! Event used by the new thread to report to its parent that it has started.
   HANDLE m_hStartedEvent;
#else
   #error "TODO: HOST_API"
#endif
   //! Function to be executed in the thread.
   std::function<void ()> m_fnInnerMain;
};

/*explicit*/ thread::thread(std::function<void ()> fnMain) :
   m_pimpl(std::make_shared<impl>(std::move(fnMain))) {
   ABC_TRACE_FUNC(this);

   m_pimpl->start(&m_pimpl);
}

thread::~thread() {
   if (joinable()) {
      // TODO: std::terminate() or something similar.
   }
}

thread::id_type thread::id() const {
   ABC_TRACE_FUNC(this);

#if ABC_HOST_API_POSIX
   return m_pimpl ? m_pimpl->m_id : 0;
#elif ABC_HOST_API_WIN32
   if (m_pimpl) {
      DWORD iTid = ::GetThreadId(m_pimpl->m_h);
      if (iTid == 0) {
         exception::throw_os_error();
      }
      return iTid;
   } else {
      return 0;
   }
#else
   #error "TODO: HOST_API"
#endif
}

void thread::join() {
   ABC_TRACE_FUNC(this);

   if (!m_pimpl) {
      // TODO: use a better exception class.
      ABC_THROW(argument_error, ());
   }
#if ABC_HOST_API_POSIX
   if (int iErr = ::pthread_join(m_pimpl->m_h, nullptr)) {
      exception::throw_os_error(iErr);
   }
#elif ABC_HOST_API_WIN32
   DWORD iRet = ::WaitForSingleObject(m_pimpl->m_h, INFINITE);
   if (iRet == WAIT_FAILED) {
      exception::throw_os_error();
   }
#else
   #error "TODO: HOST_API"
#endif
   // Release the impl instance; this will also make joinable() return false.
   m_pimpl.reset();
}

thread::native_handle_type thread::native_handle() const {
   return m_pimpl ? m_pimpl->m_h : native_handle_type();
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend – specialization for abc::thread

namespace abc {

to_str_backend<thread>::to_str_backend() {
}

to_str_backend<thread>::~to_str_backend() {
}

void to_str_backend<thread>::set_format(istr const & sFormat) {
   ABC_TRACE_FUNC(this, sFormat);

   auto it(sFormat.cbegin());

   // Add parsing of the format string here.

   // If we still have any characters, they are garbage.
   if (it != sFormat.cend()) {
      ABC_THROW(syntax_error, (
         ABC_SL("unexpected character"), sFormat, static_cast<unsigned>(it - sFormat.cbegin())
      ));
   }
}

void to_str_backend<thread>::write(thread const & thr, io::text::writer * ptwOut) {
   ABC_TRACE_FUNC(this/*, thr*/, ptwOut);

   if (thread::id_type id = thr.id()) {
      m_tsbStr.write(istr(ABC_SL("TID:")), ptwOut);
      m_tsbId.write(id, ptwOut);
   } else {
      m_tsbStr.write(istr(ABC_SL("TID:-")), ptwOut);
   }
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::this_thread

namespace abc {
namespace this_thread {

std::shared_ptr<coroutine::scheduler> const & attach_coroutine_scheduler(
   std::shared_ptr<coroutine::scheduler> pcorosched /*= nullptr*/
) {
   ABC_TRACE_FUNC(pcorosched);

   std::shared_ptr<coroutine::scheduler> & pcoroschedCurr = coroutine::scheduler::sm_pcorosched;
   if (pcorosched) {
      if (pcoroschedCurr) {
         // The current thread already has a coroutine scheduler.
         // TODO: use a better exception class.
         ABC_THROW(generic_error, ());
      }
      pcoroschedCurr = std::move(pcorosched);
   } else {
      // Create and set a new coroutine scheduler if the current thread didn’t already have one.
      if (!pcoroschedCurr) {
         pcoroschedCurr = std::make_shared<coroutine::scheduler>();
      }
   }
   return pcoroschedCurr;
}

std::shared_ptr<coroutine::scheduler> const & get_coroutine_scheduler() {
   return coroutine::scheduler::sm_pcorosched;
}

thread::id_type id() {
#if ABC_HOST_API_DARWIN
   thread::id_type id;
   ::pthread_threadid_np(nullptr, &id);
   return id;
#elif ABC_HOST_API_FREEBSD
   static_assert(
      sizeof(thread::id_type) == sizeof(decltype(::pthread_getthreadid_np())),
      "return type of ::pthread_getthreadid_np() must be the same size as thread::id_type"
   );
   return ::pthread_getthreadid_np();
#elif ABC_HOST_API_LINUX
   static_assert(
      sizeof(thread::id_type) == sizeof(::pid_t), "::pid_t must be the same size as thread::id_type"
   );
   // This is a call to ::gettid().
   return static_cast< ::pid_t>(::syscall(SYS_gettid));
#elif ABC_HOST_API_WIN32
   return ::GetCurrentThreadId();
#else
   #error "TODO: HOST_API"
#endif
}

void run_coroutines() {
   if (auto & pcorosched = get_coroutine_scheduler()) {
      pcorosched->run();
   }
}

void sleep_for_ms(unsigned iMillisecs) {
#if ABC_HOST_API_POSIX
   ::timespec tsRequested, tsRemaining;
   tsRequested.tv_sec = static_cast< ::time_t>(iMillisecs / 1000u);
   tsRequested.tv_nsec = static_cast<long>(
      static_cast<unsigned long>(iMillisecs % 1000u) * 1000000u
   );
   /* This loop will only repeat in case of EINTR. Technically ::nanosleep() may fail with EINVAL,
   but the calculation above makes that impossible. */
   while (::nanosleep(&tsRequested, &tsRemaining) < 0) {
      // Set the new requested time to whatever we didn’t get to sleep in the last nanosleep() call.
      tsRequested = tsRemaining;
   }
#elif ABC_HOST_API_WIN32
   ::Sleep(iMillisecs);
#else
   #error "TODO: HOST_API"
#endif
}

} //namespace this_thread
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Move thread started event logic into new abc::detail::simple_event class<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade 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 Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include "coroutine-scheduler.hxx"

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/thread.hxx>

#if ABC_HOST_API_POSIX
   #include <errno.h> // EINVAL errno
   #include <time.h> // nanosleep()
   #if ABC_HOST_API_DARWIN
      #include <dispatch/dispatch.h>
   #else
      #include <semaphore.h>
      #if ABC_HOST_API_FREEBSD
         #include <pthread_np.h> // pthread_getthreadid_np()
      #elif ABC_HOST_API_LINUX
         #include <sys/syscall.h> // SYS_*
         #include <unistd.h> // syscall()
      #endif
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::detail::simple_event

/*! Event that can be waited for. Not compatible with coroutines, since it doesn’t yield to a
coroutine::scheduler. */
// TODO: make this a non-coroutine-friendly general-purpose event.
namespace abc {
namespace detail {

class simple_event : public noncopyable {
public:
   //! Constructor.
   simple_event() {
#if ABC_HOST_API_DARWIN
      m_dsem = ::dispatch_semaphore_create(0);
      if (!m_dsem) {
         exception::throw_os_error();
      }
#elif ABC_HOST_API_POSIX
      if (::sem_init(&m_sem, 0, 0)) {
         exception::throw_os_error();
      }
#elif ABC_HOST_API_WIN32
      m_hEvent = ::CreateEvent(nullptr, true, false, nullptr);
      if (!m_hEvent) {
         exception::throw_os_error();
      }
#else
   #error "TODO: HOST_API"
#endif
   }

   //! Destructor.
   ~simple_event() {
#if ABC_HOST_API_DARWIN
      ::dispatch_release(m_dsem);
#elif ABC_HOST_API_POSIX
      ::sem_destroy(&m_sem);
#elif ABC_HOST_API_WIN32
      ::CloseHandle(m_hEvent);
#else
   #error "TODO: HOST_API"
#endif
   }

   //! Raises the event.
   void raise() {
#if ABC_HOST_API_DARWIN
      ::dispatch_semaphore_signal(m_dsem);
#elif ABC_HOST_API_POSIX
      ::sem_post(&m_sem);
#elif ABC_HOST_API_WIN32
      ::SetEvent(m_hEvent);
#else
   #error "TODO: HOST_API"
#endif
   }

   //! Waits for the event to be raised by another thread.
   void wait() {
#if ABC_HOST_API_DARWIN
      ::dispatch_semaphore_wait(m_dsem, DISPATCH_TIME_FOREVER);
#elif ABC_HOST_API_POSIX
      /* Block until the new thread is finished updating *this. The only possible failure is EINTR,
      so we just keep on retrying. */
      while (::sem_wait(&m_sem)) {
         ;
      }
#elif ABC_HOST_API_WIN32
      ::WaitForSingleObject(m_hEvent, INFINITE);
#else
   #error "TODO: HOST_API"
#endif
   }

private:
#if ABC_HOST_API_DARWIN
   //! Underlying dispatch semaphore.
   ::dispatch_semaphore_t m_dsem;
#elif ABC_HOST_API_POSIX
   //! Underlying POSIX semaphore.
   ::sem_t m_sem;
#elif ABC_HOST_API_WIN32
   //! Underlying event.
   ::HANDLE m_hEvent;
#else
   #error "TODO: HOST_API"
#endif
};

} //namespace detail
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::thread

namespace abc {

class thread::impl {
private:
   friend class thread;

public:
   /*! Constructor

   @param fnMain
      Initial value for m_fnInnerMain.
   */
   impl(std::function<void ()> fnMain) :
#if ABC_HOST_API_POSIX
      m_id(0),
#elif ABC_HOST_API_WIN32
      m_h(nullptr),
#else
   #error "TODO: HOST_API"
#endif
      m_pseStarted(nullptr),
      m_fnInnerMain(std::move(fnMain)) {
   }

   //! Destructor.
   ~impl() {
#if ABC_HOST_API_WIN32
      ::CloseHandle(m_h);
#endif
   }

   //! Creates a thread to run outer_main().
   void start(std::shared_ptr<impl> * ppimplThis) {
      ABC_TRACE_FUNC(this);

      detail::simple_event seStarted;
      m_pseStarted = &seStarted;
      try {
#if ABC_HOST_API_POSIX
         if (int iErr = ::pthread_create(&m_h, nullptr, &outer_main, ppimplThis)) {
            exception::throw_os_error(iErr);
         }
#elif ABC_HOST_API_WIN32
         m_h = ::CreateThread(nullptr, 0, &outer_main, ppimplThis, 0, nullptr);
         if (!m_h) {
            exception::throw_os_error();
         }
#else
   #error "TODO: HOST_API"
#endif
         // Block until the new thread is finished updating *this.
         seStarted.wait();
      } catch (...) {
         m_pseStarted = nullptr;
         throw;
      }
      m_pseStarted = nullptr;
   }

private:
   /*! Lower-level wrapper for the thread function passed to the constructor. Under POSIX, this is
   also needed to assign the thread ID to the owning abc::thread instance.

   @param p
      *this.
   @return
      Unused.
   */
#if ABC_HOST_API_POSIX
   static void * outer_main(void * p) {
#elif ABC_HOST_API_WIN32
   static DWORD WINAPI outer_main(void * p) {
#else
   #error "TODO: HOST_API"
#endif
      /* Get a copy of the shared_ptr owning *this, so that members will be guaranteed to be
      accessible even after start() returns, in the creating thread.
      Dereferencing p is safe because the creating thread, which owns *p, is blocked, waiting for
      this thread to signal that it’s finished starting. */
      std::shared_ptr<impl> pimplThis(*static_cast<std::shared_ptr<impl> *>(p));
#if ABC_HOST_API_POSIX
      pimplThis->m_id = this_thread::id();
#endif
      // Report that this thread is done with writing to *pthr.
      pimplThis->m_pseStarted->raise();
      try {
         pimplThis->m_fnInnerMain();
      } catch (std::exception const & x) {
         exception::write_with_scope_trace(nullptr, &x);
         // TODO: kill every other thread.
      } catch (...) {
         exception::write_with_scope_trace();
         // TODO: kill every other thread.
      }
#if ABC_HOST_API_POSIX
      return nullptr;
#elif ABC_HOST_API_WIN32
      return 0;
#else
   #error "TODO: HOST_API"
#endif
   }

private:
   //! OS-dependent ID/handle.
   native_handle_type m_h;
#if ABC_HOST_API_POSIX
   //! OS-dependent ID for use with OS-specific API (pthread_*_np() functions and other native API).
   id_type m_id;
#endif
   /*! Pointer to an event used by the new thread to report to its parent that it has started. Only
   non-nullptr during the execution of start(). */
   detail::simple_event * m_pseStarted;
   //! Function to be executed in the thread.
   std::function<void ()> m_fnInnerMain;
};

/*explicit*/ thread::thread(std::function<void ()> fnMain) :
   m_pimpl(std::make_shared<impl>(std::move(fnMain))) {
   ABC_TRACE_FUNC(this);

   m_pimpl->start(&m_pimpl);
}

thread::~thread() {
   if (joinable()) {
      // TODO: std::terminate() or something similar.
   }
}

thread::id_type thread::id() const {
   ABC_TRACE_FUNC(this);

#if ABC_HOST_API_POSIX
   return m_pimpl ? m_pimpl->m_id : 0;
#elif ABC_HOST_API_WIN32
   if (m_pimpl) {
      DWORD iTid = ::GetThreadId(m_pimpl->m_h);
      if (iTid == 0) {
         exception::throw_os_error();
      }
      return iTid;
   } else {
      return 0;
   }
#else
   #error "TODO: HOST_API"
#endif
}

void thread::join() {
   ABC_TRACE_FUNC(this);

   if (!m_pimpl) {
      // TODO: use a better exception class.
      ABC_THROW(argument_error, ());
   }
#if ABC_HOST_API_POSIX
   if (int iErr = ::pthread_join(m_pimpl->m_h, nullptr)) {
      exception::throw_os_error(iErr);
   }
#elif ABC_HOST_API_WIN32
   DWORD iRet = ::WaitForSingleObject(m_pimpl->m_h, INFINITE);
   if (iRet == WAIT_FAILED) {
      exception::throw_os_error();
   }
#else
   #error "TODO: HOST_API"
#endif
   // Release the impl instance; this will also make joinable() return false.
   m_pimpl.reset();
}

thread::native_handle_type thread::native_handle() const {
   return m_pimpl ? m_pimpl->m_h : native_handle_type();
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend – specialization for abc::thread

namespace abc {

to_str_backend<thread>::to_str_backend() {
}

to_str_backend<thread>::~to_str_backend() {
}

void to_str_backend<thread>::set_format(istr const & sFormat) {
   ABC_TRACE_FUNC(this, sFormat);

   auto it(sFormat.cbegin());

   // Add parsing of the format string here.

   // If we still have any characters, they are garbage.
   if (it != sFormat.cend()) {
      ABC_THROW(syntax_error, (
         ABC_SL("unexpected character"), sFormat, static_cast<unsigned>(it - sFormat.cbegin())
      ));
   }
}

void to_str_backend<thread>::write(thread const & thr, io::text::writer * ptwOut) {
   ABC_TRACE_FUNC(this/*, thr*/, ptwOut);

   if (thread::id_type id = thr.id()) {
      m_tsbStr.write(istr(ABC_SL("TID:")), ptwOut);
      m_tsbId.write(id, ptwOut);
   } else {
      m_tsbStr.write(istr(ABC_SL("TID:-")), ptwOut);
   }
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::this_thread

namespace abc {
namespace this_thread {

std::shared_ptr<coroutine::scheduler> const & attach_coroutine_scheduler(
   std::shared_ptr<coroutine::scheduler> pcorosched /*= nullptr*/
) {
   ABC_TRACE_FUNC(pcorosched);

   std::shared_ptr<coroutine::scheduler> & pcoroschedCurr = coroutine::scheduler::sm_pcorosched;
   if (pcorosched) {
      if (pcoroschedCurr) {
         // The current thread already has a coroutine scheduler.
         // TODO: use a better exception class.
         ABC_THROW(generic_error, ());
      }
      pcoroschedCurr = std::move(pcorosched);
   } else {
      // Create and set a new coroutine scheduler if the current thread didn’t already have one.
      if (!pcoroschedCurr) {
         pcoroschedCurr = std::make_shared<coroutine::scheduler>();
      }
   }
   return pcoroschedCurr;
}

std::shared_ptr<coroutine::scheduler> const & get_coroutine_scheduler() {
   return coroutine::scheduler::sm_pcorosched;
}

thread::id_type id() {
#if ABC_HOST_API_DARWIN
   thread::id_type id;
   ::pthread_threadid_np(nullptr, &id);
   return id;
#elif ABC_HOST_API_FREEBSD
   static_assert(
      sizeof(thread::id_type) == sizeof(decltype(::pthread_getthreadid_np())),
      "return type of ::pthread_getthreadid_np() must be the same size as thread::id_type"
   );
   return ::pthread_getthreadid_np();
#elif ABC_HOST_API_LINUX
   static_assert(
      sizeof(thread::id_type) == sizeof(::pid_t), "::pid_t must be the same size as thread::id_type"
   );
   // This is a call to ::gettid().
   return static_cast< ::pid_t>(::syscall(SYS_gettid));
#elif ABC_HOST_API_WIN32
   return ::GetCurrentThreadId();
#else
   #error "TODO: HOST_API"
#endif
}

void run_coroutines() {
   if (auto & pcorosched = get_coroutine_scheduler()) {
      pcorosched->run();
   }
}

void sleep_for_ms(unsigned iMillisecs) {
#if ABC_HOST_API_POSIX
   ::timespec tsRequested, tsRemaining;
   tsRequested.tv_sec = static_cast< ::time_t>(iMillisecs / 1000u);
   tsRequested.tv_nsec = static_cast<long>(
      static_cast<unsigned long>(iMillisecs % 1000u) * 1000000u
   );
   /* This loop will only repeat in case of EINTR. Technically ::nanosleep() may fail with EINVAL,
   but the calculation above makes that impossible. */
   while (::nanosleep(&tsRequested, &tsRemaining) < 0) {
      // Set the new requested time to whatever we didn’t get to sleep in the last nanosleep() call.
      tsRequested = tsRemaining;
   }
#elif ABC_HOST_API_WIN32
   ::Sleep(iMillisecs);
#else
   #error "TODO: HOST_API"
#endif
}

} //namespace this_thread
} //namespace abc

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


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015-2016 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "normalizeddiffusionbssrdf.h"

// appleseed.renderer headers.
#include "renderer/modeling/bssrdf/bssrdfsample.h"
#include "renderer/modeling/bssrdf/separablebssrdf.h"
#include "renderer/modeling/bssrdf/sss.h"
#include "renderer/modeling/input/inputevaluator.h"

// appleseed.foundation headers.
#include "foundation/image/colorspace.h"
#include "foundation/math/cdf.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"
#include "foundation/utility/memory.h"

// Standard headers.
#include <cmath>
#include <cstddef>

// Forward declarations.
namespace renderer  { class Assembly; }
namespace renderer  { class ShadingContext; }

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Normalized diffusion BSSRDF.
    //
    // Reference:
    //
    //   Approximate Reflectance Profiles for Efficient Subsurface Scattering
    //   Per H. Christensen, Brent Burley
    //   http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf
    //

    const char* Model = "normalized_diffusion_bssrdf";

    class NormalizedDiffusionBSSRDF
      : public SeparableBSSRDF
    {
      public:
        NormalizedDiffusionBSSRDF(
            const char*         name,
            const ParamArray&   params)
          : SeparableBSSRDF(name, params)
        {
            m_inputs.declare("weight", InputFormatScalar, "1.0");
            m_inputs.declare("reflectance", InputFormatSpectralReflectance);
            m_inputs.declare("reflectance_multiplier", InputFormatScalar, "1.0");
            m_inputs.declare("dmfp", InputFormatSpectralReflectance);
            m_inputs.declare("dmfp_multiplier", InputFormatScalar, "1.0");
            m_inputs.declare("outside_ior", InputFormatScalar);
            m_inputs.declare("inside_ior", InputFormatScalar);
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual size_t compute_input_data_size(
            const Assembly&     assembly) const APPLESEED_OVERRIDE
        {
            return align(sizeof(NormalizedDiffusionBSSRDFInputValues), 16);
        }

        virtual void prepare_inputs(void* data) const APPLESEED_OVERRIDE
        {
            NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<NormalizedDiffusionBSSRDFInputValues*>(data);

            // Precompute the relative index of refraction.
            values->m_eta = values->m_outside_ior / values->m_inside_ior;

            // Apply multipliers.
            values->m_reflectance *= static_cast<float>(values->m_reflectance_multiplier);
            values->m_dmfp *= static_cast<float>(values->m_dmfp_multiplier);

            if (values->m_reflectance.size() != values->m_dmfp.size())
            {
                // Since it does not really make sense to convert a dmfp,
                // a per channel distance, as if it were a color,
                // we instead always convert the reflectance to match the
                // size of the dmfp.
                if (values->m_dmfp.is_spectral())
                {
                    Spectrum::upgrade(
                        values->m_reflectance,
                        values->m_reflectance);
                }
                else
                {
                    Spectrum::downgrade(
                        m_lighting_conditions,
                        values->m_reflectance,
                        values->m_reflectance);
                }
            }

            // Clamp input values.
            values->m_reflectance = clamp(values->m_reflectance, 0.001f, 0.999f);
            values->m_dmfp = clamp_low(values->m_dmfp, 1.0e-5f);

            // Build a CDF for channel sampling.

            values->m_s.resize(values->m_reflectance.size());
            values->m_channel_pdf.resize(values->m_reflectance.size());
            values->m_channel_cdf.resize(values->m_reflectance.size());

            float cumulated_pdf = 0.0f;
            for (size_t i = 0, e = values->m_channel_pdf.size(); i < e; ++i)
            {
                const double a = static_cast<double>(values->m_reflectance[i]);
                const double s = normalized_diffusion_s(a);
                values->m_s[i] = static_cast<float>(s);

                const double l = values->m_dmfp[i];
                const float pdf = static_cast<float>(s / l);
                values->m_channel_pdf[i] = pdf;

                cumulated_pdf += pdf;
                values->m_channel_cdf[i] = cumulated_pdf;
            }

            const float rcp_cumulated_pdf = 1.0f / cumulated_pdf;
            values->m_channel_pdf *= rcp_cumulated_pdf;
            values->m_channel_cdf *= rcp_cumulated_pdf;
            values->m_channel_cdf[values->m_channel_cdf.size() - 1] = 1.0f;

            // Precompute the (square of the) max radius.
            values->m_rmax2 = 0.0;
            for (size_t i = 0, e = values->m_dmfp.size(); i < e; ++i)
            {
                const double l = static_cast<double>(values->m_dmfp[i]);
                values->m_rmax2 =
                    max(
                        normalized_diffusion_max_radius(l, values->m_s[i]),
                        values->m_rmax2);
            }

            values->m_rmax2 *= values->m_rmax2;
        }

        virtual bool sample(
            SamplingContext&    sampling_context,
            const void*         data,
            BSSRDFSample&       sample) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            if (values->m_weight == 0.0)
                return false;

            sampling_context.split_in_place(3, 1);
            const Vector3d s = sampling_context.next_vector2<3>();

            // Sample a channel.
            const float* cdf_begin = &values->m_channel_cdf[0];
            const size_t channel =
                sample_cdf(
                    cdf_begin,
                    cdf_begin + values->m_channel_cdf.size(),
                    s[0]);

            // Sample a radius.
            const double l = values->m_dmfp[channel];
            const double radius =
                normalized_diffusion_sample(s[1], l, values->m_s[channel]);

            // Sample an angle.
            const double phi = TwoPi * s[2];

            sample.m_eta = values->m_eta;
            sample.m_channel = channel;
            sample.m_point = Vector2d(radius * cos(phi), radius * sin(phi));
            sample.m_rmax2 = values->m_rmax2;

            return true;
        }

        virtual double get_eta(
            const void*         data) const APPLESEED_OVERRIDE
        {
            return reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data)->m_eta;
        }

        virtual void evaluate_profile(
            const void*         data,
            const double        square_radius,
            Spectrum&           value) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            const double radius = sqrt(square_radius);

            value.resize(values->m_reflectance.size());

            for (size_t i = 0, e = value.size(); i < e; ++i)
            {
                const double a = values->m_reflectance[i];
                const double s = values->m_s[i];
                const double l = values->m_dmfp[i];
                value[i] = static_cast<float>(normalized_diffusion_profile(radius, l, s, a));
            }

            // Return r * R(r) * weight.
            value *= static_cast<float>(radius * values->m_weight);
        }

        virtual double evaluate_pdf(
            const void*         data,
            const size_t        channel,
            const double        radius) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            // PDF of the sampled radius.
            double pdf_radius = 0.0;
            for (size_t i = 0, e = values->m_reflectance.size(); i < e; ++i)
            {
                const double l = values->m_dmfp[i];
                pdf_radius +=
                    normalized_diffusion_pdf(
                        radius,
                        l,
                        values->m_s[i])
                    * values->m_channel_pdf[i];
            }

            // PDF of the sampled angle.
            const double pdf_angle = RcpTwoPi;

            // Compute and return the final PDF.
            return pdf_radius * pdf_angle;
        }

      private:
        static const LightingConditions m_lighting_conditions;
    };

    const LightingConditions NormalizedDiffusionBSSRDF::m_lighting_conditions(
        IlluminantCIED65,
        XYZCMFCIE196410Deg);
}

//
// NormalizedDiffusionBSSRDFFactory class implementation.
//

const char* NormalizedDiffusionBSSRDFFactory::get_model() const
{
    return Model;
}

Dictionary NormalizedDiffusionBSSRDFFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", Model)
            .insert("label", "Normalized Diffusion BSSRDF");
}

DictionaryArray NormalizedDiffusionBSSRDFFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "weight")
            .insert("label", "Weight")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "reflectance")
            .insert("label", "Diffuse Surface Reflectance")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "0.5"));

    metadata.push_back(
        Dictionary()
            .insert("name", "reflectance_multiplier")
            .insert("label", "Diffuse Surface Reflectance Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "dmfp")
            .insert("label", "Diffuse Mean Free Path")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "0.5"));

    metadata.push_back(
        Dictionary()
            .insert("name", "dmfp_multiplier")
            .insert("label", "Diffuse Mean Free Path Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "outside_ior")
            .insert("label", "Outside Index of Refraction")
            .insert("type", "numeric")
            .insert("min_value", "1.0")
            .insert("max_value", "2.5")
            .insert("use", "required")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "inside_ior")
            .insert("label", "Inside Index of Refraction")
            .insert("type", "numeric")
            .insert("min_value", "1.0")
            .insert("max_value", "2.5")
            .insert("use", "required")
            .insert("default", "1.3"));

    return metadata;
}

auto_release_ptr<BSSRDF> NormalizedDiffusionBSSRDFFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return auto_release_ptr<BSSRDF>(new NormalizedDiffusionBSSRDF(name, params));
}

auto_release_ptr<BSSRDF> NormalizedDiffusionBSSRDFFactory::static_create(
    const char*         name,
    const ParamArray&   params)
{
    return auto_release_ptr<BSSRDF>(new NormalizedDiffusionBSSRDF(name, params));
}

}   // namespace renderer
<commit_msg>Fix race condition during initialization of static variables<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2015-2016 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "normalizeddiffusionbssrdf.h"

// appleseed.renderer headers.
#include "renderer/modeling/bssrdf/bssrdfsample.h"
#include "renderer/modeling/bssrdf/separablebssrdf.h"
#include "renderer/modeling/bssrdf/sss.h"
#include "renderer/modeling/input/inputevaluator.h"

// appleseed.foundation headers.
#include "foundation/image/colorspace.h"
#include "foundation/math/cdf.h"
#include "foundation/math/scalar.h"
#include "foundation/math/vector.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"
#include "foundation/utility/memory.h"

// Standard headers.
#include <cmath>
#include <cstddef>

// Forward declarations.
namespace renderer  { class Assembly; }
namespace renderer  { class ShadingContext; }

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Normalized diffusion BSSRDF.
    //
    // Reference:
    //
    //   Approximate Reflectance Profiles for Efficient Subsurface Scattering
    //   Per H. Christensen, Brent Burley
    //   http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf
    //

    const char* Model = "normalized_diffusion_bssrdf";

    class NormalizedDiffusionBSSRDF
      : public SeparableBSSRDF
    {
      public:
        NormalizedDiffusionBSSRDF(
            const char*         name,
            const ParamArray&   params)
          : SeparableBSSRDF(name, params)
          , m_lighting_conditions(IlluminantCIED65, XYZCMFCIE196410Deg)
        {
            m_inputs.declare("weight", InputFormatScalar, "1.0");
            m_inputs.declare("reflectance", InputFormatSpectralReflectance);
            m_inputs.declare("reflectance_multiplier", InputFormatScalar, "1.0");
            m_inputs.declare("dmfp", InputFormatSpectralReflectance);
            m_inputs.declare("dmfp_multiplier", InputFormatScalar, "1.0");
            m_inputs.declare("outside_ior", InputFormatScalar);
            m_inputs.declare("inside_ior", InputFormatScalar);
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual size_t compute_input_data_size(
            const Assembly&     assembly) const APPLESEED_OVERRIDE
        {
            return align(sizeof(NormalizedDiffusionBSSRDFInputValues), 16);
        }

        virtual void prepare_inputs(void* data) const APPLESEED_OVERRIDE
        {
            NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<NormalizedDiffusionBSSRDFInputValues*>(data);

            // Precompute the relative index of refraction.
            values->m_eta = values->m_outside_ior / values->m_inside_ior;

            // Apply multipliers.
            values->m_reflectance *= static_cast<float>(values->m_reflectance_multiplier);
            values->m_dmfp *= static_cast<float>(values->m_dmfp_multiplier);

            if (values->m_reflectance.size() != values->m_dmfp.size())
            {
                // Since it does not really make sense to convert a dmfp,
                // a per channel distance, as if it were a color,
                // we instead always convert the reflectance to match the
                // size of the dmfp.
                if (values->m_dmfp.is_spectral())
                {
                    Spectrum::upgrade(
                        values->m_reflectance,
                        values->m_reflectance);
                }
                else
                {
                    Spectrum::downgrade(
                        m_lighting_conditions,
                        values->m_reflectance,
                        values->m_reflectance);
                }
            }

            // Clamp input values.
            values->m_reflectance = clamp(values->m_reflectance, 0.001f, 0.999f);
            values->m_dmfp = clamp_low(values->m_dmfp, 1.0e-5f);

            // Build a CDF for channel sampling.

            values->m_s.resize(values->m_reflectance.size());
            values->m_channel_pdf.resize(values->m_reflectance.size());
            values->m_channel_cdf.resize(values->m_reflectance.size());

            float cumulated_pdf = 0.0f;
            for (size_t i = 0, e = values->m_channel_pdf.size(); i < e; ++i)
            {
                const double a = static_cast<double>(values->m_reflectance[i]);
                const double s = normalized_diffusion_s(a);
                values->m_s[i] = static_cast<float>(s);

                const double l = values->m_dmfp[i];
                const float pdf = static_cast<float>(s / l);
                values->m_channel_pdf[i] = pdf;

                cumulated_pdf += pdf;
                values->m_channel_cdf[i] = cumulated_pdf;
            }

            const float rcp_cumulated_pdf = 1.0f / cumulated_pdf;
            values->m_channel_pdf *= rcp_cumulated_pdf;
            values->m_channel_cdf *= rcp_cumulated_pdf;
            values->m_channel_cdf[values->m_channel_cdf.size() - 1] = 1.0f;

            // Precompute the (square of the) max radius.
            values->m_rmax2 = 0.0;
            for (size_t i = 0, e = values->m_dmfp.size(); i < e; ++i)
            {
                const double l = static_cast<double>(values->m_dmfp[i]);
                values->m_rmax2 =
                    max(
                        normalized_diffusion_max_radius(l, values->m_s[i]),
                        values->m_rmax2);
            }

            values->m_rmax2 *= values->m_rmax2;
        }

        virtual bool sample(
            SamplingContext&    sampling_context,
            const void*         data,
            BSSRDFSample&       sample) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            if (values->m_weight == 0.0)
                return false;

            sampling_context.split_in_place(3, 1);
            const Vector3d s = sampling_context.next_vector2<3>();

            // Sample a channel.
            const float* cdf_begin = &values->m_channel_cdf[0];
            const size_t channel =
                sample_cdf(
                    cdf_begin,
                    cdf_begin + values->m_channel_cdf.size(),
                    s[0]);

            // Sample a radius.
            const double l = values->m_dmfp[channel];
            const double radius =
                normalized_diffusion_sample(s[1], l, values->m_s[channel]);

            // Sample an angle.
            const double phi = TwoPi * s[2];

            sample.m_eta = values->m_eta;
            sample.m_channel = channel;
            sample.m_point = Vector2d(radius * cos(phi), radius * sin(phi));
            sample.m_rmax2 = values->m_rmax2;

            return true;
        }

        virtual double get_eta(
            const void*         data) const APPLESEED_OVERRIDE
        {
            return reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data)->m_eta;
        }

        virtual void evaluate_profile(
            const void*         data,
            const double        square_radius,
            Spectrum&           value) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            const double radius = sqrt(square_radius);

            value.resize(values->m_reflectance.size());

            for (size_t i = 0, e = value.size(); i < e; ++i)
            {
                const double a = values->m_reflectance[i];
                const double s = values->m_s[i];
                const double l = values->m_dmfp[i];
                value[i] = static_cast<float>(normalized_diffusion_profile(radius, l, s, a));
            }

            // Return r * R(r) * weight.
            value *= static_cast<float>(radius * values->m_weight);
        }

        virtual double evaluate_pdf(
            const void*         data,
            const size_t        channel,
            const double        radius) const APPLESEED_OVERRIDE
        {
            const NormalizedDiffusionBSSRDFInputValues* values =
                reinterpret_cast<const NormalizedDiffusionBSSRDFInputValues*>(data);

            // PDF of the sampled radius.
            double pdf_radius = 0.0;
            for (size_t i = 0, e = values->m_reflectance.size(); i < e; ++i)
            {
                const double l = values->m_dmfp[i];
                pdf_radius +=
                    normalized_diffusion_pdf(
                        radius,
                        l,
                        values->m_s[i])
                    * values->m_channel_pdf[i];
            }

            // PDF of the sampled angle.
            const double pdf_angle = RcpTwoPi;

            // Compute and return the final PDF.
            return pdf_radius * pdf_angle;
        }

      private:
        const LightingConditions m_lighting_conditions;
    };
}

//
// NormalizedDiffusionBSSRDFFactory class implementation.
//

const char* NormalizedDiffusionBSSRDFFactory::get_model() const
{
    return Model;
}

Dictionary NormalizedDiffusionBSSRDFFactory::get_model_metadata() const
{
    return
        Dictionary()
            .insert("name", Model)
            .insert("label", "Normalized Diffusion BSSRDF");
}

DictionaryArray NormalizedDiffusionBSSRDFFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "weight")
            .insert("label", "Weight")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "reflectance")
            .insert("label", "Diffuse Surface Reflectance")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "0.5"));

    metadata.push_back(
        Dictionary()
            .insert("name", "reflectance_multiplier")
            .insert("label", "Diffuse Surface Reflectance Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "dmfp")
            .insert("label", "Diffuse Mean Free Path")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "required")
            .insert("default", "0.5"));

    metadata.push_back(
        Dictionary()
            .insert("name", "dmfp_multiplier")
            .insert("label", "Diffuse Mean Free Path Multiplier")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "outside_ior")
            .insert("label", "Outside Index of Refraction")
            .insert("type", "numeric")
            .insert("min_value", "1.0")
            .insert("max_value", "2.5")
            .insert("use", "required")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "inside_ior")
            .insert("label", "Inside Index of Refraction")
            .insert("type", "numeric")
            .insert("min_value", "1.0")
            .insert("max_value", "2.5")
            .insert("use", "required")
            .insert("default", "1.3"));

    return metadata;
}

auto_release_ptr<BSSRDF> NormalizedDiffusionBSSRDFFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return auto_release_ptr<BSSRDF>(new NormalizedDiffusionBSSRDF(name, params));
}

auto_release_ptr<BSSRDF> NormalizedDiffusionBSSRDFFactory::static_create(
    const char*         name,
    const ParamArray&   params)
{
    return auto_release_ptr<BSSRDF>(new NormalizedDiffusionBSSRDF(name, params));
}

}   // namespace renderer
<|endoftext|>