<commit_before>///
/// @file  LoadBalancer.cpp
/// @brief The LoadBalancer assigns work to the individual threads
///        in the computation of the special leaves in the
///        Lagarias-Miller-Odlyzko, Deleglise-Rivat and Gourdon
///        prime counting algorithms.
///
///        Simply parallelizing the computation of the special
///        leaves in the Lagarias-Miller-Odlyzko algorithm by
///        subdividing the sieve interval by the number of threads
///        into equally sized subintervals does not scale because
///        the distribution of the special leaves is highly skewed
///        and most special leaves are in the first few segments
///        whereas later on there are very few special leaves.
///
///        This LoadBalancer gradually increases the number of
///        segments to sieve as long the expected runtime of the
///        sieve distance is smaller than the expected finish time
///        of the algorithm. Near the end the LoadBalancer will
///        gradually decrease the number of segments to sieve in
///        order to prevent that 1 thread will run much longer
///        than all the other threads.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <S2Status.hpp>
#include <Sieve.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <print.hpp>

#include <stdint.h>
#include <cmath>

using namespace std;

namespace primecount {

LoadBalancer::LoadBalancer(maxint_t x,
                           int64_t sieve_limit,
                           maxint_t sum_approx) :
  low_(0),
  max_low_(0),
  sieve_limit_(sieve_limit),
  segments_(1),
  sum_(0),
  sum_approx_(sum_approx),
  time_(get_time()),
  status_(x)
{
  // start with a tiny segment_size as most
  // special leaves are in the first few segments
  // and we need to ensure that all threads are
  // assigned an equal amount of work
  int64_t sqrt_limit = isqrt(sieve_limit);
  int64_t log = ilog(sqrt_limit);
  log = max(log, 1);
  segment_size_ = sqrt_limit / log;

  int64_t min_size = 1 << 9;
  segment_size_ = max(segment_size_, min_size);
  segment_size_ = Sieve::get_segment_size(segment_size_);

  // try to use a segment size that fits exactly
  // into the CPUs L1 data cache
  int64_t l1_dcache_size = 1 << 15;
  max_size_ = l1_dcache_size * 30;
  max_size_ = max(max_size_, sqrt_limit);
  max_size_ = Sieve::get_segment_size(max_size_);
}

maxint_t LoadBalancer::get_sum() const
{
  return sum_;
}

bool LoadBalancer::get_work(int64_t* low,
                            int64_t* segments,
                            int64_t* segment_size,
                            maxint_t sum,
                            Runtime& runtime)
{
  #pragma omp critical (get_work)
  {
    sum_ += sum;

    update(low, segments, runtime);

    *low = low_;
    *segments = segments_;
    *segment_size = segment_size_;
    low_ += segments_ * segment_size_;

    if (is_print())
      status_.print(sum_, sum_approx_);
  }

  return *low < sieve_limit_;
}

void LoadBalancer::update(int64_t* low,
                          int64_t* segments,
                          Runtime& runtime)
{
  if (*low > max_low_)
  {
    max_low_ = *low;
    segments_ = *segments;

    // We only start increasing the segment_size and segments
    // per thread once the first special leaves have been
    // found. Near the start there is a very large number of
    // leaves and we don't want a single thread to compute
    // them all by himself (which would cause scaling issues).
    if (sum_ == 0)
      return;

    if (segment_size_ < max_size_)
      segment_size_ = min(segment_size_ * 2, max_size_);
    else
      update_segments(runtime);
  }
}

/// Remaining seconds till finished
double LoadBalancer::remaining_secs() const
{
  double percent = status_.getPercent(low_, sieve_limit_, sum_, sum_approx_);
  percent = in_between(10, percent, 100);
  double total_secs = get_time() - time_;
  double secs = total_secs * (100 / percent) - total_secs;
  return secs;
}

/// Increase or decrease the number of segments per thread
/// based on the remaining runtime.
///
void LoadBalancer::update_segments(Runtime& runtime)
{
  // Near the end it is important that threads run only for
  // a short amount of time in order to ensure that all
  // threads finish nearly at the same time. Since the
  // remaining time is just a rough estimation we want to be
  // very conservative so we divide the remaining time by 4.
  double rem_secs = remaining_secs() / 4;

  // If the previous thread runtime is larger than the
  // estimated remaining time the factor that we calculate
  // below will be < 1 and we will reduce the number of
  // segments per thread. Otherwise if the factor > 1 we
  // will increase the number of segments per thread.
  double min_secs = 0.01;
  double divider = max(min_secs, runtime.secs);
  double factor = rem_secs / divider;

  // For small and medium computations the thread runtime
  // should be about 1000x the thread initialization time.
  // However for very large computations we want to further
  // reduce the thread runtimes in order to increase the
  // backup frequency. If the thread runtime is > 12 hours
  // we reduce the thread runtime to about 50x the thread
  // initialization time.
  double init_secs = max(min_secs, runtime.init);
  double init_factor = in_between(50, (3600 * 12) / init_secs, 1000);

  // Reduce the thread runtime if it is much larger than
  // its initialization time. This increases the number of
  // backups without deteriorating performance as we make
  // sure that the thread runtime is still much larger than
  // the thread initialization time.
  if (runtime.secs > min_secs &&
      runtime.secs > runtime.init * init_factor)
  {
    double old = factor;
    double next_runtime = runtime.init * init_factor;
    factor = next_runtime / runtime.secs;
    factor = min(factor, old);
  }

  // Near the end when the remaining time goes close to 0
  // the load balancer tends to reduce the number of
  // segments per thread also close to 0 which is very bad
  // for performance. The condition below fixes this issue
  // and ensures that the thread runtime is always at
  // least 10x the thread initialization time.
  if (runtime.secs > 0 &&
      runtime.secs * factor < runtime.init * 10)
  {
    double next_runtime = runtime.init * 10;
    double current_runtime = runtime.secs;
    factor = next_runtime / current_runtime;
  }

  // Since the distribution of the special leaves is highly
  // skewed (at the beginning) we want to increase the
  // number of segments per thread very slowly. Because if
  // the previously sieved interval contained no special
  // leaves but the next interval contains many special
  // leaves then sieving the next interval might take orders
  // of magnitude more time even if the interval size is
  // identical.
  factor = in_between(0.5, factor, 2.0);
  double next_runtime = runtime.secs * factor;

  if (next_runtime < min_secs)
    segments_ *= 2;
  else
  {
    double new_segments = round(segments_ * factor);
    segments_ = (int64_t) new_segments;
    segments_ = max(segments_, 1);
  }
}

} // namespace
<commit_msg>Tune load balancing<commit_after>///
/// @file  LoadBalancer.cpp
/// @brief The LoadBalancer assigns work to the individual threads
///        in the computation of the special leaves in the
///        Lagarias-Miller-Odlyzko, Deleglise-Rivat and Gourdon
///        prime counting algorithms.
///
///        Simply parallelizing the computation of the special
///        leaves in the Lagarias-Miller-Odlyzko algorithm by
///        subdividing the sieve interval by the number of threads
///        into equally sized subintervals does not scale because
///        the distribution of the special leaves is highly skewed
///        and most special leaves are in the first few segments
///        whereas later on there are very few special leaves.
///
///        This LoadBalancer gradually increases the number of
///        segments to sieve as long the expected runtime of the
///        sieve distance is smaller than the expected finish time
///        of the algorithm. Near the end the LoadBalancer will
///        gradually decrease the number of segments to sieve in
///        order to prevent that 1 thread will run much longer
///        than all the other threads.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <S2Status.hpp>
#include <Sieve.hpp>
#include <imath.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <print.hpp>

#include <stdint.h>
#include <cmath>

using namespace std;

