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

  Program:   Visualization Toolkit
  Module:    vtkImageThreshold.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkImageThreshold.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkImageThreshold, "1.36");
vtkStandardNewMacro(vtkImageThreshold);

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageThreshold::vtkImageThreshold()
{
  this->UpperThreshold = VTK_LARGE_FLOAT;
  this->LowerThreshold = -VTK_LARGE_FLOAT;
  this->ReplaceIn = 0;
  this->InValue = 0.0;
  this->ReplaceOut = 0;
  this->OutValue = 0.0;

  this->OutputScalarType = -1; // invalid; output same as input
}

//----------------------------------------------------------------------------
void vtkImageThreshold::SetInValue(float val)
{
  if (val != this->InValue || this->ReplaceIn != 1)
    {
    this->InValue = val;
    this->ReplaceIn = 1;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageThreshold::SetOutValue(float val)
{
  if (val != this->OutValue || this->ReplaceOut != 1)
    {
    this->OutValue = val;
    this->ReplaceOut = 1;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values greater than or equal to the value match.
void vtkImageThreshold::ThresholdByUpper(float thresh)
{
  if (this->LowerThreshold != thresh || this->UpperThreshold < VTK_LARGE_FLOAT)
    {
    this->LowerThreshold = thresh;
    this->UpperThreshold = VTK_LARGE_FLOAT;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values less than or equal to the value match.
void vtkImageThreshold::ThresholdByLower(float thresh)
{
  if (this->UpperThreshold != thresh || this->LowerThreshold > -VTK_LARGE_FLOAT)
    {
    this->UpperThreshold = thresh;
    this->LowerThreshold = -VTK_LARGE_FLOAT;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values in a range (inclusive) match
void vtkImageThreshold::ThresholdBetween(float lower, float upper)
{
  if (this->LowerThreshold != lower || this->UpperThreshold != upper)
    {
    this->LowerThreshold = lower;
    this->UpperThreshold = upper;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageThreshold::ExecuteInformation(vtkImageData *inData,
                                           vtkImageData *outData)
{
  if (this->OutputScalarType != -1)
    {
    outData->SetScalarType(this->OutputScalarType);
    }
  else
    {
    outData->SetScalarType(inData->GetScalarType());
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class IT, class OT>
static void vtkImageThresholdExecute(vtkImageThreshold *self,
                                     vtkImageData *inData, IT *inPtr,
                                     vtkImageData *outData, OT *outPtr,
                                     int outExt[6], int id)
{
  int idxR, idxY, idxZ;
  int maxY, maxZ;
  int inIncX, inIncY, inIncZ;
  int outIncX, outIncY, outIncZ;
  int rowLength;
  IT  lowerThreshold;
  IT  upperThreshold;
  int replaceIn = self->GetReplaceIn();
  OT  inValue;
  int replaceOut = self->GetReplaceOut();
  OT  outValue;
  IT temp;
  unsigned long count = 0;
  unsigned long target;

  // Make sure the thresholds are valid for the input scalar range
  if (self->GetLowerThreshold() < (float) inData->GetScalarTypeMin())
    {
    lowerThreshold = inData->GetScalarTypeMin();
    }
  else
    {
    lowerThreshold = (IT) self->GetLowerThreshold();
    }
  if (self->GetUpperThreshold() > (float) inData->GetScalarTypeMax())
    {
    upperThreshold = inData->GetScalarTypeMax();
    }
  else
    {
    upperThreshold = (IT) self->GetUpperThreshold();
    }

  // Make sure the replacement values are within the output scalar range
  if (self->GetInValue() < (float) outData->GetScalarTypeMin())
    {
    inValue = outData->GetScalarTypeMin();
    }
  else
    {
    inValue = (IT) self->GetInValue();
    }
  if (self->GetOutValue() > (float) outData->GetScalarTypeMax())
    {
    outValue = outData->GetScalarTypeMax();
    }
  else
    {
    outValue = (IT) self->GetOutValue();
    }

  // find the region to loop over
  rowLength = (outExt[1] - outExt[0]+1)*inData->GetNumberOfScalarComponents();
  maxY = outExt[3] - outExt[2];
  maxZ = outExt[5] - outExt[4];
  target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
  target++;

  // Get increments to march through data
  inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);

  // Loop through output pixels
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    for (idxY = 0; !self->AbortExecute && idxY <= maxY; idxY++)
      {
      if (!id)
        {
        if (!(count%target))
          {
          self->UpdateProgress(count/(50.0*target));
          }
        count++;
        }
      for (idxR = 0; idxR < rowLength; idxR++)
        {
        // Pixel operation
        temp = (*inPtr);
        if (lowerThreshold <= temp && temp <= upperThreshold)
          {
          // match
          if (replaceIn)
            {
            *outPtr = inValue;
            }
          else
            {
            *outPtr = (OT)(temp);
            }
          }
        else
          {
          // not match
          if (replaceOut)
            {
            *outPtr = outValue;
            }
          else
            {
            *outPtr = (OT)(temp);
            }
          }
        outPtr++;
        inPtr++;
        }
      outPtr += outIncY;
      inPtr += inIncY;
      }
    outPtr += outIncZ;
    inPtr += inIncZ;
    }
}

//----------------------------------------------------------------------------
template <class T>
static void vtkImageThresholdExecute1(vtkImageThreshold *self,
                                      vtkImageData *inData, T *inPtr,
                                      vtkImageData *outData,
                                      int outExt[6], int id)
{
  void *outPtr = outData->GetScalarPointerForExtent(outExt);

  switch (outData->GetScalarType())
    {
    vtkTemplateMacro7(vtkImageThresholdExecute, self, inData, inPtr,
                      outData, (VTK_TT *)(outPtr),outExt, id);
    default:
      vtkGenericWarningMacro("Execute: Unknown input ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
// This method is passed a input and output data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the datas data types.
void vtkImageThreshold::ThreadedExecute(vtkImageData *inData,
                                        vtkImageData *outData,
                                        int outExt[6], int id)
{
  void *inPtr = inData->GetScalarPointerForExtent(outExt);

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro6(vtkImageThresholdExecute1, this, inData,
                      (VTK_TT *)(inPtr), outData, outExt, id);
    default:
      vtkErrorMacro(<< "Execute: Unknown input ScalarType");
      return;
    }
}

void vtkImageThreshold::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "OutputScalarType: " << this->OutputScalarType << "\n";
  os << indent << "InValue: " << this->InValue << "\n";
  os << indent << "OutValue: " << this->OutValue << "\n";
  os << indent << "LowerThreshold: " << this->LowerThreshold << "\n";
  os << indent << "UpperThreshold: " << this->UpperThreshold << "\n";
  os << indent << "ReplaceIn: " << this->ReplaceIn << "\n";
  os << indent << "ReplaceOut: " << this->ReplaceOut << "\n";
}

<commit_msg>ERR: warnings due to bad casts. ENH: more complete checking of limits and replacement values.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageThreshold.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkImageThreshold.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkImageThreshold, "1.37");
vtkStandardNewMacro(vtkImageThreshold);

//----------------------------------------------------------------------------
// Constructor sets default values
vtkImageThreshold::vtkImageThreshold()
{
  this->UpperThreshold = VTK_LARGE_FLOAT;
  this->LowerThreshold = -VTK_LARGE_FLOAT;
  this->ReplaceIn = 0;
  this->InValue = 0.0;
  this->ReplaceOut = 0;
  this->OutValue = 0.0;

  this->OutputScalarType = -1; // invalid; output same as input
}

//----------------------------------------------------------------------------
void vtkImageThreshold::SetInValue(float val)
{
  if (val != this->InValue || this->ReplaceIn != 1)
    {
    this->InValue = val;
    this->ReplaceIn = 1;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageThreshold::SetOutValue(float val)
{
  if (val != this->OutValue || this->ReplaceOut != 1)
    {
    this->OutValue = val;
    this->ReplaceOut = 1;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values greater than or equal to the value match.
void vtkImageThreshold::ThresholdByUpper(float thresh)
{
  if (this->LowerThreshold != thresh || this->UpperThreshold < VTK_LARGE_FLOAT)
    {
    this->LowerThreshold = thresh;
    this->UpperThreshold = VTK_LARGE_FLOAT;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values less than or equal to the value match.
void vtkImageThreshold::ThresholdByLower(float thresh)
{
  if (this->UpperThreshold != thresh || this->LowerThreshold > -VTK_LARGE_FLOAT)
    {
    this->UpperThreshold = thresh;
    this->LowerThreshold = -VTK_LARGE_FLOAT;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
// The values in a range (inclusive) match
void vtkImageThreshold::ThresholdBetween(float lower, float upper)
{
  if (this->LowerThreshold != lower || this->UpperThreshold != upper)
    {
    this->LowerThreshold = lower;
    this->UpperThreshold = upper;
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkImageThreshold::ExecuteInformation(vtkImageData *inData,
                                           vtkImageData *outData)
{
  if (this->OutputScalarType != -1)
    {
    outData->SetScalarType(this->OutputScalarType);
    }
  else
    {
    outData->SetScalarType(inData->GetScalarType());
    }
}

//----------------------------------------------------------------------------
// This templated function executes the filter for any type of data.
template <class IT, class OT>
static void vtkImageThresholdExecute(vtkImageThreshold *self,
                                     vtkImageData *inData, IT *inPtr,
                                     vtkImageData *outData, OT *outPtr,
                                     int outExt[6], int id)
{
  int idxR, idxY, idxZ;
  int maxY, maxZ;
  int inIncX, inIncY, inIncZ;
  int outIncX, outIncY, outIncZ;
  int rowLength;
  IT  lowerThreshold;
  IT  upperThreshold;
  int replaceIn = self->GetReplaceIn();
  OT  inValue;
  int replaceOut = self->GetReplaceOut();
  OT  outValue;
  IT temp;
  unsigned long count = 0;
  unsigned long target;

  // Make sure the thresholds are valid for the input scalar range
  if (self->GetLowerThreshold() < (float) inData->GetScalarTypeMin())
    {
    lowerThreshold = (IT) inData->GetScalarTypeMin();
    }
  else if (self->GetLowerThreshold() > (float) inData->GetScalarTypeMax())
    {
    lowerThreshold = (IT) inData->GetScalarTypeMax();
    }
  else
    {
    lowerThreshold = (IT) self->GetLowerThreshold();
    }
  if (self->GetUpperThreshold() > (float) inData->GetScalarTypeMax())
    {
    upperThreshold = (IT) inData->GetScalarTypeMax();
    }
  else if (self->GetUpperThreshold() < (float) inData->GetScalarTypeMin())
    {
    upperThreshold = (IT) inData->GetScalarTypeMin();
    }
  else
    {
    upperThreshold = (IT) self->GetUpperThreshold();
    }

  // Make sure the replacement values are within the output scalar range
  if (self->GetInValue() < (float) outData->GetScalarTypeMin())
    {
    inValue = (OT) outData->GetScalarTypeMin();
    }
  else if (self->GetInValue() > (float) outData->GetScalarTypeMax())
    {
    inValue = (OT) outData->GetScalarTypeMax();
    }
  else
    {
    inValue = (OT) self->GetInValue();
    }
  if (self->GetOutValue() > (float) outData->GetScalarTypeMax())
    {
    outValue = (OT) outData->GetScalarTypeMax();
    }
  else if (self->GetOutValue() < (float) outData->GetScalarTypeMin())
    {
    outValue = (OT) outData->GetScalarTypeMin();
    }
  else
    {
    outValue = (OT) self->GetOutValue();
    }

  // find the region to loop over
  rowLength = (outExt[1] - outExt[0]+1)*inData->GetNumberOfScalarComponents();
  maxY = outExt[3] - outExt[2];
  maxZ = outExt[5] - outExt[4];
  target = (unsigned long)((maxZ+1)*(maxY+1)/50.0);
  target++;

  // Get increments to march through data
  inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ);
  outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);

  // Loop through output pixels
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    for (idxY = 0; !self->AbortExecute && idxY <= maxY; idxY++)
      {
      if (!id)
        {
        if (!(count%target))
          {
          self->UpdateProgress(count/(50.0*target));
          }
        count++;
        }
      for (idxR = 0; idxR < rowLength; idxR++)
        {
        // Pixel operation
        temp = (*inPtr);
        if (lowerThreshold <= temp && temp <= upperThreshold)
          {
          // match
          if (replaceIn)
            {
            *outPtr = inValue;
            }
          else
            {
            *outPtr = (OT)(temp);
            }
          }
        else
          {
          // not match
          if (replaceOut)
            {
            *outPtr = outValue;
            }
          else
            {
            *outPtr = (OT)(temp);
            }
          }
        outPtr++;
        inPtr++;
        }
      outPtr += outIncY;
      inPtr += inIncY;
      }
    outPtr += outIncZ;
    inPtr += inIncZ;
    }
}

//----------------------------------------------------------------------------
template <class T>
static void vtkImageThresholdExecute1(vtkImageThreshold *self,
                                      vtkImageData *inData, T *inPtr,
                                      vtkImageData *outData,
                                      int outExt[6], int id)
{
  void *outPtr = outData->GetScalarPointerForExtent(outExt);

  switch (outData->GetScalarType())
    {
    vtkTemplateMacro7(vtkImageThresholdExecute, self, inData, inPtr,
                      outData, (VTK_TT *)(outPtr),outExt, id);
    default:
      vtkGenericWarningMacro("Execute: Unknown input ScalarType");
      return;
    }
}

//----------------------------------------------------------------------------
// This method is passed a input and output data, and executes the filter
// algorithm to fill the output from the input.
// It just executes a switch statement to call the correct function for
// the datas data types.
void vtkImageThreshold::ThreadedExecute(vtkImageData *inData,
                                        vtkImageData *outData,
                                        int outExt[6], int id)
{
  void *inPtr = inData->GetScalarPointerForExtent(outExt);

  switch (inData->GetScalarType())
    {
    vtkTemplateMacro6(vtkImageThresholdExecute1, this, inData,
                      (VTK_TT *)(inPtr), outData, outExt, id);
    default:
      vtkErrorMacro(<< "Execute: Unknown input ScalarType");
      return;
    }
}

void vtkImageThreshold::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "OutputScalarType: " << this->OutputScalarType << "\n";
  os << indent << "InValue: " << this->InValue << "\n";
  os << indent << "OutValue: " << this->OutValue << "\n";
  os << indent << "LowerThreshold: " << this->LowerThreshold << "\n";
  os << indent << "UpperThreshold: " << this->UpperThreshold << "\n";
  os << indent << "ReplaceIn: " << this->ReplaceIn << "\n";
  os << indent << "ReplaceOut: " << this->ReplaceOut << "\n";
}

<|endoftext|>


<commit_before>/*
 * malgorithm.hpp
 *
 *  Created on: Mar 1, 2015
 *      Author: hugo
 */

#ifndef MFLASH_CPP_CORE_MALGORITHM_HPP_
#define MFLASH_CPP_CORE_MALGORITHM_HPP_

#include "type.hpp"
#include "matrixworker.hpp"

namespace mflash{

  template <class VSource, class VDestination, class E>
	class MAlgorithm{
		public:

	    /**
	     * Called before start the processing of each column to initialize the values of the output or the accumulators.
	     */
			virtual void initialize(MatrixWorker<E> &worker, Element<VDestination> &destination) = 0;

			/**
       * Called for each edge to transfers data since source to destination. On the destination is accumulated temporal state for the destination vertex,
       * if it is used multi-thread each thread maintain its own accumulator.
       */
			virtual void gather(MatrixWorker<E> &worker, Element<VSource> &source, Element<VDestination> &destination, E &edge_data) = 0;

			/**
			 * Called to combine accumulators between threads.
			 */
			virtual void sum(Element<VDestination> &accumulator1, Element<VDestination> &accumulator2, Element<VDestination> &out_accumulator) = 0;

			/**
			 * Called after combine the accumulators for each vertex to update the vertex value.
			 */
			virtual void apply(MatrixWorker<E> &worker, Element<VDestination> &out_element) = 0;

			/**
       *  Check is the initialized method is executed. By default is true.
       */
			virtual bool is_initialized(){
			  return true;
			}

			/**
       *  Check is the apply method is executed. By default is true.
       */
			virtual bool is_applied(){
			  return true;
			}

			/**
			 * Called before an iteration starts.
			 */
			virtual void before_iteration(int iteration, MatrixWorker<E> &worker){

			}

			/**
			 * Called after an iteration has finished.
			 */
      virtual void after_iteration(int iteration, MatrixWorker<E> &worker){
      }

	};

}

#endif /* MFLASH_CPP_CORE_MALGORITHM_HPP_ */
<commit_msg>Adding method to initialize source values<commit_after>/*
 * malgorithm.hpp
 *
 *  Created on: Mar 1, 2015
 *      Author: hugo
 */

#ifndef MFLASH_CPP_CORE_MALGORITHM_HPP_
#define MFLASH_CPP_CORE_MALGORITHM_HPP_

#include "type.hpp"
#include "matrixworker.hpp"

namespace mflash{

  template <class VSource, class VDestination, class E>
	class MAlgorithm{
		public:

      /**
       * Called before start the processing of each edge to initialize the values to transfer using edges.
       *
       */
      virtual void initialize_source(MatrixWorker<E> &worker, Element<VSource> &destination) {}

	    /**
	     * Called before start the processing of each each to initialize the values of the output or the accumulators.
	     */
			virtual void initialize(MatrixWorker<E> &worker, Element<VDestination> &destination) = 0;

			/**
       * Called for each edge to transfers data since source to destination. On the destination is accumulated temporal state for the destination vertex,
       * if it is used multi-thread each thread maintain its own accumulator.
       */
			virtual void gather(MatrixWorker<E> &worker, Element<VSource> &source, Element<VDestination> &destination, E &edge_data) = 0;

			/**
			 * Called to combine accumulators between threads.
			 */
			virtual void sum(Element<VDestination> &accumulator1, Element<VDestination> &accumulator2, Element<VDestination> &out_accumulator) = 0;

			/**
			 * Called after combine the accumulators for each vertex to update the vertex value.
			 */
			virtual void apply(MatrixWorker<E> &worker, Element<VDestination> &out_element) = 0;

			/**
       *  Check is the initialized method is executed. By default is false and MFlash uses the current value stored.
       *  When it is true, it is executed before iteration starts and after before_iteration method.
       *
       */
      virtual bool is_source_initialized(){
        return false;
      }

			/**
       *  Check is the initialized method is executed. By default is true.
       */
			virtual bool is_initialized(){
			  return true;
			}

			/**
       *  Check is the apply method is executed. By default is true.
       */
			virtual bool is_applied(){
			  return true;
			}

			/**
			 * Called before an iteration starts.
			 */
			virtual void before_iteration(int iteration, MatrixWorker<E> &worker){

			}

			/**
			 * Called after an iteration has finished.
			 */
      virtual void after_iteration(int iteration, MatrixWorker<E> &worker){
      }

      virtual ~MAlgorithm(){}
	};

}

#endif /* MFLASH_CPP_CORE_MALGORITHM_HPP_ */
<|endoftext|>


<commit_before>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef HEARTHSTONEPP_TASKS_HPP
#define HEARTHSTONEPP_TASKS_HPP

#include <hspp/Accounts/Player.hpp>
#include <hspp/Enums/CardEnums.hpp>
#include <hspp/Tasks/MetaData.hpp>
#include <hspp/Tasks/TaskMeta.hpp>
#include <hspp/Tasks/TaskSerializer.hpp>

namespace Hearthstonepp
{
//!
//! \brief ITask class.
//!
//! This class is interface of various task classes.
//! All classes that inherit from it must implement GetTaskID and Impl methods.
//!
class ITask
{
 public:
    template <typename T>
    static inline constexpr bool isTask =
        std::is_convertible_v<std::decay_t<T>, ITask>;

    //! Default constructor.
    ITask() = default;

    ITask(Entity* source, Entity* target);

    //! Default destructor.
    virtual ~ITask() = default;

    //! Default copy constructor.
    ITask(const ITask& task) = default;

    //! Default move constructor.
    ITask(ITask&& task) = default;

    //! Default copy assignment operator.
    ITask& operator=(const ITask& task) = default;

    //! Default move assignment operator.
    ITask& operator=(ITask&& task) = default;

    //! Sets the target.
    //! \param target A pointer to the target.
    void SetTarget(Entity* target);

    //! Calls Impl method and returns meta data.
    //! \param player The player to run task.
    //! \return The result of task processing.
    MetaData Run(Player& player);

    //! Calls Impl method and returns meta data.
    //! \param player The player to run task.
    //! \param meta The task meta that stores game status.
    //! \return The result of task processing.
    MetaData Run(Player& player, TaskMeta& meta);

    //! Returns task ID (pure virtual).
    //! \return Task ID.
    virtual TaskID GetTaskID() const = 0;

 protected:
    Entity* m_source = nullptr;
    Entity* m_target = nullptr;

 private:
    //! Processes task logic internally and returns meta data.
    //! \param player The player to run task.
    //! \return The result of task processing.
    virtual MetaData Impl(Player& player) = 0;
};
}  // namespace Hearthstonepp

namespace Task
{
//! Calls Impl method and returns meta data.
//! \param player The player to run task.
//! \return The result of task processing.
TaskMeta Run(Player& player, ITask& tasks)
{
    return task.Run(player);
}

//! Run multiple Tasks
//! \param player The player to run task.
//! \param meta The task meta that stores packed multiple game status.
template <typename... TaskType>
std::vector<TaskMeta> RunMulti(Player& player, TaskType&& task)
{
    std::vector<TaskMeta> metas;
    metas.reserve(sizeof...(tasks));

    (..., metas.push_back(tasks.run(player)));
    return metas;
}
}  // namespace Task

#endif  // HEARTHSTONEPP_TASKS_HPP
<commit_msg>fix: Fix typo<commit_after>// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef HEARTHSTONEPP_TASKS_HPP
#define HEARTHSTONEPP_TASKS_HPP

#include <hspp/Accounts/Player.hpp>
#include <hspp/Enums/CardEnums.hpp>
#include <hspp/Tasks/MetaData.hpp>
#include <hspp/Tasks/TaskMeta.hpp>
#include <hspp/Tasks/TaskSerializer.hpp>

namespace Hearthstonepp
{
//!
//! \brief ITask class.
//!
//! This class is interface of various task classes.
//! All classes that inherit from it must implement GetTaskID and Impl methods.
//!
class ITask
{
 public:
    template <typename T>
    static inline constexpr bool isTask =
        std::is_convertible_v<std::decay_t<T>, ITask>;

    //! Default constructor.
    ITask() = default;

    ITask(Entity* source, Entity* target);

    //! Default destructor.
    virtual ~ITask() = default;

    //! Default copy constructor.
    ITask(const ITask& task) = default;

    //! Default move constructor.
    ITask(ITask&& task) = default;

    //! Default copy assignment operator.
    ITask& operator=(const ITask& task) = default;

    //! Default move assignment operator.
    ITask& operator=(ITask&& task) = default;

    //! Sets the target.
    //! \param target A pointer to the target.
    void SetTarget(Entity* target);

    //! Calls Impl method and returns meta data.
    //! \param player The player to run task.
    //! \return The result of task processing.
    MetaData Run(Player& player);

    //! Calls Impl method and returns meta data.
    //! \param player The player to run task.
    //! \param meta The task meta that stores game status.
    //! \return The result of task processing.
    MetaData Run(Player& player, TaskMeta& meta);

    //! Returns task ID (pure virtual).
    //! \return Task ID.
    virtual TaskID GetTaskID() const = 0;

 protected:
    Entity* m_source = nullptr;
    Entity* m_target = nullptr;

 private:
    //! Processes task logic internally and returns meta data.
    //! \param player The player to run task.
    //! \return The result of task processing.
    virtual MetaData Impl(Player& player) = 0;
};
}  // namespace Hearthstonepp

namespace Task
{
//! Calls Impl method and returns meta data.
//! \param player The player to run task.
//! \return The result of task processing.
TaskMeta Run(Player& player, ITask& tasks)
{
    return task.Run(player);
}

//! Run multiple Tasks
//! \param player The player to run task.
//! \param meta The task meta that stores packed multiple game status.
template <typename... TaskType>
std::vector<TaskMeta> RunMulti(Player& player, TaskType&& task)
{
    std::vector<TaskMeta> metas;
    metas.reserve(sizeof...(task));

    (..., metas.push_back(task.run(player)));
    return metas;
}
}  // namespace Task

#endif  // HEARTHSTONEPP_TASKS_HPP
<|endoftext|>


<commit_before>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

void ExtractSynonyms(File * const norm_data_marc_input, const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,  std::vector<std::map<std::string, std::string>> * const synonym_maps)
{
    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(norm_data_marc_input)) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','), StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map, const std::string &searchterm) {
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcUtil::Record * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::string synonyms;
            if (record->extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values)) {
                const std::string searchphrase(StringUtil::Join(primary_values, ','));

                // First case: Look up synonyms only in one category
                if (i < synonym_maps.size()) {
                    const auto &synonym_map(synonym_maps[i]);
                    synonyms = GetMapValueOrEmptyString(synonym_map, searchphrase);
                }

                // Second case: Look up synonyms in all categories
                else {
                    for (auto &sm : synonym_maps) {
                        const auto &synonym(GetMapValueOrEmptyString(sm, searchphrase));
                        if (not synonym.empty())
                            synonyms = synonyms.empty() ? synonym : synonyms + "," + synonym;
                    }
                }

                if (synonyms.empty())
                    continue;

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != -1)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (subfield_spec.size() != 1)
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(File * const marc_input, File * marc_output, const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes, std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    MarcXmlWriter xml_writer(marc_output);

    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_input)) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        record.write(&xml_writer);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    std::unique_ptr<File> marc_input(FileUtil::OpenInputFileOrDie(marc_input_filename));

    const std::string norm_data_marc_input_filename(argv[2]);
    std::unique_ptr<File> norm_data_marc_input(FileUtil::OpenInputFileOrDie(norm_data_marc_input_filename));

    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(norm_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    File marc_output(marc_output_filename, "w");
    if (not marc_output)
        Error("can't open \"" + marc_output_filename + "\" for writing!");

    try {
        // Determine possible mappings
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_PRIMARY_SPEC, ":", &primary_tags_and_subfield_codes) < 1))
            Error("Need at least one primary field");

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) < 1))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) < 1))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes) < 1))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries, std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(norm_data_marc_input.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes, &synonym_maps);

        // Iterate over the title data
        InsertSynonyms(marc_input.get(), &marc_output, input_tags_and_subfield_codes, output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Lookup now term based<commit_after>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

void ExtractSynonyms(File * const norm_data_marc_input, const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,  std::vector<std::map<std::string, std::string>> * const synonym_maps)
{
    while (const MarcUtil::Record record = MarcUtil::Record::XmlFactory(norm_data_marc_input)) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','), StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map, const std::string &searchterm) {
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcUtil::Record * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::string synonyms;
            if (record->extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values)) {
               for (const auto searchterm : primary_values) {
                    // First case: Look up synonyms only in one category
                    if (i < synonym_maps.size()) {
                        const auto &synonym_map(synonym_maps[i]);
                        synonyms = GetMapValueOrEmptyString(synonym_map, searchterm);
                    }

                    // Second case: Look up synonyms in all categories
                    else {
                        for (auto &sm : synonym_maps) {
                            const auto &synonym(GetMapValueOrEmptyString(sm, searchterm));
                            if (not synonym.empty())
                                synonyms = synonyms.empty() ? synonym : synonyms + "," + synonym;
                        }
                    }
                }

                if (synonyms.empty())
                    continue;

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != -1)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (subfield_spec.size() != 1)
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(File * const marc_input, File * marc_output, const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes, std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    MarcXmlWriter xml_writer(marc_output);

    while (MarcUtil::Record record = MarcUtil::Record::XmlFactory(marc_input)) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        record.write(&xml_writer);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    std::unique_ptr<File> marc_input(FileUtil::OpenInputFileOrDie(marc_input_filename));

    const std::string norm_data_marc_input_filename(argv[2]);
    std::unique_ptr<File> norm_data_marc_input(FileUtil::OpenInputFileOrDie(norm_data_marc_input_filename));

    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(norm_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    File marc_output(marc_output_filename, "w");
    if (not marc_output)
        Error("can't open \"" + marc_output_filename + "\" for writing!");

    try {
        // Determine possible mappings
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_PRIMARY_SPEC, ":", &primary_tags_and_subfield_codes) < 1))
            Error("Need at least one primary field");

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) < 1))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) < 1))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes) < 1))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries, std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(norm_data_marc_input.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes, &synonym_maps);

        // Iterate over the title data
        InsertSynonyms(marc_input.get(), &marc_output, input_tags_and_subfield_codes, output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/** \file   Main.cc
 *  \brief  Default main entry point.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <iostream>//XXX
#include <stdexcept>
#include <string>
#include <cstdlib>
#include "StringUtil.h"
#include "util.h"

int Main(int argc, char *argv[]);

int main(int argc, char *argv[]) __attribute__((weak));

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    Logger::LogLevel log_level(Logger::LL_WARNING);
    if (argc > 1 and StringUtil::StartsWith(argv[1], "--verbosity=")) {
        const std::string level(argv[1] + __builtin_strlen("--verbosity="));
        if (level == "ERROR")
            log_level = Logger::LL_ERROR;
        else if (level == "WARNING")
            log_level = Logger::LL_WARNING;
        else if (level == "INFO")
            log_level = Logger::LL_INFO;
        else if (level == "DEBUG")
            log_level = Logger::LL_DEBUG;
        else
            LOG_ERROR("unknown log level \"" + level + "\"!");
        --argc, ++argv;
    }
    logger->setMinimumLogLevel(log_level);

    try {
        Main(argc, argv);
return 0;
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}

<commit_msg>Undid some debugging alteration.<commit_after>/** \file   Main.cc
 *  \brief  Default main entry point.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <iostream>//XXX
#include <stdexcept>
#include <string>
#include <cstdlib>
#include "StringUtil.h"
#include "util.h"

int Main(int argc, char *argv[]);

int main(int argc, char *argv[]) __attribute__((weak));

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    Logger::LogLevel log_level(Logger::LL_WARNING);
    if (argc > 1 and StringUtil::StartsWith(argv[1], "--verbosity=")) {
        const std::string level(argv[1] + __builtin_strlen("--verbosity="));
        if (level == "ERROR")
            log_level = Logger::LL_ERROR;
        else if (level == "WARNING")
            log_level = Logger::LL_WARNING;
        else if (level == "INFO")
            log_level = Logger::LL_INFO;
        else if (level == "DEBUG")
            log_level = Logger::LL_DEBUG;
        else
            LOG_ERROR("unknown log level \"" + level + "\"!");
        --argc, ++argv;
    }
    logger->setMinimumLogLevel(log_level);

    try {
        return Main(argc, argv);
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
}

<|endoftext|>


<commit_before>/* $Id$ */
# ifndef CPPAD_TIME_TEST_INCLUDED
# define CPPAD_TIME_TEST_INCLUDED

/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-15 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*
$begin time_test$$
$spell
	gettimeofday
	vec
	cppad.hpp
	Microsoft
	namespace
	std
	const
	cout
	ctime
	ifdef
	const
	endif
	cpp
$$

$index time_test$$
$index test, speed$$
$index test, time$$

$section Determine Amount of Time to Execute a Test$$

$head Syntax$$
$codei%# include <cppad/time_test.hpp>
%$$
$icode%time% = time_test(%test%, %time_min%)%$$
$icode%time% = time_test(%test%, %time_min%, %test_size%)%$$

$head Purpose$$
The $code time_test$$ function executes a timing test
and reports the amount of wall clock time for execution.

$head Motivation$$
It is important to separate small calculation units
and test them individually.
This way individual changes can be tested in the context of the
routine that they are in.
On many machines, accurate timing of a very short execution
sequences is not possible.
In addition,
there may be set up and tear down time for a test that
we do not really want included in the timing.
For this reason $code time_test$$
automatically determines how many times to
repeat the section of the test that we wish to time.

$head Include$$
The file $code cppad/time_test.hpp$$ defines the
$code time_test$$ function.
This file is included by $code cppad/cppad.hpp$$
and it can also be included separately with out the rest of
the $code CppAD$$ routines.

$head test$$
The $code time_test$$ argument $icode test$$ is a function,
or function object.
In the case where $icode test_size$$ is not present,
$icode test$$ supports the syntax
$codei%
	%test%(%repeat%)
%$$
In the case where $icode test_size$$ is present,
$icode test$$ supports the syntax
$codei%
	%test%(%size%, %repeat%)
%$$
In either case, the return value for $icode test$$ is $code void$$.

$subhead size$$
If the argument $icode size$$ is present,
it has prototype
$codei%
	size_t %size%
%$$
and is equal to the $icode test_size$$ argument to $code time_test$$.

$subhead repeat$$
The $icode test$$ argument $icode repeat$$ has prototype
$codei%
	size_t %repeat%
%$$
It will be equal to the $icode size$$ argument to $code time_test$$.

$head time_min$$
The argument $icode time_min$$ has prototype
$codei%
	double %time_min%
%$$
It specifies the minimum amount of time in seconds
that the $icode test$$ routine should take.
The $icode repeat$$ argument to $icode test$$ is increased
until this amount of execution time (or more) is reached.

$head test_size$$
This argument has prototype
$codei%
	size_t %test_size%
%$$
It specifies the $icode size$$ argument to $icode test$$.

$head time$$
The return value $icode time$$ has prototype
$codei%
	double %time%
%$$
and is the number of wall clock seconds that it took
to execute $icode test$$ divided by the value used for $icode repeat$$.

$head Timing$$
The routine $cref elapsed_seconds$$ will be used to determine the
amount of time it took to execute the test.

$children%
	cppad/elapsed_seconds.hpp%
	speed/example/time_test.cpp
%$$
$head Example$$
The routine $cref time_test.cpp$$ is an example and test
of $code time_test$$.

$end
-----------------------------------------------------------------------
*/

# include <algorithm>
# include <cstddef>
# include <cmath>
# include <cppad/elapsed_seconds.hpp>
# include <cppad/local/define.hpp>

# define CPPAD_EXTRA_RUN_BEFORE_TIMING 0

namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file time_test.hpp
\brief Function that preforms one timing test (for speed of execution).
*/

/*!
Preform one wall clock execution timing test.

\tparam Test
Either the type void (*)(size_t) or a function object
type that supports the same syntax.

\param test
The function, or function object, that supports the operation
test(repeat) where \c repeat is the number of times
to repeat the tests operaiton that is being timed.

\param time_min
is the minimum amount of time that \c test should take to preform
the repetitions of the operation being timed.
*/
template <class Test>
double time_test(Test test, double time_min )
{
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
	test(1);
# endif
	size_t repeat = 0;
	double s0     = elapsed_seconds();
	double s1     = s0;
	while( s1 - s0 < time_min )
	{	repeat = std::max(size_t(1), 2 * repeat);
		s0     = elapsed_seconds();
		test(repeat);
		s1     = elapsed_seconds();
	}
	double time = (s1 - s0) / double(repeat);
	return time;
}

/*!
Preform one wall clock execution timing test.

\tparam Test
Either the type void (*)(size_t, size_t) or a function object
type that supports the same syntax.

\param test
The function, or function object, that supports the operation
test(size, repeat) where
\c is the size for this test and
\c repeat is the number of times
to repeat the tests operaiton that is being timed.

\param time_min
is the minimum amount of time that \c test should take to preform
the repetitions of the operation being timed.

\param test_size
will be used for the value of \c size in the call to \c test.
*/
template <class Test>
double time_test(Test test, double time_min, size_t test_size)
{
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
	test(test_size, 1);
# endif
	size_t repeat = 0;
	double s0     = elapsed_seconds();
	double s1     = s0;
	while( s1 - s0 < time_min )
	{	repeat = std::max(size_t(1), 2 * repeat);
		s0     = elapsed_seconds();
		test(test_size, repeat);
		s1     = elapsed_seconds();
	}
	double time = (s1 - s0) / double(repeat);
	return time;
}

} // END_CPPAD_NAMESPACE

