<commit_before>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#ifndef LinearSearchKNNPropertyLimitLocalReuse_HPP
#define LinearSearchKNNPropertyLimitLocalReuse_HPP

// STL
#include <algorithm> // for lower_bound()
#include <limits> // for infinity()
#include <set>

// Boost
#include <boost/utility.hpp> // for enable_if()
#include <boost/type_traits.hpp> // for is_same()

// Custom
#include "Utilities/Utilities.hpp"

// Submodules
#include <Mask/Mask.h>
#include <Utilities/Debug/Debug.h>

/**
  * This function template is similar to std::min_element but can be used when the comparison
  * involves computing a derived quantity (a.k.a. distance). This algorithm will search for the
  * the elements in the range [first,last) with the "smallest" distances (of course, both the
  * distance metric and comparison can be overriden to perform something other than the canonical
  * Euclidean distance and less-than comparison, which would yield the element with minimum distance).
  * This function will fill the output container with a number of nearest-neighbors.
  * \tparam DistanceValueType The value-type for the distance measures.
  * \tparam DistanceFunctionType The functor type to compute the distance measure.
  */
template <typename TPatchDescriptorPropertyMap, typename TPatchDistanceFunction,
          typename TImageToWrite>
class LinearSearchKNNPropertyLimitLocalReuse : public Debug
{
  typedef float DistanceValueType;

  /** The map of vertex descriptors. */
  TPatchDescriptorPropertyMap PatchDescriptorPropertyMap;

  /** How many top patches to return. */
  unsigned int K;

  /** The function to use to compare patches. */
  TPatchDistanceFunction PatchDistanceFunction;

  /** An image indicating where each pixel came from. */
  typedef itk::Image<itk::Index<2>, 2> SourcePixelMapImageType;
  SourcePixelMapImageType* SourcePixelMapImage;

  /** The current inpainting mask. */
  Mask* MaskImage;

  /** Store the full region so that it can be reference without an image or mask. */
  itk::ImageRegion<2> FullRegion;

  unsigned int Iteration = 0;

  TImageToWrite* ImageToWrite;

  float LocalRegionSizeMultiplier;

  float MaxAllowedUsedPixelsRatio;

public:
  LinearSearchKNNPropertyLimitLocalReuse(TPatchDescriptorPropertyMap patchDescriptorPropertyMap, Mask* mask, const unsigned int k = 1000,
                                         float localRegionSizeMultiplier = 3.0f, float maxAllowedUsedPixelsRatio = 0.5f,
                                         TPatchDistanceFunction patchDistanceFunction = TPatchDistanceFunction(),
                                         SourcePixelMapImageType* sourcePixelMapImage = nullptr, TImageToWrite* imageToWrite = nullptr) :
    PatchDescriptorPropertyMap(patchDescriptorPropertyMap), K(k), PatchDistanceFunction(patchDistanceFunction),
    SourcePixelMapImage(sourcePixelMapImage), MaskImage(mask), ImageToWrite(imageToWrite),
    LocalRegionSizeMultiplier(localRegionSizeMultiplier), MaxAllowedUsedPixelsRatio(maxAllowedUsedPixelsRatio)
  {
    this->FullRegion = this->MaskImage->GetLargestPossibleRegion();
  }

  /** Set the number of nearest neighbors to return. */
  void SetK(const unsigned int k)
  {
    this->K = k;
  }

  /** Get the number of nearest neighbors to return. */
  unsigned int GetK() const
  {
    return this->K;
  }

  //   template <typename ForwardIteratorType, typename OutputContainerType>
  //   void operator()(ForwardIteratorType first, ForwardIteratorType last,
  //                   typename ForwardIteratorType::value_type queryNode, OutputContainerType& output)
  /**
    * \tparam ForwardIterator The forward-iterator type.
    * \tparam OutputContainer The container type which can contain the list of nearest-neighbors (STL like container, with iterators, insert, size, and pop_back).
    * \param first Start of the range in which to search.
    * \param last One element past the last element in the range in which to search (usually container.end() ).
    * \param output The container that will have the sorted list of elements with the smallest distance.
    * \param compare A callable object that returns true if the first element is the preferred one (less-than) of the two.
    * \param max_neighbors The maximum number of elements of smallest distance to output in the sorted list.
    */
  template <typename ForwardIteratorType, typename OutputIteratorType>
  inline OutputIteratorType
  operator()(ForwardIteratorType first, ForwardIteratorType last,
             typename ForwardIteratorType::value_type queryNode,
             OutputIteratorType outputFirst)
  {
    if(this->DebugScreenOutputs)
    {
      std::cout << "LinearSearchKNNPropertyLimitLocalReuse searching " << last - first << " patches." << std::endl;
    }

    // Nothing to do if the input range is empty
    if(first == last)
    {
      return outputFirst;
    }

    // This doesn't work correctly - the image is written but it cannot be opened in a viewer like gwenview,
    // and in Paraview it does not seem to contain columns of patches and numbers? Perhaps because of the extreme
    // size of the image?
//    if(this->DebugImages && this->Iteration == 140)
//    {
//      if(this->ImageToWrite == nullptr)
//      {
//        throw std::runtime_error("LinearSearchBestLidarTextureGradient cannot WriteTopPatches without having an ImageToWrite!");
//      }
//      PatchHelpers::WriteTopPatches(this->ImageToWrite, this->PatchDescriptorPropertyMap, first, last,
//                                    "KNNPatches", this->Iteration);
//    }

    if(this->DebugImages)
    {
      ITKHelpers::WriteIndexImage(this->SourcePixelMapImage, Helpers::GetSequentialFileName("SourcePixelMap", this->Iteration, "mha", 3));
    }

    // Use a priority queue to keep the items sorted
    typedef std::pair<DistanceValueType, ForwardIteratorType> PairType;
    typedef compare_pair_first<DistanceValueType, ForwardIteratorType, std::greater<DistanceValueType> > CompareType;
    typedef std::priority_queue< PairType, std::vector<PairType>,
        CompareType> PriorityQueueType;

    PriorityQueueType outputQueue;

    typename TPatchDescriptorPropertyMap::value_type queryDescriptor = get(this->PatchDescriptorPropertyMap, queryNode);

    typedef typename ForwardIteratorType::value_type NodeType;

    // Create a region from the node
    itk::Index<2> queryIndex = Helpers::ConvertFrom<itk::Index<2>, NodeType>(queryNode);

//    itk::ImageRegion<2> queryRegion =
//        ITKHelpers::GetRegionInRadiusAroundPixel(queryIndex,
//                                                 get(this->PatchDescriptorPropertyMap, queryNode).GetRegion().GetSize()[0]/2);

    itk::ImageRegion<2> queryRegion = queryDescriptor.GetRegion();

    // Look for pixels that have already been used

    // Create a bigger region
    itk::ImageRegion<2> largerTargetRegion =
        ITKHelpers::GetRegionInRadiusAroundPixel(queryIndex,
                                                 queryRegion.GetSize()[0]/2.0f * this->LocalRegionSizeMultiplier);
    largerTargetRegion.Crop(this->FullRegion);
    std::cout << "The region to search for repeated pixels is " << largerTargetRegion << std::endl;

    itk::ImageRegionConstIterator<SourcePixelMapImageType> sourcePixelMapIterator(this->SourcePixelMapImage,
                                                                                largerTargetRegion);

    typedef std::set<itk::Index<2>, itk::Index<2>::LexicographicCompare> UsedIndexSetType;
    UsedIndexSetType usedIndices;
    while(!sourcePixelMapIterator.IsAtEnd())
    {
      usedIndices.insert(sourcePixelMapIterator.Get());

      ++sourcePixelMapIterator;
    }

    // The queue stores the items in descending score order.
    #pragma omp parallel for
//    for(ForwardIteratorType current = first; current != last; ++current) // OpenMP 3 doesn't allow != in the loop ending condition
    for(ForwardIteratorType currentIterator = first; currentIterator < last; ++currentIterator)
    {
      NodeType currentNode = *currentIterator;

      typename TPatchDescriptorPropertyMap::value_type currentDescriptor = get(this->PatchDescriptorPropertyMap, currentNode);

      if(currentDescriptor.GetStatus() != PixelDescriptor::SOURCE_NODE)
      {
        throw std::runtime_error("LinearSearchKNNPropertyLimitLocalReuse: Node is not a source node!");
      }

      itk::ImageRegion<2> potentialSourceRegion = currentDescriptor.GetRegion();

      potentialSourceRegion.Crop(this->FullRegion);

      if(!this->MaskImage->IsValid(potentialSourceRegion))
      {
        throw std::runtime_error("LinearSearchKNNPropertyLimitLocalReuse: potentialSourceRegion is not fully valid!");
      }

      // Count the number of pixels that were already copied from this patch
      unsigned int usedPixelCounter = 0;

      itk::ImageRegionConstIteratorWithIndex<SourcePixelMapImageType>
          sourceRegionIterator(this->SourcePixelMapImage, potentialSourceRegion);

      // The image that this is iterating over is irrelevant, we just need the indices.
      itk::ImageRegionConstIteratorWithIndex<SourcePixelMapImageType>
          queryRegionIterator(this->SourcePixelMapImage, queryRegion);

      while(!sourceRegionIterator.IsAtEnd())
      {
        UsedIndexSetType::iterator usedIndexSetIterator;
        if(this->MaskImage->IsHole(queryRegionIterator.GetIndex()))
        {
          // We want to use the index value in the SourcePixelMapImage,
          // because the value might not equal the current index in the case where new patches are allowed.
          usedIndexSetIterator = usedIndices.find(sourceRegionIterator.Get());

          if(usedIndexSetIterator != usedIndices.end()) // found
          {
            usedPixelCounter++;
          }
        }

        ++sourceRegionIterator;
        ++queryRegionIterator;
      }

//      unsigned int maxUsedPixels = potentialSourceRegion.GetNumberOfPixels() / 4;
      unsigned int numberOfHolePixels = this->MaskImage->CountHolePixels(queryRegion);
      unsigned int maxAllowedUsedPixels = this->MaxAllowedUsedPixelsRatio * numberOfHolePixels;

      if(usedPixelCounter < maxAllowedUsedPixels)
      {
        DistanceValueType d = this->PatchDistanceFunction(currentDescriptor, queryDescriptor); // (source, target) (the query node is the target node)

        #pragma omp critical // There are weird crashes without this guard
        outputQueue.push(PairType(d, currentIterator));
      }
      else
      {
//        std::cout << "Prevented use because " << usedPixelCounter
//                  << " pixels were already used (out of " << numberOfHolePixels
//                  << " hole pixels)." << std::endl;
      }
    }

//    std::cout << "There are " << outputQueue.size() << " items in the queue." << std::endl;

    // Keep only the best K matches
    if(outputQueue.size() < this->K)
    {
      std::cerr << "Warning: LinearSearchKNNPropertyLimitLocalReuse only has " << outputQueue.size()
                << " nodes. (" << this->K << " were requested.)" << std::endl;
    }
    Helpers::KeepTopN(outputQueue, this->K);

//    std::cout << "There are " << outputQueue.size() << " items in the queue." << std::endl;

    if(outputQueue.size() < this->K)
    {
      std::stringstream ss;
      ss << "LinearSearchKNNPropertyLimitLocalReuse: Requested " << this->K << " items but only found " << outputQueue.size();
      throw std::runtime_error(ss.str());
    }

    std::cout << "Best patch score is: " << outputQueue.top().first << std::endl;

    // Copy the best matches from the queue into the output
    OutputIteratorType currentOutputIterator = outputFirst;
    while( !outputQueue.empty() )
    {
      *currentOutputIterator = *(outputQueue.top().second);
      outputQueue.pop();
      ++currentOutputIterator;
    }

    this->Iteration++;

    return currentOutputIterator;
  } // end operator()