namespace primecount {

LoadBalancer::LoadBalancer(maxint_t x,
                           int64_t sieve_limit,
                           maxint_t sum_approx) :
  low_(0),
  max_low_(0),
  sieve_limit_(sieve_limit),
  segments_(1),
  sum_(0),
  sum_approx_(sum_approx),
  time_(get_time()),
  status_(x)
{
  // start with a tiny segment_size as most
  // special leaves are in the first few segments
  // and we need to ensure that all threads are
  // assigned an equal amount of work
  int64_t sqrt_limit = isqrt(sieve_limit);
  int64_t log = ilog(sqrt_limit);
  log = max(log, 1);
  segment_size_ = sqrt_limit / log;

  int64_t min_size = 1 << 9;
  segment_size_ = max(segment_size_, min_size);
  segment_size_ = Sieve::get_segment_size(segment_size_);

  // try to use a segment size that fits exactly
  // into the CPUs L1 data cache
  int64_t l1_dcache_size = 1 << 15;
  max_size_ = l1_dcache_size * 30;
  max_size_ = max(max_size_, sqrt_limit);
  max_size_ = Sieve::get_segment_size(max_size_);
}

maxint_t LoadBalancer::get_sum() const
{
  return sum_;
}

bool LoadBalancer::get_work(int64_t* low,
                            int64_t* segments,
                            int64_t* segment_size,
                            maxint_t sum,
                            Runtime& runtime)
{
  #pragma omp critical (get_work)
  {
    sum_ += sum;

    update(low, segments, runtime);

    *low = low_;
    *segments = segments_;
    *segment_size = segment_size_;
    low_ += segments_ * segment_size_;

    if (is_print())
      status_.print(sum_, sum_approx_);
  }

  return *low < sieve_limit_;
}

void LoadBalancer::update(int64_t* low,
                          int64_t* segments,
                          Runtime& runtime)
{
  if (*low > max_low_)
  {
    max_low_ = *low;
    segments_ = *segments;

    // We only start increasing the segment_size and segments
    // per thread once the first special leaves have been
    // found. Near the start there is a very large number of
    // leaves and we don't want a single thread to compute
    // them all by himself (which would cause scaling issues).
    if (sum_ == 0)
      return;

    if (segment_size_ < max_size_)
      segment_size_ = min(segment_size_ * 2, max_size_);
    else
      update_segments(runtime);
  }
}

/// Remaining seconds till finished
double LoadBalancer::remaining_secs() const
{
  double percent = status_.getPercent(low_, sieve_limit_, sum_, sum_approx_);
  percent = in_between(10, percent, 100);
  double total_secs = get_time() - time_;
  double secs = total_secs * (100 / percent) - total_secs;
  return secs;
}

/// Increase or decrease the number of segments per thread
/// based on the remaining runtime.
///
void LoadBalancer::update_segments(Runtime& runtime)
{
  // Near the end it is important that threads run only for
  // a short amount of time in order to ensure that all
  // threads finish nearly at the same time. Since the
  // remaining time is just a rough estimation we want to be
  // very conservative so we divide the remaining time by 4.
  double rem_secs = remaining_secs() / 4;

  // If the previous thread runtime is larger than the
  // estimated remaining time the factor that we calculate
  // below will be < 1 and we will reduce the number of
  // segments per thread. Otherwise if the factor > 1 we
  // will increase the number of segments per thread.
  double min_secs = 0.01;
  double divider = max(min_secs, runtime.secs);
  double factor = rem_secs / divider;

  // For small and medium computations the thread runtime
  // should be about 1000x the thread initialization time.
  // However for very large computations we want to further
  // reduce the thread runtimes in order to increase the
  // backup frequency. If the thread runtime is > 6 hours
  // we reduce the thread runtime to about 50x the thread
  // initialization time.
  double init_secs = max(min_secs, runtime.init);
  double init_factor = in_between(50, (3600 * 6) / init_secs, 1000);

  // Reduce the thread runtime if it is much larger than
  // its initialization time. This increases the number of
  // backups without deteriorating performance as we make
  // sure that the thread runtime is still much larger than
  // the thread initialization time.
  if (runtime.secs > min_secs &&
      runtime.secs > runtime.init * init_factor)
  {
    double old = factor;
    double next_runtime = runtime.init * init_factor;
    factor = next_runtime / runtime.secs;
    factor = min(factor, old);
  }

  // Near the end when the remaining time goes close to 0
  // the load balancer tends to reduce the number of
  // segments per thread also close to 0 which is very bad
  // for performance. The condition below fixes this issue
  // and ensures that the thread runtime is always at
  // least 10x the thread initialization time.
  if (runtime.secs > 0 &&
      runtime.secs * factor < runtime.init * 10)
  {
    double next_runtime = runtime.init * 10;
    double current_runtime = runtime.secs;
    factor = next_runtime / current_runtime;
  }

  // Since the distribution of the special leaves is highly
  // skewed (at the beginning) we want to increase the
  // number of segments per thread very slowly. Because if
  // the previously sieved interval contained no special
  // leaves but the next interval contains many special
  // leaves then sieving the next interval might take orders
  // of magnitude more time even if the interval size is
  // identical.
  factor = in_between(0.5, factor, 2.0);
  double next_runtime = runtime.secs * factor;

  if (next_runtime < min_secs)
    segments_ *= 2;
  else
  {
    double new_segments = round(segments_ * factor);
    segments_ = (int64_t) new_segments;
    segments_ = max(segments_, 1);
  }
}

} // namespace
<|endoftext|>


<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/>.
 */
#include "ElemAttribute.hpp"

#include <sax/AttributeList.hpp>
//#include <sax/SAXException.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>

#include "AVT.hpp"
#include "Constants.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"

ElemAttribute::ElemAttribute(
			StylesheetConstructionContext&	constructionContext,
			Stylesheet&						stylesheetTree,
			const DOMString&				name,
			const AttributeList&			atts,
			int								lineNumber,
			int								columnNumber) :
	ElemTemplateElement(constructionContext,
						stylesheetTree,
						name,
						lineNumber,
						columnNumber),
	m_pNameAVT(0),
	m_pNamespaceAVT(0)
{
	const int nAttrs = atts.getLength();

	for(int i = 0; i < nAttrs; i++)
	{
		const DOMString aname(atts.getName(i));

		if(equals(aname, Constants::ATTRNAME_NAME))
		{
			m_pNameAVT = new AVT(aname, atts.getType(i), atts.getValue(i),
				*this, constructionContext);
		}
		else if(equals(aname,Constants::ATTRNAME_NAMESPACE))
		{
			m_pNamespaceAVT = new AVT(aname, atts.getType(i), atts.getValue(i),
				*this, constructionContext);
		}
		else if(!(isAttrOK(aname, atts, i, constructionContext) ||
			processSpaceAttr(aname, atts, i)))
		{
			constructionContext.error(name + " has an illegal attribute: " + aname);
		}
	}

	if(0 == m_pNameAVT)
	{
		constructionContext.error(name + " must have a name attribute.");
	}

}

ElemAttribute::~ElemAttribute()
{
	delete m_pNameAVT;

	delete m_pNamespaceAVT;
}

int
ElemAttribute::getXSLToken() const
{
	return Constants::ELEMNAME_ATTRIBUTE;
}

void
ElemAttribute::execute(
			StylesheetExecutionContext&		executionContext,
			const DOM_Node&					sourceTree,
			const DOM_Node&					sourceNode,
			const QName&					mode) const
{
	ElemTemplateElement::execute(executionContext, sourceTree, sourceNode, mode);

	assert(m_pNameAVT != 0);

	DOMString attrName;

	m_pNameAVT->evaluate(attrName, sourceNode, *this,
		executionContext.getXPathExecutionContext());

	if(!isEmpty(attrName))
	{
		if(0 != m_pNamespaceAVT)
		{
			DOMString attrNameSpace;
			m_pNamespaceAVT->evaluate(attrNameSpace, sourceNode,
				*this, executionContext.getXPathExecutionContext());

			if(!isEmpty(attrNameSpace))
			{
				DOMString prefix = executionContext.getResultPrefixForNamespace(attrNameSpace);

				if(isEmpty(prefix))
				{
					prefix = executionContext.getUniqueNameSpaceValue();

					DOMString nsDecl = DOMString("xmlns:") + prefix;

					executionContext.addResultAttribute(nsDecl, attrNameSpace);
				}

				attrName = prefix + DOMString(":") + attrName;
			}
		}

		if(!isEmpty(executionContext.getPendingElementName()))
		{
			const DOMString	val = childrenToString(executionContext, sourceTree, sourceNode, mode);

			executionContext.addResultAttribute(attrName, val);
		}
		else
		{
			//warn(templateChild, sourceNode, "Trying to add attribute after element child has been added, ignoring...");
		}
	}
}

NodeImpl* ElemAttribute::appendChild(NodeImpl* newChild)
{
	assert(dynamic_cast<ElemTemplateElement*>(newChild) != 0);

	const int	type = dynamic_cast<ElemTemplateElement*>(newChild)->getXSLToken();

	switch(type)
	{
		// char-instructions
	case Constants::ELEMNAME_TEXTLITERALRESULT:
	case Constants::ELEMNAME_APPLY_TEMPLATES:
	case Constants::ELEMNAME_APPLY_IMPORTS:
	case Constants::ELEMNAME_CALLTEMPLATE:
	case Constants::ELEMNAME_FOREACH:
	case Constants::ELEMNAME_VALUEOF:
	case Constants::ELEMNAME_COPY_OF:
	case Constants::ELEMNAME_NUMBER:
	case Constants::ELEMNAME_CHOOSE:
	case Constants::ELEMNAME_IF:
	case Constants::ELEMNAME_TEXT:
	case Constants::ELEMNAME_COPY:
	case Constants::ELEMNAME_VARIABLE:
	case Constants::ELEMNAME_MESSAGE:

		// instructions
		// case Constants.ELEMNAME_PI:
		// case Constants.ELEMNAME_COMMENT:
		// case Constants.ELEMNAME_ELEMENT:
		// case Constants.ELEMNAME_ATTRIBUTE:
		break;

	default:
		error("Can not add " + dynamic_cast<ElemTemplateElement*>(newChild)->getTagName() + " to " + getTagName());
		break;
	}

	return ElemTemplateElement::appendChild(newChild);
}
<commit_msg>Added code missing from java version<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/>.
 */
#include "ElemAttribute.hpp"

#include <sax/AttributeList.hpp>
//#include <sax/SAXException.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>

#include "AVT.hpp"
#include "Constants.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"

ElemAttribute::ElemAttribute(
			StylesheetConstructionContext&	constructionContext,
			Stylesheet&						stylesheetTree,
			const DOMString&				name,
			const AttributeList&			atts,
			int								lineNumber,
			int								columnNumber) :
	ElemTemplateElement(constructionContext,
						stylesheetTree,
						name,
						lineNumber,
						columnNumber),
	m_pNameAVT(0),
	m_pNamespaceAVT(0)
{
	const int nAttrs = atts.getLength();

	for(int i = 0; i < nAttrs; i++)
	{
		const DOMString aname(atts.getName(i));

		if(equals(aname, Constants::ATTRNAME_NAME))
		{
			m_pNameAVT = new AVT(aname, atts.getType(i), atts.getValue(i),
				*this, constructionContext);
		}
		else if(equals(aname,Constants::ATTRNAME_NAMESPACE))
		{
			m_pNamespaceAVT = new AVT(aname, atts.getType(i), atts.getValue(i),
				*this, constructionContext);
		}
		else if(!(isAttrOK(aname, atts, i, constructionContext) ||
			processSpaceAttr(aname, atts, i)))
		{
			constructionContext.error(name + " has an illegal attribute: " + aname);
		}
	}

	if(0 == m_pNameAVT)
	{
		constructionContext.error(name + " must have a name attribute.");
	}

}

ElemAttribute::~ElemAttribute()
{
	delete m_pNameAVT;

	delete m_pNamespaceAVT;
}

int
ElemAttribute::getXSLToken() const
{
	return Constants::ELEMNAME_ATTRIBUTE;
}