# undef CPPAD_EXTRA_RUN_BEFORE_TIMING
// END PROGRAM
# endif
<commit_msg>Remove invisible white space.<commit_after>/* $Id$ */
# ifndef CPPAD_TIME_TEST_INCLUDED
# define CPPAD_TIME_TEST_INCLUDED

/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-15 Bradley M. Bell

CppAD is distributed under multiple licenses. This distribution is under
the terms of the
                    Eclipse Public License Version 1.0.

A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */

/*
$begin time_test$$
$spell
	gettimeofday
	vec
	cppad.hpp
	Microsoft
	namespace
	std
	const
	cout
	ctime
	ifdef
	const
	endif
	cpp
$$

$index time_test$$
$index test, speed$$
$index test, time$$

$section Determine Amount of Time to Execute a Test$$

$head Syntax$$
$codei%# include <cppad/time_test.hpp>
%$$
$icode%time% = time_test(%test%, %time_min%)%$$
$icode%time% = time_test(%test%, %time_min%, %test_size%)%$$

$head Purpose$$
The $code time_test$$ function executes a timing test
and reports the amount of wall clock time for execution.

$head Motivation$$
It is important to separate small calculation units
and test them individually.
This way individual changes can be tested in the context of the
routine that they are in.
On many machines, accurate timing of a very short execution
sequences is not possible.
In addition,
there may be set up and tear down time for a test that
we do not really want included in the timing.
For this reason $code time_test$$
automatically determines how many times to
repeat the section of the test that we wish to time.

$head Include$$
The file $code cppad/time_test.hpp$$ defines the
$code time_test$$ function.
This file is included by $code cppad/cppad.hpp$$
and it can also be included separately with out the rest of
the $code CppAD$$ routines.

$head test$$
The $code time_test$$ argument $icode test$$ is a function,
or function object.
In the case where $icode test_size$$ is not present,
$icode test$$ supports the syntax
$codei%
	%test%(%repeat%)
%$$
In the case where $icode test_size$$ is present,
$icode test$$ supports the syntax
$codei%
	%test%(%size%, %repeat%)
%$$
In either case, the return value for $icode test$$ is $code void$$.

$subhead size$$
If the argument $icode size$$ is present,
it has prototype
$codei%
	size_t %size%
%$$
and is equal to the $icode test_size$$ argument to $code time_test$$.

$subhead repeat$$
The $icode test$$ argument $icode repeat$$ has prototype
$codei%
	size_t %repeat%
%$$
It will be equal to the $icode size$$ argument to $code time_test$$.

$head time_min$$
The argument $icode time_min$$ has prototype
$codei%
	double %time_min%
%$$
It specifies the minimum amount of time in seconds
that the $icode test$$ routine should take.
The $icode repeat$$ argument to $icode test$$ is increased
until this amount of execution time (or more) is reached.

$head test_size$$
This argument has prototype
$codei%
	size_t %test_size%
%$$
It specifies the $icode size$$ argument to $icode test$$.

$head time$$
The return value $icode time$$ has prototype
$codei%
	double %time%
%$$
and is the number of wall clock seconds that it took
to execute $icode test$$ divided by the value used for $icode repeat$$.

$head Timing$$
The routine $cref elapsed_seconds$$ will be used to determine the
amount of time it took to execute the test.

$children%
	cppad/elapsed_seconds.hpp%
	speed/example/time_test.cpp
%$$
$head Example$$
The routine $cref time_test.cpp$$ is an example and test
of $code time_test$$.

$end
-----------------------------------------------------------------------
*/