  template <typename T1, typename T2, typename Compare>
  struct compare_pair_first : std::binary_function< std::pair<T1, T2>, std::pair<T1, T2>, bool>
  {
    Compare comp;
    compare_pair_first(const Compare& aComp = Compare()) : comp(aComp) { }
    bool operator()(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y) const
    {
      return comp(x.first, y.first);
    }
  };

  /** This is the case where the output iterators contain nodes.
    * 'result' does not have to be passed by reference because it is an iterator.
    * The return type if this function is enabled is OutputIteratorType.
    */
  template <typename PairPriorityQueueType,
  typename OutputIteratorType>
  inline
  typename boost::enable_if<
  boost::is_same<
  typename std::iterator_traits<typename PairPriorityQueueType::value_type::second_type >::value_type,
  typename std::iterator_traits< OutputIteratorType >::value_type
  >,
  OutputIteratorType >::type copy_neighbors_from_queue(PairPriorityQueueType& Q, OutputIteratorType result)
  {
    OutputIteratorType first = result;
    while( !Q.empty() )
    {
      *result = *(Q.top().second);
      Q.pop();
      ++result;
    };
    std::reverse(first, result);
    return result;
  }

};

#endif
<commit_msg>Retry with more allowable repeated pixels if no usable patches are found.<commit_after>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#ifndef LinearSearchKNNPropertyLimitLocalReuse_HPP
#define LinearSearchKNNPropertyLimitLocalReuse_HPP

// STL
#include <algorithm> // for lower_bound()
#include <limits> // for infinity()
#include <set>

// Boost
#include <boost/utility.hpp> // for enable_if()
#include <boost/type_traits.hpp> // for is_same()

// Custom
#include "Utilities/Utilities.hpp"

// Submodules
#include <Mask/Mask.h>
#include <Utilities/Debug/Debug.h>

/**
  * This function template is similar to std::min_element but can be used when the comparison
  * involves computing a derived quantity (a.k.a. distance). This algorithm will search for the
  * the elements in the range [first,last) with the "smallest" distances (of course, both the
  * distance metric and comparison can be overriden to perform something other than the canonical
  * Euclidean distance and less-than comparison, which would yield the element with minimum distance).
  * This function will fill the output container with a number of nearest-neighbors.
  * \tparam DistanceValueType The value-type for the distance measures.
  * \tparam DistanceFunctionType The functor type to compute the distance measure.
  */
template <typename TPatchDescriptorPropertyMap, typename TPatchDistanceFunction,
          typename TImageToWrite>
class LinearSearchKNNPropertyLimitLocalReuse : public Debug
{
  typedef float DistanceValueType;

  /** The map of vertex descriptors. */
  TPatchDescriptorPropertyMap PatchDescriptorPropertyMap;

  /** How many top patches to return. */
  unsigned int K;

  /** The function to use to compare patches. */
  TPatchDistanceFunction PatchDistanceFunction;

  /** An image indicating where each pixel came from. */
  typedef itk::Image<itk::Index<2>, 2> SourcePixelMapImageType;
  SourcePixelMapImageType* SourcePixelMapImage;

  /** The current inpainting mask. */
  Mask* MaskImage;

  /** Store the full region so that it can be reference without an image or mask. */
  itk::ImageRegion<2> FullRegion;

  unsigned int Iteration = 0;

  TImageToWrite* ImageToWrite;

  float LocalRegionSizeMultiplier;

  float MaxAllowedUsedPixelsRatio;

public:
  LinearSearchKNNPropertyLimitLocalReuse(TPatchDescriptorPropertyMap patchDescriptorPropertyMap, Mask* mask, const unsigned int k = 1000,
                                         float localRegionSizeMultiplier = 3.0f, float maxAllowedUsedPixelsRatio = 0.5f,
                                         TPatchDistanceFunction patchDistanceFunction = TPatchDistanceFunction(),
                                         SourcePixelMapImageType* sourcePixelMapImage = nullptr, TImageToWrite* imageToWrite = nullptr) :
    PatchDescriptorPropertyMap(patchDescriptorPropertyMap), K(k), PatchDistanceFunction(patchDistanceFunction),
    SourcePixelMapImage(sourcePixelMapImage), MaskImage(mask), ImageToWrite(imageToWrite),
    LocalRegionSizeMultiplier(localRegionSizeMultiplier), MaxAllowedUsedPixelsRatio(maxAllowedUsedPixelsRatio)
  {
    this->FullRegion = this->MaskImage->GetLargestPossibleRegion();
  }

  /** Set the number of nearest neighbors to return. */
  void SetK(const unsigned int k)
  {
    this->K = k;
  }

  /** Get the number of nearest neighbors to return. */
  unsigned int GetK() const
  {
    return this->K;
  }

  typedef std::set<itk::Index<2>, itk::Index<2>::LexicographicCompare> UsedIndexSetType;