void
ElemAttribute::execute(
			StylesheetExecutionContext&		executionContext,
			const DOM_Node&					sourceTree,
			const DOM_Node&					sourceNode,
			const QName&					mode) const
{
	ElemTemplateElement::execute(executionContext, sourceTree, sourceNode, mode);

	assert(m_pNameAVT != 0);

	DOMString attrName;
	DOMString origAttrName = attrName;      // save original attribute name
	int indexOfNSSep = 0;

	m_pNameAVT->evaluate(attrName, sourceNode, *this,
		executionContext.getXPathExecutionContext());

	if(!isEmpty(attrName))
	{
	   DOMString attrNameSpace;
		if(0 != m_pNamespaceAVT)
		{
			m_pNamespaceAVT->evaluate(attrNameSpace, sourceNode,
				*this, executionContext.getXPathExecutionContext());

			if(!isEmpty(attrNameSpace))
			{
				DOMString prefix = executionContext.getResultPrefixForNamespace(attrNameSpace);

				if(isEmpty(prefix))
				{
					prefix = executionContext.getUniqueNameSpaceValue();

					DOMString nsDecl = DOMString("xmlns:") + prefix;

					executionContext.addResultAttribute(nsDecl, attrNameSpace);
				}
				indexOfNSSep = indexOf(origAttrName, ':');
				if(indexOfNSSep >= 0)
					attrName = substring(attrName, indexOfNSSep+1);
				attrName = prefix + DOMString(":") + attrName;
			}
		}
      // Note we are using original attribute name for these tests.
		else if(!isEmpty(executionContext.getPendingElementName())
				&& !equals(origAttrName, "xmlns"))
		{
			// make sure that if a prefix is specified on the attribute name, it is valid
			indexOfNSSep = indexOf(origAttrName, ':');
			if(indexOfNSSep >= 0)
			{
				DOMString nsprefix = substring(origAttrName, 0, indexOfNSSep);
				attrNameSpace = getNamespaceForPrefix(nsprefix);
				if (isEmpty(attrNameSpace))
				{
					// Could not resolve prefix
					// @@ TODO: processor.warn(XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX, new Object[]{nsprefix});
				}
			}
			if (indexOfNSSep<0 || ! isEmpty(attrNameSpace))
			{
				const DOMString val = childrenToString(executionContext,
					sourceTree, sourceNode, mode);
				executionContext.addResultAttribute(attrName, val);
			}
			else
			{
				//warn(templateChild, sourceNode, "Trying to add attribute after element child has been added, ignoring...");
			}
		}
	}
}

NodeImpl* ElemAttribute::appendChild(NodeImpl* newChild)
{
	assert(dynamic_cast<ElemTemplateElement*>(newChild) != 0);

	const int	type = dynamic_cast<ElemTemplateElement*>(newChild)->getXSLToken();

	switch(type)
	{
		// char-instructions
	case Constants::ELEMNAME_TEXTLITERALRESULT:
	case Constants::ELEMNAME_APPLY_TEMPLATES:
	case Constants::ELEMNAME_APPLY_IMPORTS:
	case Constants::ELEMNAME_CALLTEMPLATE:
	case Constants::ELEMNAME_FOREACH:
	case Constants::ELEMNAME_VALUEOF:
	case Constants::ELEMNAME_COPY_OF:
	case Constants::ELEMNAME_NUMBER:
	case Constants::ELEMNAME_CHOOSE:
	case Constants::ELEMNAME_IF:
	case Constants::ELEMNAME_TEXT:
	case Constants::ELEMNAME_COPY:
	case Constants::ELEMNAME_VARIABLE:
	case Constants::ELEMNAME_MESSAGE:

		// instructions
		// case Constants.ELEMNAME_PI:
		// case Constants.ELEMNAME_COMMENT:
		// case Constants.ELEMNAME_ELEMENT:
		// case Constants.ELEMNAME_ATTRIBUTE:
		break;

	default:
		error("Can not add " + dynamic_cast<ElemTemplateElement*>(newChild)->getTagName() + " to " + getTagName());
		break;
	}

	return ElemTemplateElement::appendChild(newChild);
}
<|endoftext|>


<commit_before>#include "WeakTactic.hpp"
#include "Bind.hpp"

namespace wrd {

    WRD_DEF_THIS(WeakTactic)

    wbool This::assign(Bind& me, const Bind& rhs) {
        if(&me == &rhs) return true;

        me._tactic = rhs._tactic;
        return me.bind(rhs.get());
    }

    wbool This::unbind(Bind& me) {
        me._itsId.rel();
        return true;
    }

    wbool This::bind(Bind& me, const Instance& it) {
        unbind(me);
        //  regardless of result from _onStrong binder can bind:
        //      there are two reasons:
        //          because Block has equal lifecycle to what it bind, if there is
        //          a request by user to refer a bind for binding freed instance,
        //          user has responsibilty to treat wrongly.
        //          so, we should not consider such cases.
        //
        //      and:
        //          no matter how block reacts, anyway it won't refuse binder's
        //          refering. for instance, the scenario for binding non-heap allocated
        //          instance.
        me._itsId = it.getId();
        WRD_DI("Bind(%x) binds Instance(%x) of %s class",
                &me, &it, it.getType().getName().c_str());
        return true;
    }

    This This::singletone;
}
<commit_msg>- [memlite] remove WeakTactic::bind log. * it's not quite useful but make me hard to catch the point when see logs.<commit_after>#include "WeakTactic.hpp"
#include "Bind.hpp"

namespace wrd {

    WRD_DEF_THIS(WeakTactic)

    wbool This::assign(Bind& me, const Bind& rhs) {
        if(&me == &rhs) return true;

        me._tactic = rhs._tactic;
        return me.bind(rhs.get());
    }

    wbool This::unbind(Bind& me) {
        me._itsId.rel();
        return true;
    }

    wbool This::bind(Bind& me, const Instance& it) {
        unbind(me);
        //  regardless of result from _onStrong binder can bind:
        //      there are two reasons:
        //          because Block has equal lifecycle to what it bind, if there is
        //          a request by user to refer a bind for binding freed instance,
        //          user has responsibilty to treat wrongly.
        //          so, we should not consider such cases.
        //
        //      and:
        //          no matter how block reacts, anyway it won't refuse binder's
        //          refering. for instance, the scenario for binding non-heap allocated
        //          instance.
        me._itsId = it.getId();
        return true;
    }

    This This::singletone;
}
<|endoftext|>