# include <algorithm>
# include <cstddef>
# include <cmath>
# include <cppad/elapsed_seconds.hpp>
# include <cppad/local/define.hpp>

# define CPPAD_EXTRA_RUN_BEFORE_TIMING 0

namespace CppAD { // BEGIN_CPPAD_NAMESPACE
/*!
\file time_test.hpp
\brief Function that preforms one timing test (for speed of execution).
*/

/*!
Preform one wall clock execution timing test.

\tparam Test
Either the type void (*)(size_t) or a function object
type that supports the same syntax.

\param test
The function, or function object, that supports the operation
test(repeat) where \c repeat is the number of times
to repeat the tests operaiton that is being timed.

\param time_min
is the minimum amount of time that \c test should take to preform
the repetitions of the operation being timed.
*/
template <class Test>
double time_test(Test test, double time_min )
{
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
	test(1);
# endif
	size_t repeat = 0;
	double s0     = elapsed_seconds();
	double s1     = s0;
	while( s1 - s0 < time_min )
	{	repeat = std::max(size_t(1), 2 * repeat);
		s0     = elapsed_seconds();
		test(repeat);
		s1     = elapsed_seconds();
	}
	double time = (s1 - s0) / double(repeat);
	return time;
}

/*!
Preform one wall clock execution timing test.

\tparam Test
Either the type void (*)(size_t, size_t) or a function object
type that supports the same syntax.

\param test
The function, or function object, that supports the operation
test(size, repeat) where
\c is the size for this test and
\c repeat is the number of times
to repeat the tests operaiton that is being timed.

\param time_min
is the minimum amount of time that \c test should take to preform
the repetitions of the operation being timed.

\param test_size
will be used for the value of \c size in the call to \c test.
*/
template <class Test>
double time_test(Test test, double time_min, size_t test_size)
{
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
	test(test_size, 1);
# endif
	size_t repeat = 0;
	double s0     = elapsed_seconds();
	double s1     = s0;
	while( s1 - s0 < time_min )
	{	repeat = std::max(size_t(1), 2 * repeat);
		s0     = elapsed_seconds();
		test(test_size, repeat);
		s1     = elapsed_seconds();
	}
	double time = (s1 - s0) / double(repeat);
	return time;
}

} // END_CPPAD_NAMESPACE

