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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

=========================================================================*/
#include "itkExceptionObject.h"
#include "itkNeighborhood.h"
#include "otbImage.h"
#include "itkVariableLengthVector.h"
#include "itkConstNeighborhoodIterator.h"
#include "otbTextureImageFunction.h"
#include "otbFunctionWithNeighborhoodToImageFilter.h"
#include "otbTextureFunctorBase.h"

template <class TIterInput1, class TIterInput2, class TOutput>
class TextureFunctorTest
{
public:
  TextureFunctorTest()
  {
    m_Offset.Fill(1);
  };
  ~TextureFunctorTest() {};

  typedef TIterInput1                    IterType1;
  typedef TIterInput2                    IterType2;
  typedef TOutput                        OutputType;
  typedef typename IterType1::OffsetType OffsetType;
  typedef typename IterType1::InternalPixelType InternalPixelType;
  typedef typename IterType1::ImageType  ImageType;
  typedef itk::Neighborhood<InternalPixelType, ::itk::GetImageDimension<ImageType>::ImageDimension>    NeighborhoodType;

  void SetOffset(OffsetType off){ m_Offset=off; };

  inline TOutput operator()(const IterType1 &it, const IterType2 &itOff)
    {
      return static_cast<OutputType>(it.GetCenterPixel()[0]);
    }

  double ComputeOverSingleChannel(const NeighborhoodType &neigh, const NeighborhoodType &neighOff)
  {
    return 0.;
  }

 private:
  OffsetType m_Offset;
};

int otbFunctionWithNeighborhoodToImageFilterNew(int argc, char * argv[])
{
  const unsigned int Dimension = 2;
  typedef double PixelType;
  typedef otb::Image<PixelType,Dimension>           ImageType;
  typedef itk::VariableLengthVector<double>         VectorType;
  typedef itk::ConstNeighborhoodIterator<ImageType> IteratorType;

  typedef TextureFunctorTest<IteratorType, IteratorType, VectorType>                     FunctorType;
  typedef otb::TextureImageFunction<ImageType, FunctorType>                              FunctionType;
  typedef otb::FunctionWithNeighborhoodToImageFilter<ImageType, ImageType, FunctionType> FilterType;

  // Instantiating object
  FilterType::Pointer object = FilterType::New();

  return EXIT_SUCCESS;
}
<commit_msg>ENH : forgive a change after texture functor refactoring<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

=========================================================================*/
#include "itkExceptionObject.h"
#include "itkNeighborhood.h"
#include "otbImage.h"
//#include "itkVariableLengthVector.h"
//#include "itkConstNeighborhoodIterator.h"
#include "otbTextureImageFunction.h"
#include "otbFunctionWithNeighborhoodToImageFilter.h"
#include "itkOffset.h"
//#include "otbTextureFunctorBase.h"

template <class TInputScalarType, class TOutputScalarType>//IterInput1, class TIterInput2, class TOutput>
class TextureFunctorTest
{
public:
  TextureFunctorTest()
  {
    m_Offset.Fill(1);
  };
  ~TextureFunctorTest() {};

  typedef itk::Offset<> OffsetType;
  typedef itk::Neighborhood<TInputScalarType, 2>    NeighborhoodType;

  void SetOffset(OffsetType off){ m_Offset=off; };

  inline TOutputScalarType operator()(const NeighborhoodType &neigh)
    {
      return static_cast<TOutputScalarType>(neigh.GetCenterValue());
    }

 private:
  OffsetType m_Offset;
};