  //   template <typename ForwardIteratorType, typename OutputContainerType>
  //   void operator()(ForwardIteratorType first, ForwardIteratorType last,
  //                   typename ForwardIteratorType::value_type queryNode, OutputContainerType& output)
  /**
    * \tparam ForwardIterator The forward-iterator type.
    * \tparam OutputContainer The container type which can contain the list of nearest-neighbors (STL like container, with iterators, insert, size, and pop_back).
    * \param first Start of the range in which to search.
    * \param last One element past the last element in the range in which to search (usually container.end() ).
    * \param output The container that will have the sorted list of elements with the smallest distance.
    * \param compare A callable object that returns true if the first element is the preferred one (less-than) of the two.
    * \param max_neighbors The maximum number of elements of smallest distance to output in the sorted list.
    */
  template <typename TForwardIterator, typename TOutputIterator>
  inline TOutputIterator
  operator()(TForwardIterator first, TForwardIterator last,
             typename TForwardIterator::value_type queryNode,
             TOutputIterator outputFirst)
  {
    if(this->DebugScreenOutputs)
    {
      std::cout << "LinearSearchKNNPropertyLimitLocalReuse searching " << last - first << " patches." << std::endl;
    }

    // Nothing to do if the input range is empty
    if(first == last)
    {
      return outputFirst;
    }

    // This doesn't work correctly - the image is written but it cannot be opened in a viewer like gwenview,
    // and in Paraview it does not seem to contain columns of patches and numbers? Perhaps because of the extreme
    // size of the image?
//    if(this->DebugImages && this->Iteration == 140)
//    {
//      if(this->ImageToWrite == nullptr)
//      {
//        throw std::runtime_error("LinearSearchBestLidarTextureGradient cannot WriteTopPatches without having an ImageToWrite!");
//      }
//      PatchHelpers::WriteTopPatches(this->ImageToWrite, this->PatchDescriptorPropertyMap, first, last,
//                                    "KNNPatches", this->Iteration);
//    }

    if(this->DebugImages)
    {
      ITKHelpers::WriteIndexImage(this->SourcePixelMapImage, Helpers::GetSequentialFileName("SourcePixelMap", this->Iteration, "mha", 3));
    }

    // Use a priority queue to keep the items sorted
    typedef std::pair<DistanceValueType, TForwardIterator> PairType;
    typedef compare_pair_first<DistanceValueType, TForwardIterator, std::greater<DistanceValueType> > CompareType;
    typedef std::priority_queue< PairType, std::vector<PairType>,
        CompareType> PriorityQueueType;

    typedef typename TPatchDescriptorPropertyMap::value_type DescriptorType;
    DescriptorType queryDescriptor = get(this->PatchDescriptorPropertyMap, queryNode);

    typedef typename TForwardIterator::value_type NodeType;

    // Create a region from the node
    itk::Index<2> queryIndex = Helpers::ConvertFrom<itk::Index<2>, NodeType>(queryNode);

    itk::ImageRegion<2> queryRegion = queryDescriptor.GetRegion();

    // Look for pixels that have already been used

    // Create a bigger region
    itk::ImageRegion<2> largerTargetRegion =
        ITKHelpers::GetRegionInRadiusAroundPixel(queryIndex,
                                                 queryRegion.GetSize()[0]/2.0f * this->LocalRegionSizeMultiplier);
    largerTargetRegion.Crop(this->FullRegion);
    std::cout << "The region to search for repeated pixels is " << largerTargetRegion << std::endl;

    itk::ImageRegionConstIterator<SourcePixelMapImageType> sourcePixelMapIterator(this->SourcePixelMapImage,
                                                                                largerTargetRegion);

    UsedIndexSetType usedIndices;
    while(!sourcePixelMapIterator.IsAtEnd())
    {
      usedIndices.insert(sourcePixelMapIterator.Get());

      ++sourcePixelMapIterator;
    }

    unsigned int numberOfHolePixels = this->MaskImage->CountHolePixels(queryRegion);
    unsigned int maxAllowedUsedPixels = this->MaxAllowedUsedPixelsRatio * numberOfHolePixels;

    PriorityQueueType outputQueue;
    while(outputQueue.size() == 0)
    {
      outputQueue = FindUsablePatches<PriorityQueueType, TForwardIterator, DescriptorType>(first, last, usedIndices, maxAllowedUsedPixels, queryDescriptor);
      maxAllowedUsedPixels += 10;
    }

//    std::cout << "There are " << outputQueue.size() << " items in the queue." << std::endl;

    // Keep only the best K matches
    if(outputQueue.size() < this->K)
    {
      std::cerr << "Warning: LinearSearchKNNPropertyLimitLocalReuse only has " << outputQueue.size()
                << " nodes. (" << this->K << " were requested.)" << std::endl;
    }
    Helpers::KeepTopN(outputQueue, this->K);

//    std::cout << "There are " << outputQueue.size() << " items in the queue." << std::endl;

    if(outputQueue.size() < this->K)
    {
      std::stringstream ss;
      ss << "LinearSearchKNNPropertyLimitLocalReuse: Requested " << this->K << " items but only found " << outputQueue.size();
      throw std::runtime_error(ss.str());
    }

    std::cout << "Best patch score is: " << outputQueue.top().first << std::endl;

    // Copy the best matches from the queue into the output
    TOutputIterator currentOutputIterator = outputFirst;
    while( !outputQueue.empty() )
    {
      *currentOutputIterator = *(outputQueue.top().second);
      outputQueue.pop();
      ++currentOutputIterator;
    }

    this->Iteration++;

    return currentOutputIterator;
  } // end operator()

  template <typename T1, typename T2, typename Compare>
  struct compare_pair_first : std::binary_function< std::pair<T1, T2>, std::pair<T1, T2>, bool>
  {
    Compare comp;
    compare_pair_first(const Compare& aComp = Compare()) : comp(aComp) { }
    bool operator()(const std::pair<T1, T2>& x, const std::pair<T1, T2>& y) const
    {
      return comp(x.first, y.first);
    }
  };

  /** This is the case where the output iterators contain nodes.
    * 'result' does not have to be passed by reference because it is an iterator.
    * The return type if this function is enabled is OutputIteratorType.
    */
  template <typename PairPriorityQueueType,
  typename OutputIteratorType>
  inline
  typename boost::enable_if<
  boost::is_same<
  typename std::iterator_traits<typename PairPriorityQueueType::value_type::second_type >::value_type,
  typename std::iterator_traits< OutputIteratorType >::value_type
  >,
  OutputIteratorType >::type copy_neighbors_from_queue(PairPriorityQueueType& Q, OutputIteratorType result)
  {
    OutputIteratorType first = result;
    while( !Q.empty() )
    {
      *result = *(Q.top().second);
      Q.pop();
      ++result;
    };
    std::reverse(first, result);
    return result;
  }

  template <typename TPriorityQueue, typename TForwardIterator, typename TDescriptor>
  TPriorityQueue FindUsablePatches(TForwardIterator first, TForwardIterator last,
                                   UsedIndexSetType usedIndices, unsigned int maxAllowedUsedPixels, TDescriptor& queryDescriptor)
  {
    TPriorityQueue outputQueue;

    typedef typename TForwardIterator::value_type NodeType;

    // The queue stores the items in descending score order.
    #pragma omp parallel for
//    for(ForwardIteratorType current = first; current != last; ++current) // OpenMP 3 doesn't allow != in the loop ending condition
    for(TForwardIterator currentIterator = first; currentIterator < last; ++currentIterator)
    {
      NodeType currentNode = *currentIterator;

      itk::ImageRegion<2> queryRegion = queryDescriptor.GetRegion();

      typename TPatchDescriptorPropertyMap::value_type currentDescriptor = get(this->PatchDescriptorPropertyMap, currentNode);

      if(currentDescriptor.GetStatus() != PixelDescriptor::SOURCE_NODE)
      {
        throw std::runtime_error("LinearSearchKNNPropertyLimitLocalReuse: Node is not a source node!");
      }

      itk::ImageRegion<2> potentialSourceRegion = currentDescriptor.GetRegion();

      potentialSourceRegion.Crop(this->FullRegion);

      if(!this->MaskImage->IsValid(potentialSourceRegion))
      {
        throw std::runtime_error("LinearSearchKNNPropertyLimitLocalReuse: potentialSourceRegion is not fully valid!");
      }

      // Count the number of pixels that were already copied from this patch
      unsigned int usedPixelCounter = 0;

      itk::ImageRegionConstIteratorWithIndex<SourcePixelMapImageType>
          sourceRegionIterator(this->SourcePixelMapImage, potentialSourceRegion);

      // The image that this is iterating over is irrelevant, we just need the indices.
      itk::ImageRegionConstIteratorWithIndex<SourcePixelMapImageType>
          queryRegionIterator(this->SourcePixelMapImage, queryRegion);

      while(!sourceRegionIterator.IsAtEnd())
      {
        UsedIndexSetType::iterator usedIndexSetIterator;
        if(this->MaskImage->IsHole(queryRegionIterator.GetIndex()))
        {
          // We want to use the index value in the SourcePixelMapImage,
          // because the value might not equal the current index in the case where new patches are allowed.
          usedIndexSetIterator = usedIndices.find(sourceRegionIterator.Get());

          if(usedIndexSetIterator != usedIndices.end()) // found
          {
            usedPixelCounter++;
          }
        }

        ++sourceRegionIterator;
        ++queryRegionIterator;
      }

      typedef std::pair<DistanceValueType, TForwardIterator> PairType;
      if(usedPixelCounter <= maxAllowedUsedPixels)
      {
        DistanceValueType d = this->PatchDistanceFunction(currentDescriptor, queryDescriptor); // (source, target) (the query node is the target node)

        #pragma omp critical // There are weird crashes without this guard
        outputQueue.push(PairType(d, currentIterator));
      }
      else
      {
//        std::cout << "Prevented use because " << usedPixelCounter
//                  << " pixels were already used (out of " << numberOfHolePixels
//                  << " hole pixels)." << std::endl;
      }
    } // end loop over all patches

    return outputQueue;
  }

};

#endif
<|endoftext|>


<commit_before>#include <barcode/perkattribmenu.hpp>