# undef CPPAD_EXTRA_RUN_BEFORE_TIMING
// END PROGRAM
# endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2001-2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

#ifndef __EXEC_CONTEXT_HH__
#define __EXEC_CONTEXT_HH__

#include "sim/host.hh"
#include "mem/mem_req.hh"
#include "mem/functional_mem/functional_memory.hh"
#include "sim/serialize.hh"

// forward declaration: see functional_memory.hh
class FunctionalMemory;
class PhysicalMemory;
class BaseCPU;

#ifdef FULL_SYSTEM

#include "targetarch/alpha_memory.hh"
class MemoryController;

#include "kern/tru64/kernel_stats.hh"
#include "sim/system.hh"
#include "sim/sw_context.hh"

#else // !FULL_SYSTEM

#include "sim/process.hh"

#endif // FULL_SYSTEM

//
// The ExecContext object represents a functional context for
// instruction execution.  It incorporates everything required for
// architecture-level functional simulation of a single thread.
//

class ExecContext
{
  public:
    enum Status
    {
        /// Initialized but not running yet.  All CPUs start in
        /// this state, but most transition to Active on cycle 1.
        /// In MP or SMT systems, non-primary contexts will stay
        /// in this state until a thread is assigned to them.
        Unallocated,

        /// Running.  Instructions should be executed only when
        /// the context is in this state.
        Active,