<commit_before>/* medToolBoxRegistration.cpp ---
 *
 * Author: Julien Wintz
 * Copyright (C) 2008 - Julien Wintz, Inria.
 * Created: Fri Feb 19 09:06:02 2010 (+0100)
 * Version: $Id$
 * Last-Updated: Wed Nov 10 16:32:30 2010 (+0100)
 *           By: Julien Wintz
 *     Update #: 272
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include "medToolBoxRegistration.h"

#include <dtkCore/dtkAbstractDataFactory.h>
#include <dtkCore/dtkAbstractData.h>
#include <dtkCore/dtkAbstractProcessFactory.h>
#include <dtkCore/dtkAbstractProcess.h>
#include <dtkCore/dtkAbstractViewInteractor.h>

#include <medDataManager.h>
#include <medViewManager.h>
#include <medMessageController.h>
#include <medMetaDataKeys.h>
#include <medAbstractView.h>

#include <medAbstractDataImage.h>

#include <medToolBoxTab.h>
#include <medToolBoxFactory.h>

#include <medToolBoxRegistrationCustom.h>

#include <QtGui>

class medToolBoxRegistrationPrivate
{
public:
//    medDropSite *processDropSiteFixed;
//    medDropSite *processDropSiteMoving;

//    QRadioButton *blendRadio;
//    QRadioButton *checkerboardRadio;
//    QSlider *layoutFuseSlider;

    QPushButton * saveImageButton;
    QPushButton * saveTransButton;

    QComboBox *toolboxes;
    medAbstractView *fixedView;
    medAbstractView *movingView;
    medAbstractView *fuseView;

    dtkSmartPointer<medAbstractDataImage> fixedData;
    dtkSmartPointer<medAbstractDataImage> movingData;

    dtkAbstractProcess * process;

    medToolBoxRegistrationCustom * customToolBox;
};

medToolBoxRegistration::medToolBoxRegistration(QWidget *parent) : medToolBox(parent), d(new medToolBoxRegistrationPrivate)
{
    d->fuseView = 0;
    d->fixedData  = NULL;
    d->movingData = NULL;
    d->fixedView  = NULL;
    d->movingView = NULL;
    d->process = NULL;

    // Process section
    d->saveImageButton = new QPushButton(tr("Save Image"),this);
    connect (d->saveImageButton, SIGNAL(clicked()), this, SLOT(onSaveImage()));

    d->saveTransButton = new QPushButton(tr("Save Transformation"),this);
    connect (d->saveTransButton, SIGNAL(clicked()), this, SLOT(onSaveTrans()));

    // --- Setting up custom toolboxes list ---

    d->toolboxes = new QComboBox(this);
    d->toolboxes->addItem(tr("Choose algorithm"));
    medToolBoxFactory* tbFactory =medToolBoxFactory::instance();
    int i=1;
    foreach(QString toolbox, tbFactory->registrationToolBoxes())
    {
        QPair<const QString&, const QString&> pair =
                tbFactory->registrationToolBoxDetailsFromId(toolbox);
        QString name = pair.first;
        QString description = pair.second;
        qDebug() << "Added registration toolbox" << name;
        d->toolboxes->addItem(name, toolbox);
        d->toolboxes->setItemData(i,
                                  description,
                                  Qt::ToolTipRole);
        i++;
    }

    connect(d->toolboxes, SIGNAL(activated(int)), this, SLOT(onToolBoxChosen(int)));

    // /////////////////////////////////////////////////////////////////
    // Setup
    // /////////////////////////////////////////////////////////////////

    // ---
    QButtonGroup *layoutButtonGroup = new QButtonGroup(this);
    layoutButtonGroup->addButton(d->saveImageButton);
    layoutButtonGroup->addButton(d->saveTransButton);

    QHBoxLayout *layoutButtonLayout = new QHBoxLayout;
    layoutButtonLayout->addWidget(d->saveImageButton);
    layoutButtonLayout->addWidget(d->saveTransButton);

    QVBoxLayout *layoutLayout = new QVBoxLayout;
    layoutLayout->addLayout(layoutButtonLayout);

    QWidget * layoutSection = new QWidget(this);
    layoutSection->setLayout(layoutLayout);

    addWidget(d->toolboxes);
    addWidget(layoutSection);
    //addWidget(d->saveImageButton);
    //addWidget(d->saveTransButton);

    this->setTitle(tr("Registration"));
    d->customToolBox = NULL;

    //Connect Message Controller:
    connect(this,SIGNAL(showError(QObject*,const QString&,unsigned int)),
            medMessageController::instance(),SLOT(showError(QObject*,const QString&,unsigned int)));
    connect(this,SIGNAL(showInfo(QObject*,const QString&,unsigned int)),
            medMessageController::instance(),SLOT(showInfo(QObject*,const QString&,unsigned int)));
}

medToolBoxRegistration::~medToolBoxRegistration(void)
{
    delete d;

    d = NULL;
}

dtkAbstractView *medToolBoxRegistration::fixedView(void)
{
    return d->fixedView;
}

dtkAbstractView *medToolBoxRegistration::movingView(void)
{
    return d->movingView;
}

dtkAbstractView *medToolBoxRegistration::fuseView(void)
{
    return d->fuseView;
}

medAbstractDataImage *medToolBoxRegistration::fixedData(void)
{
    return d->fixedData;
}

medAbstractDataImage *medToolBoxRegistration::movingData(void)
{
    return d->movingData;
}

//void medToolBoxRegistration::onBlendModeSet(bool value)
//{
//    if (value)
//        if (d->fuseView)
//            if (dtkAbstractViewInteractor *interactor = d->fuseView->interactor("v3dViewFuseInteractor")) {
//                interactor->setProperty("FusionStyle", "blend");
//                d->fuseView->update();
//            }
//}

//void medToolBoxRegistration::onCheckerboardModeSet(bool value)
//{
//    if (value)
//        if (d->fuseView)
//            if (dtkAbstractViewInteractor *interactor = d->fuseView->interactor("v3dViewFuseInteractor")) {
//                interactor->setProperty("FusionStyle", "checkerboard");
//                d->fuseView->update();
//            }
//}

void medToolBoxRegistration::onFixedImageDropped (const medDataIndex& index)
{

    if (!index.isValid())
        return;

    d->fixedData = medDataManager::instance()->data(index);

    if (!d->fixedData)
        return;

    d->fixedView = dynamic_cast<medAbstractView*>
                   (medViewManager::instance()->views(index).first());

    if(!d->fixedView) {
        qDebug() << "Unable to retrieve fixed view";
	return;
    }

    if (d->fuseView)
    {
        if (d->movingView && d->fuseView->layerCount()==1)
        {
            //only the moving view has been set: shift it to layer 1
            d->fuseView->setData(d->fixedData,0);
            d->fuseView->setData(d->movingData,1);
        }
        else
        {
            //either both views are set, or only the fixed view
            d->fuseView->setData(d->fixedData,0);
        }
        d->fuseView->reset();
        d->fuseView->update();
    }
}

void medToolBoxRegistration::onMovingImageDropped (const medDataIndex& index)
{

    if (!index.isValid())
        return;

    d->movingData = medDataManager::instance()->data(index);

    if (!d->movingData)
        return;

    d->movingView = dynamic_cast<medAbstractView*>
                    (medViewManager::instance()->views
                     (index).first());

    if(!d->movingView) {
        qDebug() << "Unable to retrieve moving view";
	return;
    }

    if (d->fixedView) {
        d->movingView->update();
    }

    if (d->fixedView)
    {
        //already one layer present
        d->fuseView->setData(d->movingData,1);
    }
    else
    {
        //only the moving view is set
        d->fuseView->setData(d->movingData,0);
    }
    //d->fuseView->reset();
    d->fuseView->update();
}

void medToolBoxRegistration::onToolBoxChosen(int index)
{
    //get identifier for toolbox.
    QString id = d->toolboxes->itemData(index).toString();

    medToolBoxRegistrationCustom *toolbox = medToolBoxFactory::instance()->createCustomRegistrationToolBox(id);

    if(!toolbox) {
        qWarning() << "Unable to instanciate" << id << "toolbox";
        return;
    }

    toolbox->setRegistrationToolBox(this);
    //get rid of old toolBox
    if (d->customToolBox)
    {
        emit removeToolBox(d->customToolBox);
        delete d->customToolBox;
    }
    d->customToolBox = toolbox;
    toolbox->show();
    emit addToolBox(toolbox);

    connect (toolbox, SIGNAL (success()), this, SLOT (onSuccess()));
    connect (toolbox, SIGNAL (failure()), this, SIGNAL (failure()));
}

void medToolBoxRegistration::setFuseView(dtkAbstractView *view)
{
    if (!view)
        return;

    d->fuseView = dynamic_cast <medAbstractView*> (view);
//    d->fuseView->enableInteractor("v3dViewFuseInteractor");
//    dtkAbstractViewInteractor *interactor = d->fuseView->interactor("v3dViewFuseInteractor");

//    connect(d->layoutFuseSlider, SIGNAL(valueChanged(int)), interactor,
//            SLOT(onBlendAlphaValueSet(int)));
//    connect(d->layoutFuseSlider, SIGNAL(valueChanged(int)), interactor,
//            SLOT(onCheckerboardDivisionCountValueSet(int)));
}

void medToolBoxRegistration::clear(void)
{

    //maybe clear the customtoolbox?
    if (d->customToolBox)
        d->customToolBox->clear();
}

dtkAbstractProcess * medToolBoxRegistration::process(void)
{
    return d->process;
}

void medToolBoxRegistration::setProcess(dtkAbstractProcess* proc)
{
    d->process = proc;
}

void medToolBoxRegistration::onSaveImage()
{
    if ( !d->movingData)
    {
        emit showError(this, tr  ("Please Select a moving image before saving"),3000);
        return;
    }
    if (!d->process )
    {
        emit showError(this, tr  ("Please run the registration before saving"),3000);
        return;
    }
    QFileDialog dialog(this, tr("Save Image"),
                               QDir::homePath(),
                               tr("MetaFile (*.mha *.mhd);;Nifty (*.nii);;Analyse (*.hdr);;Nrrd (*.nrrd);;VTK (*.vtk);;All supported files (*.mha *.mhd *.nii *.hdr *.nrrd)"));
    dialog.setDefaultSuffix("mha");
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    QStringList fileName;
    if (dialog.exec())
        fileName = dialog.selectedFiles();

    qDebug() << fileName;

    if (!fileName.isEmpty())
    {
        //qDebug()<< (void *) d->movingData;
        //qDebug()<<  d->movingView->data();
        if (d->process->write(fileName[0]))
        {
            emit(showInfo(this, tr  ("Registered Image Saved"),3000));
        }
        else
        {
            emit(showError(this, tr  ("Image saving failed, no suitable writer found"),3000));
        }
    }

}

void medToolBoxRegistration::onSaveTrans()
{
    if (!d->movingData)
    {
        emit showError(this, tr  ("Please Select a moving image before saving"),3000);
        return;
    }
    if (!d->process )
    {
        emit showError(this, tr  ("Please run the registration before saving"),3000);
        return;
    }
    QFileDialog dialog(this, tr("Save Transformation"),
                               QDir::homePath(),
                               tr("Transformation (*.txt);;MetaFile (*.mha *.mhd);;Nifty (*.nii);;Analyse (*.hdr);;Nrrd (*.nrrd);;VTK (*.vtk);;All supported files (*.mha *.mhd *.nii *.hdr *.nrrd)"));

    dialog.setDefaultSuffix("mha");
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    QStringList fileName;
    if (dialog.exec())
        fileName = dialog.selectedFiles();

    qDebug() << fileName;

    if (!fileName.isEmpty())
    {
        //qDebug()<< (void *) d->movingData;
        //qDebug()<<  d->movingView->data();
        QStringList transformFileName;
        transformFileName << "" << fileName[0];
        if (d->process->write(transformFileName))
        {
            emit(showInfo(this, tr  ("Registered Image Saved"),3000));
        }
        else
        {
            emit(showError(this, tr  ("Image saving failed, no suitable writer found"),3000));
        }
    }
}

void medToolBoxRegistration::onSuccess()
{
    dtkAbstractData *output = d->process->output();

    foreach(QString metaData, d->fixedData->metaDataList())
        output->addMetaData(metaData,d->fixedData->metaDataValues(metaData));

    foreach(QString property, d->fixedData->propertyList())
        output->addProperty(property,d->fixedData->propertyValues(property));

    QString newDescription = d->movingData->metadata(medMetaDataKeys::SeriesDescription.key());
    newDescription += " registered";
    output->setMetaData(medMetaDataKeys::SeriesDescription.key(), newDescription);

    medDataManager::instance()->importNonPersistent(output);

    if(output)
    {
        d->movingView->setData(output,0);
        d->fixedView->unlink (d->movingView);
        d->fixedView->link (d->movingView);
        d->movingView->update();
        d->fuseView->setData(output,1);
        d->fuseView->update();

    }
}
<commit_msg>Removed comments<commit_after>/* medToolBoxRegistration.cpp ---
 *
 * Author: Julien Wintz
 * Copyright (C) 2008 - Julien Wintz, Inria.
 * Created: Fri Feb 19 09:06:02 2010 (+0100)
 * Version: $Id$
 * Last-Updated: Wed Nov 10 16:32:30 2010 (+0100)
 *           By: Julien Wintz
 *     Update #: 272
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include "medToolBoxRegistration.h"

#include <dtkCore/dtkAbstractDataFactory.h>
#include <dtkCore/dtkAbstractData.h>
#include <dtkCore/dtkAbstractProcessFactory.h>
#include <dtkCore/dtkAbstractProcess.h>
#include <dtkCore/dtkAbstractViewInteractor.h>

#include <medDataManager.h>
#include <medViewManager.h>
#include <medMessageController.h>
#include <medMetaDataKeys.h>
#include <medAbstractView.h>

#include <medAbstractDataImage.h>

#include <medToolBoxTab.h>
#include <medToolBoxFactory.h>

#include <medToolBoxRegistrationCustom.h>

#include <QtGui>

class medToolBoxRegistrationPrivate
{
public:
    QPushButton * saveImageButton;
    QPushButton * saveTransButton;

    QComboBox *toolboxes;
    medAbstractView *fixedView;
    medAbstractView *movingView;
    medAbstractView *fuseView;

    dtkSmartPointer<medAbstractDataImage> fixedData;
    dtkSmartPointer<medAbstractDataImage> movingData;

    dtkAbstractProcess * process;

    medToolBoxRegistrationCustom * customToolBox;
};

medToolBoxRegistration::medToolBoxRegistration(QWidget *parent) : medToolBox(parent), d(new medToolBoxRegistrationPrivate)
{
    d->fuseView = 0;
    d->fixedData  = NULL;
    d->movingData = NULL;
    d->fixedView  = NULL;
    d->movingView = NULL;
    d->process = NULL;

    // Process section
    d->saveImageButton = new QPushButton(tr("Save Image"),this);
    connect (d->saveImageButton, SIGNAL(clicked()), this, SLOT(onSaveImage()));

    d->saveTransButton = new QPushButton(tr("Save Transformation"),this);
    connect (d->saveTransButton, SIGNAL(clicked()), this, SLOT(onSaveTrans()));

    // --- Setting up custom toolboxes list ---

    d->toolboxes = new QComboBox(this);
    d->toolboxes->addItem(tr("Choose algorithm"));
    medToolBoxFactory* tbFactory =medToolBoxFactory::instance();
    int i=1;
    foreach(QString toolbox, tbFactory->registrationToolBoxes())
    {
        QPair<const QString&, const QString&> pair =
                tbFactory->registrationToolBoxDetailsFromId(toolbox);
        QString name = pair.first;
        QString description = pair.second;
//        qDebug() << "Added registration toolbox" << name;
        d->toolboxes->addItem(name, toolbox);
        d->toolboxes->setItemData(i,
                                  description,
                                  Qt::ToolTipRole);
        i++;
    }

    connect(d->toolboxes, SIGNAL(activated(int)), this, SLOT(onToolBoxChosen(int)));

    // /////////////////////////////////////////////////////////////////
    // Setup
    // /////////////////////////////////////////////////////////////////

    // ---
    QButtonGroup *layoutButtonGroup = new QButtonGroup(this);
    layoutButtonGroup->addButton(d->saveImageButton);
    layoutButtonGroup->addButton(d->saveTransButton);

    QHBoxLayout *layoutButtonLayout = new QHBoxLayout;
    layoutButtonLayout->addWidget(d->saveImageButton);
    layoutButtonLayout->addWidget(d->saveTransButton);

    QVBoxLayout *layoutLayout = new QVBoxLayout;
    layoutLayout->addLayout(layoutButtonLayout);

    QWidget * layoutSection = new QWidget(this);
    layoutSection->setLayout(layoutLayout);

    addWidget(d->toolboxes);
    addWidget(layoutSection);
    //addWidget(d->saveImageButton);
    //addWidget(d->saveTransButton);

    this->setTitle(tr("Registration"));
    d->customToolBox = NULL;

    //Connect Message Controller:
    connect(this,SIGNAL(showError(QObject*,const QString&,unsigned int)),
            medMessageController::instance(),SLOT(showError(QObject*,const QString&,unsigned int)));
    connect(this,SIGNAL(showInfo(QObject*,const QString&,unsigned int)),
            medMessageController::instance(),SLOT(showInfo(QObject*,const QString&,unsigned int)));
}

medToolBoxRegistration::~medToolBoxRegistration(void)
{
    delete d;

    d = NULL;
}

dtkAbstractView *medToolBoxRegistration::fixedView(void)
{
    return d->fixedView;
}

dtkAbstractView *medToolBoxRegistration::movingView(void)
{
    return d->movingView;
}

dtkAbstractView *medToolBoxRegistration::fuseView(void)
{
    return d->fuseView;
}

medAbstractDataImage *medToolBoxRegistration::fixedData(void)
{
    return d->fixedData;
}

medAbstractDataImage *medToolBoxRegistration::movingData(void)
{
    return d->movingData;
}

void medToolBoxRegistration::onFixedImageDropped (const medDataIndex& index)
{

    if (!index.isValid())
        return;

    d->fixedData = medDataManager::instance()->data(index);

    if (!d->fixedData)
        return;

    d->fixedView = dynamic_cast<medAbstractView*>
                   (medViewManager::instance()->views(index).first());

    if(!d->fixedView) {
        qDebug() << "Unable to retrieve fixed view";
	return;
    }

    if (d->fuseView)
    {
        if (d->movingView && d->fuseView->layerCount()==1)
        {
            //only the moving view has been set: shift it to layer 1
            d->fuseView->setData(d->fixedData,0);
            d->fuseView->setData(d->movingData,1);
        }
        else
        {
            //either both views are set, or only the fixed view
            d->fuseView->setData(d->fixedData,0);
        }
        d->fuseView->reset();
        d->fuseView->update();
    }
}

void medToolBoxRegistration::onMovingImageDropped (const medDataIndex& index)
{

    if (!index.isValid())
        return;

    d->movingData = medDataManager::instance()->data(index);

    if (!d->movingData)
        return;

    d->movingView = dynamic_cast<medAbstractView*>
                    (medViewManager::instance()->views
                     (index).first());

    if(!d->movingView) {
        qDebug() << "Unable to retrieve moving view";
	return;
    }

    if (d->fixedView) {
        d->movingView->update();
    }

    if (d->fixedView)
    {
        //already one layer present
        d->fuseView->setData(d->movingData,1);
    }
    else
    {
        //only the moving view is set
        d->fuseView->setData(d->movingData,0);
    }
    //d->fuseView->reset();
    d->fuseView->update();
}

void medToolBoxRegistration::onToolBoxChosen(int index)
{
    //get identifier for toolbox.
    QString id = d->toolboxes->itemData(index).toString();

    medToolBoxRegistrationCustom *toolbox = medToolBoxFactory::instance()->createCustomRegistrationToolBox(id);

    if(!toolbox) {
        qWarning() << "Unable to instantiate" << id << "toolbox";
        return;
    }

    toolbox->setRegistrationToolBox(this);
    //get rid of old toolBox
    if (d->customToolBox)
    {
        emit removeToolBox(d->customToolBox);
        delete d->customToolBox;
    }
    d->customToolBox = toolbox;
    toolbox->show();
    emit addToolBox(toolbox);

    connect (toolbox, SIGNAL (success()), this, SLOT (onSuccess()));
    connect (toolbox, SIGNAL (failure()), this, SIGNAL (failure()));
}

void medToolBoxRegistration::setFuseView(dtkAbstractView *view)
{
    if (!view)
        return;

    d->fuseView = dynamic_cast <medAbstractView*> (view);
}

void medToolBoxRegistration::clear(void)
{

    //maybe clear the customtoolbox?
    if (d->customToolBox)
        d->customToolBox->clear();
}

dtkAbstractProcess * medToolBoxRegistration::process(void)
{
    return d->process;
}

void medToolBoxRegistration::setProcess(dtkAbstractProcess* proc)
{
    d->process = proc;
}

void medToolBoxRegistration::onSaveImage()
{
    if ( !d->movingData)
    {
        emit showError(this, tr  ("Please Select a moving image before saving"),3000);
        return;
    }
    if (!d->process )
    {
        emit showError(this, tr  ("Please run the registration before saving"),3000);
        return;
    }
    QFileDialog dialog(this, tr("Save Image"),
                               QDir::homePath(),
                               tr("MetaFile (*.mha *.mhd);;Nifty (*.nii);;Analyse (*.hdr);;Nrrd (*.nrrd);;VTK (*.vtk);;All supported files (*.mha *.mhd *.nii *.hdr *.nrrd)"));
    dialog.setDefaultSuffix("mha");
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    QStringList fileName;
    if (dialog.exec())
        fileName = dialog.selectedFiles();

    qDebug() << fileName;

    if (!fileName.isEmpty())
    {
        //qDebug()<< (void *) d->movingData;
        //qDebug()<<  d->movingView->data();
        if (d->process->write(fileName[0]))
        {
            emit(showInfo(this, tr  ("Registered Image Saved"),3000));
        }
        else
        {
            emit(showError(this, tr  ("Image saving failed, no suitable writer found"),3000));
        }
    }

}

void medToolBoxRegistration::onSaveTrans()
{
    if (!d->movingData)
    {
        emit showError(this, tr  ("Please Select a moving image before saving"),3000);
        return;
    }
    if (!d->process )
    {
        emit showError(this, tr  ("Please run the registration before saving"),3000);
        return;
    }
    QFileDialog dialog(this, tr("Save Transformation"),
                               QDir::homePath(),
                               tr("Transformation (*.txt);;MetaFile (*.mha *.mhd);;Nifty (*.nii);;Analyse (*.hdr);;Nrrd (*.nrrd);;VTK (*.vtk);;All supported files (*.mha *.mhd *.nii *.hdr *.nrrd)"));

    dialog.setDefaultSuffix("mha");
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    QStringList fileName;
    if (dialog.exec())
        fileName = dialog.selectedFiles();

    qDebug() << fileName;

    if (!fileName.isEmpty())
    {
        //qDebug()<< (void *) d->movingData;
        //qDebug()<<  d->movingView->data();
        QStringList transformFileName;
        transformFileName << "" << fileName[0];
        if (d->process->write(transformFileName))
        {
            emit(showInfo(this, tr  ("Registered Image Saved"),3000));
        }
        else
        {
            emit(showError(this, tr  ("Image saving failed, no suitable writer found"),3000));
        }
    }
}

void medToolBoxRegistration::onSuccess()
{
    dtkAbstractData *output = d->process->output();

    foreach(QString metaData, d->fixedData->metaDataList())
        output->addMetaData(metaData,d->fixedData->metaDataValues(metaData));

    foreach(QString property, d->fixedData->propertyList())
        output->addProperty(property,d->fixedData->propertyValues(property));

    QString newDescription = d->movingData->metadata(medMetaDataKeys::SeriesDescription.key());
    newDescription += " registered";
    output->setMetaData(medMetaDataKeys::SeriesDescription.key(), newDescription);

    medDataManager::instance()->importNonPersistent(output);

    if(output)
    {
        d->movingView->setData(output,0);
        d->fixedView->unlink (d->movingView);
        d->fixedView->link (d->movingView);
        d->movingView->update();
        d->fuseView->setData(output,1);
        d->fuseView->update();

    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "gfx/codec/png_codec.h"
#include "net/test/test_server.h"
#include "ui/base/clipboard/clipboard.h"

extern base::hash_map<std::string, int> g_test_timeout_overrides;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;
static const int kLoadingTestTimeoutMs = 60000;

// The loading test is really a collection of tests, each one being a different
// PDF file.  But it would be busy work to add a different test for each file.
// Since we run them all in one test, we want a bigger timeout.
class IncreaseLoadingTimeout {
 public:
  IncreaseLoadingTimeout() {
    g_test_timeout_overrides["PDFBrowserTest.Loading"] = kLoadingTestTimeoutMs;
  }
};

IncreaseLoadingTimeout g_increase_loading_timeout;

class PDFBrowserTest : public InProcessBrowserTest,
                       public NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    EnableDOMAutomation();

    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));

    scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info(
        WindowSizer::CreateDefaultMonitorInfoProvider());
    gfx::Rect screen_bounds = monitor_info->GetPrimaryMonitorBounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);

    browser()->window()->SetBounds(bounds);
  }

  void VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    RenderViewHost* host =
        browser()->GetSelectedTabContents()->render_view_host();

    host->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(this,
                                   NotificationType::TAB_SNAPSHOT_TAKEN,
                                   Source<RenderViewHost>(host));
    ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result "
        "at " << snapshot_filename_.value().c_str();
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        browser()->GetSelectedTabContentsWrapper(), query, true, false, NULL));
  }

 private:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kForceInternalPDFPlugin);
  }

  // NotificationObserver
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == NotificationType::LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen NotificationType::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Basic FLAKY_Basic
#else
#define MAYBE_Basic Basic
#endif

// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Basic) {

  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_Scroll FLAKY_Scroll
#else
#define MAYBE_Scroll Scroll
#endif

// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  tab_contents->render_view_host()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest_scroll.png"));
}

#if defined(OS_MACOSX)
// See http://crbug.com/63223
#define MAYBE_FindAndCopy FLAKY_FindAndCopy
#else
#define MAYBE_FindAndCopy FindAndCopy
#endif

IN_PROC_BROWSER_TEST_F(PDFBrowserTest, MAYBE_FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      browser()->GetSelectedTabContentsWrapper(), UTF8ToUTF16("adipiscing"),
      true, false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[ui::Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(objects);

  browser()->GetSelectedTabContents()->render_view_host()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(browser()->GetSelectedTabContents()->controller());
  NotificationRegistrar registrar;
  registrar.Add(this,
                NotificationType::LOAD_STOP,
                Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = WideToASCII(file_path.BaseName().ToWStringHack());

#if defined(OS_MACOSX) || defined(OS_LINUX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous NotificationType::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
          browser()->GetSelectedTabContents()->render_view_host(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      ui_test_utils::WaitForLoadStop(controller);
    }
  }
}

}  // namespace
<commit_msg>Get rid of pdf browser test flakiness.  The issue was slight changes in the font sub-pixel rendering.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/window_sizer.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "gfx/codec/png_codec.h"
#include "net/test/test_server.h"
#include "ui/base/clipboard/clipboard.h"

extern base::hash_map<std::string, int> g_test_timeout_overrides;

namespace {

// Include things like browser frame and scrollbar and make sure we're bigger
// than the test pdf document.
static const int kBrowserWidth = 1000;
static const int kBrowserHeight = 600;
static const int kLoadingTestTimeoutMs = 60000;

// The loading test is really a collection of tests, each one being a different
// PDF file.  But it would be busy work to add a different test for each file.
// Since we run them all in one test, we want a bigger timeout.
class IncreaseLoadingTimeout {
 public:
  IncreaseLoadingTimeout() {
    g_test_timeout_overrides["PDFBrowserTest.Loading"] = kLoadingTestTimeoutMs;
  }
};

IncreaseLoadingTimeout g_increase_loading_timeout;

class PDFBrowserTest : public InProcessBrowserTest,
                       public NotificationObserver {
 public:
  PDFBrowserTest()
      : snapshot_different_(true),
        next_dummy_search_value_(0),
        load_stop_notification_count_(0) {
    EnableDOMAutomation();

    pdf_test_server_.reset(new net::TestServer(
        net::TestServer::TYPE_HTTP,
        FilePath(FILE_PATH_LITERAL("pdf/test"))));
  }

 protected:
  // Use our own TestServer so that we can serve files from the pdf directory.
  net::TestServer* pdf_test_server() { return pdf_test_server_.get(); }

  int load_stop_notification_count() const {
    return load_stop_notification_count_;
  }

  FilePath GetPDFTestDir() {
    return FilePath(FilePath::kCurrentDirectory).AppendASCII("..").
        AppendASCII("..").AppendASCII("..").AppendASCII("pdf").
        AppendASCII("test");
  }

  void Load() {
    // Make sure to set the window size before rendering, as otherwise rendering
    // to a smaller window and then expanding leads to slight anti-aliasing
    // differences of the text and the pixel comparison fails.
    gfx::Rect bounds(gfx::Rect(0, 0, kBrowserWidth, kBrowserHeight));
    scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_info(
        WindowSizer::CreateDefaultMonitorInfoProvider());
    gfx::Rect screen_bounds = monitor_info->GetPrimaryMonitorBounds();
    ASSERT_GT(screen_bounds.width(), kBrowserWidth);
    ASSERT_GT(screen_bounds.height(), kBrowserHeight);
    browser()->window()->SetBounds(bounds);

    GURL url(ui_test_utils::GetTestUrl(
        GetPDFTestDir(),
        FilePath(FILE_PATH_LITERAL("pdf_browsertest.pdf"))));
    ui_test_utils::NavigateToURL(browser(), url);
  }

  void VerifySnapshot(const std::string& expected_filename) {
    snapshot_different_ = true;
    expected_filename_ = expected_filename;
    RenderViewHost* host =
        browser()->GetSelectedTabContents()->render_view_host();

    host->CaptureSnapshot();
    ui_test_utils::RegisterAndWait(this,
                                   NotificationType::TAB_SNAPSHOT_TAKEN,
                                   Source<RenderViewHost>(host));
    ASSERT_FALSE(snapshot_different_) << "Rendering didn't match, see result "
        "at " << snapshot_filename_.value().c_str();
  }

  void WaitForResponse() {
    // Even if the plugin has loaded the data or scrolled, because of how
    // pepper painting works, we might not have the data.  One way to force this
    // to be flushed is to do a find operation, since on this two-page test
    // document, it'll wait for us to flush the renderer message loop twice and
    // also the browser's once, at which point we're guaranteed to have updated
    // the backingstore.  Hacky, but it works.
    // Note that we need to change the text each time, because if we don't the
    // renderer code will think the second message is to go to next result, but
    // there are none so the plugin will assert.

    string16 query = UTF8ToUTF16(
        std::string("xyzxyz" + base::IntToString(next_dummy_search_value_++)));
    ASSERT_EQ(0, ui_test_utils::FindInPage(
        browser()->GetSelectedTabContentsWrapper(), query, true, false, NULL));
  }

 private:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitch(switches::kForceInternalPDFPlugin);
  }

  // NotificationObserver
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    if (type == NotificationType::TAB_SNAPSHOT_TAKEN) {
      MessageLoopForUI::current()->Quit();
      FilePath reference = ui_test_utils::GetTestFilePath(
          GetPDFTestDir(),
          FilePath().AppendASCII(expected_filename_));
      base::PlatformFileInfo info;
      ASSERT_TRUE(file_util::GetFileInfo(reference, &info));
      int size = static_cast<size_t>(info.size);
      scoped_array<char> data(new char[size]);
      ASSERT_EQ(size, file_util::ReadFile(reference, data.get(), size));

      int w, h;
      std::vector<unsigned char> decoded;
      ASSERT_TRUE(gfx::PNGCodec::Decode(
          reinterpret_cast<unsigned char*>(data.get()), size,
          gfx::PNGCodec::FORMAT_BGRA, &decoded, &w, &h));
      int32* ref_pixels = reinterpret_cast<int32*>(&decoded[0]);

      const SkBitmap* bitmap = Details<const SkBitmap>(details).ptr();
      int32* pixels = static_cast<int32*>(bitmap->getPixels());

      // Get the background color, and use it to figure out the x-offsets in
      // each image.  The reason is that depending on the theme in the OS, the
      // same browser width can lead to slightly different plugin sizes, so the
      // pdf content will start at different x offsets.
      // Also note that the images we saved are cut off before the scrollbar, as
      // that'll change depending on the theme, and also cut off vertically so
      // that the ui controls don't show up, as those fade-in and so the timing
      // will affect their transparency.
      int32 bg_color = ref_pixels[0];
      int ref_x_offset, snapshot_x_offset;
      for (ref_x_offset = 0; ref_x_offset < w; ++ref_x_offset) {
        if (ref_pixels[ref_x_offset] != bg_color)
          break;
      }

      for (snapshot_x_offset = 0; snapshot_x_offset < bitmap->width();
           ++snapshot_x_offset) {
        if (pixels[snapshot_x_offset] != bg_color)
          break;
      }

      int x_max = std::min(
          w - ref_x_offset, bitmap->width() - snapshot_x_offset);
      int y_max = std::min(h, bitmap->height());
      int stride = bitmap->rowBytes();
      snapshot_different_ = false;
      for (int y = 0; y < y_max && !snapshot_different_; ++y) {
        for (int x = 0; x < x_max && !snapshot_different_; ++x) {
          if (pixels[y * stride / sizeof(int32) + x + snapshot_x_offset] !=
              ref_pixels[y * w + x + ref_x_offset])
            snapshot_different_ = true;
        }
      }

      if (snapshot_different_) {
        std::vector<unsigned char> png_data;
        gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &png_data);
        if (file_util::CreateTemporaryFile(&snapshot_filename_)) {
          file_util::WriteFile(snapshot_filename_,
              reinterpret_cast<char*>(&png_data[0]), png_data.size());
        }
      }
    } else if (type == NotificationType::LOAD_STOP) {
      load_stop_notification_count_++;
    }
  }

  // True if the snapshot differed from the expected value.
  bool snapshot_different_;
  // Internal variable used to synchronize to the renderer.
  int next_dummy_search_value_;
  // The filename of the bitmap to compare the snapshot to.
  std::string expected_filename_;
  // If the snapshot is different, holds the location where it's saved.
  FilePath snapshot_filename_;
  // How many times we've seen NotificationType::LOAD_STOP.
  int load_stop_notification_count_;

  scoped_ptr<net::TestServer> pdf_test_server_;
};

// Tests basic PDF rendering.  This can be broken depending on bad merges with
// the vendor, so it's important that we have basic sanity checking.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Basic) {

  ASSERT_NO_FATAL_FAILURE(Load());
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest.png"));
}

// Tests that scrolling works.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Scroll) {
  ASSERT_NO_FATAL_FAILURE(Load());

  // We use wheel mouse event since that's the only one we can easily push to
  // the renderer.  There's no way to push a cross-platform keyboard event at
  // the moment.
  WebKit::WebMouseWheelEvent wheel_event;
  wheel_event.type = WebKit::WebInputEvent::MouseWheel;
  wheel_event.deltaY = -200;
  wheel_event.wheelTicksY = -2;
  TabContents* tab_contents = browser()->GetSelectedTabContents();
  tab_contents->render_view_host()->ForwardWheelEvent(wheel_event);
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());
  ASSERT_NO_FATAL_FAILURE(VerifySnapshot("pdf_browsertest_scroll.png"));
}

IN_PROC_BROWSER_TEST_F(PDFBrowserTest, FindAndCopy) {
  ASSERT_NO_FATAL_FAILURE(Load());
  // Verifies that find in page works.
  ASSERT_EQ(3, ui_test_utils::FindInPage(
      browser()->GetSelectedTabContentsWrapper(), UTF8ToUTF16("adipiscing"),
      true, false, NULL));

  // Verify that copying selected text works.
  ui::Clipboard clipboard;
  // Reset the clipboard first.
  ui::Clipboard::ObjectMap objects;
  ui::Clipboard::ObjectMapParams params;
  params.push_back(std::vector<char>());
  objects[ui::Clipboard::CBF_TEXT] = params;
  clipboard.WriteObjects(objects);

  browser()->GetSelectedTabContents()->render_view_host()->Copy();
  ASSERT_NO_FATAL_FAILURE(WaitForResponse());

  std::string text;
  clipboard.ReadAsciiText(ui::Clipboard::BUFFER_STANDARD, &text);
  ASSERT_EQ("adipiscing", text);
}

// Tests that loading async pdfs works correctly (i.e. document fully loads).
// This also loads all documents that used to crash, to ensure we don't have
// regressions.
IN_PROC_BROWSER_TEST_F(PDFBrowserTest, Loading) {
  ASSERT_TRUE(pdf_test_server()->Start());

  NavigationController* controller =
      &(browser()->GetSelectedTabContents()->controller());
  NotificationRegistrar registrar;
  registrar.Add(this,
                NotificationType::LOAD_STOP,
                Source<NavigationController>(controller));
  std::string base_url = std::string("files/");

  file_util::FileEnumerator file_enumerator(
      ui_test_utils::GetTestFilePath(GetPDFTestDir(), FilePath()),
      false,
      file_util::FileEnumerator::FILES,
      FILE_PATH_LITERAL("*.pdf"));
  for (FilePath file_path = file_enumerator.Next();
       !file_path.empty();
       file_path = file_enumerator.Next()) {
    std::string filename = WideToASCII(file_path.BaseName().ToWStringHack());

#if defined(OS_MACOSX) || defined(OS_LINUX)
    if (filename == "sample.pdf")
      continue;  // Crashes on Mac and Linux.  http://crbug.com/63549
#endif

    LOG(WARNING) << "PDFBrowserTest.Loading: " << filename;

    GURL url = pdf_test_server()->GetURL(base_url + filename);
    ui_test_utils::NavigateToURL(browser(), url);

    while (true) {
      int last_count = load_stop_notification_count();
      // We might get extraneous NotificationType::LOAD_STOP notifications when
      // doing async loading.  This happens when the first loader is cancelled
      // and before creating a byte-range request loader.
      bool complete = false;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
          browser()->GetSelectedTabContents()->render_view_host(),
          std::wstring(),
          L"window.domAutomationController.send(plugin.documentLoadComplete())",
          &complete));
      if (complete)
        break;

      // Check if the LOAD_STOP notification could have come while we run a
      // nested message loop for the JS call.
      if (last_count != load_stop_notification_count())
        continue;
      ui_test_utils::WaitForLoadStop(controller);
    }
  }
}

}  // namespace
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 * ConcurrencyTests.cpp
 *
 *  Created on: Nov 25, 2010
 *      Author: Dimitar Asenov
 **********************************************************************************************************************/