int otbFunctionWithNeighborhoodToImageFilterNew(int argc, char * argv[])
{
  const unsigned int Dimension = 2;
  typedef double PixelType;
  typedef otb::Image<PixelType,Dimension>           ImageType;
  typedef itk::VariableLengthVector<double>         VectorType;
  typedef itk::ConstNeighborhoodIterator<ImageType> IteratorType;

  typedef TextureFunctorTest<PixelType, PixelType>                                       FunctorType;
  typedef otb::TextureImageFunction<ImageType, FunctorType>                              FunctionType;
  typedef otb::FunctionWithNeighborhoodToImageFilter<ImageType, ImageType, FunctionType> FilterType;

  // Instantiating object
  FilterType::Pointer object = FilterType::New();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "Resolver.h"

#include "Requirement.h"

#include <cassert>
#include <exception>
#include <map>
#include <set>
#include <stdexcept>

using namespace Arbiter;
using namespace Resolver;

namespace {

struct DependencyNode final
{
  public:
    const ArbiterProjectIdentifier _project;
    const ArbiterSelectedVersion _proposedVersion;

    std::unique_ptr<ArbiterRequirement> _requirement;
    std::set<DependencyNode> _dependencies;

    DependencyNode (ArbiterProjectIdentifier project, ArbiterSelectedVersion proposedVersion, const ArbiterRequirement &requirement)
      : _project(std::move(project))
      , _proposedVersion(std::move(proposedVersion))
      , _requirement(requirement.clone())
    {
      assert(_requirement->satisfiedBy(_proposedVersion._semanticVersion));
    }

    bool operator== (const DependencyNode &other) const
    {
      return _project == other._project && _proposedVersion == other._proposedVersion;
    }

    bool operator< (const DependencyNode &other) const
    {
      if (_project != other._project) {
        // There's no well-defined ordering between nodes for different
        // projects, and we don't want them to appear equal within a set.
        return true;
      }

      // Sort such that higher versions are tried first.
      return _proposedVersion > other._proposedVersion;
    }
};

std::ostream &operator<< (std::ostream &os, const DependencyNode &node)
{
  return os
    << node._project << " @ " << node._proposedVersion
    << " (restricted to " << *node._requirement << ")";
}

class DependencyGraph final
{
  public:
    std::set<DependencyNode> _allNodes;
    std::map<DependencyNode, std::set<DependencyNode>> _edges;
    std::set<DependencyNode> _roots;

    bool operator== (const DependencyGraph &other) const
    {
      return _edges == other._edges && _roots == other._roots;
    }
};

std::ostream &operator<< (std::ostream &os, const DependencyGraph &graph)
{
  os << "Roots:";
  for (const DependencyNode &root : graph._roots) {
    os << "\n\t" << root;
  }

  os << "\n\nEdges";
  for (const auto &pair : graph._edges) {
    const DependencyNode &node = pair.first;
    os << "\n\t" << node._project << " ->";

    const auto &dependencies = pair.second;
    for (const DependencyNode &dep : dependencies) {
      os << "\n\t\t" << dep;
    }
  }

  return os;
}

} // namespace

ArbiterResolver *ArbiterCreateResolver (ArbiterResolverBehaviors behaviors, const ArbiterDependencyList *dependencyList, ArbiterUserValue context)
{
  return new ArbiterResolver(std::move(behaviors), *dependencyList, ArbiterResolver::Context(std::move(context)));
}

const void *ArbiterResolverContext (const ArbiterResolver *resolver)
{
  return resolver->_context.data();
}

bool ArbiterResolvedAllDependencies (const ArbiterResolver *resolver)
{
  return resolver->resolvedAll();
}

void ArbiterStartResolvingNextDependency (ArbiterResolver *resolver, ArbiterResolverCallbacks callbacks)
{
  resolver->resolveNext().add_callback([resolver, callbacks = std::move(callbacks)](const auto &result) {
    try {
      const ResolvedDependency &dependency = result.rightOrThrowLeft();
      callbacks.onSuccess(resolver, &dependency.projectIdentifier, &dependency.selectedVersion);
    } catch (const std::exception &ex) {
      callbacks.onError(resolver, ex.what());
    }
  });
}

void ArbiterFreeResolver (ArbiterResolver *resolver)
{
  delete resolver;
}

ResolvedDependency ResolvedDependency::takeOwnership (ArbiterDependencyListFetch fetch) noexcept
{
  std::unique_ptr<ArbiterProjectIdentifier> project(const_cast<ArbiterProjectIdentifier *>(fetch.project));
  std::unique_ptr<ArbiterSelectedVersion> selectedVersion(const_cast<ArbiterSelectedVersion *>(fetch.selectedVersion));

  return ResolvedDependency { std::move(*project), std::move(*selectedVersion) };
}

bool ResolvedDependency::operator== (const ResolvedDependency &other) const noexcept
{
  return projectIdentifier == other.projectIdentifier && selectedVersion == other.selectedVersion;
}

bool ArbiterResolver::resolvedAll () const noexcept
{
  return _remainingDependencies._dependencies.empty();
}

Arbiter::Future<ResolvedDependency> resolveNext ()
{
  Arbiter::Promise<ResolvedDependency> promise;

  // TODO: Actually resolve

  return promise.get_future();
}

Arbiter::Future<ArbiterDependencyList> ArbiterResolver::insertDependencyListFetch (ResolvedDependency dependency)
{
  std::lock_guard<std::mutex> guard(_fetchesMutex);

  return _dependencyListFetches[std::move(dependency)].get_future();
}

Arbiter::Promise<ArbiterDependencyList> ArbiterResolver::extractDependencyListFetch (const ResolvedDependency &dependency)
{
  std::lock_guard<std::mutex> guard(_fetchesMutex);

  Arbiter::Promise<ArbiterDependencyList> promise = std::move(_dependencyListFetches.at(dependency));
  _dependencyListFetches.erase(dependency);

  return promise;
}

Arbiter::Future<ArbiterDependencyList> ArbiterResolver::fetchDependencyList (ResolvedDependency dependency)
{
  // Eventually freed in the C callback function.
  auto project = std::make_unique<ArbiterProjectIdentifier>(dependency.projectIdentifier);
  auto version = std::make_unique<ArbiterSelectedVersion>(dependency.selectedVersion);

  auto future = insertDependencyListFetch(std::move(dependency));

  _behaviors.fetchDependencyList(
    ArbiterDependencyListFetch { this, project.release(), version.release() },
    &dependencyListFetchOnSuccess,
    &dependencyListFetchOnError
  );

  return future;
}

void ArbiterResolver::dependencyListFetchOnSuccess (ArbiterDependencyListFetch cFetch, const ArbiterDependencyList *fetchedList)
{
  auto &resolver = *const_cast<ArbiterResolver *>(cFetch.resolver);
  auto dependency = ResolvedDependency::takeOwnership(cFetch);

  resolver
    .extractDependencyListFetch(dependency)
    .set_value(*fetchedList);
}

void ArbiterResolver::dependencyListFetchOnError (ArbiterDependencyListFetch cFetch)
{
  auto &resolver = *const_cast<ArbiterResolver *>(cFetch.resolver);
  auto dependency = ResolvedDependency::takeOwnership(cFetch);

  resolver
    .extractDependencyListFetch(dependency)
    // TODO: Better error reporting
    .set_exception(std::make_exception_ptr(std::runtime_error("Dependency list fetch failed")));
}
<commit_msg>Implement sharing of dependency nodes, and graph insertion<commit_after>#include "Resolver.h"

#include "Hash.h"
#include "Requirement.h"

#include <cassert>
#include <exception>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>

using namespace Arbiter;
using namespace Resolver;

namespace {

/**
 * A node in, or being considered for, an acyclic dependency graph.
 */
class DependencyNode final
{
  public:
    struct Hash final
    {
      public:
        size_t operator() (const DependencyNode &node) const
        {
          return hashOf(node._project);
        }
    };

    const ArbiterProjectIdentifier _project;

    /**
     * The version of the dependency that this node represents.
     *
     * This version is merely "proposed" because it depends on the final
     * resolution of the graph, as well as whether any "better" graphs exist.
     */
    const ArbiterSelectedVersion _proposedVersion;

    DependencyNode (ArbiterProjectIdentifier project, ArbiterSelectedVersion proposedVersion, const ArbiterRequirement &requirement)
      : _project(std::move(project))
      , _proposedVersion(std::move(proposedVersion))
      , _state(std::make_shared<State>())
    {
      setRequirement(requirement);
    }

    DependencyNode (const DependencyNode &other) noexcept
      : _project(other._project)
      , _proposedVersion(other._proposedVersion)
      , _state(other._state)
    {}

    DependencyNode (DependencyNode &&other) noexcept
      : _project(other._project)
      , _proposedVersion(other._proposedVersion)
      , _state(std::move(other._state))
    {}

    DependencyNode &operator= (const DependencyNode &other) = delete;
    DependencyNode &operator= (DependencyNode &&other) = delete;

    bool operator== (const DependencyNode &other) const
    {
      // For the purposes of node lookup in a graph, this is the only field
      // which matters.
      return _project == other._project;
    }

    /**
     * The current requirement(s) applied to this dependency.
     *
     * This specifier may change as the graph is added to, and the requirements
     * become more stringent.
     */
    const ArbiterRequirement &requirement () const noexcept
    {
      return *_state->_requirement;
    }

    void setRequirement (const ArbiterRequirement &requirement)
    {
      setRequirement(requirement.clone());
    }

    void setRequirement (std::unique_ptr<ArbiterRequirement> requirement)
    {
      assert(requirement);
      assert(requirement->satisfiedBy(_proposedVersion._semanticVersion));

      _state->_requirement = std::move(requirement);
    }

    std::unordered_set<DependencyNode, Hash> &dependencies () noexcept
    {
      return _state->_dependencies;
    }

    const std::unordered_set<DependencyNode, Hash> &dependencies () const noexcept
    {
      return _state->_dependencies;
    }

  private:
    struct State final
    {
      public:
        std::unique_ptr<ArbiterRequirement> _requirement;
        std::unordered_set<DependencyNode, Hash> _dependencies;
    };

    std::shared_ptr<State> _state;
};

std::ostream &operator<< (std::ostream &os, const DependencyNode &node)
{
  return os
    << node._project << " @ " << node._proposedVersion
    << " (restricted to " << node.requirement() << ")";
}

} // namespace

namespace std {

template<>
struct hash<DependencyNode> final
{
  public:
    size_t operator() (const DependencyNode &node) const
    {
      return DependencyNode::Hash()(node);
    }
};

} // namespace std

namespace {

/**
 * Represents an acyclic dependency graph in which each project appears at most
 * once.
 *
 * Dependency graphs can exist in an incomplete state, but will never be
 * inconsistent (i.e., include versions that are known to be invalid given the
 * current graph).
 */
class DependencyGraph final
{
  public:
    /**
     * A full list of all nodes included in the graph.
     */
    std::unordered_set<DependencyNode> _allNodes;

    /**
     * Maps between nodes in the graph and their immediate dependencies.
     */
    std::unordered_map<DependencyNode, std::unordered_set<DependencyNode>> _edges;

    /**
     * The root nodes of the graph (i.e., those dependencies that are listed by
     * the top-level project).
     */
    std::unordered_set<DependencyNode> _roots;

    bool operator== (const DependencyGraph &other) const
    {
      return _edges == other._edges && _roots == other._roots;
    }

    /**
     * Attempts to add the given node into the graph, as a dependency of
     * `dependent` if specified.
     *
     * If the given node refers to a project which already exists in the graph,
     * this method will attempt to intersect the version requirements of both.
     *
     * Returns a pointer to the node as actually inserted into the graph (which
     * may be different from the node passed in), or `nullptr` if this addition
     * would make the graph inconsistent.
     */
    DependencyNode *addNode (const DependencyNode &inputNode, const DependencyNode *dependent)
    {
      auto nodeInsertion = _allNodes.insert(inputNode);

      // Unordered collections rightly discourage mutation so hashes don't get
      // invalidated, but we've already handled this in the implementation of
      // DependencyNode.
      DependencyNode &insertedNode = const_cast<DependencyNode &>(*nodeInsertion.first);

      // If no insertion was actually performed, we need to unify our input with
      // what was already there.
      if (!nodeInsertion.second) {
        if (auto newRequirement = insertedNode.requirement().intersect(inputNode.requirement())) {
          if (!newRequirement->satisfiedBy(insertedNode._proposedVersion._semanticVersion)) {
            // This strengthened requirement invalidates the version we've
            // proposed in this graph, so the graph would become inconsistent.
            return nullptr;
          }

          insertedNode.setRequirement(std::move(newRequirement));
        } else {
          // If intersecting the requirements is impossible, the versions
          // currently shouldn't be able to match.
          //
          // Notably, though, Carthage does permit scenarios like this when
          // pinned to a branch. Arbiter doesn't support requirements like this
          // right now, but may in the future.
          assert(inputNode._proposedVersion != insertedNode._proposedVersion);
          return nullptr;
        }
      }

      if (dependent) {
        _edges[*dependent].insert(insertedNode);
      } else {
        _roots.insert(insertedNode);
      }

      return &insertedNode;
    }
};

std::ostream &operator<< (std::ostream &os, const DependencyGraph &graph)
{
  os << "Roots:";
  for (const DependencyNode &root : graph._roots) {
    os << "\n\t" << root;
  }

  os << "\n\nEdges";
  for (const auto &pair : graph._edges) {
    const DependencyNode &node = pair.first;
    os << "\n\t" << node._project << " ->";

    const auto &dependencies = pair.second;
    for (const DependencyNode &dep : dependencies) {
      os << "\n\t\t" << dep;
    }
  }

  return os;
}

} // namespace

ArbiterResolver *ArbiterCreateResolver (ArbiterResolverBehaviors behaviors, const ArbiterDependencyList *dependencyList, ArbiterUserValue context)
{
  return new ArbiterResolver(std::move(behaviors), *dependencyList, ArbiterResolver::Context(std::move(context)));
}

const void *ArbiterResolverContext (const ArbiterResolver *resolver)
{
  return resolver->_context.data();
}

bool ArbiterResolvedAllDependencies (const ArbiterResolver *resolver)
{
  return resolver->resolvedAll();
}

void ArbiterStartResolvingNextDependency (ArbiterResolver *resolver, ArbiterResolverCallbacks callbacks)
{
  resolver->resolveNext().add_callback([resolver, callbacks = std::move(callbacks)](const auto &result) {
    try {
      const ResolvedDependency &dependency = result.rightOrThrowLeft();
      callbacks.onSuccess(resolver, &dependency.projectIdentifier, &dependency.selectedVersion);
    } catch (const std::exception &ex) {
      callbacks.onError(resolver, ex.what());
    }
  });
}

void ArbiterFreeResolver (ArbiterResolver *resolver)
{
  delete resolver;
}

ResolvedDependency ResolvedDependency::takeOwnership (ArbiterDependencyListFetch fetch) noexcept
{
  std::unique_ptr<ArbiterProjectIdentifier> project(const_cast<ArbiterProjectIdentifier *>(fetch.project));
  std::unique_ptr<ArbiterSelectedVersion> selectedVersion(const_cast<ArbiterSelectedVersion *>(fetch.selectedVersion));

  return ResolvedDependency { std::move(*project), std::move(*selectedVersion) };
}

bool ResolvedDependency::operator== (const ResolvedDependency &other) const noexcept
{
  return projectIdentifier == other.projectIdentifier && selectedVersion == other.selectedVersion;
}

bool ArbiterResolver::resolvedAll () const noexcept
{
  return _remainingDependencies._dependencies.empty();
}

Arbiter::Future<ResolvedDependency> resolveNext ()
{
  Arbiter::Promise<ResolvedDependency> promise;

  // TODO: Actually resolve

  return promise.get_future();
}

Arbiter::Future<ArbiterDependencyList> ArbiterResolver::insertDependencyListFetch (ResolvedDependency dependency)
{
  std::lock_guard<std::mutex> guard(_fetchesMutex);

  return _dependencyListFetches[std::move(dependency)].get_future();
}

Arbiter::Promise<ArbiterDependencyList> ArbiterResolver::extractDependencyListFetch (const ResolvedDependency &dependency)
{
  std::lock_guard<std::mutex> guard(_fetchesMutex);

  Arbiter::Promise<ArbiterDependencyList> promise = std::move(_dependencyListFetches.at(dependency));
  _dependencyListFetches.erase(dependency);

  return promise;
}

Arbiter::Future<ArbiterDependencyList> ArbiterResolver::fetchDependencyList (ResolvedDependency dependency)
{
  // Eventually freed in the C callback function.
  auto project = std::make_unique<ArbiterProjectIdentifier>(dependency.projectIdentifier);
  auto version = std::make_unique<ArbiterSelectedVersion>(dependency.selectedVersion);

  auto future = insertDependencyListFetch(std::move(dependency));

  _behaviors.fetchDependencyList(
    ArbiterDependencyListFetch { this, project.release(), version.release() },
    &dependencyListFetchOnSuccess,
    &dependencyListFetchOnError
  );

  return future;
}

void ArbiterResolver::dependencyListFetchOnSuccess (ArbiterDependencyListFetch cFetch, const ArbiterDependencyList *fetchedList)
{
  auto &resolver = *const_cast<ArbiterResolver *>(cFetch.resolver);
  auto dependency = ResolvedDependency::takeOwnership(cFetch);

  resolver
    .extractDependencyListFetch(dependency)
    .set_value(*fetchedList);
}

void ArbiterResolver::dependencyListFetchOnError (ArbiterDependencyListFetch cFetch)
{
  auto &resolver = *const_cast<ArbiterResolver *>(cFetch.resolver);
  auto dependency = ResolvedDependency::takeOwnership(cFetch);

  resolver
    .extractDependencyListFetch(dependency)
    // TODO: Better error reporting
    .set_exception(std::make_exception_ptr(std::runtime_error("Dependency list fetch failed")));
}
<|endoftext|>


<commit_before>#ifndef CV_ADAPTERS_ROWRANGE_HPP
#define	CV_ADAPTERS_ROWRANGE_HPP

#include <iterator>
#include <opencv2/core/core.hpp>

template <typename T>
class RowRangeConstIterator : public std::iterator<std::forward_iterator_tag, T>
    {
    public:
        RowRangeConstIterator()
        : data()
        , row()
        , position(0)
        {}

        RowRangeConstIterator(const cv::Mat_<T>& m, int index)
        : data(m)
        , row(data.row(index))
        , position(index)
        {
            CV_DbgAssert(position >= 0 && position <= data.rows + 1);
        }

        const cv::Mat_<T>& operator*() const
        {
            return row;
        }

        bool operator==(const RowRangeConstIterator& that) const
        {
            return this->position == that.position;
        }

        bool operator!=(const RowRangeConstIterator& that) const
        {
            return !(*this == that);
        }

        bool operator<(const RowRangeConstIterator& that) const
        {
            return this->position < that.position;
        }

        bool operator>(const RowRangeConstIterator& that) const
        {
            return this->position > that.position;
        }

        bool operator<=(const RowRangeConstIterator& that) const
        {
            return !(*this > that);
        }

        bool operator>=(const RowRangeConstIterator& that) const
        {
            return !(*this < that);
        }

    protected:
        const cv::Mat_<T>& data;
        mutable cv::Mat_<T> row;
        int position;
    };

template <typename T>
class RowRangeIterator : public RowRangeConstIterator
{
public:
    RowRangeIterator(const cv::Mat_<T>& m, int position)
    : RowRangeConstIterator(m, position)
    {}

};

template <typename T>
class RowRange
{
public:
    typedef RowRangeConstIterator const_iterator;
    typedef RowRangeIterator iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    typedef std::reverse_iterator<iterator> reverse_iterator;

    RowRange(cv::Mat m)
    : data(m)
    {
        CV_Assert(m.type() == cv::DataType<T>::type);
    }

    RowRange(cv::Mat_<T> m)
    : data(m) {}

private:
    cv::Mat_<T> data;
    cv::Range range;
};

#endif	/* CV_ADAPTERS_ROWRANGE_HPP */

<commit_msg>Completing const iterator.<commit_after>#ifndef CV_ADAPTERS_ROWRANGE_HPP
#define	CV_ADAPTERS_ROWRANGE_HPP

#include <iterator>
#include <opencv2/core/core.hpp>

template <typename T>
class RowRangeConstIterator : public std::iterator<std::forward_iterator_tag, T>
    {
    public:
        RowRangeConstIterator()
        : data()
        , row()
        , position(0)
        {}

        RowRangeConstIterator(const cv::Mat_<T>& m, int index)
        : data(m)
        , row(data.row(index))
        , position(index)
        {
            CV_DbgAssert(position >= 0 && position <= data.rows + 1);
        }

        // Dereference
        const cv::Mat_<T>& operator*() const
        {
            return row;
        }

        const cv::Mat_<T>* operator->() const
        {
            return &row;
        }

        // Logical comparison
        bool operator==(const RowRangeConstIterator& that) const
        {
            return this->position == that.position;
        }

        bool operator!=(const RowRangeConstIterator& that) const
        {
            return !(*this == that);
        }

        bool operator<(const RowRangeConstIterator& that) const
        {
            return this->position < that.position;
        }

        bool operator>(const RowRangeConstIterator& that) const
        {
            return this->position > that.position;
        }

        bool operator<=(const RowRangeConstIterator& that) const
        {
            return !(*this > that);
        }

        bool operator>=(const RowRangeConstIterator& that) const
        {
            return !(*this < that);
        }

        // Increment
        RowRangeConstIterator& operator++()
        {
            ++position;
            return *this;
        }

        RowRangeConstIterator operator++(int) const
        {
            RowRangeConstIterator tmp(*this);
            ++(*this);
            return tmp;
        }

    protected:
        const cv::Mat_<T>& data;
        mutable cv::Mat_<T> row;
        int position;
    };

template <typename T>
class RowRangeIterator : public RowRangeConstIterator
{
public:
    RowRangeIterator(const cv::Mat_<T>& m, int position)
    : RowRangeConstIterator(m, position)
    {}

};

template <typename T>
class RowRange
{
public:
    typedef RowRangeConstIterator const_iterator;
    typedef RowRangeIterator iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    typedef std::reverse_iterator<iterator> reverse_iterator;

    RowRange(cv::Mat m)
    : data(m)
    {
        CV_Assert(m.type() == cv::DataType<T>::type);
    }

    RowRange(cv::Mat_<T> m)
    : data(m) {}

private:
    cv::Mat_<T> data;
    cv::Range range;
};

#endif	/* CV_ADAPTERS_ROWRANGE_HPP */

<|endoftext|>


<commit_before>#include "server/connection_handler_impl.h"

#include "envoy/event/dispatcher.h"
#include "envoy/event/timer.h"
#include "envoy/network/filter.h"
#include "envoy/stats/scope.h"
#include "envoy/stats/timespan.h"

#include "common/network/connection_impl.h"
#include "common/network/utility.h"

#include "extensions/transport_sockets/well_known_names.h"

namespace Envoy {
namespace Server {

ConnectionHandlerImpl::ConnectionHandlerImpl(spdlog::logger& logger, Event::Dispatcher& dispatcher)
    : logger_(logger), dispatcher_(dispatcher), disable_listeners_(false) {}

void ConnectionHandlerImpl::addListener(Network::ListenerConfig& config) {
  ActiveListenerPtr l(new ActiveListener(*this, config));
  if (disable_listeners_) {
    l->listener_->disable();
  }
  listeners_.emplace_back(config.socket().localAddress(), std::move(l));
}

void ConnectionHandlerImpl::removeListeners(uint64_t listener_tag) {
  for (auto listener = listeners_.begin(); listener != listeners_.end();) {
    if (listener->second->listener_tag_ == listener_tag) {
      listener = listeners_.erase(listener);
    } else {
      ++listener;
    }
  }
}

void ConnectionHandlerImpl::stopListeners(uint64_t listener_tag) {
  for (auto& listener : listeners_) {
    if (listener.second->listener_tag_ == listener_tag) {
      listener.second->listener_.reset();
    }
  }
}

void ConnectionHandlerImpl::stopListeners() {
  for (auto& listener : listeners_) {
    listener.second->listener_.reset();
  }
}

void ConnectionHandlerImpl::disableListeners() {
  disable_listeners_ = true;
  for (auto& listener : listeners_) {
    listener.second->listener_->disable();
  }
}

void ConnectionHandlerImpl::enableListeners() {
  disable_listeners_ = false;
  for (auto& listener : listeners_) {
    listener.second->listener_->enable();
  }
}

void ConnectionHandlerImpl::ActiveListener::removeConnection(ActiveConnection& connection) {
  ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "adding to cleanup list",
                           *connection.connection_);
  ActiveConnectionPtr removed = connection.removeFromList(connections_);
  parent_.dispatcher_.deferredDelete(std::move(removed));
  ASSERT(parent_.num_connections_ > 0);
  parent_.num_connections_--;
}

ConnectionHandlerImpl::ActiveListener::ActiveListener(ConnectionHandlerImpl& parent,
                                                      Network::ListenerConfig& config)
    : ActiveListener(parent,
                     parent.dispatcher_.createListener(
                         config.socket(), *this, config.handOffRestoredDestinationConnections()),
                     config) {}

ConnectionHandlerImpl::ActiveListener::ActiveListener(ConnectionHandlerImpl& parent,
                                                      Network::ListenerPtr&& listener,
                                                      Network::ListenerConfig& config)
    : parent_(parent), listener_(std::move(listener)),
      stats_(generateStats(config.listenerScope())),
      listener_filters_timeout_(config.listenerFiltersTimeout()),
      listener_tag_(config.listenerTag()), config_(config) {}

ConnectionHandlerImpl::ActiveListener::~ActiveListener() {
  // Purge sockets that have not progressed to connections. This should only happen when
  // a listener filter stops iteration and never resumes.
  while (!sockets_.empty()) {
    ActiveSocketPtr removed = sockets_.front()->removeFromList(sockets_);
    parent_.dispatcher_.deferredDelete(std::move(removed));
  }

  while (!connections_.empty()) {
    connections_.front()->connection_->close(Network::ConnectionCloseType::NoFlush);
  }

  parent_.dispatcher_.clearDeferredDeleteList();
}

Network::Listener*
ConnectionHandlerImpl::findListenerByAddress(const Network::Address::Instance& address) {
  ActiveListener* listener = findActiveListenerByAddress(address);
  return listener ? listener->listener_.get() : nullptr;
}

ConnectionHandlerImpl::ActiveListener*
ConnectionHandlerImpl::findActiveListenerByAddress(const Network::Address::Instance& address) {
  // This is a linear operation, may need to add a map<address, listener> to improve performance.
  // However, linear performance might be adequate since the number of listeners is small.
  // We do not return stopped listeners.
  auto listener_it = std::find_if(
      listeners_.begin(), listeners_.end(),
      [&address](const std::pair<Network::Address::InstanceConstSharedPtr, ActiveListenerPtr>& p) {
        return p.second->listener_ != nullptr && p.first->type() == Network::Address::Type::Ip &&
               *(p.first) == address;
      });

  // If there is exact address match, return the corresponding listener.
  if (listener_it != listeners_.end()) {
    return listener_it->second.get();
  }

  // Otherwise, we need to look for the wild card match, i.e., 0.0.0.0:[address_port].
  // We do not return stopped listeners.
  // TODO(wattli): consolidate with previous search for more efficiency.
  listener_it = std::find_if(
      listeners_.begin(), listeners_.end(),
      [&address](const std::pair<Network::Address::InstanceConstSharedPtr, ActiveListenerPtr>& p) {
        return p.second->listener_ != nullptr && p.first->type() == Network::Address::Type::Ip &&
               p.first->ip()->port() == address.ip()->port() && p.first->ip()->isAnyAddress();
      });
  return (listener_it != listeners_.end()) ? listener_it->second.get() : nullptr;
}

void ConnectionHandlerImpl::ActiveSocket::onTimeout() {
  listener_.stats_.downstream_pre_cx_timeout_.inc();
  ASSERT(inserted());
  unlink();
}

void ConnectionHandlerImpl::ActiveSocket::startTimer() {
  if (listener_.listener_filters_timeout_.count() > 0) {
    timer_ = listener_.parent_.dispatcher_.createTimer([this]() -> void { onTimeout(); });
    timer_->enableTimer(listener_.listener_filters_timeout_);
  }
}

void ConnectionHandlerImpl::ActiveSocket::unlink() {
  ActiveSocketPtr removed = removeFromList(listener_.sockets_);
  if (removed->timer_ != nullptr) {
    removed->timer_->disableTimer();
  }
  listener_.parent_.dispatcher_.deferredDelete(std::move(removed));
}

void ConnectionHandlerImpl::ActiveSocket::continueFilterChain(bool success) {
  if (success) {
    if (iter_ == accept_filters_.end()) {
      iter_ = accept_filters_.begin();
    } else {
      iter_ = std::next(iter_);
    }

    for (; iter_ != accept_filters_.end(); iter_++) {
      Network::FilterStatus status = (*iter_)->onAccept(*this);
      if (status == Network::FilterStatus::StopIteration) {
        // The filter is responsible for calling us again at a later time to continue the filter
        // chain from the next filter.
        return;
      }
    }
    // Successfully ran all the accept filters.

    // Check if the socket may need to be redirected to another listener.
    ActiveListener* new_listener = nullptr;

    if (hand_off_restored_destination_connections_ && socket_->localAddressRestored()) {
      // Find a listener associated with the original destination address.
      new_listener = listener_.parent_.findActiveListenerByAddress(*socket_->localAddress());
    }
    if (new_listener != nullptr) {
      // Hands off connections redirected by iptables to the listener associated with the
      // original destination address. Pass 'hand_off_restored_destionations' as false to
      // prevent further redirection.
      new_listener->onAccept(std::move(socket_), false);
    } else {
      // Set default transport protocol if none of the listener filters did it.
      if (socket_->detectedTransportProtocol().empty()) {
        socket_->setDetectedTransportProtocol(
            Extensions::TransportSockets::TransportSocketNames::get().RawBuffer);
      }
      // Create a new connection on this listener.
      listener_.newConnection(std::move(socket_));
    }
  }

  // Filter execution concluded, unlink and delete this ActiveSocket if it was linked.
  if (inserted()) {
    unlink();
  }
}

void ConnectionHandlerImpl::ActiveListener::onAccept(
    Network::ConnectionSocketPtr&& socket, bool hand_off_restored_destination_connections) {
  Network::Address::InstanceConstSharedPtr local_address = socket->localAddress();
  auto active_socket = std::make_unique<ActiveSocket>(*this, std::move(socket),
                                                      hand_off_restored_destination_connections);

  // Create and run the filters
  config_.filterChainFactory().createListenerFilterChain(*active_socket);
  active_socket->continueFilterChain(true);

  // Move active_socket to the sockets_ list if filter iteration needs to continue later.
  // Otherwise we let active_socket be destructed when it goes out of scope.
  if (active_socket->iter_ != active_socket->accept_filters_.end()) {
    active_socket->startTimer();
    active_socket->moveIntoListBack(std::move(active_socket), sockets_);
  }
}

void ConnectionHandlerImpl::ActiveListener::newConnection(Network::ConnectionSocketPtr&& socket) {
  // Find matching filter chain.
  const auto filter_chain = config_.filterChainManager().findFilterChain(*socket);
  if (filter_chain == nullptr) {
    ENVOY_LOG_TO_LOGGER(parent_.logger_, debug,
                        "closing connection: no matching filter chain found");
    stats_.no_filter_chain_match_.inc();
    socket->close();
    return;
  }

  auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr);
  Network::ConnectionPtr new_connection =
      parent_.dispatcher_.createServerConnection(std::move(socket), std::move(transport_socket));
  new_connection->setBufferLimits(config_.perConnectionBufferLimitBytes());
  new_connection->setWriteFilterOrder(config_.reverseWriteFilterOrder());

  const bool empty_filter_chain = !config_.filterChainFactory().createNetworkFilterChain(
      *new_connection, filter_chain->networkFilterFactories());
  if (empty_filter_chain) {
    ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "closing connection: no filters",
                             *new_connection);
    new_connection->close(Network::ConnectionCloseType::NoFlush);
    return;
  }

  onNewConnection(std::move(new_connection));
}