        /// Temporarily inactive.  Entered while waiting for
        /// synchronization, etc.
        Suspended,

        /// Permanently shut down.  Entered when target executes
        /// m5exit pseudo-instruction.  When all contexts enter
        /// this state, the simulation will terminate.
        Halted
    };

  private:
    Status _status;

  public:
    Status status() const { return _status; }

    /// Set the status to Active.  Optional delay indicates number of
    /// cycles to wait before beginning execution.
    void activate(int delay = 1);

    /// Set the status to Suspended.
    void suspend();

    /// Set the status to Unallocated.
    void deallocate();

    /// Set the status to Halted.
    void halt();

#ifdef FULL_SYSTEM
  public:
    KernelStats kernelStats;
#endif

  public:
    RegFile regs;	// correct-path register context

    // pointer to CPU associated with this context
    BaseCPU *cpu;

    // Current instruction
    MachInst inst;

    // Index of hardware thread context on the CPU that this represents.
    int thread_num;

    // ID of this context w.r.t. the System or Process object to which
    // it belongs.  For full-system mode, this is the system CPU ID.
    int cpu_id;

#ifdef FULL_SYSTEM

    FunctionalMemory *mem;
    AlphaITB *itb;
    AlphaDTB *dtb;
    System *system;

    // the following two fields are redundant, since we can always
    // look them up through the system pointer, but we'll leave them
    // here for now for convenience
    MemoryController *memCtrl;
    PhysicalMemory *physmem;