PerkAttribMenu::PerkAttribMenu()
{

}

PerkAttribMenu::~PerkAttribMenu()
{
}
void PerkAttribMenu::render(bool & thing, Hydra::Renderer::Batch * renderBatch, float delta)
{
	ImGui::SetNextWindowSize(ImVec2(500, 1000), ImGuiCond_Once);
	ImGui::Begin("Attributes", &thing, ImGuiWindowFlags_MenuBar);

	//Whatever you choose in the editor will be added/multiplied by
	//whatever values the player already has

	ImGui::RadioButton("Bullet: ", &Bullet.mesh, 0); ImGui::SameLine();
	ImGui::RadioButton("Star: ", &Bullet.mesh, 1); ImGui::SameLine();
	ImGui::RadioButton("Trident: ", &Bullet.mesh, 2); ImGui::SameLine();
	ImGui::RadioButton("Banana: ", &Bullet.mesh, 3); ImGui::SameLine();
	ImGui::RadioButton("Duck: ", &Bullet.mesh, 4);

	ImGui::Separator();
	ImGui::Checkbox("Glow on/off", &Bullet.glow);
	ImGui::Separator();
	ImGui::Text("Glow Intensity:"); ImGui::SameLine(); ImGui::DragFloat("                             ", &Bullet.glowIntensity, 0.01f);
	ImGui::Separator();
	ImGui::Text("Bullet Size:"); ImGui::SameLine(); ImGui::DragFloat("", &Bullet.bulletSize, 0.01f);
	ImGui::Separator();
	ImGui::Text("Bullet Damage:"); ImGui::SameLine(); ImGui::DragFloat("  ",&Bullet.dmg, 0.01f);
	ImGui::Separator();
	ImGui::Text("Weapon Recoil:"); ImGui::SameLine(); ImGui::DragFloat("   ", &Bullet.recoil, 0.01f);
	ImGui::Separator();
	ImGui::Text("Mag Ammo:"); ImGui::SameLine(); ImGui::DragInt("      ", &Bullet.currentMagAmmo);
	ImGui::Separator();
	ImGui::Text("Shot Spread:"); ImGui::SameLine(); ImGui::DragFloat("       ", &Bullet.bulletSpread, 0.01f);
	ImGui::Separator();
	ImGui::Text("Shot RPM:"); ImGui::SameLine(); ImGui::DragFloat("          ", &Bullet.roundsPerMinute, 0.01f);
	ImGui::Separator();
	ImGui::ColorPicker4("Bullet Color:",(float*)&Bullet.bulletColor,ImGuiColorEditFlags_RGB);
	ImGui::Separator();
	ImGui::Text("Perk Description:");
	ImGui::InputText("                            ", Bullet.perkDescription, 128);
	ImGui::Separator();
	//ImGui::RadioButton("Multiplier", &Bullet.multi); ImGui::SameLine(); ImGui::RadioButton("Adder", &Bullet.add);
	ImGui::Checkbox("Multiplier", &Bullet.Multiplier), ImGui::SameLine(); ImGui::Checkbox("Adder", &Bullet.Adder);
	//ImGui::Checkbox("Bullet Mesh", )
	//if (Bullet.mesh != lastMesh) {
	//
	//}

	if (ImGui::Button("Export", ImVec2(200, 75)))
	{
		openPopup = true;
	}

	if (openPopup)
	{
		ImGui::OpenPopup("Exporter");
		if (ImGui::BeginPopup("Exporter"))
		{
			ImGui::Text("Write the name of your Perk:");
			ImGui::InputText("  ", Bullet.perkName, 128);

			if (ImGui::Button("Done", ImVec2(200, 75)))
			{
				writeToFile(Bullet.perkName);
				openPopup = false;
			}
			ImGui::SameLine();
			if (ImGui::Button("Exit", ImVec2(50, 75)))
			{
				openPopup = false;
			}
			ImGui::EndPopup();
		}
	}

	ImGui::End();
}

void PerkAttribMenu::updateBullet(BulletInfo& bullet)
{
	bullet = Bullet;
}

void PerkAttribMenu::writeToFile(const char* fileName)
{
	//file << Bullet.bulletSize;
	//file << Bullet.dmg;
	//file << Bullet.recoil;
	//file << Bullet.currentMagAmmo;
	//file << Bullet.bulletSpread;
	//file << Bullet.roundsPerMinute;
	//file << Bullet.bulletColor[0];
	//file << Bullet.bulletColor[1];
	//file << Bullet.bulletColor[2];
	//file.write(reinterpret_cast<char *>(&Bullet.perkDescription), sizeof(char));
	//binary
	//file << Bullet.perkDescription;

	std::string name = fileName;
	std::string filepath = "assets/perks/" + name + ".PERK";
	std::ofstream file;
	file.open(filepath, std::ios::binary);

	file.write(reinterpret_cast<char *>(&Bullet.bulletSize), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.dmg), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.recoil), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.currentMagAmmo), sizeof(int));
	file.write(reinterpret_cast<char *>(&Bullet.bulletSpread), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.roundsPerMinute), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[0]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[1]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[2]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.Adder), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.Multiplier), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.glow), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.glowIntensity), sizeof(float));
	file.write(reinterpret_cast<char *> (&Bullet.mesh), sizeof(int));

	std::string description = Bullet.perkDescription;
	int size = description.size();

	file.write(reinterpret_cast<char*>(&size), sizeof(int));
	file.write(description.data(), size);

	file.close();
}

<commit_msg>Screw pop ups<commit_after>#include <barcode/perkattribmenu.hpp>

PerkAttribMenu::PerkAttribMenu()
{

}

PerkAttribMenu::~PerkAttribMenu()
{
}
void PerkAttribMenu::render(bool & thing, Hydra::Renderer::Batch * renderBatch, float delta)
{
	ImGui::SetNextWindowSize(ImVec2(500, 1000), ImGuiCond_Once);
	ImGui::Begin("Attributes", &thing, ImGuiWindowFlags_MenuBar);

	//Whatever you choose in the editor will be added/multiplied by
	//whatever values the player already has

	ImGui::RadioButton("Bullet", &Bullet.mesh, 0); ImGui::SameLine();
	ImGui::RadioButton("Star", &Bullet.mesh, 1); ImGui::SameLine();
	ImGui::RadioButton("Trident", &Bullet.mesh, 2); ImGui::SameLine();
	ImGui::RadioButton("Banana", &Bullet.mesh, 3); ImGui::SameLine();
	ImGui::RadioButton("Duck", &Bullet.mesh, 4);

	ImGui::Separator();
	ImGui::Checkbox("Glow on/off", &Bullet.glow);
	ImGui::Separator();
	ImGui::Text("Glow Intensity:"); ImGui::SameLine(); ImGui::DragFloat("                             ", &Bullet.glowIntensity, 0.01f);
	ImGui::Separator();
	ImGui::Text("Bullet Size:"); ImGui::SameLine(); ImGui::DragFloat("", &Bullet.bulletSize, 0.01f);
	ImGui::Separator();
	ImGui::Text("Bullet Damage:"); ImGui::SameLine(); ImGui::DragFloat("  ",&Bullet.dmg, 0.01f);
	ImGui::Separator();
	ImGui::Text("Weapon Recoil:"); ImGui::SameLine(); ImGui::DragFloat("   ", &Bullet.recoil, 0.01f);
	ImGui::Separator();
	//if (ImGui::IsItemHovered())
	//{
	//	ImGui::SetTooltip("This will add the amount of ammo that will fit in your magazine");
	//}
	ImGui::Text("Mag Ammo:"); ImGui::SameLine(); ImGui::DragInt("      ", &Bullet.currentMagAmmo);
	ImGui::Separator();
	//if (ImGui::IsItemHovered())
	//{
	//	ImGui::SetTooltip("This will make the shots go in dirrenrent direction");
	//}
	ImGui::Text("Shot Spread:"); ImGui::SameLine(); ImGui::DragFloat("       ", &Bullet.bulletSpread, 0.01f);
	ImGui::Separator();
	//if (ImGui::IsItemHovered())
	//{
	//	ImGui::SetTooltip("This will add the amount of shots you'll fire per minute");
	//}
	ImGui::Text("Shot RPM:"); ImGui::SameLine(); ImGui::DragFloat("          ", &Bullet.roundsPerMinute, 0.01f);
	ImGui::Separator();
	ImGui::ColorPicker4("Bullet Color:",(float*)&Bullet.bulletColor,ImGuiColorEditFlags_RGB);
	ImGui::Separator();
	ImGui::Text("Perk Description:");
	ImGui::InputText("                            ", Bullet.perkDescription, 128);
	ImGui::Separator();
	//ImGui::RadioButton("Multiplier", &Bullet.multi); ImGui::SameLine(); ImGui::RadioButton("Adder", &Bullet.add);
	ImGui::Checkbox("Multiplier", &Bullet.Multiplier), ImGui::SameLine(); ImGui::Checkbox("Adder", &Bullet.Adder);
	//ImGui::Checkbox("Bullet Mesh", )
	//if (Bullet.mesh != lastMesh) {
	//
	//}

	if (ImGui::Button("Export", ImVec2(200, 75)))
	{
		openPopup = true;
	}

	if (openPopup)
	{
		ImGui::OpenPopup("Exporter");
		if (ImGui::BeginPopup("Exporter"))
		{
			ImGui::Text("Write the name of your Perk:");
			ImGui::InputText("  ", Bullet.perkName, 128);

			if (ImGui::Button("Done", ImVec2(200, 75)))
			{
				writeToFile(Bullet.perkName);
				openPopup = false;
			}
			ImGui::SameLine();
			if (ImGui::Button("Exit", ImVec2(50, 75)))
			{
				openPopup = false;
			}
			ImGui::EndPopup();
		}
	}

	ImGui::End();
}