void ConnectionHandlerImpl::ActiveListener::onNewConnection(
    Network::ConnectionPtr&& new_connection) {
  ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "new connection", *new_connection);

  // If the connection is already closed, we can just let this connection immediately die.
  if (new_connection->state() != Network::Connection::State::Closed) {
    ActiveConnectionPtr active_connection(
        new ActiveConnection(*this, std::move(new_connection), parent_.dispatcher_.timeSystem()));
    active_connection->moveIntoList(std::move(active_connection), connections_);
    parent_.num_connections_++;
  }
}

ConnectionHandlerImpl::ActiveConnection::ActiveConnection(ActiveListener& listener,
                                                          Network::ConnectionPtr&& new_connection,
                                                          Event::TimeSystem& time_system)
    : listener_(listener), connection_(std::move(new_connection)),
      conn_length_(new Stats::Timespan(listener_.stats_.downstream_cx_length_ms_, time_system)) {
  // We just universally set no delay on connections. Theoretically we might at some point want
  // to make this configurable.
  connection_->noDelay(true);
  connection_->addConnectionCallbacks(*this);
  listener_.stats_.downstream_cx_total_.inc();
  listener_.stats_.downstream_cx_active_.inc();
}

ConnectionHandlerImpl::ActiveConnection::~ActiveConnection() {
  listener_.stats_.downstream_cx_active_.dec();
  listener_.stats_.downstream_cx_destroy_.inc();
  conn_length_->complete();
}