    SWContext *swCtx;
#else
    Process *process;

    FunctionalMemory *mem;	// functional storage for process address space

    // Address space ID.  Note that this is used for TIMING cache
    // simulation only; all functional memory accesses should use
    // one of the FunctionalMemory pointers above.
    short asid;

#endif

    /**
     * Temporary storage to pass the source address from copy_load to
     * copy_store.
     * @todo Remove this temporary when we have a better way to do it.
     */
    Addr copySrcAddr;
    /**
     * Temp storage for the physical source address of a copy.
     * @todo Remove this temporary when we have a better way to do it.
     */
    Addr copySrcPhysAddr;

    /*
     * number of executed instructions, for matching with syscall trace
     * points in EIO files.
     */
    Counter func_exe_inst;

    //
    // Count failed store conditionals so we can warn of apparent
    // application deadlock situations.
    unsigned storeCondFailures;

    // constructor: initialize context from given process structure
#ifdef FULL_SYSTEM
    ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
                AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem);
#else
    ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
    ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
                int _asid);
#endif
    virtual ~ExecContext() {}

    virtual void takeOverFrom(ExecContext *oldContext);

    void regStats(const std::string &name);

    void serialize(std::ostream &os);
    void unserialize(Checkpoint *cp, const std::string &section);

#ifdef FULL_SYSTEM
    bool validInstAddr(Addr addr) { return true; }
    bool validDataAddr(Addr addr) { return true; }
    int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
    int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }

    Fault translateInstReq(MemReqPtr &req)
    {
        return itb->translate(req);
    }

    Fault translateDataReadReq(MemReqPtr &req)
    {
        return dtb->translate(req, false);
    }

    Fault translateDataWriteReq(MemReqPtr &req)
    {
        return dtb->translate(req, true);
    }

#else
    bool validInstAddr(Addr addr)
    { return process->validInstAddr(addr); }

    bool validDataAddr(Addr addr)
    { return process->validDataAddr(addr); }

    int getInstAsid() { return asid; }
    int getDataAsid() { return asid; }

    Fault dummyTranslation(MemReqPtr &req)
    {
#if 0
        assert((req->vaddr >> 48 & 0xffff) == 0);
#endif

        // put the asid in the upper 16 bits of the paddr
        req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
        req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
        return No_Fault;
    }
    Fault translateInstReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataReadReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataWriteReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }

#endif

    template <class T>
    Fault read(MemReqPtr &req, T &data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
        if (req->flags & LOCKED) {
            MiscRegFile *cregs = &req->xc->regs.miscRegs;
            cregs->lock_addr = req->paddr;
            cregs->lock_flag = true;
        }
#endif
        return mem->read(req, data);
    }

    template <class T>
    Fault write(MemReqPtr &req, T &data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)

        MiscRegFile *cregs;

        // If this is a store conditional, act appropriately
        if (req->flags & LOCKED) {
            cregs = &req->xc->regs.miscRegs;

            if (req->flags & UNCACHEABLE) {
                // Don't update result register (see stq_c in isa_desc)
                req->result = 2;
                req->xc->storeCondFailures = 0;//Needed? [RGD]
            } else {
                req->result = cregs->lock_flag;
                if (!cregs->lock_flag ||
                    ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
                    cregs->lock_flag = false;
                    if (((++req->xc->storeCondFailures) % 100000) == 0) {
                        std::cerr << "Warning: "
                                  << req->xc->storeCondFailures
                                  << " consecutive store conditional failures "
                                  << "on cpu " << req->xc->cpu_id
                                  << std::endl;
                    }
                    return No_Fault;
                }
                else req->xc->storeCondFailures = 0;
            }
        }

        // Need to clear any locked flags on other proccessors for
        // this address.  Only do this for succsful Store Conditionals
        // and all other stores (WH64?).  Unsuccessful Store
        // Conditionals would have returned above, and wouldn't fall
        // through.
        for (int i = 0; i < system->execContexts.size(); i++){
            cregs = &system->execContexts[i]->regs.miscRegs;
            if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
                cregs->lock_flag = false;
            }
        }

#endif
        return mem->write(req, data);
    }

    virtual bool misspeculating();

    MachInst getInst() { return inst; }

    void setInst(MachInst new_inst)
    {
        inst = new_inst;
    }

    Fault instRead(MemReqPtr &req)
    {
        return mem->read(req, inst);
    }

    //
    // New accessors for new decoder.
    //
    uint64_t readIntReg(int reg_idx)
    {
        return regs.intRegFile[reg_idx];
    }

    float readFloatRegSingle(int reg_idx)
    {
        return (float)regs.floatRegFile.d[reg_idx];
    }

    double readFloatRegDouble(int reg_idx)
    {
        return regs.floatRegFile.d[reg_idx];
    }

    uint64_t readFloatRegInt(int reg_idx)
    {
        return regs.floatRegFile.q[reg_idx];
    }

    void setIntReg(int reg_idx, uint64_t val)
    {
        regs.intRegFile[reg_idx] = val;
    }

    void setFloatRegSingle(int reg_idx, float val)
    {
        regs.floatRegFile.d[reg_idx] = (double)val;
    }

    void setFloatRegDouble(int reg_idx, double val)
    {
        regs.floatRegFile.d[reg_idx] = val;
    }

    void setFloatRegInt(int reg_idx, uint64_t val)
    {
        regs.floatRegFile.q[reg_idx] = val;
    }

    uint64_t readPC()
    {
        return regs.pc;
    }

    void setNextPC(uint64_t val)
    {
        regs.npc = val;
    }

    uint64_t readUniq()
    {
        return regs.miscRegs.uniq;
    }

    void setUniq(uint64_t val)
    {
        regs.miscRegs.uniq = val;
    }

    uint64_t readFpcr()
    {
        return regs.miscRegs.fpcr;
    }

    void setFpcr(uint64_t val)
    {
        regs.miscRegs.fpcr = val;
    }

#ifdef FULL_SYSTEM
    uint64_t readIpr(int idx, Fault &fault);
    Fault setIpr(int idx, uint64_t val);
    int readIntrFlag() { return regs.intrflag; }
    void setIntrFlag(int val) { regs.intrflag = val; }
    Fault hwrei();
    bool inPalMode() { return PC_PAL(regs.pc); }
    void ev5_trap(Fault fault);
    bool simPalCheck(int palFunc);
#endif

    /** Meant to be more generic trap function to be
     *  called when an instruction faults.
     *  @param fault The fault generated by executing the instruction.
     *  @todo How to do this properly so it's dependent upon ISA only?
     */

    void trap(Fault fault);

#ifndef FULL_SYSTEM
    IntReg getSyscallArg(int i)
    {
        return regs.intRegFile[ArgumentReg0 + i];
    }

    // used to shift args for indirect syscall
    void setSyscallArg(int i, IntReg val)
    {
        regs.intRegFile[ArgumentReg0 + i] = val;
    }

    void setSyscallReturn(int64_t return_value)
    {
        // check for error condition.  Alpha syscall convention is to
        // indicate success/failure in reg a3 (r19) and put the
        // return value itself in the standard return value reg (v0).
        const int RegA3 = 19;	// only place this is used
        if (return_value >= 0) {
            // no error
            regs.intRegFile[RegA3] = 0;
            regs.intRegFile[ReturnValueReg] = return_value;
        } else {
            // got an error, return details
            regs.intRegFile[RegA3] = (IntReg) -1;
            regs.intRegFile[ReturnValueReg] = -return_value;
        }
    }

    void syscall()
    {
        process->syscall(this);
    }
#endif
};

// for non-speculative execution context, spec_mode is always false
inline bool
ExecContext::misspeculating()
{
    return false;
}

#endif // __EXEC_CONTEXT_HH__
<commit_msg>lift common code *kernel_stats.* into the kern directory.<commit_after>/*
 * Copyright (c) 2001-2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

#ifndef __EXEC_CONTEXT_HH__
#define __EXEC_CONTEXT_HH__

#include "sim/host.hh"
#include "mem/mem_req.hh"
#include "mem/functional_mem/functional_memory.hh"
#include "sim/serialize.hh"

// forward declaration: see functional_memory.hh
class FunctionalMemory;
class PhysicalMemory;
class BaseCPU;

#ifdef FULL_SYSTEM

#include "targetarch/alpha_memory.hh"
class MemoryController;

#include "kern/kernel_stats.hh"
#include "sim/system.hh"
#include "sim/sw_context.hh"

#else // !FULL_SYSTEM

#include "sim/process.hh"

#endif // FULL_SYSTEM

//
// The ExecContext object represents a functional context for
// instruction execution.  It incorporates everything required for
// architecture-level functional simulation of a single thread.
//

class ExecContext
{
  public:
    enum Status
    {
        /// Initialized but not running yet.  All CPUs start in
        /// this state, but most transition to Active on cycle 1.
        /// In MP or SMT systems, non-primary contexts will stay
        /// in this state until a thread is assigned to them.
        Unallocated,

        /// Running.  Instructions should be executed only when
        /// the context is in this state.
        Active,

        /// Temporarily inactive.  Entered while waiting for
        /// synchronization, etc.
        Suspended,

        /// Permanently shut down.  Entered when target executes
        /// m5exit pseudo-instruction.  When all contexts enter
        /// this state, the simulation will terminate.
        Halted
    };

  private:
    Status _status;

  public:
    Status status() const { return _status; }

    /// Set the status to Active.  Optional delay indicates number of
    /// cycles to wait before beginning execution.
    void activate(int delay = 1);

    /// Set the status to Suspended.
    void suspend();

    /// Set the status to Unallocated.
    void deallocate();

    /// Set the status to Halted.
    void halt();

#ifdef FULL_SYSTEM
  public:
    KernelStats kernelStats;
#endif

  public:
    RegFile regs;	// correct-path register context

    // pointer to CPU associated with this context
    BaseCPU *cpu;

    // Current instruction
    MachInst inst;

    // Index of hardware thread context on the CPU that this represents.
    int thread_num;

    // ID of this context w.r.t. the System or Process object to which
    // it belongs.  For full-system mode, this is the system CPU ID.
    int cpu_id;

#ifdef FULL_SYSTEM

    FunctionalMemory *mem;
    AlphaITB *itb;
    AlphaDTB *dtb;
    System *system;

    // the following two fields are redundant, since we can always
    // look them up through the system pointer, but we'll leave them
    // here for now for convenience
    MemoryController *memCtrl;
    PhysicalMemory *physmem;

    SWContext *swCtx;
#else
    Process *process;

    FunctionalMemory *mem;	// functional storage for process address space

    // Address space ID.  Note that this is used for TIMING cache
    // simulation only; all functional memory accesses should use
    // one of the FunctionalMemory pointers above.
    short asid;

#endif

    /**
     * Temporary storage to pass the source address from copy_load to
     * copy_store.
     * @todo Remove this temporary when we have a better way to do it.
     */
    Addr copySrcAddr;
    /**
     * Temp storage for the physical source address of a copy.
     * @todo Remove this temporary when we have a better way to do it.
     */
    Addr copySrcPhysAddr;

    /*
     * number of executed instructions, for matching with syscall trace
     * points in EIO files.
     */
    Counter func_exe_inst;

    //
    // Count failed store conditionals so we can warn of apparent
    // application deadlock situations.
    unsigned storeCondFailures;

    // constructor: initialize context from given process structure