void PerkAttribMenu::updateBullet(BulletInfo& bullet)
{
	bullet = Bullet;
}

void PerkAttribMenu::writeToFile(const char* fileName)
{
	//file << Bullet.bulletSize;
	//file << Bullet.dmg;
	//file << Bullet.recoil;
	//file << Bullet.currentMagAmmo;
	//file << Bullet.bulletSpread;
	//file << Bullet.roundsPerMinute;
	//file << Bullet.bulletColor[0];
	//file << Bullet.bulletColor[1];
	//file << Bullet.bulletColor[2];
	//file.write(reinterpret_cast<char *>(&Bullet.perkDescription), sizeof(char));
	//binary
	//file << Bullet.perkDescription;

	std::string name = fileName;
	std::string filepath = "assets/perks/" + name + ".PERK";
	std::ofstream file;
	file.open(filepath, std::ios::binary);

	file.write(reinterpret_cast<char *>(&Bullet.bulletSize), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.dmg), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.recoil), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.currentMagAmmo), sizeof(int));
	file.write(reinterpret_cast<char *>(&Bullet.bulletSpread), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.roundsPerMinute), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[0]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[1]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.bulletColor[2]), sizeof(float));
	file.write(reinterpret_cast<char *>(&Bullet.Adder), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.Multiplier), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.glow), sizeof(bool));
	file.write(reinterpret_cast<char *>(&Bullet.glowIntensity), sizeof(float));
	file.write(reinterpret_cast<char *> (&Bullet.mesh), sizeof(int));

	std::string description = Bullet.perkDescription;
	int size = description.size();

	file.write(reinterpret_cast<char*>(&size), sizeof(int));
	file.write(description.data(), size);

	file.close();
}

<|endoftext|>


<commit_before>#include "astutil.h"
#include "expr.h"
#include "passes.h"
#include "runtime.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

/*** name_matches_method
 ***   returns true iff function name matches a method name in class
 ***/
static bool
name_matches_method(const char* name, Type* type) {
  if (!strcmp(name, type->symbol->name))
    return false;
  forv_Vec(Symbol, method, type->methods) {
    if (method && !strcmp(name, method->name))
      return true;
  }
  forv_Vec(Type, pt, type->dispatchParents) {
    if (name_matches_method(name, pt))
      return true;
  }
  if (ClassType* ct = toClassType(type)) {
    Type *outerType = ct->symbol->defPoint->parentSymbol->type;
    if (ClassType* outer = toClassType(outerType))
      if (name_matches_method(name, outer))
        return true;
  }
  return false;
}

/*** name_matches_method_local
 ***   returns true iff function name matches a method name in class
 ***   not including any classes this class is nested in
 ***/
static bool
name_matches_method_local(const char* name, Type* type) {
  if (!strcmp(name, type->symbol->name))
    return false;
  forv_Vec(Symbol, method, type->methods) {
    if (method && !strcmp(name, method->name))
      return true;
  }
  forv_Vec(Type, pt, type->dispatchParents) {
    if (name_matches_method(name, pt))
      return true;
  }
  return false;
}

static BlockStmt*
find_outer_loop(Expr* stmt) {
  if (BlockStmt* block = toBlockStmt(stmt))
    if (block->isLoop())
      return block;
  if (stmt->parentExpr)
    return find_outer_loop(stmt->parentExpr);
  return NULL;
}

static void
resolveGotoLabel(GotoStmt* gotoStmt) {
  if (gotoStmt->label->var == gNil) {
    BlockStmt* loop = find_outer_loop(gotoStmt);
    if (!loop)
      USR_FATAL(gotoStmt, "break or continue is not in a loop");
    if (gotoStmt->gotoTag == GOTO_BREAK)
      gotoStmt->label->replace(new SymExpr(loop->post_loop));
    else if (gotoStmt->gotoTag == GOTO_CONTINUE)
      gotoStmt->label->replace(new SymExpr(loop->pre_loop));
    else
      INT_FATAL(gotoStmt, "Unexpected goto type");
  } else if (!gotoStmt->label->var) {
    const char* name = gotoStmt->label->unresolved;
    if (gotoStmt->gotoTag == GOTO_BREAK)
      name = astr("_post", name);
    Vec<BaseAST*> asts;
    collect_asts(&asts, gotoStmt->parentSymbol);
    forv_Vec(BaseAST, ast, asts) {
      if (LabelSymbol* ls = toLabelSymbol(ast)) {
        if (!strcmp(ls->name, name))
          gotoStmt->label->replace(new SymExpr(ls));
      }
    }
  }
}