ListenerStats ConnectionHandlerImpl::generateStats(Stats::Scope& scope) {
  return {ALL_LISTENER_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope), POOL_HISTOGRAM(scope))};
}

} // namespace Server
} // namespace Envoy
<commit_msg>Useless line in onAccept and should be removed. (#5299)<commit_after>#include "server/connection_handler_impl.h"

#include "envoy/event/dispatcher.h"
#include "envoy/event/timer.h"
#include "envoy/network/filter.h"
#include "envoy/stats/scope.h"
#include "envoy/stats/timespan.h"

#include "common/network/connection_impl.h"
#include "common/network/utility.h"

#include "extensions/transport_sockets/well_known_names.h"

namespace Envoy {
namespace Server {

ConnectionHandlerImpl::ConnectionHandlerImpl(spdlog::logger& logger, Event::Dispatcher& dispatcher)
    : logger_(logger), dispatcher_(dispatcher), disable_listeners_(false) {}

void ConnectionHandlerImpl::addListener(Network::ListenerConfig& config) {
  ActiveListenerPtr l(new ActiveListener(*this, config));
  if (disable_listeners_) {
    l->listener_->disable();
  }
  listeners_.emplace_back(config.socket().localAddress(), std::move(l));
}

void ConnectionHandlerImpl::removeListeners(uint64_t listener_tag) {
  for (auto listener = listeners_.begin(); listener != listeners_.end();) {
    if (listener->second->listener_tag_ == listener_tag) {
      listener = listeners_.erase(listener);
    } else {
      ++listener;
    }
  }
}

void ConnectionHandlerImpl::stopListeners(uint64_t listener_tag) {
  for (auto& listener : listeners_) {
    if (listener.second->listener_tag_ == listener_tag) {
      listener.second->listener_.reset();
    }
  }
}

void ConnectionHandlerImpl::stopListeners() {
  for (auto& listener : listeners_) {
    listener.second->listener_.reset();
  }
}

void ConnectionHandlerImpl::disableListeners() {
  disable_listeners_ = true;
  for (auto& listener : listeners_) {
    listener.second->listener_->disable();
  }
}

void ConnectionHandlerImpl::enableListeners() {
  disable_listeners_ = false;
  for (auto& listener : listeners_) {
    listener.second->listener_->enable();
  }
}

void ConnectionHandlerImpl::ActiveListener::removeConnection(ActiveConnection& connection) {
  ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "adding to cleanup list",
                           *connection.connection_);
  ActiveConnectionPtr removed = connection.removeFromList(connections_);
  parent_.dispatcher_.deferredDelete(std::move(removed));
  ASSERT(parent_.num_connections_ > 0);
  parent_.num_connections_--;
}

ConnectionHandlerImpl::ActiveListener::ActiveListener(ConnectionHandlerImpl& parent,
                                                      Network::ListenerConfig& config)
    : ActiveListener(parent,
                     parent.dispatcher_.createListener(
                         config.socket(), *this, config.handOffRestoredDestinationConnections()),
                     config) {}

ConnectionHandlerImpl::ActiveListener::ActiveListener(ConnectionHandlerImpl& parent,
                                                      Network::ListenerPtr&& listener,
                                                      Network::ListenerConfig& config)
    : parent_(parent), listener_(std::move(listener)),
      stats_(generateStats(config.listenerScope())),
      listener_filters_timeout_(config.listenerFiltersTimeout()),
      listener_tag_(config.listenerTag()), config_(config) {}

ConnectionHandlerImpl::ActiveListener::~ActiveListener() {
  // Purge sockets that have not progressed to connections. This should only happen when
  // a listener filter stops iteration and never resumes.
  while (!sockets_.empty()) {
    ActiveSocketPtr removed = sockets_.front()->removeFromList(sockets_);
    parent_.dispatcher_.deferredDelete(std::move(removed));
  }

  while (!connections_.empty()) {
    connections_.front()->connection_->close(Network::ConnectionCloseType::NoFlush);
  }

  parent_.dispatcher_.clearDeferredDeleteList();
}

Network::Listener*
ConnectionHandlerImpl::findListenerByAddress(const Network::Address::Instance& address) {
  ActiveListener* listener = findActiveListenerByAddress(address);
  return listener ? listener->listener_.get() : nullptr;
}

ConnectionHandlerImpl::ActiveListener*
ConnectionHandlerImpl::findActiveListenerByAddress(const Network::Address::Instance& address) {
  // This is a linear operation, may need to add a map<address, listener> to improve performance.
  // However, linear performance might be adequate since the number of listeners is small.
  // We do not return stopped listeners.
  auto listener_it = std::find_if(
      listeners_.begin(), listeners_.end(),
      [&address](const std::pair<Network::Address::InstanceConstSharedPtr, ActiveListenerPtr>& p) {
        return p.second->listener_ != nullptr && p.first->type() == Network::Address::Type::Ip &&
               *(p.first) == address;
      });

  // If there is exact address match, return the corresponding listener.
  if (listener_it != listeners_.end()) {
    return listener_it->second.get();
  }

  // Otherwise, we need to look for the wild card match, i.e., 0.0.0.0:[address_port].
  // We do not return stopped listeners.
  // TODO(wattli): consolidate with previous search for more efficiency.
  listener_it = std::find_if(
      listeners_.begin(), listeners_.end(),
      [&address](const std::pair<Network::Address::InstanceConstSharedPtr, ActiveListenerPtr>& p) {
        return p.second->listener_ != nullptr && p.first->type() == Network::Address::Type::Ip &&
               p.first->ip()->port() == address.ip()->port() && p.first->ip()->isAnyAddress();
      });
  return (listener_it != listeners_.end()) ? listener_it->second.get() : nullptr;
}

void ConnectionHandlerImpl::ActiveSocket::onTimeout() {
  listener_.stats_.downstream_pre_cx_timeout_.inc();
  ASSERT(inserted());
  unlink();
}

void ConnectionHandlerImpl::ActiveSocket::startTimer() {
  if (listener_.listener_filters_timeout_.count() > 0) {
    timer_ = listener_.parent_.dispatcher_.createTimer([this]() -> void { onTimeout(); });
    timer_->enableTimer(listener_.listener_filters_timeout_);
  }
}

void ConnectionHandlerImpl::ActiveSocket::unlink() {
  ActiveSocketPtr removed = removeFromList(listener_.sockets_);
  if (removed->timer_ != nullptr) {
    removed->timer_->disableTimer();
  }
  listener_.parent_.dispatcher_.deferredDelete(std::move(removed));
}

void ConnectionHandlerImpl::ActiveSocket::continueFilterChain(bool success) {
  if (success) {
    if (iter_ == accept_filters_.end()) {
      iter_ = accept_filters_.begin();
    } else {
      iter_ = std::next(iter_);
    }

    for (; iter_ != accept_filters_.end(); iter_++) {
      Network::FilterStatus status = (*iter_)->onAccept(*this);
      if (status == Network::FilterStatus::StopIteration) {
        // The filter is responsible for calling us again at a later time to continue the filter
        // chain from the next filter.
        return;
      }
    }
    // Successfully ran all the accept filters.

    // Check if the socket may need to be redirected to another listener.
    ActiveListener* new_listener = nullptr;

    if (hand_off_restored_destination_connections_ && socket_->localAddressRestored()) {
      // Find a listener associated with the original destination address.
      new_listener = listener_.parent_.findActiveListenerByAddress(*socket_->localAddress());
    }
    if (new_listener != nullptr) {
      // Hands off connections redirected by iptables to the listener associated with the
      // original destination address. Pass 'hand_off_restored_destionations' as false to
      // prevent further redirection.
      new_listener->onAccept(std::move(socket_), false);
    } else {
      // Set default transport protocol if none of the listener filters did it.
      if (socket_->detectedTransportProtocol().empty()) {
        socket_->setDetectedTransportProtocol(
            Extensions::TransportSockets::TransportSocketNames::get().RawBuffer);
      }
      // Create a new connection on this listener.
      listener_.newConnection(std::move(socket_));
    }
  }

  // Filter execution concluded, unlink and delete this ActiveSocket if it was linked.
  if (inserted()) {
    unlink();
  }
}

void ConnectionHandlerImpl::ActiveListener::onAccept(
    Network::ConnectionSocketPtr&& socket, bool hand_off_restored_destination_connections) {
  auto active_socket = std::make_unique<ActiveSocket>(*this, std::move(socket),
                                                      hand_off_restored_destination_connections);

  // Create and run the filters
  config_.filterChainFactory().createListenerFilterChain(*active_socket);
  active_socket->continueFilterChain(true);

  // Move active_socket to the sockets_ list if filter iteration needs to continue later.
  // Otherwise we let active_socket be destructed when it goes out of scope.
  if (active_socket->iter_ != active_socket->accept_filters_.end()) {
    active_socket->startTimer();
    active_socket->moveIntoListBack(std::move(active_socket), sockets_);
  }
}

void ConnectionHandlerImpl::ActiveListener::newConnection(Network::ConnectionSocketPtr&& socket) {
  // Find matching filter chain.
  const auto filter_chain = config_.filterChainManager().findFilterChain(*socket);
  if (filter_chain == nullptr) {
    ENVOY_LOG_TO_LOGGER(parent_.logger_, debug,
                        "closing connection: no matching filter chain found");
    stats_.no_filter_chain_match_.inc();
    socket->close();
    return;
  }

  auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr);
  Network::ConnectionPtr new_connection =
      parent_.dispatcher_.createServerConnection(std::move(socket), std::move(transport_socket));
  new_connection->setBufferLimits(config_.perConnectionBufferLimitBytes());
  new_connection->setWriteFilterOrder(config_.reverseWriteFilterOrder());

  const bool empty_filter_chain = !config_.filterChainFactory().createNetworkFilterChain(
      *new_connection, filter_chain->networkFilterFactories());
  if (empty_filter_chain) {
    ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "closing connection: no filters",
                             *new_connection);
    new_connection->close(Network::ConnectionCloseType::NoFlush);
    return;
  }

  onNewConnection(std::move(new_connection));
}