#include "modelbase.h"
#include "selftest/headers/SelfTestSuite.h"
#include "BinaryNode.h"
#include "BinaryWithPosition.h"
#include "BinaryNodeUnit.h"
#include "Model.h"
#include "nodes/Integer.h"
#include "nodes/Text.h"

namespace Model {

TEST(ModelBase, ConcurrentRead)
{
	Model model;

	BinaryNode* root = dynamic_cast<BinaryNode*> (model.createRoot("BinaryNode"));

	model.beginModification(root, "make tree");
	root->makeLeftNode();
	root->makeRightNode();
	root->text()->set("Troot");
	root->left()->text()->set("Tleft");
	root->right()->text()->set("Tright");
	model.endModification();
	CHECK_INT_EQUAL(0,0)

}

}
<commit_msg>Added a test for the single unit write mechanism<commit_after>/***********************************************************************************************************************
 * ConcurrencyTests.cpp
 *
 *  Created on: Nov 25, 2010
 *      Author: Dimitar Asenov
 **********************************************************************************************************************/

#include "modelbase.h"
#include "selftest/headers/SelfTestSuite.h"
#include "BinaryNode.h"
#include "BinaryWithPosition.h"
#include "BinaryNodeUnit.h"
#include "Model.h"
#include "nodes/Integer.h"
#include "nodes/Text.h"