static void resolveEnumeratedTypes() {
  forv_Vec(BaseAST, ast, gAsts) {
    if (CallExpr* call = toCallExpr(ast)) {
      if (call->isNamed(".")) {
        if (SymExpr* first = toSymExpr(call->get(1))) {
          if (SymExpr* second = toSymExpr(call->get(2))) {
            if (!first->unresolved) {
              if (EnumType* type = toEnumType(first->var->type)) {
                VarSymbol* var = toVarSymbol(second->var);
                const char* name;
                if (var) {
                  if (var->immediate &&
                      var->immediate->const_kind == CONST_KIND_STRING) {
                    name = var->immediate->v_string;
                    INT_ASSERT(name);
                  }
                } else {
                  name = second->unresolved;
                }
                for_alist(constant, type->constants) {
                  DefExpr* def = toDefExpr(constant);
                  INT_ASSERT(def);
                  if (!strcmp(def->sym->name, name)) {
                    call->replace(new SymExpr(def->sym));
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

void scopeResolve(void) {
  //
  // resolve type of this for methods
  //
  forv_Vec(FnSymbol, fn, gFns) {
    if (fn->_this && fn->_this->type == dtUnknown) {
      if (SymExpr* sym = toSymExpr(fn->_this->defPoint->exprType)) {
        if (!sym->var) {
          TypeSymbol* ts = toTypeSymbol(sym->lookup(sym->unresolved));
          sym->var = ts;
          sym->unresolved = NULL;
          sym->remove();
        }
        fn->_this->type = sym->var->type;
        fn->_this->type->methods.add(fn);
      }
    }
  }

  forv_Vec(BaseAST, ast, gAsts) {
    currentLineno = ast->lineno;
    currentFilename = ast->filename;

    // Translate M.x where M is a ModuleSymbol into just x
    // where x is the symbol from module M.
    if (CallExpr* callExpr = toCallExpr(ast)) {
      SymExpr *base, *sym1, *sym2;
      ModuleSymbol *module;
      if ((base = toSymExpr(callExpr->baseExpr)) &&
          (base->isNamed("."))                   &&
          (sym1 = toSymExpr(callExpr->get(1)))   &&
          (module = toModuleSymbol(sym1->var))   &&
          (sym2 = toSymExpr(callExpr->get(2)))) {
        SymExpr *newSym =
          new SymExpr(module->block->blkScope->lookup(get_string(sym2)));
        callExpr->replace(newSym);
      }
    }

    if (SymExpr* symExpr = toSymExpr(ast)) {
      if (symExpr->unresolved) {
        const char* name = symExpr->unresolved;
        if (symExpr->isNamed(".") || !symExpr->parentSymbol)
          continue;

        if (!symExpr->parentSymbol)
          continue;

        Symbol* sym = symExpr->parentScope->lookup(name, NULL, false);
        if (!sym)
          sym = symExpr->parentScope->lookup(name, NULL, true);

        bool handleFunctionWithoutParens = false;
        for (Symbol* tmp = sym; tmp; tmp = tmp->overloadNext) {
          if (FnSymbol* fn = toFnSymbol(tmp)) {
            if (!fn->isMethod && fn->noParens) {
              symExpr->replace(new CallExpr(fn));
              handleFunctionWithoutParens = true;
            }
          }
        }
        if (handleFunctionWithoutParens)
          continue;

        // sjd: stopgap to avoid shadowing variables or functions by methods
        while (FnSymbol* fn = toFnSymbol(sym)) {
          if (fn->isMethod)
            sym = sym->overloadNext;
          else
            break;
        }

        FnSymbol* fn = toFnSymbol(sym);
        TypeSymbol* type = toTypeSymbol(sym);
        if (sym) {
          if (!fn) {
            symExpr->var = sym;
            symExpr->unresolved = NULL;
          }
          if (type)
            if (UserType* ut = toUserType(type->type)) {
              ASTMap map;
              Expr* e = ut->typeExpr->copy(&map);

              // detect recursively defined type aliases
              Vec<BaseAST*> asts;
              map.get_values(asts);
              forv_Vec(BaseAST, ast, asts) {
                if (SymExpr* se = toSymExpr(ast))
                  if (TypeSymbol* ts = toTypeSymbol(se->var))
                    if (isUserType(ts->type))
                      USR_FATAL(se, "type alias is recursive");
              }

              symExpr->replace(e);
              continue;
            }
        }

        // Apply 'this' and 'outer' in methods where necessary
        {
          Symbol* parent = symExpr->parentSymbol;
          while (!toModuleSymbol(parent)) {
            if (FnSymbol* method = toFnSymbol(parent)) {

              // stopgap bug fix: do not let methods shadow symbols
              // that are more specific than methods
              if (sym && sym->getFunction() == method)
                break;

              if (method->_this && symExpr->var != method->_this) {
                Type* type = method->_this->type;
                if ((sym && toClassType(sym->parentScope->astParent)) ||
                    name_matches_method(name, type)) {
                  CallExpr* call = toCallExpr(symExpr->parentExpr);
                  if (call && call->baseExpr == symExpr &&
                      call->numActuals() >= 2 &&
                      toSymExpr(call->get(1)) &&
                      toSymExpr(call->get(1))->var == gMethodToken) {
                    symExpr->var = NULL;
                    symExpr->unresolved = name;
                  } else {
                    ClassType* ct = toClassType(type);
                    int nestDepth = 0;
                    if (name_matches_method(name, type)) {
                      while (ct && !name_matches_method_local(name, ct)) {
                        // count how many classes out from current depth that
                        // this method is first defined in
                        nestDepth += 1;
                        ct = toClassType
                          (ct->symbol->defPoint->parentSymbol->type);
                      }
                    } else {
                      while (ct && !ct->structScope->lookupLocal(name)) {
                        // count how many classes out from current depth that
                        // this symbol is first defined in
                        nestDepth += 1;
                        ct = toClassType
                          (ct->symbol->defPoint->parentSymbol->type);
                      }
                    }

                    Expr *dot = NULL;
                    for (int i=0; i<=nestDepth; i++) {
                      // Apply implicit this pointers and outer this pointers
                      if (i == 0) {
                        if (i < nestDepth) {
                          dot = new CallExpr(".",
                                             method->_this,
                                             new_StringSymbol("outer"));
                        } else {
                          if (isTypeSymbol(sym))
                            dot = new CallExpr(".", method->_this, sym);
                          else
                            dot = new CallExpr(".",
                                               method->_this,
                                               new_StringSymbol(name));
                        }
                      } else {
                        if (i < nestDepth) {
                          dot = new CallExpr(".",
                                             dot, new_StringSymbol("outer"));
                        } else {
                          if (isTypeSymbol(sym))
                            dot = new CallExpr(".", dot, sym);
                          else
                            dot = new CallExpr(".", dot, new_StringSymbol(name));
                        }
                      }
                    }
                    symExpr->replace(dot);
                  }
                }
                break;
              }
            }
            parent = parent->defPoint->parentSymbol;
          }
        }
      }
    } else if (GotoStmt* gs = toGotoStmt(ast)) {
      resolveGotoLabel(gs);
    }
  }

  resolveEnumeratedTypes();

  forv_Vec(TypeSymbol, type, gTypes) {
    if (toUserType(type->type)) {
      type->defPoint->remove();
    }
  }
}
<commit_msg>Clean up enum field access code.<commit_after>#include "astutil.h"
#include "expr.h"
#include "passes.h"
#include "runtime.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

/*** name_matches_method
 ***   returns true iff function name matches a method name in class
 ***/
static bool
name_matches_method(const char* name, Type* type) {
  if (!strcmp(name, type->symbol->name))
    return false;
  forv_Vec(Symbol, method, type->methods) {
    if (method && !strcmp(name, method->name))
      return true;
  }
  forv_Vec(Type, pt, type->dispatchParents) {
    if (name_matches_method(name, pt))
      return true;
  }
  if (ClassType* ct = toClassType(type)) {
    Type *outerType = ct->symbol->defPoint->parentSymbol->type;
    if (ClassType* outer = toClassType(outerType))
      if (name_matches_method(name, outer))
        return true;
  }
  return false;
}

/*** name_matches_method_local
 ***   returns true iff function name matches a method name in class
 ***   not including any classes this class is nested in
 ***/
static bool
name_matches_method_local(const char* name, Type* type) {
  if (!strcmp(name, type->symbol->name))
    return false;
  forv_Vec(Symbol, method, type->methods) {
    if (method && !strcmp(name, method->name))
      return true;
  }
  forv_Vec(Type, pt, type->dispatchParents) {
    if (name_matches_method(name, pt))
      return true;
  }
  return false;
}

static BlockStmt*
find_outer_loop(Expr* stmt) {
  if (BlockStmt* block = toBlockStmt(stmt))
    if (block->isLoop())
      return block;
  if (stmt->parentExpr)
    return find_outer_loop(stmt->parentExpr);
  return NULL;
}

static void
resolveGotoLabel(GotoStmt* gotoStmt) {
  if (gotoStmt->label->var == gNil) {
    BlockStmt* loop = find_outer_loop(gotoStmt);
    if (!loop)
      USR_FATAL(gotoStmt, "break or continue is not in a loop");
    if (gotoStmt->gotoTag == GOTO_BREAK)
      gotoStmt->label->replace(new SymExpr(loop->post_loop));
    else if (gotoStmt->gotoTag == GOTO_CONTINUE)
      gotoStmt->label->replace(new SymExpr(loop->pre_loop));
    else
      INT_FATAL(gotoStmt, "Unexpected goto type");
  } else if (!gotoStmt->label->var) {
    const char* name = gotoStmt->label->unresolved;
    if (gotoStmt->gotoTag == GOTO_BREAK)
      name = astr("_post", name);
    Vec<BaseAST*> asts;
    collect_asts(&asts, gotoStmt->parentSymbol);
    forv_Vec(BaseAST, ast, asts) {
      if (LabelSymbol* ls = toLabelSymbol(ast)) {
        if (!strcmp(ls->name, name))
          gotoStmt->label->replace(new SymExpr(ls));
      }
    }
  }
}

//
// Resolve EnumTypeName.fieldName to the symbol named fieldName in the
// enumerated type named EnumTypeName.
//
static void resolveEnumeratedTypes() {
  forv_Vec(BaseAST, ast, gAsts) {
    if (CallExpr* call = toCallExpr(ast)) {
      if (call->isNamed(".")) {
        if (SymExpr* first = toSymExpr(call->get(1))) {
          if (first->unresolved)
            continue; // EnumTypeName should be resolved already
          if (EnumType* type = toEnumType(first->var->type)) {
            if (SymExpr* second = toSymExpr(call->get(2))) {
              const char* name;
              INT_ASSERT(get_string(second, &name));
              for_enums(constant, type) {
                if (!strcmp(constant->sym->name, name)) {
                  call->replace(new SymExpr(constant->sym));
                }
              }
            }
          }
        }
      }
    }
  }
}

void scopeResolve(void) {
  //
  // resolve type of this for methods
  //
  forv_Vec(FnSymbol, fn, gFns) {
    if (fn->_this && fn->_this->type == dtUnknown) {
      if (SymExpr* sym = toSymExpr(fn->_this->defPoint->exprType)) {
        if (!sym->var) {
          TypeSymbol* ts = toTypeSymbol(sym->lookup(sym->unresolved));
          sym->var = ts;
          sym->unresolved = NULL;
          sym->remove();
        }
        fn->_this->type = sym->var->type;
        fn->_this->type->methods.add(fn);
      }
    }
  }

  forv_Vec(BaseAST, ast, gAsts) {
    currentLineno = ast->lineno;
    currentFilename = ast->filename;

    // Translate M.x where M is a ModuleSymbol into just x
    // where x is the symbol from module M.
    if (CallExpr* callExpr = toCallExpr(ast)) {
      SymExpr *base, *sym1, *sym2;
      ModuleSymbol *module;
      if ((base = toSymExpr(callExpr->baseExpr)) &&
          (base->isNamed("."))                   &&
          (sym1 = toSymExpr(callExpr->get(1)))   &&
          (module = toModuleSymbol(sym1->var))   &&
          (sym2 = toSymExpr(callExpr->get(2)))) {
        SymExpr *newSym =
          new SymExpr(module->block->blkScope->lookup(get_string(sym2)));
        callExpr->replace(newSym);
      }
    }

    if (SymExpr* symExpr = toSymExpr(ast)) {
      if (symExpr->unresolved) {
        const char* name = symExpr->unresolved;
        if (symExpr->isNamed(".") || !symExpr->parentSymbol)
          continue;

        if (!symExpr->parentSymbol)
          continue;

        Symbol* sym = symExpr->parentScope->lookup(name, NULL, false);
        if (!sym)
          sym = symExpr->parentScope->lookup(name, NULL, true);

        bool handleFunctionWithoutParens = false;
        for (Symbol* tmp = sym; tmp; tmp = tmp->overloadNext) {
          if (FnSymbol* fn = toFnSymbol(tmp)) {
            if (!fn->isMethod && fn->noParens) {
              symExpr->replace(new CallExpr(fn));
              handleFunctionWithoutParens = true;
            }
          }
        }
        if (handleFunctionWithoutParens)
          continue;

        // sjd: stopgap to avoid shadowing variables or functions by methods
        while (FnSymbol* fn = toFnSymbol(sym)) {
          if (fn->isMethod)
            sym = sym->overloadNext;
          else
            break;
        }

        FnSymbol* fn = toFnSymbol(sym);
        TypeSymbol* type = toTypeSymbol(sym);
        if (sym) {
          if (!fn) {
            symExpr->var = sym;
            symExpr->unresolved = NULL;
          }
          if (type)
            if (UserType* ut = toUserType(type->type)) {
              ASTMap map;
              Expr* e = ut->typeExpr->copy(&map);

              // detect recursively defined type aliases
              Vec<BaseAST*> asts;
              map.get_values(asts);
              forv_Vec(BaseAST, ast, asts) {
                if (SymExpr* se = toSymExpr(ast))
                  if (TypeSymbol* ts = toTypeSymbol(se->var))
                    if (isUserType(ts->type))
                      USR_FATAL(se, "type alias is recursive");
              }

              symExpr->replace(e);
              continue;
            }
        }

        // Apply 'this' and 'outer' in methods where necessary
        {
          Symbol* parent = symExpr->parentSymbol;
          while (!toModuleSymbol(parent)) {
            if (FnSymbol* method = toFnSymbol(parent)) {

              // stopgap bug fix: do not let methods shadow symbols
              // that are more specific than methods
              if (sym && sym->getFunction() == method)
                break;

              if (method->_this && symExpr->var != method->_this) {
                Type* type = method->_this->type;
                if ((sym && toClassType(sym->parentScope->astParent)) ||
                    name_matches_method(name, type)) {
                  CallExpr* call = toCallExpr(symExpr->parentExpr);
                  if (call && call->baseExpr == symExpr &&
                      call->numActuals() >= 2 &&
                      toSymExpr(call->get(1)) &&
                      toSymExpr(call->get(1))->var == gMethodToken) {
                    symExpr->var = NULL;
                    symExpr->unresolved = name;
                  } else {
                    ClassType* ct = toClassType(type);
                    int nestDepth = 0;
                    if (name_matches_method(name, type)) {
                      while (ct && !name_matches_method_local(name, ct)) {
                        // count how many classes out from current depth that
                        // this method is first defined in
                        nestDepth += 1;
                        ct = toClassType
                          (ct->symbol->defPoint->parentSymbol->type);
                      }
                    } else {
                      while (ct && !ct->structScope->lookupLocal(name)) {
                        // count how many classes out from current depth that
                        // this symbol is first defined in
                        nestDepth += 1;
                        ct = toClassType
                          (ct->symbol->defPoint->parentSymbol->type);
                      }
                    }

                    Expr *dot = NULL;
                    for (int i=0; i<=nestDepth; i++) {
                      // Apply implicit this pointers and outer this pointers
                      if (i == 0) {
                        if (i < nestDepth) {
                          dot = new CallExpr(".",
                                             method->_this,
                                             new_StringSymbol("outer"));
                        } else {
                          if (isTypeSymbol(sym))
                            dot = new CallExpr(".", method->_this, sym);
                          else
                            dot = new CallExpr(".",
                                               method->_this,
                                               new_StringSymbol(name));
                        }
                      } else {
                        if (i < nestDepth) {
                          dot = new CallExpr(".",
                                             dot, new_StringSymbol("outer"));
                        } else {
                          if (isTypeSymbol(sym))
                            dot = new CallExpr(".", dot, sym);
                          else
                            dot = new CallExpr(".", dot, new_StringSymbol(name));
                        }
                      }
                    }
                    symExpr->replace(dot);
                  }
                }
                break;
              }
            }
            parent = parent->defPoint->parentSymbol;
          }
        }
      }
    } else if (GotoStmt* gs = toGotoStmt(ast)) {
      resolveGotoLabel(gs);
    }
  }

  resolveEnumeratedTypes();

  forv_Vec(TypeSymbol, type, gTypes) {
    if (toUserType(type->type)) {
      type->defPoint->remove();
    }
  }
}
<|endoftext|>


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

#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>

#include <graphene/chain/database.hpp>
#include <graphene/chain/hardfork.hpp>

namespace graphene { namespace chain {

namespace detail {

bool _is_authorized_asset(
   const database& d,
   const account_object& acct,
   const asset_object& asset_obj)
{
   if( d.head_block_time() > HARDFORK_416_TIME )
   {
      if( !(asset_obj.options.flags & white_list) )
         return true;
   }

   for( const auto id : acct.blacklisting_accounts )
   {
      if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() )
         return false;
   }

   if( d.head_block_time() > HARDFORK_415_TIME )
   {
      if( asset_obj.options.whitelist_authorities.size() == 0 )
         return true;
   }

   for( const auto id : acct.whitelisting_accounts )
   {
      if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() )
         return true;
   }

   return false;
}

} // detail

} } // graphene::chain
<commit_msg>Remove now-redundant white_list bit check from _is_authorized_asset() #566<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>

#include <graphene/chain/database.hpp>
#include <graphene/chain/hardfork.hpp>

namespace graphene { namespace chain {

namespace detail {

bool _is_authorized_asset(
   const database& d,
   const account_object& acct,
   const asset_object& asset_obj)
{
   for( const auto id : acct.blacklisting_accounts )
   {
      if( asset_obj.options.blacklist_authorities.find(id) != asset_obj.options.blacklist_authorities.end() )
         return false;
   }

   if( d.head_block_time() > HARDFORK_415_TIME )
   {
      if( asset_obj.options.whitelist_authorities.size() == 0 )
         return true;
   }

   for( const auto id : acct.whitelisting_accounts )
   {
      if( asset_obj.options.whitelist_authorities.find(id) != asset_obj.options.whitelist_authorities.end() )
         return true;
   }

   return false;
}

} // detail

} } // graphene::chain
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2006 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.
 *
 * Authors: Ali Saidi
 */

#include <iostream>

#include "arch/arm/system.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
#include "mem/physical.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/full_system.hh"

using namespace std;
using namespace Linux;

ArmSystem::ArmSystem(Params *p)
    : System(p),
      bootLoaders(), bootldr(nullptr),
      _haveSecurity(p->have_security),
      _haveLPAE(p->have_lpae),
      _haveVirtualization(p->have_virtualization),
      _genericTimer(nullptr),
      _highestELIs64(p->highest_el_is_64),
      _resetAddr64(p->reset_addr_64),
      _physAddrRange64(p->phys_addr_range_64),
      _haveLargeAsid64(p->have_large_asid_64),
      multiProc(p->multi_proc)
{
    // Check if the physical address range is valid
    if (_highestELIs64 && (
            _physAddrRange64 < 32 ||
            _physAddrRange64 > 48 ||
            (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
        fatal("Invalid physical address range (%d)\n", _physAddrRange64);
    }

    bootLoaders.reserve(p->boot_loader.size());
    for (const auto &bl : p->boot_loader) {
        std::unique_ptr<ObjectFile> obj;
        obj.reset(createObjectFile(bl));

        fatal_if(!obj, "Could not read bootloader: %s\n", bl);
        bootLoaders.emplace_back(std::move(obj));
    }

    if (kernel) {
        bootldr = getBootLoader(kernel);
    } else if (!bootLoaders.empty()) {
        // No kernel specified, default to the first boot loader
        bootldr = bootLoaders[0].get();
    }

    if (!bootLoaders.empty() && !bootldr)
        fatal("Can't find a matching boot loader / kernel combination!");

    if (bootldr) {
        bootldr->loadGlobalSymbols(debugSymbolTable);
        if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
            warn("Highest ARM exception-level set to AArch32 but bootloader "
                  "is for AArch64. Assuming you wanted these to match.\n");
            _highestELIs64 = true;
        } else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) {
            warn("Highest ARM exception-level set to AArch64 but bootloader "
                  "is for AArch32. Assuming you wanted these to match.\n");
            _highestELIs64 = false;
        }
    }

    debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
}

void
ArmSystem::initState()
{
    // Moved from the constructor to here since it relies on the
    // address map being resolved in the interconnect

    // Call the initialisation of the super class
    System::initState();

    const Params* p = params();

    if (bootldr) {
        bootldr->loadSections(physProxy);

        uint8_t jump_to_bl_32[] =
        {
            0x07, 0xf0, 0xa0, 0xe1  // branch to r7 in aarch32
        };

        uint8_t jump_to_bl_64[] =
        {
            0xe0, 0x00, 0x1f, 0xd6  // instruction "br x7" in aarch64
        };

        // write the jump to branch table into address 0
        if (!_highestELIs64)
            physProxy.writeBlob(0x0, jump_to_bl_32, sizeof(jump_to_bl_32));
        else
            physProxy.writeBlob(0x0, jump_to_bl_64, sizeof(jump_to_bl_64));

        inform("Using bootloader at address %#x\n", bootldr->entryPoint());

        // Put the address of the boot loader into r7 so we know
        // where to branch to after the reset fault
        // All other values needed by the boot loader to know what to do
        if (!p->gic_cpu_addr || !p->flags_addr)
            fatal("gic_cpu_addr && flags_addr must be set with bootloader\n");

        for (int i = 0; i < threadContexts.size(); i++) {
            if (!_highestELIs64)
                threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) +
                        loadAddrOffset);
            threadContexts[i]->setIntReg(4, params()->gic_cpu_addr);
            threadContexts[i]->setIntReg(5, params()->flags_addr);
            threadContexts[i]->setIntReg(7, bootldr->entryPoint());
        }
        inform("Using kernel entry physical address at %#x\n",
               (kernelEntry & loadAddrMask) + loadAddrOffset);
    } else {
        // Set the initial PC to be at start of the kernel code
        if (!_highestELIs64)
            threadContexts[0]->pcState((kernelEntry & loadAddrMask) +
                    loadAddrOffset);
    }
}

bool
ArmSystem::haveSecurity(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveSecurity();
}

ArmSystem::~ArmSystem()
{
    if (debugPrintkEvent)
        delete debugPrintkEvent;
}

ObjectFile *
ArmSystem::getBootLoader(ObjectFile *const obj)
{
    for (auto &bl : bootLoaders) {
        if (bl->getArch() == obj->getArch())
            return bl.get();
    }

    return nullptr;
}

bool
ArmSystem::haveLPAE(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveLPAE();
}

bool
ArmSystem::haveVirtualization(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveVirtualization();
}

bool
ArmSystem::highestELIs64(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestELIs64();
}

ExceptionLevel
ArmSystem::highestEL(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestEL();
}

Addr
ArmSystem::resetAddr64(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->resetAddr64();
}

uint8_t
ArmSystem::physAddrRange(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrRange();
}

Addr
ArmSystem::physAddrMask(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrMask();
}

bool
ArmSystem::haveLargeAsid64(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->haveLargeAsid64();
}

ArmSystem *
ArmSystemParams::create()
{
    return new ArmSystem(this);
}

void
GenericArmSystem::initState()
{
    // Moved from the constructor to here since it relies on the
    // address map being resolved in the interconnect

    // Call the initialisation of the super class
    ArmSystem::initState();
}

GenericArmSystem *
GenericArmSystemParams::create()
{

    return new GenericArmSystem(this);
}
<commit_msg>arm: Make EL checks available in SE mode<commit_after>/*
 * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2006 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.
 *
 * Authors: Ali Saidi
 */

#include <iostream>

#include "arch/arm/system.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
#include "mem/physical.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/full_system.hh"

using namespace std;
using namespace Linux;

ArmSystem::ArmSystem(Params *p)
    : System(p),
      bootLoaders(), bootldr(nullptr),
      _haveSecurity(p->have_security),
      _haveLPAE(p->have_lpae),
      _haveVirtualization(p->have_virtualization),
      _genericTimer(nullptr),
      _highestELIs64(p->highest_el_is_64),
      _resetAddr64(p->reset_addr_64),
      _physAddrRange64(p->phys_addr_range_64),
      _haveLargeAsid64(p->have_large_asid_64),
      multiProc(p->multi_proc)
{
    // Check if the physical address range is valid
    if (_highestELIs64 && (
            _physAddrRange64 < 32 ||
            _physAddrRange64 > 48 ||
            (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
        fatal("Invalid physical address range (%d)\n", _physAddrRange64);
    }

    bootLoaders.reserve(p->boot_loader.size());
    for (const auto &bl : p->boot_loader) {
        std::unique_ptr<ObjectFile> obj;
        obj.reset(createObjectFile(bl));

        fatal_if(!obj, "Could not read bootloader: %s\n", bl);
        bootLoaders.emplace_back(std::move(obj));
    }

    if (kernel) {
        bootldr = getBootLoader(kernel);
    } else if (!bootLoaders.empty()) {
        // No kernel specified, default to the first boot loader
        bootldr = bootLoaders[0].get();
    }

    if (!bootLoaders.empty() && !bootldr)
        fatal("Can't find a matching boot loader / kernel combination!");

    if (bootldr) {
        bootldr->loadGlobalSymbols(debugSymbolTable);
        if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
            warn("Highest ARM exception-level set to AArch32 but bootloader "
                  "is for AArch64. Assuming you wanted these to match.\n");
            _highestELIs64 = true;
        } else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) {
            warn("Highest ARM exception-level set to AArch64 but bootloader "
                  "is for AArch32. Assuming you wanted these to match.\n");
            _highestELIs64 = false;
        }
    }

    debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
}

void
ArmSystem::initState()
{
    // Moved from the constructor to here since it relies on the
    // address map being resolved in the interconnect

    // Call the initialisation of the super class
    System::initState();

    const Params* p = params();

    if (bootldr) {
        bootldr->loadSections(physProxy);

        uint8_t jump_to_bl_32[] =
        {
            0x07, 0xf0, 0xa0, 0xe1  // branch to r7 in aarch32
        };

        uint8_t jump_to_bl_64[] =
        {
            0xe0, 0x00, 0x1f, 0xd6  // instruction "br x7" in aarch64
        };

        // write the jump to branch table into address 0
        if (!_highestELIs64)
            physProxy.writeBlob(0x0, jump_to_bl_32, sizeof(jump_to_bl_32));
        else
            physProxy.writeBlob(0x0, jump_to_bl_64, sizeof(jump_to_bl_64));

        inform("Using bootloader at address %#x\n", bootldr->entryPoint());

        // Put the address of the boot loader into r7 so we know
        // where to branch to after the reset fault
        // All other values needed by the boot loader to know what to do
        if (!p->gic_cpu_addr || !p->flags_addr)
            fatal("gic_cpu_addr && flags_addr must be set with bootloader\n");

        for (int i = 0; i < threadContexts.size(); i++) {
            if (!_highestELIs64)
                threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) +
                        loadAddrOffset);
            threadContexts[i]->setIntReg(4, params()->gic_cpu_addr);
            threadContexts[i]->setIntReg(5, params()->flags_addr);
            threadContexts[i]->setIntReg(7, bootldr->entryPoint());
        }
        inform("Using kernel entry physical address at %#x\n",
               (kernelEntry & loadAddrMask) + loadAddrOffset);
    } else {
        // Set the initial PC to be at start of the kernel code
        if (!_highestELIs64)
            threadContexts[0]->pcState((kernelEntry & loadAddrMask) +
                    loadAddrOffset);
    }
}

bool
ArmSystem::haveSecurity(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveSecurity();
}

ArmSystem::~ArmSystem()
{
    if (debugPrintkEvent)
        delete debugPrintkEvent;
}

ObjectFile *
ArmSystem::getBootLoader(ObjectFile *const obj)
{
    for (auto &bl : bootLoaders) {
        if (bl->getArch() == obj->getArch())
            return bl.get();
    }

    return nullptr;
}

bool
ArmSystem::haveLPAE(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveLPAE();
}

bool
ArmSystem::haveVirtualization(ThreadContext *tc)
{
    if (!FullSystem)
        return false;

    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
    assert(a_sys);
    return a_sys->haveVirtualization();
}

bool
ArmSystem::highestELIs64(ThreadContext *tc)
{
    return FullSystem ?
        dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestELIs64() :
        true;
}

ExceptionLevel
ArmSystem::highestEL(ThreadContext *tc)
{
    return FullSystem ?
        dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestEL() :
        EL1;
}

Addr
ArmSystem::resetAddr64(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->resetAddr64();
}

uint8_t
ArmSystem::physAddrRange(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrRange();
}

Addr
ArmSystem::physAddrMask(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrMask();
}

bool
ArmSystem::haveLargeAsid64(ThreadContext *tc)
{
    return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->haveLargeAsid64();
}

ArmSystem *
ArmSystemParams::create()
{
    return new ArmSystem(this);
}

void
GenericArmSystem::initState()
{
    // Moved from the constructor to here since it relies on the
    // address map being resolved in the interconnect

    // Call the initialisation of the super class
    ArmSystem::initState();
}

GenericArmSystem *
GenericArmSystemParams::create()
{

    return new GenericArmSystem(this);
}
<|endoftext|>