void ConnectionHandlerImpl::ActiveListener::onNewConnection(
    Network::ConnectionPtr&& new_connection) {
  ENVOY_CONN_LOG_TO_LOGGER(parent_.logger_, debug, "new connection", *new_connection);

  // If the connection is already closed, we can just let this connection immediately die.
  if (new_connection->state() != Network::Connection::State::Closed) {
    ActiveConnectionPtr active_connection(
        new ActiveConnection(*this, std::move(new_connection), parent_.dispatcher_.timeSystem()));
    active_connection->moveIntoList(std::move(active_connection), connections_);
    parent_.num_connections_++;
  }
}

ConnectionHandlerImpl::ActiveConnection::ActiveConnection(ActiveListener& listener,
                                                          Network::ConnectionPtr&& new_connection,
                                                          Event::TimeSystem& time_system)
    : listener_(listener), connection_(std::move(new_connection)),
      conn_length_(new Stats::Timespan(listener_.stats_.downstream_cx_length_ms_, time_system)) {
  // We just universally set no delay on connections. Theoretically we might at some point want
  // to make this configurable.
  connection_->noDelay(true);
  connection_->addConnectionCallbacks(*this);
  listener_.stats_.downstream_cx_total_.inc();
  listener_.stats_.downstream_cx_active_.inc();
}

ConnectionHandlerImpl::ActiveConnection::~ActiveConnection() {
  listener_.stats_.downstream_cx_active_.dec();
  listener_.stats_.downstream_cx_destroy_.inc();
  conn_length_->complete();
}

ListenerStats ConnectionHandlerImpl::generateStats(Stats::Scope& scope) {
  return {ALL_LISTENER_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope), POOL_HISTOGRAM(scope))};
}

} // namespace Server
} // namespace Envoy
<|endoftext|>


<commit_before>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Config.h"
#include "Driver.h"
#include "Error.h"
#include "SymbolTable.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/LTO/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace lld {
namespace coff {

SymbolTable::SymbolTable() {
  resolve(new (Alloc) DefinedAbsolute("__ImageBase", Config->ImageBase));
  if (!Config->EntryName.empty())
    resolve(new (Alloc) Undefined(Config->EntryName));
}

void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
  Files.push_back(std::move(File));
}

std::error_code SymbolTable::run() {
  while (FileIdx < Files.size()) {
    InputFile *F = Files[FileIdx++].get();
    if (Config->Verbose)
      llvm::outs() << "Reading " << F->getShortName() << "\n";
    if (auto EC = F->parse())
      return EC;
    if (auto *P = dyn_cast<ObjectFile>(F)) {
      ObjectFiles.push_back(P);
    } else if (auto *P = dyn_cast<ArchiveFile>(F)) {
      ArchiveFiles.push_back(P);
    } else if (auto *P = dyn_cast<BitcodeFile>(F)) {
      BitcodeFiles.push_back(P);
    } else {
      ImportFiles.push_back(cast<ImportFile>(F));
    }

    for (SymbolBody *B : F->getSymbols())
      if (B->isExternal())
        if (auto EC = resolve(B))
          return EC;

    // If a object file contains .drectve section,
    // read that and add files listed there.
    StringRef S = F->getDirectives();
    if (!S.empty())
      if (auto EC = Driver->parseDirectives(S))
        return EC;
  }
  return std::error_code();
}

bool SymbolTable::reportRemainingUndefines() {
  bool Ret = false;
  for (auto &I : Symtab) {
    Symbol *Sym = I.second;
    auto *Undef = dyn_cast<Undefined>(Sym->Body);
    if (!Undef)
      continue;
    if (SymbolBody *Alias = Undef->getWeakAlias()) {
      Sym->Body = Alias->getReplacement();
      if (!isa<Defined>(Sym->Body)) {
        // Aliases are yet another symbols pointed by other symbols
        // that could also remain undefined.
        llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
        Ret = true;
      }
      continue;
    }
    llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
    Ret = true;
  }
  return Ret;
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
std::error_code SymbolTable::resolve(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    ++Version;
    return std::error_code();
  }
  New->setBackref(Sym);

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  SymbolBody *Existing = Sym->Body;
  int comp = Existing->compare(New);
  if (comp < 0) {
    Sym->Body = New;
    ++Version;
  }
  if (comp == 0) {
    llvm::errs() << "duplicate symbol: " << Name << "\n";
    return make_error_code(LLDError::DuplicateSymbols);
  }

  // If we have an Undefined symbol for a Lazy symbol, we need
  // to read an archive member to replace the Lazy symbol with
  // a Defined symbol.
  if (isa<Undefined>(Existing) || isa<Undefined>(New))
    if (auto *B = dyn_cast<Lazy>(Sym->Body))
      return addMemberFile(B);
  return std::error_code();
}

// Reads an archive member file pointed by a given symbol.
std::error_code SymbolTable::addMemberFile(Lazy *Body) {
  auto FileOrErr = Body->getMember();
  if (auto EC = FileOrErr.getError())
    return EC;
  std::unique_ptr<InputFile> File = std::move(FileOrErr.get());

  // getMember returns an empty buffer if the member was already
  // read from the library.
  if (!File)
    return std::error_code();
  if (Config->Verbose)
    llvm::outs() << "Loaded " << File->getShortName() << " for "
                 << Body->getName() << "\n";
  addFile(std::move(File));
  return std::error_code();
}

std::vector<Chunk *> SymbolTable::getChunks() {
  std::vector<Chunk *> Res;
  for (ObjectFile *File : ObjectFiles) {
    std::vector<Chunk *> &V = File->getChunks();
    Res.insert(Res.end(), V.begin(), V.end());
  }
  return Res;
}

Defined *SymbolTable::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  if (auto *Def = dyn_cast<Defined>(It->second->Body))
    return Def;
  return nullptr;
}

std::error_code SymbolTable::resolveLazy(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return std::error_code();
  if (auto *B = dyn_cast<Lazy>(It->second->Body)) {
    if (auto EC = addMemberFile(B))
      return EC;
    return run();
  }
  return std::error_code();
}

// Windows specific -- Link default entry point name.
ErrorOr<StringRef> SymbolTable::findDefaultEntry() {
  // If it's DLL, the rule is easy.
  if (Config->DLL) {
    StringRef Sym = "_DllMainCRTStartup";
    if (auto EC = resolve(new (Alloc) Undefined(Sym)))
      return EC;
    return Sym;
  }

  // User-defined main functions and their corresponding entry points.
  static const char *Entries[][2] = {
      {"main", "mainCRTStartup"},
      {"wmain", "wmainCRTStartup"},
      {"WinMain", "WinMainCRTStartup"},
      {"wWinMain", "wWinMainCRTStartup"},
  };
  for (auto E : Entries) {
    resolveLazy(E[1]);
    if (find(E[1]))
      return StringRef(E[1]);
    if (!find(E[0]))
      continue;
    if (auto EC = resolve(new (Alloc) Undefined(E[1])))
      return EC;
    return StringRef(E[1]);
  }
  llvm::errs() << "entry point must be defined\n";
  return make_error_code(LLDError::InvalidOption);
}