namespace Model {

TEST(ModelBase, SingleWriteUnitCheck)
{
	Model model;

	BinaryNode* root = dynamic_cast<BinaryNode*> (model.createRoot("BinaryNode"));

	model.beginModification(root, "make tree");
	BinaryNode* left = root->makeLeftNode();
	BinaryNode* right = root->makeRightNode("BinaryNodeUnit");
	BinaryNode* one = root->left()->makeLeftNode("BinaryNodeUnit");
	BinaryNode* two = root->left()->makeRightNode("BinaryNodeUnit");
	model.endModification();

	CHECK_STR_EQUAL(QString(), root->text()->get());
	CHECK_STR_EQUAL(QString(), left->text()->get());
	CHECK_STR_EQUAL(QString(), right->text()->get());
	CHECK_STR_EQUAL(QString(), one->text()->get());
	CHECK_STR_EQUAL(QString(), two->text()->get());

	model.beginModification(root, "Modify root");

	root->text()->set("This is ok");
	CHECK_STR_EQUAL("This is ok", root->text()->get());

	CHECK_FOR_EXCEPTION(ModelException, one->text()->set("This should fail"));
	CHECK_STR_EQUAL(QString(), one->text()->get());

	model.changeModificationTarget(one);
	CHECK_FOR_EXCEPTION(ModelException, root->text()->set("This should fail"));
	CHECK_STR_EQUAL("This is ok", root->text()->get());

	one->text()->set("one set");
	CHECK_STR_EQUAL("one set", one->text()->get());

	model.endModification();

	model.beginModification(NULL);
	model.undo();
	model.endModification();

	CHECK_STR_EQUAL(QString(), root->text()->get());
	CHECK_STR_EQUAL(QString(), left->text()->get());
	CHECK_STR_EQUAL(QString(), right->text()->get());
	CHECK_STR_EQUAL(QString(), one->text()->get());
	CHECK_STR_EQUAL(QString(), two->text()->get());

	model.beginModification(NULL);
	model.redo();
	model.endModification();

	CHECK_STR_EQUAL("This is ok", root->text()->get());
	CHECK_STR_EQUAL(QString(), left->text()->get());
	CHECK_STR_EQUAL(QString(), right->text()->get());
	CHECK_STR_EQUAL("one set", one->text()->get());
	CHECK_STR_EQUAL(QString(), two->text()->get());
}

}
<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "mozart.hh"