#ifdef FULL_SYSTEM
    ExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
                AlphaITB *_itb, AlphaDTB *_dtb, FunctionalMemory *_dem);
#else
    ExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid);
    ExecContext(BaseCPU *_cpu, int _thread_num, FunctionalMemory *_mem,
                int _asid);
#endif
    virtual ~ExecContext() {}

    virtual void takeOverFrom(ExecContext *oldContext);

    void regStats(const std::string &name);

    void serialize(std::ostream &os);
    void unserialize(Checkpoint *cp, const std::string &section);

#ifdef FULL_SYSTEM
    bool validInstAddr(Addr addr) { return true; }
    bool validDataAddr(Addr addr) { return true; }
    int getInstAsid() { return ITB_ASN_ASN(regs.ipr[TheISA::IPR_ITB_ASN]); }
    int getDataAsid() { return DTB_ASN_ASN(regs.ipr[TheISA::IPR_DTB_ASN]); }

    Fault translateInstReq(MemReqPtr &req)
    {
        return itb->translate(req);
    }

    Fault translateDataReadReq(MemReqPtr &req)
    {
        return dtb->translate(req, false);
    }

    Fault translateDataWriteReq(MemReqPtr &req)
    {
        return dtb->translate(req, true);
    }

#else
    bool validInstAddr(Addr addr)
    { return process->validInstAddr(addr); }

    bool validDataAddr(Addr addr)
    { return process->validDataAddr(addr); }

    int getInstAsid() { return asid; }
    int getDataAsid() { return asid; }

    Fault dummyTranslation(MemReqPtr &req)
    {
#if 0
        assert((req->vaddr >> 48 & 0xffff) == 0);
#endif

        // put the asid in the upper 16 bits of the paddr
        req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
        req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
        return No_Fault;
    }
    Fault translateInstReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataReadReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }
    Fault translateDataWriteReq(MemReqPtr &req)
    {
        return dummyTranslation(req);
    }

#endif

    template <class T>
    Fault read(MemReqPtr &req, T &data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)
        if (req->flags & LOCKED) {
            MiscRegFile *cregs = &req->xc->regs.miscRegs;
            cregs->lock_addr = req->paddr;
            cregs->lock_flag = true;
        }
#endif
        return mem->read(req, data);
    }

    template <class T>
    Fault write(MemReqPtr &req, T &data)
    {
#if defined(TARGET_ALPHA) && defined(FULL_SYSTEM)

        MiscRegFile *cregs;

        // If this is a store conditional, act appropriately
        if (req->flags & LOCKED) {
            cregs = &req->xc->regs.miscRegs;

            if (req->flags & UNCACHEABLE) {
                // Don't update result register (see stq_c in isa_desc)
                req->result = 2;
                req->xc->storeCondFailures = 0;//Needed? [RGD]
            } else {
                req->result = cregs->lock_flag;
                if (!cregs->lock_flag ||
                    ((cregs->lock_addr & ~0xf) != (req->paddr & ~0xf))) {
                    cregs->lock_flag = false;
                    if (((++req->xc->storeCondFailures) % 100000) == 0) {
                        std::cerr << "Warning: "
                                  << req->xc->storeCondFailures
                                  << " consecutive store conditional failures "
                                  << "on cpu " << req->xc->cpu_id
                                  << std::endl;
                    }
                    return No_Fault;
                }
                else req->xc->storeCondFailures = 0;
            }
        }

        // Need to clear any locked flags on other proccessors for
        // this address.  Only do this for succsful Store Conditionals
        // and all other stores (WH64?).  Unsuccessful Store
        // Conditionals would have returned above, and wouldn't fall
        // through.
        for (int i = 0; i < system->execContexts.size(); i++){
            cregs = &system->execContexts[i]->regs.miscRegs;
            if ((cregs->lock_addr & ~0xf) == (req->paddr & ~0xf)) {
                cregs->lock_flag = false;
            }
        }

#endif
        return mem->write(req, data);
    }

    virtual bool misspeculating();

    MachInst getInst() { return inst; }

    void setInst(MachInst new_inst)
    {
        inst = new_inst;
    }

    Fault instRead(MemReqPtr &req)
    {
        return mem->read(req, inst);
    }

    //
    // New accessors for new decoder.
    //
    uint64_t readIntReg(int reg_idx)
    {
        return regs.intRegFile[reg_idx];
    }

    float readFloatRegSingle(int reg_idx)
    {
        return (float)regs.floatRegFile.d[reg_idx];
    }

    double readFloatRegDouble(int reg_idx)
    {
        return regs.floatRegFile.d[reg_idx];
    }

    uint64_t readFloatRegInt(int reg_idx)
    {
        return regs.floatRegFile.q[reg_idx];
    }

    void setIntReg(int reg_idx, uint64_t val)
    {
        regs.intRegFile[reg_idx] = val;
    }

    void setFloatRegSingle(int reg_idx, float val)
    {
        regs.floatRegFile.d[reg_idx] = (double)val;
    }

    void setFloatRegDouble(int reg_idx, double val)
    {
        regs.floatRegFile.d[reg_idx] = val;
    }

    void setFloatRegInt(int reg_idx, uint64_t val)
    {
        regs.floatRegFile.q[reg_idx] = val;
    }

    uint64_t readPC()
    {
        return regs.pc;
    }

    void setNextPC(uint64_t val)
    {
        regs.npc = val;
    }

    uint64_t readUniq()
    {
        return regs.miscRegs.uniq;
    }

    void setUniq(uint64_t val)
    {
        regs.miscRegs.uniq = val;
    }

    uint64_t readFpcr()
    {
        return regs.miscRegs.fpcr;
    }

    void setFpcr(uint64_t val)
    {
        regs.miscRegs.fpcr = val;
    }

#ifdef FULL_SYSTEM
    uint64_t readIpr(int idx, Fault &fault);
    Fault setIpr(int idx, uint64_t val);
    int readIntrFlag() { return regs.intrflag; }
    void setIntrFlag(int val) { regs.intrflag = val; }
    Fault hwrei();
    bool inPalMode() { return PC_PAL(regs.pc); }
    void ev5_trap(Fault fault);
    bool simPalCheck(int palFunc);
#endif

    /** Meant to be more generic trap function to be
     *  called when an instruction faults.
     *  @param fault The fault generated by executing the instruction.
     *  @todo How to do this properly so it's dependent upon ISA only?
     */

    void trap(Fault fault);

#ifndef FULL_SYSTEM
    IntReg getSyscallArg(int i)
    {
        return regs.intRegFile[ArgumentReg0 + i];
    }

    // used to shift args for indirect syscall
    void setSyscallArg(int i, IntReg val)
    {
        regs.intRegFile[ArgumentReg0 + i] = val;
    }

    void setSyscallReturn(int64_t return_value)
    {
        // check for error condition.  Alpha syscall convention is to
        // indicate success/failure in reg a3 (r19) and put the
        // return value itself in the standard return value reg (v0).
        const int RegA3 = 19;	// only place this is used
        if (return_value >= 0) {
            // no error
            regs.intRegFile[RegA3] = 0;
            regs.intRegFile[ReturnValueReg] = return_value;
        } else {
            // got an error, return details
            regs.intRegFile[RegA3] = (IntReg) -1;
            regs.intRegFile[ReturnValueReg] = -return_value;
        }
    }

    void syscall()
    {
        process->syscall(this);
    }
#endif
};

// for non-speculative execution context, spec_mode is always false
inline bool
ExecContext::misspeculating()
{
    return false;
}

#endif // __EXEC_CONTEXT_HH__
<|endoftext|>