std::error_code SymbolTable::addUndefined(StringRef Name) {
  return resolve(new (Alloc) Undefined(Name));
}

// Resolve To, and make From an alias to To.
std::error_code SymbolTable::rename(StringRef From, StringRef To) {
  // If From is not undefined, do nothing.
  // Otherwise, rename it to see if To can be resolved instead.
  auto It = Symtab.find(From);
  if (It == Symtab.end())
    return std::error_code();
  Symbol *Sym = It->second;
  if (!isa<Undefined>(Sym->Body))
    return std::error_code();
  SymbolBody *Body = new (Alloc) Undefined(To);
  if (auto EC = resolve(Body))
    return EC;
  Sym->Body = Body->getReplacement();
  Body->setBackref(Sym);
  ++Version;
  return std::error_code();
}

void SymbolTable::dump() {
  for (auto &P : Symtab) {
    Symbol *Ref = P.second;
    if (auto *Body = dyn_cast<Defined>(Ref->Body))
      llvm::dbgs() << Twine::utohexstr(Config->ImageBase + Body->getRVA())
                   << " " << Body->getName() << "\n";
  }
}

std::error_code SymbolTable::addCombinedLTOObject() {
  if (BitcodeFiles.empty())
    return std::error_code();

  // Create an object file and add it to the symbol table by replacing any
  // DefinedBitcode symbols with the definitions in the object file.
  LTOCodeGenerator CG;
  auto FileOrErr = createLTOObject(&CG);
  if (auto EC = FileOrErr.getError())
    return EC;
  ObjectFile *Obj = FileOrErr.get();

  // Skip the combined object file as the file is processed below
  // rather than by run().
  ++FileIdx;

  for (SymbolBody *Body : Obj->getSymbols()) {
    if (!Body->isExternal())
      continue;
    // Find an existing Symbol. We should not see any new undefined symbols at
    // this point.
    StringRef Name = Body->getName();
    Symbol *&Sym = Symtab[Name];
    if (!Sym) {
      if (!isa<Defined>(Body)) {
        llvm::errs() << "LTO: undefined symbol: " << Name << '\n';
        return make_error_code(LLDError::BrokenFile);
      }
      Sym = new (Alloc) Symbol(Body);
      Body->setBackref(Sym);
      continue;
    }
    Body->setBackref(Sym);

    if (isa<DefinedBitcode>(Sym->Body)) {
      // The symbol should now be defined.
      if (!isa<Defined>(Body)) {
        llvm::errs() << "LTO: undefined symbol: " << Name << '\n';
        return make_error_code(LLDError::BrokenFile);
      }
      Sym->Body = Body;
    } else {
      int comp = Sym->Body->compare(Body);
      if (comp < 0)
        Sym->Body = Body;
      if (comp == 0) {
        llvm::errs() << "LTO: unexpected duplicate symbol: " << Name << "\n";
        return make_error_code(LLDError::BrokenFile);
      }
    }

    // We may see new references to runtime library symbols such as __chkstk
    // here. These symbols must be wholly defined in non-bitcode files.
    if (auto *B = dyn_cast<Lazy>(Sym->Body))
      addMemberFile(B);
  }

  size_t NumBitcodeFiles = BitcodeFiles.size();
  if (auto EC = run())
    return EC;
  if (BitcodeFiles.size() != NumBitcodeFiles) {
    llvm::errs() << "LTO: late loaded symbol created new bitcode reference\n";
    return make_error_code(LLDError::BrokenFile);
  }

  // New runtime library symbol references may have created undefined references.
  if (reportRemainingUndefines())
    return make_error_code(LLDError::BrokenFile);
  return std::error_code();
}

// Combine and compile bitcode files and then return the result
// as a regular COFF object file.
ErrorOr<ObjectFile *> SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
  // All symbols referenced by non-bitcode objects must be preserved.
  for (ObjectFile *File : ObjectFiles)
    for (SymbolBody *Body : File->getSymbols())
      if (auto *S = dyn_cast<DefinedBitcode>(Body->getReplacement()))
        CG->addMustPreserveSymbol(S->getName());

  // Likewise for bitcode symbols which we initially resolved to non-bitcode.
  for (BitcodeFile *File : BitcodeFiles)
    for (SymbolBody *Body : File->getSymbols())
      if (isa<DefinedBitcode>(Body) &&
          !isa<DefinedBitcode>(Body->getReplacement()))
        CG->addMustPreserveSymbol(Body->getName());

  // Likewise for other symbols that must be preserved.
  for (StringRef Name : Config->GCRoots)
    if (isa<DefinedBitcode>(Symtab[Name]->Body))
      CG->addMustPreserveSymbol(Name);

  CG->setModule(BitcodeFiles[0]->releaseModule());
  for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
    CG->addModule(BitcodeFiles[I]->getModule());

  std::string ErrMsg;
  LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership
  if (!LTOMB) {
    llvm::errs() << ErrMsg << '\n';
    return make_error_code(LLDError::BrokenFile);
  }
  auto *Obj = new ObjectFile(LTOMB->getMemBufferRef());
  Files.emplace_back(Obj);
  ObjectFiles.push_back(Obj);
  if (auto EC = Obj->parse())
    return EC;
  return Obj;
}

} // namespace coff
} // namespace lld
<commit_msg>COFF: Add some error checking to SymbolTable::addCombinedLTOObject().<commit_after>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Config.h"
#include "Driver.h"
#include "Error.h"
#include "SymbolTable.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/LTO/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace lld {
namespace coff {

SymbolTable::SymbolTable() {
  resolve(new (Alloc) DefinedAbsolute("__ImageBase", Config->ImageBase));
  if (!Config->EntryName.empty())
    resolve(new (Alloc) Undefined(Config->EntryName));
}

void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
  Files.push_back(std::move(File));
}

std::error_code SymbolTable::run() {
  while (FileIdx < Files.size()) {
    InputFile *F = Files[FileIdx++].get();
    if (Config->Verbose)
      llvm::outs() << "Reading " << F->getShortName() << "\n";
    if (auto EC = F->parse())
      return EC;
    if (auto *P = dyn_cast<ObjectFile>(F)) {
      ObjectFiles.push_back(P);
    } else if (auto *P = dyn_cast<ArchiveFile>(F)) {
      ArchiveFiles.push_back(P);
    } else if (auto *P = dyn_cast<BitcodeFile>(F)) {
      BitcodeFiles.push_back(P);
    } else {
      ImportFiles.push_back(cast<ImportFile>(F));
    }

    for (SymbolBody *B : F->getSymbols())
      if (B->isExternal())
        if (auto EC = resolve(B))
          return EC;

    // If a object file contains .drectve section,
    // read that and add files listed there.
    StringRef S = F->getDirectives();
    if (!S.empty())
      if (auto EC = Driver->parseDirectives(S))
        return EC;
  }
  return std::error_code();
}

bool SymbolTable::reportRemainingUndefines() {
  bool Ret = false;
  for (auto &I : Symtab) {
    Symbol *Sym = I.second;
    auto *Undef = dyn_cast<Undefined>(Sym->Body);
    if (!Undef)
      continue;
    if (SymbolBody *Alias = Undef->getWeakAlias()) {
      Sym->Body = Alias->getReplacement();
      if (!isa<Defined>(Sym->Body)) {
        // Aliases are yet another symbols pointed by other symbols
        // that could also remain undefined.
        llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
        Ret = true;
      }
      continue;
    }
    llvm::errs() << "undefined symbol: " << Undef->getName() << "\n";
    Ret = true;
  }
  return Ret;
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
std::error_code SymbolTable::resolve(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym) {
    Sym = new (Alloc) Symbol(New);
    New->setBackref(Sym);
    ++Version;
    return std::error_code();
  }
  New->setBackref(Sym);

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  SymbolBody *Existing = Sym->Body;
  int comp = Existing->compare(New);
  if (comp < 0) {
    Sym->Body = New;
    ++Version;
  }
  if (comp == 0) {
    llvm::errs() << "duplicate symbol: " << Name << "\n";
    return make_error_code(LLDError::DuplicateSymbols);
  }

  // If we have an Undefined symbol for a Lazy symbol, we need
  // to read an archive member to replace the Lazy symbol with
  // a Defined symbol.
  if (isa<Undefined>(Existing) || isa<Undefined>(New))
    if (auto *B = dyn_cast<Lazy>(Sym->Body))
      return addMemberFile(B);
  return std::error_code();
}

// Reads an archive member file pointed by a given symbol.
std::error_code SymbolTable::addMemberFile(Lazy *Body) {
  auto FileOrErr = Body->getMember();
  if (auto EC = FileOrErr.getError())
    return EC;
  std::unique_ptr<InputFile> File = std::move(FileOrErr.get());

  // getMember returns an empty buffer if the member was already
  // read from the library.
  if (!File)
    return std::error_code();
  if (Config->Verbose)
    llvm::outs() << "Loaded " << File->getShortName() << " for "
                 << Body->getName() << "\n";
  addFile(std::move(File));
  return std::error_code();
}

std::vector<Chunk *> SymbolTable::getChunks() {
  std::vector<Chunk *> Res;
  for (ObjectFile *File : ObjectFiles) {
    std::vector<Chunk *> &V = File->getChunks();
    Res.insert(Res.end(), V.begin(), V.end());
  }
  return Res;
}

Defined *SymbolTable::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  if (auto *Def = dyn_cast<Defined>(It->second->Body))
    return Def;
  return nullptr;
}

std::error_code SymbolTable::resolveLazy(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return std::error_code();
  if (auto *B = dyn_cast<Lazy>(It->second->Body)) {
    if (auto EC = addMemberFile(B))
      return EC;
    return run();
  }
  return std::error_code();
}

// Windows specific -- Link default entry point name.
ErrorOr<StringRef> SymbolTable::findDefaultEntry() {
  // If it's DLL, the rule is easy.
  if (Config->DLL) {
    StringRef Sym = "_DllMainCRTStartup";
    if (auto EC = resolve(new (Alloc) Undefined(Sym)))
      return EC;
    return Sym;
  }

  // User-defined main functions and their corresponding entry points.
  static const char *Entries[][2] = {
      {"main", "mainCRTStartup"},
      {"wmain", "wmainCRTStartup"},
      {"WinMain", "WinMainCRTStartup"},
      {"wWinMain", "wWinMainCRTStartup"},
  };
  for (auto E : Entries) {
    resolveLazy(E[1]);
    if (find(E[1]))
      return StringRef(E[1]);
    if (!find(E[0]))
      continue;
    if (auto EC = resolve(new (Alloc) Undefined(E[1])))
      return EC;
    return StringRef(E[1]);
  }
  llvm::errs() << "entry point must be defined\n";
  return make_error_code(LLDError::InvalidOption);
}