namespace mozart {

//////////////////////
// PropertyRegistry //
//////////////////////

PropertyRegistry::PropertyRegistry(VirtualMachineOptions options) {
  // Print

  config.printDepth = 10;
  config.printWidth = 20;

  // Errors

  config.errorsDebug = true;
  config.errorsDepth = 10;
  config.errorsWidth = 20;
  config.errorsThread = 40;

  // Garbage collection, aka memory management

  config.minimalHeapSize = options.minimalHeapSize;
  config.maximalHeapSize = options.maximalHeapSize;
  config.heapSize = config.minimalHeapSize;
  config.desiredFreeMemPercentageAfterGC = 75; // percent
  config.gcThresholdTolerance = 10; // percent
  computeInitialGCThreshold();
  computeMaxGCThreshold();
  config.autoGC = true;

  // Memory usage statistics

  stats.activeMemory = 0;
  stats.totalUsedMemory = 0;
}

void PropertyRegistry::registerPredefined(VM vm) {
  // Initialize value properties only now since they need the heap
  config.defaultExceptionHandler = new (vm) StableNode(vm, buildNil(vm));
  config.errorPrefix = new (vm) StableNode(vm, buildNil(vm));

  // Threads

  registerReadOnlyProp<nativeint>(vm, "threads.runnable",
    [] (VM vm) -> nativeint {
      return vm->getThreadPool().getRunnableCount();
    });
  registerConstantProp(vm, "threads.created", 0);
  registerConstantProp(vm, "threads.min", 1);

  // Print

  registerReadWriteProp(vm, "print.depth", config.printDepth);
  registerReadWriteProp(vm, "print.width", config.printWidth);

  // Errors

  registerProp(vm, "errors.handler",
    [this] (VM vm) -> UnstableNode {
      return { vm, *config.defaultExceptionHandler };
    },
    [this] (VM vm, RichNode value) {
      config.defaultExceptionHandler = value.getStableRef(vm);
    }
  );

  registerProp(vm, "errors.prefix",
    [this] (VM vm) -> UnstableNode {
      return { vm, *config.errorPrefix };
    },
    [this] (VM vm, RichNode value) {
      config.errorPrefix = value.getStableRef(vm);
    }
  );

  registerReadWriteProp(vm, "errors.debug", config.errorsDebug);
  registerReadWriteProp(vm, "errors.depth", config.errorsDepth);
  registerReadWriteProp(vm, "errors.width", config.errorsWidth);
  registerReadWriteProp(vm, "errors.thread", config.errorsThread);

  // Garbage collection, aka memory management

  registerConstantProp(vm, "gc.watcher", ReadOnlyVariable::build(vm));

  registerReadOnlyProp<nativeint>(vm, "gc.size",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocated();
    });