std::error_code SymbolTable::addUndefined(StringRef Name) {
  return resolve(new (Alloc) Undefined(Name));
}

// Resolve To, and make From an alias to To.
std::error_code SymbolTable::rename(StringRef From, StringRef To) {
  // If From is not undefined, do nothing.
  // Otherwise, rename it to see if To can be resolved instead.
  auto It = Symtab.find(From);
  if (It == Symtab.end())
    return std::error_code();
  Symbol *Sym = It->second;
  if (!isa<Undefined>(Sym->Body))
    return std::error_code();
  SymbolBody *Body = new (Alloc) Undefined(To);
  if (auto EC = resolve(Body))
    return EC;
  Sym->Body = Body->getReplacement();
  Body->setBackref(Sym);
  ++Version;
  return std::error_code();
}

void SymbolTable::dump() {
  for (auto &P : Symtab) {
    Symbol *Ref = P.second;
    if (auto *Body = dyn_cast<Defined>(Ref->Body))
      llvm::dbgs() << Twine::utohexstr(Config->ImageBase + Body->getRVA())
                   << " " << Body->getName() << "\n";
  }
}

std::error_code SymbolTable::addCombinedLTOObject() {
  if (BitcodeFiles.empty())
    return std::error_code();

  // Create an object file and add it to the symbol table by replacing any
  // DefinedBitcode symbols with the definitions in the object file.
  LTOCodeGenerator CG;
  auto FileOrErr = createLTOObject(&CG);
  if (auto EC = FileOrErr.getError())
    return EC;
  ObjectFile *Obj = FileOrErr.get();

  // Skip the combined object file as the file is processed below
  // rather than by run().
  ++FileIdx;

  for (SymbolBody *Body : Obj->getSymbols()) {
    if (!Body->isExternal())
      continue;
    // Find an existing Symbol. We should not see any new undefined symbols at
    // this point.
    StringRef Name = Body->getName();
    Symbol *&Sym = Symtab[Name];
    if (!Sym) {
      if (!isa<Defined>(Body)) {
        llvm::errs() << "LTO: undefined symbol: " << Name << '\n';
        return make_error_code(LLDError::BrokenFile);
      }
      Sym = new (Alloc) Symbol(Body);
      Body->setBackref(Sym);
      continue;
    }
    Body->setBackref(Sym);

    if (isa<DefinedBitcode>(Sym->Body)) {
      // The symbol should now be defined.
      if (!isa<Defined>(Body)) {
        llvm::errs() << "LTO: undefined symbol: " << Name << '\n';
        return make_error_code(LLDError::BrokenFile);
      }
      Sym->Body = Body;
    } else {
      int comp = Sym->Body->compare(Body);
      if (comp < 0)
        Sym->Body = Body;
      if (comp == 0) {
        llvm::errs() << "LTO: unexpected duplicate symbol: " << Name << "\n";
        return make_error_code(LLDError::BrokenFile);
      }
    }

    // We may see new references to runtime library symbols such as __chkstk
    // here. These symbols must be wholly defined in non-bitcode files.
    if (auto *B = dyn_cast<Lazy>(Sym->Body))
      if (auto EC = addMemberFile(B))
        return EC;
  }

  size_t NumBitcodeFiles = BitcodeFiles.size();
  if (auto EC = run())
    return EC;
  if (BitcodeFiles.size() != NumBitcodeFiles) {
    llvm::errs() << "LTO: late loaded symbol created new bitcode reference\n";
    return make_error_code(LLDError::BrokenFile);
  }

  // New runtime library symbol references may have created undefined references.
  if (reportRemainingUndefines())
    return make_error_code(LLDError::BrokenFile);
  return std::error_code();
}

// Combine and compile bitcode files and then return the result
// as a regular COFF object file.
ErrorOr<ObjectFile *> SymbolTable::createLTOObject(LTOCodeGenerator *CG) {
  // All symbols referenced by non-bitcode objects must be preserved.
  for (ObjectFile *File : ObjectFiles)
    for (SymbolBody *Body : File->getSymbols())
      if (auto *S = dyn_cast<DefinedBitcode>(Body->getReplacement()))
        CG->addMustPreserveSymbol(S->getName());

  // Likewise for bitcode symbols which we initially resolved to non-bitcode.
  for (BitcodeFile *File : BitcodeFiles)
    for (SymbolBody *Body : File->getSymbols())
      if (isa<DefinedBitcode>(Body) &&
          !isa<DefinedBitcode>(Body->getReplacement()))
        CG->addMustPreserveSymbol(Body->getName());

  // Likewise for other symbols that must be preserved.
  for (StringRef Name : Config->GCRoots)
    if (isa<DefinedBitcode>(Symtab[Name]->Body))
      CG->addMustPreserveSymbol(Name);

  CG->setModule(BitcodeFiles[0]->releaseModule());
  for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
    CG->addModule(BitcodeFiles[I]->getModule());

  std::string ErrMsg;
  LTOMB = CG->compile(false, false, false, ErrMsg); // take MB ownership
  if (!LTOMB) {
    llvm::errs() << ErrMsg << '\n';
    return make_error_code(LLDError::BrokenFile);
  }
  auto *Obj = new ObjectFile(LTOMB->getMemBufferRef());
  Files.emplace_back(Obj);
  ObjectFiles.push_back(Obj);
  if (auto EC = Obj->parse())
    return EC;
  return Obj;
}

} // namespace coff
} // namespace lld
<|endoftext|>


<commit_before>/*
	Copyright (c) 2016 Xavier Leclercq

	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.
*/

/*
	Part of this file were copied from the Chart.js project (http://chartjs.org/)
	and translated into C++.

	The files of the Chart.js project have the following copyright and license.

	Copyright (c) 2013-2016 Nick Downie
	Released under the MIT license
	https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
*/

#include "wxchartgrid.h"
#include "wxchartutilities.h"
#include <wx/pen.h>
#include <sstream>

wxChartGrid::wxChartGrid(const wxPoint2DDouble &position,
						 const wxSize &size,
						 const wxVector<wxString> &labels,
						 wxDouble minValue,
						 wxDouble maxValue,
						 const wxChartGridOptions& options)
	: m_options(options), m_position(position),
	m_mapping(
		size,
		(options.GetXAxisOptions().GetLabelType() == wxCHARTAXISLABELTYPE_POINT ? labels.size() - 1: labels.size())
		),
	m_XAxis(new wxChartAxis(labels, options.GetXAxisOptions())),
	m_YAxis(new wxChartAxis(options.GetYAxisOptions())),
	m_needsFit(true)
{
	wxDouble effectiveMinValue = minValue;
	if (m_YAxis->GetOptions().GetStartValueMode() == wxCHARTAXISVALUEMODE_EXPLICIT)
	{
		effectiveMinValue = m_YAxis->GetOptions().GetStartValue();
	}
	wxDouble effectiveMaxValue = maxValue;
	if (m_YAxis->GetOptions().GetEndValueMode() == wxCHARTAXISVALUEMODE_EXPLICIT)
	{
		effectiveMaxValue = m_YAxis->GetOptions().GetEndValue();
	}

	wxDouble graphMinValue;
	wxDouble graphMaxValue;
	wxDouble valueRange = 0;
	wxChartUtilities::CalculateGridRange(effectiveMinValue, effectiveMaxValue,
		graphMinValue, graphMaxValue, valueRange, m_steps, m_stepValue);
	m_mapping.SetMinValue(graphMinValue);
	m_mapping.SetMaxValue(graphMaxValue);

	wxVector<wxChartLabel> yLabels;
	BuildYLabels(m_mapping.GetMinValue(), m_steps, m_stepValue, yLabels);
	m_YAxis->SetLabels(yLabels);
}

bool wxChartGrid::HitTest(const wxPoint &point) const
{
	return false;
}

wxPoint2DDouble wxChartGrid::GetTooltipPosition() const
{
	return wxPoint2DDouble(0, 0);
}

void wxChartGrid::Draw(wxGraphicsContext &gc)
{
	Fit(gc);

	wxDouble yLabelGap = (m_mapping.GetStartPoint().m_y - m_mapping.GetEndPoint().m_y) / m_steps;
	wxDouble xStart = m_mapping.GetLeftPadding();

	if (m_options.ShowHorizontalLines())
	{
		for (size_t i = 1; i < m_YAxis->GetNumberOfTickMarks(); ++i)
		{
			wxDouble yLabelCenter = m_mapping.GetStartPoint().m_y - (yLabelGap * i);
			wxDouble linePositionY = yLabelCenter;

			wxGraphicsPath path = gc.CreatePath();
			path.MoveToPoint(xStart, linePositionY);
			path.AddLineToPoint(m_mapping.GetSize().GetWidth() - m_mapping.GetRightPadding() + m_XAxis->GetOptions().GetOverhang(), linePositionY);

			wxPen pen1(m_options.GetGridLineColor(), m_options.GetGridLineWidth());
			gc.SetPen(pen1);
			gc.StrokePath(path);
		}
	}

	if (m_options.ShowVerticalLines())
	{
		for (size_t i = 1; i < m_XAxis->GetNumberOfTickMarks(); ++i)
		{
			wxDouble linePosition = m_XAxis->GetTickMarkPosition(i).m_x;

			wxGraphicsPath path = gc.CreatePath();
			path.MoveToPoint(linePosition, m_mapping.GetStartPoint().m_y);
			path.AddLineToPoint(linePosition, m_mapping.GetEndPoint().m_y - m_YAxis->GetOptions().GetOverhang());

			wxPen pen1(m_options.GetGridLineColor(), m_options.GetGridLineWidth());
			gc.SetPen(pen1);
			gc.StrokePath(path);
		}
	}

	m_XAxis->Draw(gc);
	m_YAxis->Draw(gc);
}

void wxChartGrid::Resize(const wxSize &size)
{
	m_mapping.SetSize(size);
	m_needsFit = true;
}

const wxChartGridMapping& wxChartGrid::GetMapping() const
{
	return m_mapping;
}

void wxChartGrid::Fit(wxGraphicsContext &gc)
{
	if (!m_needsFit)
	{
		return;
	}

	wxDouble startPoint = m_mapping.GetSize().GetHeight() - (m_YAxis->GetOptions().GetFontOptions().GetSize() + 15) - 5; // -5 to pad labels
	wxDouble endPoint = m_YAxis->GetOptions().GetFontOptions().GetSize();

	// Apply padding settings to the start and end point.
	//this.startPoint += this.padding;
	//this.endPoint -= this.padding;

	m_YAxis->UpdateLabelSizes(gc);
	m_XAxis->UpdateLabelSizes(gc);

	wxDouble leftPadding = 0;
	wxDouble rightPadding = 0;
	CalculatePadding(*m_XAxis, *m_YAxis, leftPadding, rightPadding);

	if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
	{
		m_XAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(m_mapping.GetSize().GetWidth() - rightPadding, startPoint));
		m_YAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(leftPadding, endPoint));
	}
	else if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
	{
		m_XAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(leftPadding, endPoint));
		m_YAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(m_mapping.GetSize().GetWidth() - rightPadding, startPoint));
	}

	m_XAxis->UpdateLabelPositions();
	m_YAxis->UpdateLabelPositions();

	m_mapping.Fit(leftPadding, rightPadding, wxPoint2DDouble(0, startPoint), wxPoint2DDouble(0, endPoint));

	m_needsFit = false;
}

void wxChartGrid::BuildYLabels(wxDouble minValue,
							   size_t steps,
							   wxDouble stepValue,
							   wxVector<wxChartLabel> &labels)
{
	size_t stepDecimalPlaces = wxChartUtilities::GetDecimalPlaces();

	for (size_t i = 0; i <= steps; ++i)
	{
		wxDouble value = minValue + (i * stepValue);//.toFixed(stepDecimalPlaces);
		std::stringstream valueStr;
		valueStr << value;

		labels.push_back(wxChartLabel(valueStr.str()));
	}
}

void wxChartGrid::CalculatePadding(const wxChartAxis &xAxis,
								   const wxChartAxis &yAxis,
								   wxDouble &left,
								   wxDouble &right)
{
	if (xAxis.GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
	{
		// Either the first x label or any of the y labels can be the widest
		// so they are all taken into account to compute the left padding
		left = yAxis.GetLabelMaxWidth();
		if ((xAxis.GetLabels().size() > 0) && ((xAxis.GetLabels().front().GetSize().GetWidth() / 2) > left))
		{
			left = (xAxis.GetLabels().front().GetSize().GetWidth() / 2);
		}

		right = 0;
		if (xAxis.GetLabels().size() > 0)
		{
			right = (xAxis.GetLabels().back().GetSize().GetWidth() / 2);
		}
	}
	else if (xAxis.GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
	{
		// Either the first y label or any of the x labels can be the widest
		// so they are all taken into account to compute the left padding
		left = xAxis.GetLabelMaxWidth();
		if ((yAxis.GetLabels().size() > 0) && ((yAxis.GetLabels().front().GetSize().GetWidth() / 2) > left))
		{
			left = (yAxis.GetLabels().front().GetSize().GetWidth() / 2);
		}

		right = 0;
		if (yAxis.GetLabels().size() > 0)
		{
			right = (yAxis.GetLabels().back().GetSize().GetWidth() / 2);
		}
	}
}
<commit_msg>Fixed grid lines for bar charts<commit_after>/*
	Copyright (c) 2016 Xavier Leclercq

	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.
*/

/*
	Part of this file were copied from the Chart.js project (http://chartjs.org/)
	and translated into C++.

	The files of the Chart.js project have the following copyright and license.

	Copyright (c) 2013-2016 Nick Downie
	Released under the MIT license
	https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
*/

#include "wxchartgrid.h"
#include "wxchartutilities.h"
#include <wx/pen.h>
#include <sstream>

wxChartGrid::wxChartGrid(const wxPoint2DDouble &position,
						 const wxSize &size,
						 const wxVector<wxString> &labels,
						 wxDouble minValue,
						 wxDouble maxValue,
						 const wxChartGridOptions& options)
	: m_options(options), m_position(position),
	m_mapping(
		size,
		(options.GetXAxisOptions().GetLabelType() == wxCHARTAXISLABELTYPE_POINT ? labels.size() - 1: labels.size())
		),
	m_XAxis(new wxChartAxis(labels, options.GetXAxisOptions())),
	m_YAxis(new wxChartAxis(options.GetYAxisOptions())),
	m_needsFit(true)
{
	wxDouble effectiveMinValue = minValue;
	if (m_YAxis->GetOptions().GetStartValueMode() == wxCHARTAXISVALUEMODE_EXPLICIT)
	{
		effectiveMinValue = m_YAxis->GetOptions().GetStartValue();
	}
	wxDouble effectiveMaxValue = maxValue;
	if (m_YAxis->GetOptions().GetEndValueMode() == wxCHARTAXISVALUEMODE_EXPLICIT)
	{
		effectiveMaxValue = m_YAxis->GetOptions().GetEndValue();
	}

	wxDouble graphMinValue;
	wxDouble graphMaxValue;
	wxDouble valueRange = 0;
	wxChartUtilities::CalculateGridRange(effectiveMinValue, effectiveMaxValue,
		graphMinValue, graphMaxValue, valueRange, m_steps, m_stepValue);
	m_mapping.SetMinValue(graphMinValue);
	m_mapping.SetMaxValue(graphMaxValue);

	wxVector<wxChartLabel> yLabels;
	BuildYLabels(m_mapping.GetMinValue(), m_steps, m_stepValue, yLabels);
	m_YAxis->SetLabels(yLabels);
}

bool wxChartGrid::HitTest(const wxPoint &point) const
{
	return false;
}

wxPoint2DDouble wxChartGrid::GetTooltipPosition() const
{
	return wxPoint2DDouble(0, 0);
}

void wxChartGrid::Draw(wxGraphicsContext &gc)
{
	Fit(gc);

	if (m_options.ShowHorizontalLines())
	{
		const wxChartAxis* verticalAxis = 0;
		if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
		{
			verticalAxis = m_XAxis.get();
		}
		else if (m_YAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
		{
			verticalAxis = m_YAxis.get();
		}

		for (size_t i = 1; i < verticalAxis->GetNumberOfTickMarks(); ++i)
		{
			wxDouble yLabelCenter = verticalAxis->GetTickMarkPosition(i).m_y;
			wxDouble linePositionY = yLabelCenter;

			wxGraphicsPath path = gc.CreatePath();
			path.MoveToPoint(m_mapping.GetLeftPadding(), linePositionY);
			path.AddLineToPoint(m_mapping.GetSize().GetWidth() - m_mapping.GetRightPadding() + verticalAxis->GetOptions().GetOverhang(), linePositionY);

			wxPen pen1(m_options.GetGridLineColor(), m_options.GetGridLineWidth());
			gc.SetPen(pen1);
			gc.StrokePath(path);
		}
	}

	if (m_options.ShowVerticalLines())
	{
		const wxChartAxis* horizontalAxis = 0;
		if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
		{
			horizontalAxis = m_XAxis.get();
		}
		else if (m_YAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
		{
			horizontalAxis = m_YAxis.get();
		}

		for (size_t i = 1; i < horizontalAxis->GetNumberOfTickMarks(); ++i)
		{
			wxDouble linePosition = horizontalAxis->GetTickMarkPosition(i).m_x;

			wxGraphicsPath path = gc.CreatePath();
			path.MoveToPoint(linePosition, m_mapping.GetStartPoint().m_y);
			path.AddLineToPoint(linePosition, m_mapping.GetEndPoint().m_y - horizontalAxis->GetOptions().GetOverhang());

			wxPen pen1(m_options.GetGridLineColor(), m_options.GetGridLineWidth());
			gc.SetPen(pen1);
			gc.StrokePath(path);
		}
	}

	m_XAxis->Draw(gc);
	m_YAxis->Draw(gc);
}

void wxChartGrid::Resize(const wxSize &size)
{
	m_mapping.SetSize(size);
	m_needsFit = true;
}

const wxChartGridMapping& wxChartGrid::GetMapping() const
{
	return m_mapping;
}

void wxChartGrid::Fit(wxGraphicsContext &gc)
{
	if (!m_needsFit)
	{
		return;
	}

	wxDouble startPoint = m_mapping.GetSize().GetHeight() - (m_YAxis->GetOptions().GetFontOptions().GetSize() + 15) - 5; // -5 to pad labels
	wxDouble endPoint = m_YAxis->GetOptions().GetFontOptions().GetSize();

	// Apply padding settings to the start and end point.
	//this.startPoint += this.padding;
	//this.endPoint -= this.padding;

	m_YAxis->UpdateLabelSizes(gc);
	m_XAxis->UpdateLabelSizes(gc);

	wxDouble leftPadding = 0;
	wxDouble rightPadding = 0;
	CalculatePadding(*m_XAxis, *m_YAxis, leftPadding, rightPadding);

	if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
	{
		m_XAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(m_mapping.GetSize().GetWidth() - rightPadding, startPoint));
		m_YAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(leftPadding, endPoint));
	}
	else if (m_XAxis->GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
	{
		m_XAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(leftPadding, endPoint));
		m_YAxis->Fit(wxPoint2DDouble(leftPadding, startPoint), wxPoint2DDouble(m_mapping.GetSize().GetWidth() - rightPadding, startPoint));
	}

	m_XAxis->UpdateLabelPositions();
	m_YAxis->UpdateLabelPositions();

	m_mapping.Fit(leftPadding, rightPadding, wxPoint2DDouble(0, startPoint), wxPoint2DDouble(0, endPoint));

	m_needsFit = false;
}

void wxChartGrid::BuildYLabels(wxDouble minValue,
							   size_t steps,
							   wxDouble stepValue,
							   wxVector<wxChartLabel> &labels)
{
	size_t stepDecimalPlaces = wxChartUtilities::GetDecimalPlaces();

	for (size_t i = 0; i <= steps; ++i)
	{
		wxDouble value = minValue + (i * stepValue);//.toFixed(stepDecimalPlaces);
		std::stringstream valueStr;
		valueStr << value;

		labels.push_back(wxChartLabel(valueStr.str()));
	}
}

void wxChartGrid::CalculatePadding(const wxChartAxis &xAxis,
								   const wxChartAxis &yAxis,
								   wxDouble &left,
								   wxDouble &right)
{
	if (xAxis.GetOptions().GetPosition() == wxCHARTAXISPOSITION_BOTTOM)
	{
		// Either the first x label or any of the y labels can be the widest
		// so they are all taken into account to compute the left padding
		left = yAxis.GetLabelMaxWidth();
		if ((xAxis.GetLabels().size() > 0) && ((xAxis.GetLabels().front().GetSize().GetWidth() / 2) > left))
		{
			left = (xAxis.GetLabels().front().GetSize().GetWidth() / 2);
		}

		right = 0;
		if (xAxis.GetLabels().size() > 0)
		{
			right = (xAxis.GetLabels().back().GetSize().GetWidth() / 2);
		}
	}
	else if (xAxis.GetOptions().GetPosition() == wxCHARTAXISPOSITION_LEFT)
	{
		// Either the first y label or any of the x labels can be the widest
		// so they are all taken into account to compute the left padding
		left = xAxis.GetLabelMaxWidth();
		if ((yAxis.GetLabels().size() > 0) && ((yAxis.GetLabels().front().GetSize().GetWidth() / 2) > left))
		{
			left = (yAxis.GetLabels().front().GetSize().GetWidth() / 2);
		}

		right = 0;
		if (yAxis.GetLabels().size() > 0)
		{
			right = (yAxis.GetLabels().back().GetSize().GetWidth() / 2);
		}
	}
}
<|endoftext|>