  registerReadOnlyProp(vm, "gc.active", stats.activeMemory);
  registerReadOnlyProp(vm, "gc.threshold", config.gcThreshold);
  registerReadOnlyProp(vm, "gc.heapsize", config.heapSize);

  registerReadWriteProp<nativeint>(vm, "gc.min",
    [this] (VM vm) {
      return config.minimalHeapSize;
    },
    [this] (VM vm, nativeint value) {
      if (value > 0 && value < config.maximalHeapSize)
        config.minimalHeapSize = value;
    }
  );
  registerReadWriteProp<nativeint>(vm, "gc.max",
    [this] (VM vm) {
      return config.maximalHeapSize;
    },
    [this] (VM vm, nativeint value) {
      if (value > config.minimalHeapSize) {
        config.maximalHeapSize = value;
        computeMaxGCThreshold();
      }
    }
  );
  registerReadWriteProp(vm, "gc.free", config.desiredFreeMemPercentageAfterGC);
  registerReadWriteProp(vm, "gc.tolerance", config.gcThresholdTolerance);
  registerReadWriteProp(vm, "gc.on", config.autoGC);

  registerValueProp(vm, "gc.codeCycles", 1); // compatibility, ignored

  // Memory usage statistics - most are irrelevant in Mozart 2

  registerReadOnlyProp<nativeint>(vm, "memory.freelist",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocatedInFreeList();
    });

  registerReadOnlyProp<nativeint>(vm, "memory.heap",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocatedOutsideFreeList() +
        vm->getPropertyRegistry().stats.totalUsedMemory;
    });

  registerConstantProp(vm, "memory.atoms", 0);
  registerConstantProp(vm, "memory.names", 0);
  registerConstantProp(vm, "memory.code", 0);

  // Priorities

  // TODO: these should be mutable, but does the code handle it?
  registerConstantProp(vm, "priorities.high", HiToMiddlePriorityRatio);
  registerConstantProp(vm, "priorities.medium", MiddleToLowPriorityRatio);

  // Messages

  registerValueProp(vm, "messages.gc", false);
  registerValueProp(vm, "messages.idle", false);

  // Limits

  registerConstantProp(vm, "limits.int.min", SmallInt::min());
  registerConstantProp(vm, "limits.int.max", SmallInt::max());
  registerConstantProp(vm, "limits.bytecode.xregisters",
                       std::numeric_limits<ByteCode>::max());

  // Time

  registerConstantProp(vm, "time.user", 0);
  registerConstantProp(vm, "time.system", 0);
  registerConstantProp(vm, "time.total", 0);
  registerConstantProp(vm, "time.run", 0);
  registerConstantProp(vm, "time.idle", 0);
  registerConstantProp(vm, "time.copy", 0);
  registerConstantProp(vm, "time.propagate", 0);
  registerConstantProp(vm, "time.gc", 0);
  registerValueProp(vm, "time.detailed", false);

  // FD

  registerConstantProp(vm, "fd.variables", 0);
  registerConstantProp(vm, "fd.propagators", 0);
  registerConstantProp(vm, "fd.invoked", 0);
  registerValueProp(vm, "fd.threshold", 0);

  // Spaces

  registerConstantProp(vm, "spaces.created", 0);
  registerConstantProp(vm, "spaces.cloned", 0);
  registerConstantProp(vm, "spaces.committed", 0);
  registerConstantProp(vm, "spaces.failed", 0);
  registerConstantProp(vm, "spaces.succeeded", 0);

  // Easy access to Oz procedures
  registerValueProp(vm, "pickle.pack", unit);

  // Config - generated by CMake

#include "properties-config.cc"
}

}
<commit_msg>Fix comparison warnings of GCC in heap size properties<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "mozart.hh"

namespace mozart {

//////////////////////
// PropertyRegistry //
//////////////////////

PropertyRegistry::PropertyRegistry(VirtualMachineOptions options) {
  // Print

  config.printDepth = 10;
  config.printWidth = 20;

  // Errors

  config.errorsDebug = true;
  config.errorsDepth = 10;
  config.errorsWidth = 20;
  config.errorsThread = 40;

  // Garbage collection, aka memory management

  config.minimalHeapSize = options.minimalHeapSize;
  config.maximalHeapSize = options.maximalHeapSize;
  config.heapSize = config.minimalHeapSize;
  config.desiredFreeMemPercentageAfterGC = 75; // percent
  config.gcThresholdTolerance = 10; // percent
  computeInitialGCThreshold();
  computeMaxGCThreshold();
  config.autoGC = true;

  // Memory usage statistics

  stats.activeMemory = 0;
  stats.totalUsedMemory = 0;
}

void PropertyRegistry::registerPredefined(VM vm) {
  // Initialize value properties only now since they need the heap
  config.defaultExceptionHandler = new (vm) StableNode(vm, buildNil(vm));
  config.errorPrefix = new (vm) StableNode(vm, buildNil(vm));

  // Threads

  registerReadOnlyProp<nativeint>(vm, "threads.runnable",
    [] (VM vm) -> nativeint {
      return vm->getThreadPool().getRunnableCount();
    });
  registerConstantProp(vm, "threads.created", 0);
  registerConstantProp(vm, "threads.min", 1);

  // Print

  registerReadWriteProp(vm, "print.depth", config.printDepth);
  registerReadWriteProp(vm, "print.width", config.printWidth);

  // Errors

  registerProp(vm, "errors.handler",
    [this] (VM vm) -> UnstableNode {
      return { vm, *config.defaultExceptionHandler };
    },
    [this] (VM vm, RichNode value) {
      config.defaultExceptionHandler = value.getStableRef(vm);
    }
  );

  registerProp(vm, "errors.prefix",
    [this] (VM vm) -> UnstableNode {
      return { vm, *config.errorPrefix };
    },
    [this] (VM vm, RichNode value) {
      config.errorPrefix = value.getStableRef(vm);
    }
  );

  registerReadWriteProp(vm, "errors.debug", config.errorsDebug);
  registerReadWriteProp(vm, "errors.depth", config.errorsDepth);
  registerReadWriteProp(vm, "errors.width", config.errorsWidth);
  registerReadWriteProp(vm, "errors.thread", config.errorsThread);

  // Garbage collection, aka memory management

  registerConstantProp(vm, "gc.watcher", ReadOnlyVariable::build(vm));

  registerReadOnlyProp<nativeint>(vm, "gc.size",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocated();
    });

  registerReadOnlyProp(vm, "gc.active", stats.activeMemory);
  registerReadOnlyProp(vm, "gc.threshold", config.gcThreshold);
  registerReadOnlyProp(vm, "gc.heapsize", config.heapSize);

  registerReadWriteProp<nativeint>(vm, "gc.min",
    [this] (VM vm) {
      return config.minimalHeapSize;
    },
    [this] (VM vm, nativeint value) {
      if (value > 0 && (size_t) value < config.maximalHeapSize)
        config.minimalHeapSize = value;
    }
  );
  registerReadWriteProp<nativeint>(vm, "gc.max",
    [this] (VM vm) {
      return config.maximalHeapSize;
    },
    [this] (VM vm, nativeint value) {
      if (value > 0 && (size_t) value > config.minimalHeapSize) {
        config.maximalHeapSize = value;
        computeMaxGCThreshold();
      }
    }
  );
  registerReadWriteProp(vm, "gc.free", config.desiredFreeMemPercentageAfterGC);
  registerReadWriteProp(vm, "gc.tolerance", config.gcThresholdTolerance);
  registerReadWriteProp(vm, "gc.on", config.autoGC);

  registerValueProp(vm, "gc.codeCycles", 1); // compatibility, ignored

  // Memory usage statistics - most are irrelevant in Mozart 2

  registerReadOnlyProp<nativeint>(vm, "memory.freelist",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocatedInFreeList();
    });

  registerReadOnlyProp<nativeint>(vm, "memory.heap",
    [] (VM vm) -> nativeint {
      return vm->getMemoryManager().getAllocatedOutsideFreeList() +
        vm->getPropertyRegistry().stats.totalUsedMemory;
    });

  registerConstantProp(vm, "memory.atoms", 0);
  registerConstantProp(vm, "memory.names", 0);
  registerConstantProp(vm, "memory.code", 0);

  // Priorities

  // TODO: these should be mutable, but does the code handle it?
  registerConstantProp(vm, "priorities.high", HiToMiddlePriorityRatio);
  registerConstantProp(vm, "priorities.medium", MiddleToLowPriorityRatio);

  // Messages

  registerValueProp(vm, "messages.gc", false);
  registerValueProp(vm, "messages.idle", false);

  // Limits

  registerConstantProp(vm, "limits.int.min", SmallInt::min());
  registerConstantProp(vm, "limits.int.max", SmallInt::max());
  registerConstantProp(vm, "limits.bytecode.xregisters",
                       std::numeric_limits<ByteCode>::max());

  // Time

  registerConstantProp(vm, "time.user", 0);
  registerConstantProp(vm, "time.system", 0);
  registerConstantProp(vm, "time.total", 0);
  registerConstantProp(vm, "time.run", 0);
  registerConstantProp(vm, "time.idle", 0);
  registerConstantProp(vm, "time.copy", 0);
  registerConstantProp(vm, "time.propagate", 0);
  registerConstantProp(vm, "time.gc", 0);
  registerValueProp(vm, "time.detailed", false);

  // FD

  registerConstantProp(vm, "fd.variables", 0);
  registerConstantProp(vm, "fd.propagators", 0);
  registerConstantProp(vm, "fd.invoked", 0);
  registerValueProp(vm, "fd.threshold", 0);

  // Spaces

  registerConstantProp(vm, "spaces.created", 0);
  registerConstantProp(vm, "spaces.cloned", 0);
  registerConstantProp(vm, "spaces.committed", 0);
  registerConstantProp(vm, "spaces.failed", 0);
  registerConstantProp(vm, "spaces.succeeded", 0);

  // Easy access to Oz procedures
  registerValueProp(vm, "pickle.pack", unit);

  // Config - generated by CMake

#include "properties-config.cc"
}

}
<|endoftext|>