<commit_before>#ifndef DUNE_GDT_LOCALOPERATOR_FV_HH
#define DUNE_GDT_LOCALOPERATOR_FV_HH

#include "interfaces.hh"

namespace Dune {
namespace GDT {

enum class SlopeLimiters
{
  minmod,
  mc,
  superbee,
  no_slope
};

// forwards
template <class NumericalFluxType>
class LocalCouplingFVOperator;

template <class NumericalFluxType>
class LocalBoundaryFVOperator;

template <class RHSEvaluationImp>
class LocalRHSFVOperator;

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
class LocalReconstructionFVOperator;

namespace internal {

// Traits
template <class NumericalFluxType>
struct LocalCouplingFVOperatorTraits
{
  typedef LocalCouplingFVOperator<NumericalFluxType> derived_type;
};

template <class NumericalFluxType>
struct LocalBoundaryFVOperatorTraits
{
  typedef LocalBoundaryFVOperator<NumericalFluxType> derived_type;
};

template <class RHSEvaluationImp>
struct LocalRHSFVOperatorTraits
{
  typedef LocalRHSFVOperator<RHSEvaluationImp> derived_type;
};

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
struct LocalReconstructionFVOperatorTraits
{
  typedef LocalReconstructionFVOperator<MatrixImp, BoundaryValueFunctionImp, slope_limiter> derived_type;
  typedef MatrixImp MatrixType;
  typedef BoundaryValueFunctionImp BoundaryValueFunctionType;
  typedef typename BoundaryValueFunctionType::RangeFieldType RangeFieldType;
  static const size_t dimRange = BoundaryValueFunctionType::dimRange;
};

template <SlopeLimiters slope_limiter, class VectorType>
struct ChooseLimiter
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right,
                          const VectorType& centered_slope);
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::minmod, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right,
                          const VectorType& /*centered_slope*/)
  {
    VectorType ret;
    for (size_t ii = 0; ii < slope_left.size(); ++ii) {
      const auto slope_left_abs  = std::abs(slope_left[ii]);
      const auto slope_right_abs = std::abs(slope_right[ii]);
      if (slope_left_abs < slope_right_abs && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_left[ii];
      else if (DSC::FloatCmp::ge(slope_left_abs, slope_right_abs) && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_right[ii];
      else
        ret[ii] = 0.0;
    }
    return ret;
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::superbee, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right, const VectorType& centered_slope)
  {
    typedef ChooseLimiter<SlopeLimiters::minmod, VectorType> MinmodType;
    return maxmod(MinmodType::limit(slope_left, slope_right * 2.0, centered_slope),
                  MinmodType::limit(slope_left * 2.0, slope_right, centered_slope));
  }

  static VectorType maxmod(const VectorType& slope_left, const VectorType& slope_right)
  {
    VectorType ret;
    for (size_t ii = 0; ii < slope_left.size(); ++ii) {
      const auto slope_left_abs  = std::abs(slope_left[ii]);
      const auto slope_right_abs = std::abs(slope_right[ii]);
      if (slope_left_abs > slope_right_abs && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_left[ii];
      else if (DSC::FloatCmp::le(slope_left_abs, slope_right_abs) && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_right[ii];
      else
        ret[ii] = 0.0;
    }
    return ret;
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::mc, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right, const VectorType& centered_slope)
  {
    typedef ChooseLimiter<SlopeLimiters::minmod, VectorType> MinmodType;
    return MinmodType::limit(
        MinmodType::limit(slope_left * 2.0, slope_right * 2.0, centered_slope), centered_slope, centered_slope);
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::no_slope, VectorType>
{
  static VectorType limit(const VectorType& /*slope_left*/, const VectorType& /*slope_right*/,
                          const VectorType& /*centered_slope*/)
  {
    return VectorType(0);
  }
};

} // namespace internal

template <class NumericalFluxType>
class LocalCouplingFVOperator
    : public LocalCouplingOperatorInterface<internal::LocalCouplingFVOperatorTraits<NumericalFluxType>>
{
public:
  template <class... Args>
  explicit LocalCouplingFVOperator(Args&&... args)
    : numerical_flux_(std::forward<Args>(args)...)
  {
  }

  template <class SourceType, class IntersectionType, class SpaceType, class VectorType>
  void apply(const SourceType& source, const IntersectionType& intersection,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_entity,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_neighbor) const
  {
    const auto entity                         = intersection.inside();
    const auto neighbor                       = intersection.outside();
    const auto local_source_entity            = source.local_function(entity);
    const auto local_source_neighbor          = source.local_function(neighbor);
    const auto geometry_intersection          = intersection.geometry();
    const auto local_functions_tuple_entity   = numerical_flux_.local_functions(entity);
    const auto local_functions_tuple_neighbor = numerical_flux_.local_functions(neighbor);
    const DSC::FieldVector<typename LocalDiscreteFunction<SpaceType, VectorType>::DomainFieldType,
                           LocalDiscreteFunction<SpaceType, VectorType>::dimRange> result =
        numerical_flux_.evaluate(local_functions_tuple_entity,
                                 local_functions_tuple_neighbor,
                                 *local_source_entity,
                                 *local_source_neighbor,
                                 intersection,
                                 geometry_intersection.local(geometry_intersection.center()));
    local_range_entity.vector().add(result * (1.0 / entity.geometry().volume()));
    local_range_neighbor.vector().add(result * (-1.0 / neighbor.geometry().volume()));
  }

private:
  const NumericalFluxType numerical_flux_;
};

template <class NumericalFluxType>
class LocalBoundaryFVOperator
    : public LocalBoundaryOperatorInterface<internal::LocalBoundaryFVOperatorTraits<NumericalFluxType>>
{
public:
  template <class... Args>
  explicit LocalBoundaryFVOperator(Args&&... args)
    : numerical_flux_(std::forward<Args>(args)...)
  {
  }

  template <class SourceType, class IntersectionType, class SpaceType, class VectorType>
  void apply(const SourceType& source, const IntersectionType& intersection,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_entity) const
  {
    const auto entity                = intersection.inside();
    const auto local_source_entity   = source.local_function(entity);
    const auto geometry_intersection = intersection.geometry();
    const auto local_functions_tuple = numerical_flux_.local_functions(entity);
    auto result                      = numerical_flux_.evaluate(local_functions_tuple,
                                           *local_source_entity,
                                           intersection,
                                           geometry_intersection.local(geometry_intersection.center()));
    result /= entity.geometry().volume();
    local_range_entity.vector().add(result);
  }

private:
  const NumericalFluxType numerical_flux_;
};

/** TODO: add support for time-dependent RHS
 *  TODO: implement as integral operator??
 * */
template <class RHSEvaluationImp>
class LocalRHSFVOperator : public LocalOperatorInterface<internal::LocalRHSFVOperatorTraits<RHSEvaluationImp>>
{
public:
  explicit LocalRHSFVOperator(const RHSEvaluationImp& rhs_evaluation)
    : rhs_evaluation_(rhs_evaluation)
  {
  }

  template <class SourceType, class RangeSpaceType, class VectorType>
  void apply(const SourceType& source, LocalDiscreteFunction<RangeSpaceType, VectorType>& local_range) const
  {
    const auto entity              = local_range.entity();
    const auto local_source_entity = source.local_function(entity);
    const auto x_local             = entity.geometry().local(entity.geometry().center());
    const auto u                   = local_source_entity->evaluate(x_local);
    const auto result = rhs_evaluation_.evaluate(u, entity, x_local);
    local_range.vector().add(result);
  }

private:
  const RHSEvaluationImp& rhs_evaluation_;
};

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
class LocalReconstructionFVOperator
    : public LocalOperatorInterface<internal::LocalReconstructionFVOperatorTraits<MatrixImp, BoundaryValueFunctionImp,
                                                                                slope_limiter>>
{
  typedef internal::LocalReconstructionFVOperatorTraits<MatrixImp, BoundaryValueFunctionImp, slope_limiter> Traits;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const size_t dimRange = Traits::dimRange;
  typedef typename DSC::FieldVector<RangeFieldType, dimRange> StuffFieldVectorType;

public:
  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::BoundaryValueFunctionType BoundaryValueFunctionType;

  explicit LocalReconstructionFVOperator(const MatrixType& eigenvectors, const MatrixType& eigenvectors_inverse,
                                         const BoundaryValueFunctionType& boundary_values)
    : eigenvectors_(eigenvectors)
    , eigenvectors_inverse_(eigenvectors_inverse)
    , boundary_values_(boundary_values)
  {
  }

  template <class SourceType, class RangeSpaceType, class VectorType>
  void apply(const SourceType& source, LocalDiscreteFunction<RangeSpaceType, VectorType>& local_range) const
  {
    const auto entity     = local_range.entity();
    const auto& grid_view = local_range.space().grid_view();
    // get reconstruction vector and mapper
    auto& reconstruction_vector       = local_range.vector();
    const auto& reconstruction_mapper = local_range.space().mapper();
    const auto entity_center          = entity.geometry().center();
    // walk over intersections to get values of discrete function on left and right neighbor entity
    typename SourceType::RangeType u_left, u_right;
    typename SourceType::RangeType u_entity =
        source.local_discrete_function(entity)->evaluate(entity.geometry().local(entity_center));
    const auto i_it_end = grid_view.iend(entity);
    for (auto i_it = grid_view.ibegin(entity); i_it != i_it_end; ++i_it) {
      const auto& intersection = *i_it;
      if (intersection.neighbor()) {
        const auto neighbor        = intersection.outside();
        const auto neighbor_center = neighbor.geometry().center();
        const bool boundary = intersection.boundary();
        if ((neighbor_center[0] < entity_center[0] && !boundary) || (neighbor_center[0] > entity_center[0] && boundary))
          u_left = source.local_discrete_function(neighbor)->evaluate(neighbor.geometry().local(neighbor_center));
        else
          u_right = source.local_discrete_function(neighbor)->evaluate(neighbor.geometry().local(neighbor_center));
      } else {
        if (intersection.geometry().center()[0] < entity_center[0])
          u_left = boundary_values_.local_function(entity)->evaluate(intersection.geometryInInside().center());
        else
          u_right = boundary_values_.local_function(entity)->evaluate(intersection.geometryInInside().center());
      }
    }

    // diagonalize the system of equations from u_t + A*u_x = 0 to w_t + D*w_x = 0 where D = R^(-1)*A*R, w = R^(-1)*u
    // and R matrix of eigenvectors of A
    const StuffFieldVectorType w_left(eigenvectors_inverse_ * u_left);
    const StuffFieldVectorType w_right(eigenvectors_inverse_ * u_right);
    const StuffFieldVectorType w_entity(eigenvectors_inverse_ * u_entity);

    const StuffFieldVectorType w_slope_left     = w_entity - w_left;
    const StuffFieldVectorType w_slope_right    = w_right - w_entity;
    const StuffFieldVectorType w_centered_slope = w_right * RangeFieldType(0.5) - w_left * RangeFieldType(0.5);
    const StuffFieldVectorType w_slope = internal::ChooseLimiter<slope_limiter, StuffFieldVectorType>::limit(
        w_slope_left, w_slope_right, w_centered_slope);
    const StuffFieldVectorType half_w_slope          = w_slope * RangeFieldType(0.5);
    const StuffFieldVectorType w_reconstructed_left  = w_entity - half_w_slope;
    const StuffFieldVectorType w_reconstructed_right = w_entity + half_w_slope;

    // convert back to u variable
    const StuffFieldVectorType u_reconstructed_left(eigenvectors_ * w_reconstructed_left);
    const StuffFieldVectorType u_reconstructed_right(eigenvectors_ * w_reconstructed_right);

    for (size_t factor_index = 0; factor_index < dimRange; ++factor_index) {
      // set values on dofs, dof with local index 0 for each factor space corresponds to basis function 1 - x, local
      // index 1 to x
      reconstruction_vector.set(reconstruction_mapper.mapToLocal(factor_index, entity, 0),
                                u_reconstructed_left[factor_index]);
      reconstruction_vector.set(reconstruction_mapper.mapToLocal(factor_index, entity, 1),
                                u_reconstructed_right[factor_index]);
    }
  } // void apply(...)

private:
  const MatrixType& eigenvectors_;
  const MatrixType& eigenvectors_inverse_;
  const BoundaryValueFunctionImp& boundary_values_;
};

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCALOPERATOR_FV_HH
<commit_msg>[localoperator.fv] do not copy entity<commit_after>#ifndef DUNE_GDT_LOCALOPERATOR_FV_HH
#define DUNE_GDT_LOCALOPERATOR_FV_HH

#include "interfaces.hh"

namespace Dune {
namespace GDT {

enum class SlopeLimiters
{
  minmod,
  mc,
  superbee,
  no_slope
};

// forwards
template <class NumericalFluxType>
class LocalCouplingFVOperator;

template <class NumericalFluxType>
class LocalBoundaryFVOperator;

template <class RHSEvaluationImp>
class LocalRHSFVOperator;

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
class LocalReconstructionFVOperator;

namespace internal {

// Traits
template <class NumericalFluxType>
struct LocalCouplingFVOperatorTraits
{
  typedef LocalCouplingFVOperator<NumericalFluxType> derived_type;
};

template <class NumericalFluxType>
struct LocalBoundaryFVOperatorTraits
{
  typedef LocalBoundaryFVOperator<NumericalFluxType> derived_type;
};

template <class RHSEvaluationImp>
struct LocalRHSFVOperatorTraits
{
  typedef LocalRHSFVOperator<RHSEvaluationImp> derived_type;
};

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
struct LocalReconstructionFVOperatorTraits
{
  typedef LocalReconstructionFVOperator<MatrixImp, BoundaryValueFunctionImp, slope_limiter> derived_type;
  typedef MatrixImp MatrixType;
  typedef BoundaryValueFunctionImp BoundaryValueFunctionType;
  typedef typename BoundaryValueFunctionType::RangeFieldType RangeFieldType;
  static const size_t dimRange = BoundaryValueFunctionType::dimRange;
};

template <SlopeLimiters slope_limiter, class VectorType>
struct ChooseLimiter
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right,
                          const VectorType& centered_slope);
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::minmod, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right,
                          const VectorType& /*centered_slope*/)
  {
    VectorType ret;
    for (size_t ii = 0; ii < slope_left.size(); ++ii) {
      const auto slope_left_abs  = std::abs(slope_left[ii]);
      const auto slope_right_abs = std::abs(slope_right[ii]);
      if (slope_left_abs < slope_right_abs && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_left[ii];
      else if (DSC::FloatCmp::ge(slope_left_abs, slope_right_abs) && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_right[ii];
      else
        ret[ii] = 0.0;
    }
    return ret;
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::superbee, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right, const VectorType& centered_slope)
  {
    typedef ChooseLimiter<SlopeLimiters::minmod, VectorType> MinmodType;
    return maxmod(MinmodType::limit(slope_left, slope_right * 2.0, centered_slope),
                  MinmodType::limit(slope_left * 2.0, slope_right, centered_slope));
  }

  static VectorType maxmod(const VectorType& slope_left, const VectorType& slope_right)
  {
    VectorType ret;
    for (size_t ii = 0; ii < slope_left.size(); ++ii) {
      const auto slope_left_abs  = std::abs(slope_left[ii]);
      const auto slope_right_abs = std::abs(slope_right[ii]);
      if (slope_left_abs > slope_right_abs && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_left[ii];
      else if (DSC::FloatCmp::le(slope_left_abs, slope_right_abs) && slope_left[ii] * slope_right[ii] > 0)
        ret[ii] = slope_right[ii];
      else
        ret[ii] = 0.0;
    }
    return ret;
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::mc, VectorType>
{
  static VectorType limit(const VectorType& slope_left, const VectorType& slope_right, const VectorType& centered_slope)
  {
    typedef ChooseLimiter<SlopeLimiters::minmod, VectorType> MinmodType;
    return MinmodType::limit(
        MinmodType::limit(slope_left * 2.0, slope_right * 2.0, centered_slope), centered_slope, centered_slope);
  }
};

template <class VectorType>
struct ChooseLimiter<SlopeLimiters::no_slope, VectorType>
{
  static VectorType limit(const VectorType& /*slope_left*/, const VectorType& /*slope_right*/,
                          const VectorType& /*centered_slope*/)
  {
    return VectorType(0);
  }
};

} // namespace internal

template <class NumericalFluxType>
class LocalCouplingFVOperator
    : public LocalCouplingOperatorInterface<internal::LocalCouplingFVOperatorTraits<NumericalFluxType>>
{
public:
  template <class... Args>
  explicit LocalCouplingFVOperator(Args&&... args)
    : numerical_flux_(std::forward<Args>(args)...)
  {
  }

  template <class SourceType, class IntersectionType, class SpaceType, class VectorType>
  void apply(const SourceType& source, const IntersectionType& intersection,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_entity,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_neighbor) const
  {
    const auto entity                         = intersection.inside();
    const auto neighbor                       = intersection.outside();
    const auto local_source_entity            = source.local_function(entity);
    const auto local_source_neighbor          = source.local_function(neighbor);
    const auto geometry_intersection          = intersection.geometry();
    const auto local_functions_tuple_entity   = numerical_flux_.local_functions(entity);
    const auto local_functions_tuple_neighbor = numerical_flux_.local_functions(neighbor);
    const DSC::FieldVector<typename LocalDiscreteFunction<SpaceType, VectorType>::DomainFieldType,
                           LocalDiscreteFunction<SpaceType, VectorType>::dimRange> result =
        numerical_flux_.evaluate(local_functions_tuple_entity,
                                 local_functions_tuple_neighbor,
                                 *local_source_entity,
                                 *local_source_neighbor,
                                 intersection,
                                 geometry_intersection.local(geometry_intersection.center()));
    local_range_entity.vector().add(result * (1.0 / entity.geometry().volume()));
    local_range_neighbor.vector().add(result * (-1.0 / neighbor.geometry().volume()));
  }

private:
  const NumericalFluxType numerical_flux_;
};

template <class NumericalFluxType>
class LocalBoundaryFVOperator
    : public LocalBoundaryOperatorInterface<internal::LocalBoundaryFVOperatorTraits<NumericalFluxType>>
{
public:
  template <class... Args>
  explicit LocalBoundaryFVOperator(Args&&... args)
    : numerical_flux_(std::forward<Args>(args)...)
  {
  }

  template <class SourceType, class IntersectionType, class SpaceType, class VectorType>
  void apply(const SourceType& source, const IntersectionType& intersection,
             LocalDiscreteFunction<SpaceType, VectorType>& local_range_entity) const
  {
    const auto entity                = intersection.inside();
    const auto local_source_entity   = source.local_function(entity);
    const auto geometry_intersection = intersection.geometry();
    const auto local_functions_tuple = numerical_flux_.local_functions(entity);
    auto result                      = numerical_flux_.evaluate(local_functions_tuple,
                                           *local_source_entity,
                                           intersection,
                                           geometry_intersection.local(geometry_intersection.center()));
    result /= entity.geometry().volume();
    local_range_entity.vector().add(result);
  }

private:
  const NumericalFluxType numerical_flux_;
};

/** TODO: add support for time-dependent RHS
 *  TODO: implement as integral operator??
 * */
template <class RHSEvaluationImp>
class LocalRHSFVOperator : public LocalOperatorInterface<internal::LocalRHSFVOperatorTraits<RHSEvaluationImp>>
{
public:
  explicit LocalRHSFVOperator(const RHSEvaluationImp& rhs_evaluation)
    : rhs_evaluation_(rhs_evaluation)
  {
  }

  template <class SourceType, class RangeSpaceType, class VectorType>
  void apply(const SourceType& source, LocalDiscreteFunction<RangeSpaceType, VectorType>& local_range) const
  {
    const auto& entity             = local_range.entity();
    const auto local_source_entity = source.local_function(entity);
    const auto x_local             = entity.geometry().local(entity.geometry().center());
    const auto u                   = local_source_entity->evaluate(x_local);
    const auto result = rhs_evaluation_.evaluate(u, entity, x_local);
    local_range.vector().add(result);
  }

private:
  const RHSEvaluationImp& rhs_evaluation_;
};

template <class MatrixImp, class BoundaryValueFunctionImp, SlopeLimiters slope_limiter>
class LocalReconstructionFVOperator
    : public LocalOperatorInterface<internal::LocalReconstructionFVOperatorTraits<MatrixImp, BoundaryValueFunctionImp,
                                                                                slope_limiter>>
{
  typedef internal::LocalReconstructionFVOperatorTraits<MatrixImp, BoundaryValueFunctionImp, slope_limiter> Traits;
  typedef typename Traits::RangeFieldType RangeFieldType;
  static const size_t dimRange = Traits::dimRange;
  typedef typename DSC::FieldVector<RangeFieldType, dimRange> StuffFieldVectorType;

public:
  typedef typename Traits::MatrixType MatrixType;
  typedef typename Traits::BoundaryValueFunctionType BoundaryValueFunctionType;

  explicit LocalReconstructionFVOperator(const MatrixType& eigenvectors, const MatrixType& eigenvectors_inverse,
                                         const BoundaryValueFunctionType& boundary_values)
    : eigenvectors_(eigenvectors)
    , eigenvectors_inverse_(eigenvectors_inverse)
    , boundary_values_(boundary_values)
  {
  }

  template <class SourceType, class RangeSpaceType, class VectorType>
  void apply(const SourceType& source, LocalDiscreteFunction<RangeSpaceType, VectorType>& local_range) const
  {
    const auto& entity    = local_range.entity();
    const auto& grid_view = local_range.space().grid_view();
    // get reconstruction vector and mapper
    auto& reconstruction_vector       = local_range.vector();
    const auto& reconstruction_mapper = local_range.space().mapper();
    const auto entity_center          = entity.geometry().center();
    // walk over intersections to get values of discrete function on left and right neighbor entity
    typename SourceType::RangeType u_left, u_right;
    typename SourceType::RangeType u_entity =
        source.local_discrete_function(entity)->evaluate(entity.geometry().local(entity_center));
    const auto i_it_end = grid_view.iend(entity);
    for (auto i_it = grid_view.ibegin(entity); i_it != i_it_end; ++i_it) {
      const auto& intersection = *i_it;
      if (intersection.neighbor()) {
        const auto neighbor        = intersection.outside();
        const auto neighbor_center = neighbor.geometry().center();
        const bool boundary = intersection.boundary();
        if ((neighbor_center[0] < entity_center[0] && !boundary) || (neighbor_center[0] > entity_center[0] && boundary))
          u_left = source.local_discrete_function(neighbor)->evaluate(neighbor.geometry().local(neighbor_center));
        else
          u_right = source.local_discrete_function(neighbor)->evaluate(neighbor.geometry().local(neighbor_center));
      } else {
        if (intersection.geometry().center()[0] < entity_center[0])
          u_left = boundary_values_.local_function(entity)->evaluate(intersection.geometryInInside().center());
        else
          u_right = boundary_values_.local_function(entity)->evaluate(intersection.geometryInInside().center());
      }
    }

    // diagonalize the system of equations from u_t + A*u_x = 0 to w_t + D*w_x = 0 where D = R^(-1)*A*R, w = R^(-1)*u
    // and R matrix of eigenvectors of A
    const StuffFieldVectorType w_left(eigenvectors_inverse_ * u_left);
    const StuffFieldVectorType w_right(eigenvectors_inverse_ * u_right);
    const StuffFieldVectorType w_entity(eigenvectors_inverse_ * u_entity);

    const StuffFieldVectorType w_slope_left     = w_entity - w_left;
    const StuffFieldVectorType w_slope_right    = w_right - w_entity;
    const StuffFieldVectorType w_centered_slope = w_right * RangeFieldType(0.5) - w_left * RangeFieldType(0.5);
    const StuffFieldVectorType w_slope = internal::ChooseLimiter<slope_limiter, StuffFieldVectorType>::limit(
        w_slope_left, w_slope_right, w_centered_slope);
    const StuffFieldVectorType half_w_slope          = w_slope * RangeFieldType(0.5);
    const StuffFieldVectorType w_reconstructed_left  = w_entity - half_w_slope;
    const StuffFieldVectorType w_reconstructed_right = w_entity + half_w_slope;

    // convert back to u variable
    const StuffFieldVectorType u_reconstructed_left(eigenvectors_ * w_reconstructed_left);
    const StuffFieldVectorType u_reconstructed_right(eigenvectors_ * w_reconstructed_right);

    for (size_t factor_index = 0; factor_index < dimRange; ++factor_index) {
      // set values on dofs, dof with local index 0 for each factor space corresponds to basis function 1 - x, local
      // index 1 to x
      reconstruction_vector.set(reconstruction_mapper.mapToLocal(factor_index, entity, 0),
                                u_reconstructed_left[factor_index]);
      reconstruction_vector.set(reconstruction_mapper.mapToLocal(factor_index, entity, 1),
                                u_reconstructed_right[factor_index]);
    }
  } // void apply(...)

private:
  const MatrixType& eigenvectors_;
  const MatrixType& eigenvectors_inverse_;
  const BoundaryValueFunctionImp& boundary_values_;
};

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCALOPERATOR_FV_HH
<|endoftext|>


<commit_before>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#elif defined (HAVE_CONFIG_H)
  #include <config.h>
#endif // HAVE_CMAKE_CONFIG

#include <utility>
#include <type_traits>

#include <dune/stuff/test/test_common.hh>

#include <dune/common/float_cmp.hh>

#include <dune/pymor/common/exceptions.hh>
#include <dune/pymor/parameters/base.hh>
#include <dune/pymor/parameters/functional.hh>
#include <dune/pymor/la/container/dunedynamic.hh>
#include <dune/pymor/la/container.hh>
#include <dune/pymor/operators/interfaces.hh>
#include <dune/pymor/operators/affine.hh>
#include <dune/pymor/operators/dunedynamic.hh>
//#if HAVE_EIGEN
//  #include <dune/pymor/operators/eigen.hh>
//#endif
//#include <dune/pymor/operators.hh>

using namespace Dune;
using namespace Dune::Pymor;

static const size_t dim = 4;

typedef testing::Types<
                        Dune::Pymor::Operators::DuneDynamic< double >
//#if HAVE_EIGEN
//                      , std::pair< Dune::Pymor::Operators::EigenDenseMatrix,
//                                   Dune::Pymor::LA::EigenDenseVector >
//                      , std::pair< Dune::Pymor::Operators::EigenRowMajorSparseMatrix,
//                                   Dune::Pymor::LA::EigenDenseVector >
//#endif // HAVE_EIGEN
                      > ContainerBasedOperatorTypes;

template< class OperatorType >
struct ContainerBasedOperatorTest
  : public ::testing::Test
{
  void check() const
  {
    // static tests
    typedef typename OperatorType::Traits         Traits;
    // * of the traits
    typedef typename Traits::derived_type T_derived_type;
    static_assert(std::is_same< OperatorType, T_derived_type >::value,
                  "OperatorType::Traits::derived_type is wrong!");
    typedef typename Traits::SourceType   T_SourceType;
    typedef typename Traits::RangeType    T_RangeType;
    typedef typename Traits::ScalarType   T_ScalarType;
    typedef typename Traits::InverseType  T_InverseType;
    // * of the class itself (aka the derived type)
    typedef typename OperatorType::SourceType     D_SourceType;
    typedef typename OperatorType::RangeType      D_RangeType;
    typedef typename OperatorType::ScalarType     D_ScalarType;
    typedef typename OperatorType::InverseType    D_InverseType;
    typedef typename OperatorType::ContainerType  D_ContainerType;
    // * of the class as the operator interface
    typedef OperatorInterface< Traits >         InterfaceType;
    static_assert(std::is_base_of< OperatorInterface< Traits >, OperatorType >::value,
                  "OperatorType has to be derived from OperaotrInterface is wrong!");
    typedef typename InterfaceType::SourceType  I_SourceType;
    typedef typename InterfaceType::RangeType   I_RangeType;
    typedef typename InterfaceType::ScalarType  I_ScalarType;
    typedef typename InterfaceType::InverseType D_InverseType;
    // * of the class as the container interface
    static_assert(std::is_base_of< LA::ProvidesContainer< Traits >, OperatorType >::value,
                  "OperatorType has to be derived from LA::ProvidesContainer!");
    // dynamic tests
    // * of the class itself (aka the derived type)
    OperatorType d_from_ptr(new D_ContainerType(LA::createContainer(D_ContainerType(), dim)));
    OperatorType d_from_shared_ptr(std::make_shared< D_ContainerType >(LA::createContainer(D_ContainerType(), dim)));
    d_from_shared_ptr = d_from_ptr;
    OperatorType DUNE_UNUSED(d_copy_constructor)(d_from_ptr); // <- at this point, all operators share the same matrix!
    const bool d_linear = d_from_ptr.linear();
    if (!d_linear) DUNE_PYMOR_THROW(PymorException, "");
    if (d_from_ptr.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    const unsigned int d_dim_source = d_from_ptr.dim_source();
    if (d_dim_source != dim) DUNE_PYMOR_THROW(PymorException, d_dim_source);
    const unsigned int d_dim_range = d_from_ptr.dim_range();
    if (d_dim_range != dim) DUNE_PYMOR_THROW(PymorException, d_dim_range);
    D_SourceType source = LA::createContainer(D_SourceType(), dim);
    D_SourceType range = d_from_ptr.apply(source);
    d_from_ptr.apply(source, range);
    D_ScalarType DUNE_UNUSED(d_apply2) = d_from_ptr.apply2(range, source);
    std::vector< std::string > d_invert_options = d_from_ptr.invert_options();
    D_InverseType d_inverse = d_from_ptr.invert(d_invert_options[0]);
    d_inverse.apply(range, source);
    d_from_ptr.apply_inverse(source, range, d_invert_options[0]);
  }
}; // struct ContainerBasedOperatorTest

TYPED_TEST_CASE(ContainerBasedOperatorTest, ContainerBasedOperatorTypes);
TYPED_TEST(ContainerBasedOperatorTest, OPERATORS) {
  this->check();
}

template< class OperatorImp >
struct LinearAffinelyDecomposedContainerBasedOperatorTest
  : public ::testing::Test
{
  void check() const
  {
    // static tests
    typedef Operators::LinearAffinelyDecomposedContainerBased< OperatorImp > OperatorType;
    typedef typename OperatorType::Traits Traits;
    // * of the traits
    typedef typename Traits::derived_type T_derived_type;
    static_assert(std::is_same< OperatorType, T_derived_type >::value,
                  "OperatorType::Traits::derived_type is wrong!");
    typedef typename Traits::ComponentType ComponentType;
    // * of the class itself (aka the derived type)
    typedef typename OperatorType::ComponentType  D_ComponentType;
    typedef typename OperatorType::FrozenType     D_FrozenType;
    typedef typename OperatorType::ScalarType     D_ScalarType;
    typedef typename OperatorType::SourceType     D_SourceType;
    typedef typename OperatorType::RangeType      D_RangeType;
    typedef typename OperatorType::InverseType    D_InverseType;
    // * of the class as the interface
    typedef AffinelyDecomposedOperatorInterface< Traits > InterfaceType;
    typedef typename InterfaceType::derived_type I_derived_type;
    static_assert(std::is_same< OperatorType, I_derived_type >::value,
                  "InterfaceType::derived_type is wrong!");
    typedef typename InterfaceType::ComponentType I_ComponentType;
    typedef typename InterfaceType::FrozenType    I_FrozenType;
    typedef typename InterfaceType::ScalarType    I_ScalarType;
    typedef typename InterfaceType::SourceType    I_SourceType;
    typedef typename InterfaceType::RangeType     I_RangeType;
    typedef typename InterfaceType::InverseType   I_InverseType;
    // dynamic tests
    // * of the class itself (aka the derived type)
    typedef typename OperatorImp::ContainerType MatrixType;
    typedef LA::AffinelyDecomposedConstContainer< MatrixType > AffinelyDecomposedMatrixType;
    AffinelyDecomposedMatrixType affinelyDecomposedMatrix(new MatrixType(LA::createContainer(MatrixType(), dim)));
    affinelyDecomposedMatrix.register_component(new MatrixType((LA::createContainer(MatrixType(), dim))),
                                                new ParameterFunctional("diffusion", 1, "diffusion[0]"));
    affinelyDecomposedMatrix.register_component(new MatrixType((LA::createContainer(MatrixType(), dim))),
                                                new ParameterFunctional("force", 2, "force[0]"));
    const Parameter mu = {{"diffusion", "force"},
                          {{1.0}, {1.0, 1.0}}};
    if (affinelyDecomposedMatrix.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                                 = " << mu.type()
                       << "\naffinelyDecomposedMatrix.parameter_type() = "
                       << affinelyDecomposedMatrix.parameter_type());
    OperatorType d_operator(affinelyDecomposedMatrix);
    if (!d_operator.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    if (d_operator.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                   = " << mu.type()
                       << "\nd_operator.parameter_type() = " << d_operator.parameter_type());
    const unsigned int d_num_components = d_operator.num_components();
    if (d_num_components != 2) DUNE_PYMOR_THROW(PymorException, d_num_components);
    for (unsigned int qq = 0; qq < d_num_components; ++qq) {
      D_ComponentType component = d_operator.component(qq);
      if (component.parametric()) DUNE_PYMOR_THROW(PymorException, "");
      ParameterFunctional DUNE_UNUSED(coefficient) = d_operator.coefficient(qq);
    }
    if (!d_operator.has_affine_part()) DUNE_PYMOR_THROW(PymorException, "");
    D_ComponentType d_affine_part = d_operator.affine_part();
    if (d_affine_part.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    D_FrozenType d_frozen = d_operator.freeze_parameter(mu);
    if (d_frozen.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    D_SourceType d_source(dim, D_ScalarType(1));
    D_RangeType d_range = d_operator.apply(d_source, mu);
    D_RangeType d_frozen_apply = d_frozen.apply(d_source);
    if (!d_range.almost_equal(d_frozen_apply)) DUNE_PYMOR_THROW(PymorException, "");
    std::vector< std::string > d_invert_options = d_operator.invert_options();
    D_InverseType d_inverse = d_operator.invert(d_invert_options[0], mu);
    d_inverse.apply(d_range, d_source);
    d_operator.apply_inverse(d_source, d_range, d_invert_options[0], mu);
    // * of the class as the interface
    InterfaceType& i_operator = static_cast< InterfaceType& >(d_operator);
    if (!i_operator.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    if (i_operator.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                   = " << mu.type()
                       << "\ni_operator.parameter_type() = " << i_operator.parameter_type());
    const unsigned int i_num_components = i_operator.num_components();
    if (i_num_components != 2) DUNE_PYMOR_THROW(PymorException, i_num_components);
    for (unsigned int qq = 0; qq < i_num_components; ++qq) {
      I_ComponentType component = i_operator.component(qq);
      if (component.parametric()) DUNE_PYMOR_THROW(PymorException, "");
      ParameterFunctional DUNE_UNUSED(coefficient) = i_operator.coefficient(qq);
    }
    if (!i_operator.has_affine_part()) DUNE_PYMOR_THROW(PymorException, "");
    I_ComponentType i_affine_part = i_operator.affine_part();
    if (i_affine_part.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    I_FrozenType i_frozen = i_operator.freeze_parameter(mu);
    if (i_frozen.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    I_SourceType i_source(dim, I_ScalarType(1));
    I_RangeType i_range = i_operator.apply(i_source, mu);
    I_RangeType i_frozen_apply = i_frozen.apply(i_source);
    if (!i_range.almost_equal(i_frozen_apply)) DUNE_PYMOR_THROW(PymorException, "");
    std::vector< std::string > i_invert_options = i_operator.invert_options();
    I_InverseType i_inverse = i_operator.invert(i_invert_options[0], mu);
    i_inverse.apply(i_range, i_source);
    i_operator.apply_inverse(i_source, i_range, i_invert_options[0], mu);
  }
}; // struct LinearAffinelyDecomposedContainerBasedOperatorTest

TYPED_TEST_CASE(LinearAffinelyDecomposedContainerBasedOperatorTest, ContainerBasedOperatorTypes);
TYPED_TEST(LinearAffinelyDecomposedContainerBasedOperatorTest, OPERATORS) {
  this->check();
}

int main(int argc, char** argv)
{
//  try {
    test_init(argc, argv);
    return RUN_ALL_TESTS();
//  } catch (Dune::PymorException &e) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("dune-pymor reported: ") << e << std::endl;
//  } catch (Dune::Exception &e) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("Dune reported error: ") << e << std::endl;
//  } catch (...) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("Unknown exception thrown!") << std::endl;
//  }
}
<commit_msg>[test.operators]<commit_after>// This file is part of the dune-pymor project:
//   https://github.com/pyMor/dune-pymor
// Copyright Holders: Felix Albrecht, Stephan Rave
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#elif defined (HAVE_CONFIG_H)
  #include <config.h>
#endif // HAVE_CMAKE_CONFIG

#include <utility>
#include <type_traits>

#include <dune/stuff/test/test_common.hh>

#include <dune/common/float_cmp.hh>

#include <dune/pymor/common/exceptions.hh>
#include <dune/pymor/parameters/base.hh>
#include <dune/pymor/parameters/functional.hh>
#include <dune/pymor/la/container/dunedynamic.hh>
#include <dune/pymor/la/container.hh>
#include <dune/pymor/operators/interfaces.hh>
#include <dune/pymor/operators/affine.hh>
#include <dune/pymor/operators/dunedynamic.hh>
//#if HAVE_EIGEN
//  #include <dune/pymor/operators/eigen.hh>
//#endif
//#include <dune/pymor/operators.hh>

using namespace Dune;
using namespace Dune::Pymor;

static const size_t dim = 4;

typedef testing::Types<
                        Dune::Pymor::Operators::DuneDynamic< double >
//#if HAVE_EIGEN
//                      , std::pair< Dune::Pymor::Operators::EigenDenseMatrix,
//                                   Dune::Pymor::LA::EigenDenseVector >
//                      , std::pair< Dune::Pymor::Operators::EigenRowMajorSparseMatrix,
//                                   Dune::Pymor::LA::EigenDenseVector >
//#endif // HAVE_EIGEN
                      > ContainerBasedOperatorTypes;

template< class OperatorType >
struct ContainerBasedOperatorTest
  : public ::testing::Test
{
  void check() const
  {
    // static tests
    typedef typename OperatorType::Traits         Traits;
    // * of the traits
    typedef typename Traits::derived_type T_derived_type;
    static_assert(std::is_same< OperatorType, T_derived_type >::value,
                  "OperatorType::Traits::derived_type is wrong!");
    typedef typename Traits::SourceType   T_SourceType;
    typedef typename Traits::RangeType    T_RangeType;
    typedef typename Traits::ScalarType   T_ScalarType;
    typedef typename Traits::InverseType  T_InverseType;
    // * of the class itself (aka the derived type)
    typedef typename OperatorType::SourceType     D_SourceType;
    typedef typename OperatorType::RangeType      D_RangeType;
    typedef typename OperatorType::ScalarType     D_ScalarType;
    typedef typename OperatorType::InverseType    D_InverseType;
    typedef typename OperatorType::ContainerType  D_ContainerType;
    // * of the class as the operator interface
    typedef OperatorInterface< Traits >         InterfaceType;
    static_assert(std::is_base_of< OperatorInterface< Traits >, OperatorType >::value,
                  "OperatorType has to be derived from OperaotrInterface is wrong!");
    typedef typename InterfaceType::SourceType  I_SourceType;
    typedef typename InterfaceType::RangeType   I_RangeType;
    typedef typename InterfaceType::ScalarType  I_ScalarType;
    typedef typename InterfaceType::InverseType I_InverseType;
    // * of the class as the container interface
    static_assert(std::is_base_of< LA::ProvidesContainer< Traits >, OperatorType >::value,
                  "OperatorType has to be derived from LA::ProvidesContainer!");
    // dynamic tests
    // * of the class itself (aka the derived type)
    OperatorType d_from_ptr(new D_ContainerType(LA::createContainer(D_ContainerType(), dim)));
    OperatorType d_from_shared_ptr(std::make_shared< D_ContainerType >(LA::createContainer(D_ContainerType(), dim)));
    d_from_shared_ptr = d_from_ptr;
    OperatorType DUNE_UNUSED(d_copy_constructor)(d_from_ptr); // <- at this point, all operators share the same matrix!
    const bool d_linear = d_from_ptr.linear();
    if (!d_linear) DUNE_PYMOR_THROW(PymorException, "");
    if (d_from_ptr.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    const unsigned int d_dim_source = d_from_ptr.dim_source();
    if (d_dim_source != dim) DUNE_PYMOR_THROW(PymorException, d_dim_source);
    const unsigned int d_dim_range = d_from_ptr.dim_range();
    if (d_dim_range != dim) DUNE_PYMOR_THROW(PymorException, d_dim_range);
    D_SourceType source = LA::createContainer(D_SourceType(), dim);
    D_SourceType range = d_from_ptr.apply(source);
    d_from_ptr.apply(source, range);
    D_ScalarType DUNE_UNUSED(d_apply2) = d_from_ptr.apply2(range, source);
    std::vector< std::string > d_invert_options = d_from_ptr.invert_options();
    D_InverseType d_inverse = d_from_ptr.invert(d_invert_options[0]);
    d_inverse.apply(range, source);
    d_from_ptr.apply_inverse(source, range, d_invert_options[0]);
  }
}; // struct ContainerBasedOperatorTest

TYPED_TEST_CASE(ContainerBasedOperatorTest, ContainerBasedOperatorTypes);
TYPED_TEST(ContainerBasedOperatorTest, OPERATORS) {
  this->check();
}

template< class OperatorImp >
struct LinearAffinelyDecomposedContainerBasedOperatorTest
  : public ::testing::Test
{
  void check() const
  {
    // static tests
    typedef Operators::LinearAffinelyDecomposedContainerBased< OperatorImp > OperatorType;
    typedef typename OperatorType::Traits Traits;
    // * of the traits
    typedef typename Traits::derived_type T_derived_type;
    static_assert(std::is_same< OperatorType, T_derived_type >::value,
                  "OperatorType::Traits::derived_type is wrong!");
    typedef typename Traits::ComponentType ComponentType;
    // * of the class itself (aka the derived type)
    typedef typename OperatorType::ComponentType  D_ComponentType;
    typedef typename OperatorType::FrozenType     D_FrozenType;
    typedef typename OperatorType::ScalarType     D_ScalarType;
    typedef typename OperatorType::SourceType     D_SourceType;
    typedef typename OperatorType::RangeType      D_RangeType;
    typedef typename OperatorType::InverseType    D_InverseType;
    // * of the class as the interface
    typedef AffinelyDecomposedOperatorInterface< Traits > InterfaceType;
    typedef typename InterfaceType::derived_type I_derived_type;
    static_assert(std::is_same< OperatorType, I_derived_type >::value,
                  "InterfaceType::derived_type is wrong!");
    typedef typename InterfaceType::ComponentType I_ComponentType;
    typedef typename InterfaceType::FrozenType    I_FrozenType;
    typedef typename InterfaceType::ScalarType    I_ScalarType;
    typedef typename InterfaceType::SourceType    I_SourceType;
    typedef typename InterfaceType::RangeType     I_RangeType;
    typedef typename InterfaceType::InverseType   I_InverseType;
    // dynamic tests
    // * of the class itself (aka the derived type)
    typedef typename OperatorImp::ContainerType MatrixType;
    typedef LA::AffinelyDecomposedConstContainer< MatrixType > AffinelyDecomposedMatrixType;
    AffinelyDecomposedMatrixType affinelyDecomposedMatrix(new MatrixType(LA::createContainer(MatrixType(), dim)));
    affinelyDecomposedMatrix.register_component(new MatrixType((LA::createContainer(MatrixType(), dim))),
                                                new ParameterFunctional("diffusion", 1, "diffusion[0]"));
    affinelyDecomposedMatrix.register_component(new MatrixType((LA::createContainer(MatrixType(), dim))),
                                                new ParameterFunctional("force", 2, "force[0]"));
    const Parameter mu = {{"diffusion", "force"},
                          {{1.0}, {1.0, 1.0}}};
    if (affinelyDecomposedMatrix.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                                 = " << mu.type()
                       << "\naffinelyDecomposedMatrix.parameter_type() = "
                       << affinelyDecomposedMatrix.parameter_type());
    OperatorType d_operator(affinelyDecomposedMatrix);
    if (!d_operator.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    if (d_operator.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                   = " << mu.type()
                       << "\nd_operator.parameter_type() = " << d_operator.parameter_type());
    const unsigned int d_num_components = d_operator.num_components();
    if (d_num_components != 2) DUNE_PYMOR_THROW(PymorException, d_num_components);
    for (unsigned int qq = 0; qq < d_num_components; ++qq) {
      D_ComponentType component = d_operator.component(qq);
      if (component.parametric()) DUNE_PYMOR_THROW(PymorException, "");
      ParameterFunctional DUNE_UNUSED(coefficient) = d_operator.coefficient(qq);
    }
    if (!d_operator.has_affine_part()) DUNE_PYMOR_THROW(PymorException, "");
    D_ComponentType d_affine_part = d_operator.affine_part();
    if (d_affine_part.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    D_FrozenType d_frozen = d_operator.freeze_parameter(mu);
    if (d_frozen.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    D_SourceType d_source(dim, D_ScalarType(1));
    D_RangeType d_range = d_operator.apply(d_source, mu);
    D_RangeType d_frozen_apply = d_frozen.apply(d_source);
    if (!d_range.almost_equal(d_frozen_apply)) DUNE_PYMOR_THROW(PymorException, "");
    std::vector< std::string > d_invert_options = d_operator.invert_options();
    D_InverseType d_inverse = d_operator.invert(d_invert_options[0], mu);
    d_inverse.apply(d_range, d_source);
    d_operator.apply_inverse(d_source, d_range, d_invert_options[0], mu);
    // * of the class as the interface
    InterfaceType& i_operator = static_cast< InterfaceType& >(d_operator);
    if (!i_operator.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    if (i_operator.parameter_type() != mu.type())
      DUNE_PYMOR_THROW(PymorException,
                       "\nmu.type()                   = " << mu.type()
                       << "\ni_operator.parameter_type() = " << i_operator.parameter_type());
    const unsigned int i_num_components = i_operator.num_components();
    if (i_num_components != 2) DUNE_PYMOR_THROW(PymorException, i_num_components);
    for (unsigned int qq = 0; qq < i_num_components; ++qq) {
      I_ComponentType component = i_operator.component(qq);
      if (component.parametric()) DUNE_PYMOR_THROW(PymorException, "");
      ParameterFunctional DUNE_UNUSED(coefficient) = i_operator.coefficient(qq);
    }
    if (!i_operator.has_affine_part()) DUNE_PYMOR_THROW(PymorException, "");
    I_ComponentType i_affine_part = i_operator.affine_part();
    if (i_affine_part.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    I_FrozenType i_frozen = i_operator.freeze_parameter(mu);
    if (i_frozen.parametric()) DUNE_PYMOR_THROW(PymorException, "");
    I_SourceType i_source(dim, I_ScalarType(1));
    I_RangeType i_range = i_operator.apply(i_source, mu);
    I_RangeType i_frozen_apply = i_frozen.apply(i_source);
    if (!i_range.almost_equal(i_frozen_apply)) DUNE_PYMOR_THROW(PymorException, "");
    std::vector< std::string > i_invert_options = i_operator.invert_options();
    I_InverseType i_inverse = i_operator.invert(i_invert_options[0], mu);
    i_inverse.apply(i_range, i_source);
    i_operator.apply_inverse(i_source, i_range, i_invert_options[0], mu);
  }
}; // struct LinearAffinelyDecomposedContainerBasedOperatorTest

TYPED_TEST_CASE(LinearAffinelyDecomposedContainerBasedOperatorTest, ContainerBasedOperatorTypes);
TYPED_TEST(LinearAffinelyDecomposedContainerBasedOperatorTest, OPERATORS) {
  this->check();
}

int main(int argc, char** argv)
{
//  try {
    test_init(argc, argv);
    return RUN_ALL_TESTS();
//  } catch (Dune::PymorException &e) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("dune-pymor reported: ") << e << std::endl;
//  } catch (Dune::Exception &e) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("Dune reported error: ") << e << std::endl;
//  } catch (...) {
//    std::cerr << Dune::Stuff::Common::colorStringRed("Unknown exception thrown!") << std::endl;
//  }
}
<|endoftext|>


<commit_before>/**
 * @file crc32c.cpp
 * @brief Node.js bindings for CRC-32C calculation using hardware-acceleration, when available.
 *
 * The code below provides the bindings for the node-addon allowing for interfacing of C/C++ code with
 * JavaScript. It chooses between two versions of the CRC-32C calculator:
 * - The hardware-accelerated version that uses Intel's SSE 4.2 instructions, implemented in crc32c_sse42.cpp
 * - A table-lookup based CRC calculated implemented in software for non-Nehalam-based architectures
 *
 * NOTES:
 * - This code, though originally designed for little-endian hardware, should work for all platforms.
 * - Table-based CRC-32C implementation based on code by Mark Adler at http://stackoverflow.com/a/17646775.
 *
 * @author Anand Suresh <anandsuresh@gmail.com>
 */

#include <stdint.h>
#include <nan.h>

#include "crc32c.h"

using namespace v8;
using namespace node;

// Bit-mask for the SSE 4.2 flag in the CPU ID
#define SSE4_2_FLAG         0x100000

// The CRC-32C polynomial in reversed bit order
#define CRC32C_POLYNOMIAL   0x82f63b78

// Stores the CRC-32 lookup table for the software-fallback implementation
static uint32_t crc32cTable[8][256];

/**
 * Cross-platform CPU feature set detection to check for availability of hardware-based CRC-32C
 */
void cpuid(uint32_t op, uint32_t reg[4]) {
#if defined(_WIN64) || defined(_WIN32)
    #include <intrin.h>
    __cpuid((int *)reg, 1);
#elif defined(__x86_64__)
    __asm__ volatile(
        "pushq %%rbx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popq  %%rbx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#elif defined(__i386__)
    __asm__ volatile(
        "pushl %%ebx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popl  %%ebx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#else
    reg[0] = reg[1] = reg[2] = reg[3] = 0;
#endif
}

/**
 * Returns whether or not Intel's Streaming SIMD Extensions 4.2 is available on the hardware
 *
 * @return true if Intel's Streaming SIMD Extensions 4.2 are present; otherwise false
 */
bool isSSE42Available() {
    uint32_t reg[4];

    cpuid(1, reg);
    return ((reg[2] >> 20) & 1) == 1;
}

/**
 * Initializes the CRC-32C lookup table for software-based CRC calculation
 */
void initCrcTable() {
    uint32_t i, j, crc;

    for (i = 0; i < 256; i++) {
        crc = i;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc32cTable[0][i] = crc;
    }

    for (i = 0; i < 256; i++) {
        crc = crc32cTable[0][i];
        for (j = 1; j < 8; j++) {
            crc = crc32cTable[0][crc & 0xff] ^ (crc >> 8);
            crc32cTable[j][i] = crc;
        }
    }
}

/**
 * Calculates CRC-32C using the lookup table
 *
 * @param initialCrc The initial CRC to use for the operation
 * @param buf The buffer that stores the data whose CRC is to be calculated
 * @param len The size of the buffer
 * @return The CRC-32C of the data in the buffer
 */
uint32_t swCrc32c(uint32_t initialCrc, const char *buf, size_t len) {
    const char *next = buf;
    uint64_t crc = initialCrc;

    // If the string is empty, return 0
    if (len == 0) return (uint32_t)crc;

    // XOR the initial CRC with INT_MAX
    crc ^= 0xFFFFFFFF;

    // Process byte-by-byte until aligned to 8-byte boundary
    while (len && ((uintptr_t) next & 7) != 0) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // Process 8 bytes at a time
    while (len >= 8) {
        crc ^= *(uint64_t *) next;
        crc = crc32cTable[7][(crc >>  0) & 0xff] ^ crc32cTable[6][(crc >>  8) & 0xff]
            ^ crc32cTable[5][(crc >> 16) & 0xff] ^ crc32cTable[4][(crc >> 24) & 0xff]
            ^ crc32cTable[3][(crc >> 32) & 0xff] ^ crc32cTable[2][(crc >> 40) & 0xff]
            ^ crc32cTable[1][(crc >> 48) & 0xff] ^ crc32cTable[0][(crc >> 56)];
        next += 8;
        len -= 8;
    }

    // Process any remaining bytes
    while (len) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // XOR again with INT_MAX
    return (uint32_t)(crc ^= 0xFFFFFFFF);
}

/**
 * Returns whether or not hardware support is available for CRC calculation
 */
NAN_METHOD(isHardwareCrcSupported) {
    Nan::HandleScope scope;
    info.GetReturnValue().Set(Nan::New<Boolean>(isSSE42Available()));
}

/**
 * Calculates CRC-32C for the specified string/buffer
 */
NAN_METHOD(calculateCrc) {
    Nan::HandleScope scope;
    uint32_t initCrc;
    uint32_t crc;
    bool useHardwareCrc;

    // Ensure an argument is passed
    if (info.Length() < 1) {
        info.GetReturnValue().Set(Nan::New<Integer>(0));
    } else if (info.Length() > 3) {
        Nan::ThrowTypeError("Invalid number of arguments!");
        return;
    }

    // Check if the table-lookup is required
    if (!info[0]->IsBoolean()) {
        Nan::ThrowTypeError("useHardwareCrc isn't a boolean value as expected!");
        return;
    }
    useHardwareCrc = info[0]->BooleanValue();

    // Check for any initial CRC passed to the function
    if (info.Length() > 2) {
        if (!(info[2]->IsUint32())) {
            Nan::ThrowTypeError("Initial CRC-32C is not an integer value as expected!");
            return;
        }
        initCrc = info[2]->Uint32Value();
    } else {
        initCrc = 0;
    }

    // Ensure the argument is a buffer or a string
    if (node::Buffer::HasInstance(info[1])) {
        Local<Object> buf = info[1]->ToObject();

        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)Buffer::Data(buf), (size_t)Buffer::Length(buf));
        } else {
            crc = swCrc32c(initCrc, (const char *)Buffer::Data(buf), (size_t)Buffer::Length(buf));
        }
    } else if (info[1]->IsObject()) {
        Nan::ThrowTypeError("Cannot compute CRC-32C for objects!");
        return;
    } else {
        Local<String> strInput = info[1]->ToString();

        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)(*String::Utf8Value(strInput)), (size_t)strInput->Utf8Length());
        } else {
            crc = swCrc32c(initCrc, (const char *)(*String::Utf8Value(strInput)), (size_t)strInput->Utf8Length());
        }
    }

    // Calculate the 32-bit CRC
    info.GetReturnValue().Set(Nan::New<Uint32>(crc));
}

/**
 * Initialize the module
 */
void init(Local<Object> exports) {
    initCrcTable();

    Nan::SetMethod(exports, "isHardwareCrcSupported", isHardwareCrcSupported);
    Nan::SetMethod(exports, "calculateCrc", calculateCrc);
}

NODE_MODULE(sse4_crc32, init)
<commit_msg>Fix compilation with MSVS 2017<commit_after>/**
 * @file crc32c.cpp
 * @brief Node.js bindings for CRC-32C calculation using hardware-acceleration, when available.
 *
 * The code below provides the bindings for the node-addon allowing for interfacing of C/C++ code with
 * JavaScript. It chooses between two versions of the CRC-32C calculator:
 * - The hardware-accelerated version that uses Intel's SSE 4.2 instructions, implemented in crc32c_sse42.cpp
 * - A table-lookup based CRC calculated implemented in software for non-Nehalam-based architectures
 *
 * NOTES:
 * - This code, though originally designed for little-endian hardware, should work for all platforms.
 * - Table-based CRC-32C implementation based on code by Mark Adler at http://stackoverflow.com/a/17646775.
 *
 * @author Anand Suresh <anandsuresh@gmail.com>
 */

#include <stdint.h>
#include <nan.h>

#include "crc32c.h"

using namespace v8;
using namespace node;

// Bit-mask for the SSE 4.2 flag in the CPU ID
#define SSE4_2_FLAG         0x100000

// The CRC-32C polynomial in reversed bit order
#define CRC32C_POLYNOMIAL   0x82f63b78

// Stores the CRC-32 lookup table for the software-fallback implementation
static uint32_t crc32cTable[8][256];

/**
 * Cross-platform CPU feature set detection to check for availability of hardware-based CRC-32C
 */
#ifdef _MSC_VER
#include <intrin.h> // __cpuid
#endif
void cpuid(uint32_t op, uint32_t reg[4]) {
#if defined(_MSC_VER)
    __cpuid((int *)reg, 1);
#elif defined(__x86_64__)
    __asm__ volatile(
        "pushq %%rbx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popq  %%rbx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#elif defined(__i386__)
    __asm__ volatile(
        "pushl %%ebx       \n\t"
        "cpuid             \n\t"
        "movl  %%ebx, %1   \n\t"
        "popl  %%ebx       \n\t"
        : "=a"(reg[0]), "=r"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
        : "a"(op)
        : "cc");
#else
    reg[0] = reg[1] = reg[2] = reg[3] = 0;
#endif
}

/**
 * Returns whether or not Intel's Streaming SIMD Extensions 4.2 is available on the hardware
 *
 * @return true if Intel's Streaming SIMD Extensions 4.2 are present; otherwise false
 */
bool isSSE42Available() {
    uint32_t reg[4];

    cpuid(1, reg);
    return ((reg[2] >> 20) & 1) == 1;
}

/**
 * Initializes the CRC-32C lookup table for software-based CRC calculation
 */
void initCrcTable() {
    uint32_t i, j, crc;

    for (i = 0; i < 256; i++) {
        crc = i;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLYNOMIAL : crc >> 1;
        crc32cTable[0][i] = crc;
    }

    for (i = 0; i < 256; i++) {
        crc = crc32cTable[0][i];
        for (j = 1; j < 8; j++) {
            crc = crc32cTable[0][crc & 0xff] ^ (crc >> 8);
            crc32cTable[j][i] = crc;
        }
    }
}

/**
 * Calculates CRC-32C using the lookup table
 *
 * @param initialCrc The initial CRC to use for the operation
 * @param buf The buffer that stores the data whose CRC is to be calculated
 * @param len The size of the buffer
 * @return The CRC-32C of the data in the buffer
 */
uint32_t swCrc32c(uint32_t initialCrc, const char *buf, size_t len) {
    const char *next = buf;
    uint64_t crc = initialCrc;

    // If the string is empty, return 0
    if (len == 0) return (uint32_t)crc;

    // XOR the initial CRC with INT_MAX
    crc ^= 0xFFFFFFFF;

    // Process byte-by-byte until aligned to 8-byte boundary
    while (len && ((uintptr_t) next & 7) != 0) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // Process 8 bytes at a time
    while (len >= 8) {
        crc ^= *(uint64_t *) next;
        crc = crc32cTable[7][(crc >>  0) & 0xff] ^ crc32cTable[6][(crc >>  8) & 0xff]
            ^ crc32cTable[5][(crc >> 16) & 0xff] ^ crc32cTable[4][(crc >> 24) & 0xff]
            ^ crc32cTable[3][(crc >> 32) & 0xff] ^ crc32cTable[2][(crc >> 40) & 0xff]
            ^ crc32cTable[1][(crc >> 48) & 0xff] ^ crc32cTable[0][(crc >> 56)];
        next += 8;
        len -= 8;
    }

    // Process any remaining bytes
    while (len) {
        crc = crc32cTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8);
        len--;
    }

    // XOR again with INT_MAX
    return (uint32_t)(crc ^= 0xFFFFFFFF);
}

/**
 * Returns whether or not hardware support is available for CRC calculation
 */
NAN_METHOD(isHardwareCrcSupported) {
    Nan::HandleScope scope;
    info.GetReturnValue().Set(Nan::New<Boolean>(isSSE42Available()));
}

/**
 * Calculates CRC-32C for the specified string/buffer
 */
NAN_METHOD(calculateCrc) {
    Nan::HandleScope scope;
    uint32_t initCrc;
    uint32_t crc;
    bool useHardwareCrc;

    // Ensure an argument is passed
    if (info.Length() < 1) {
        info.GetReturnValue().Set(Nan::New<Integer>(0));
    } else if (info.Length() > 3) {
        Nan::ThrowTypeError("Invalid number of arguments!");
        return;
    }

    // Check if the table-lookup is required
    if (!info[0]->IsBoolean()) {
        Nan::ThrowTypeError("useHardwareCrc isn't a boolean value as expected!");
        return;
    }
    useHardwareCrc = info[0]->BooleanValue();

    // Check for any initial CRC passed to the function
    if (info.Length() > 2) {
        if (!(info[2]->IsUint32())) {
            Nan::ThrowTypeError("Initial CRC-32C is not an integer value as expected!");
            return;
        }
        initCrc = info[2]->Uint32Value();
    } else {
        initCrc = 0;
    }

    // Ensure the argument is a buffer or a string
    if (node::Buffer::HasInstance(info[1])) {
        Local<Object> buf = info[1]->ToObject();

        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)Buffer::Data(buf), (size_t)Buffer::Length(buf));
        } else {
            crc = swCrc32c(initCrc, (const char *)Buffer::Data(buf), (size_t)Buffer::Length(buf));
        }
    } else if (info[1]->IsObject()) {
        Nan::ThrowTypeError("Cannot compute CRC-32C for objects!");
        return;
    } else {
        Local<String> strInput = info[1]->ToString();

        if (useHardwareCrc) {
            crc = hwCrc32c(initCrc, (const char *)(*String::Utf8Value(strInput)), (size_t)strInput->Utf8Length());
        } else {
            crc = swCrc32c(initCrc, (const char *)(*String::Utf8Value(strInput)), (size_t)strInput->Utf8Length());
        }
    }

    // Calculate the 32-bit CRC
    info.GetReturnValue().Set(Nan::New<Uint32>(crc));
}

/**
 * Initialize the module
 */
void init(Local<Object> exports) {
    initCrcTable();

    Nan::SetMethod(exports, "isHardwareCrcSupported", isHardwareCrcSupported);
    Nan::SetMethod(exports, "calculateCrc", calculateCrc);
}

NODE_MODULE(sse4_crc32, init)
<|endoftext|>


<commit_before>// -*- compile-command: "g++ -std=c++11 -Wall -Werror -Weffc++ -pedantic -DINCLUDE_CTYPER_MAIN `mysql_config --cflags` -o ctyper ctyper.cpp `mysql_config --libs`" -*-

#include "ctyper.hpp"
#include <assert.h>

CTyper CTyper::s_instance;
const char* _CType::s_allowed_types = "ijklIJKLntdfsb";

/**
 * @brief Array of type bundles so a single search yields complete type information.
 *
 * I had too many switch statements to get iclass_casters, MYSQL_TYPEs,
 * type names, etc.  I created the CTyper class to provide access to these
 * _CType instances so a program can get everything it needs to deal with
 * a data object with a once-and-for-all search.
 *
 * The array elements are arranged so that the first group of elements
 * match to unique class_types (vclasses.hpp) enumerations.
 *
 * Following the first group of unique types are other types that use the
 * same iclass_caster under different names.  Searches using these alternate
 * names will return an appropriate set of values for accessing the data.
 *
 * I used the SQL script get_possible_param_types.sql to create the list of
 * types that I wanted to match.
 */
const _CType CTyper::s_types[] = {
   { MYSQL_TYPE_TINY, false, CT_INT_TINY, _CType::TYPE_TINY,
     sizeof(int8_t), ai_tiny::cast_and_use, "BOOL", "bool",
     "boolean", "boolean-value" },

   { MYSQL_TYPE_TINY, false, CT_INT_TINY, _CType::TYPE_TINY,
     sizeof(int8_t), ai_tiny::cast_and_use, "TINYINT", "tinyint",
     "float", "value"},
   { MYSQL_TYPE_TINY, true, CT_UINT_TINY, _CType::TYPE_UTINY,
     sizeof(int8_t), ai_utiny::cast_and_use, "TINYINT", "tinyint",
     "float", "value"},

   { MYSQL_TYPE_SHORT, false, CT_INT_SHORT, _CType::TYPE_SHORT,
     sizeof(int16_t), ai_short::cast_and_use, "SMALLINT", "shortint",
     "float", "value"},
   { MYSQL_TYPE_SHORT, true, CT_UINT_SHORT, _CType::TYPE_USHORT,
     sizeof(int16_t), ai_ushort::cast_and_use, "SMALLINT", "shortint",
     "float", "value"},

   { MYSQL_TYPE_LONG, false, CT_INT_LONG, _CType::TYPE_LONG,
     sizeof(int32_t), ai_long::cast_and_use, "INT", "int",
     "float", "value"},
   { MYSQL_TYPE_LONG, true, CT_UINT_LONG, _CType::TYPE_ULONG,
     sizeof(int32_t), ai_ulong::cast_and_use, "INT", "int",
     "float", "value"},

   { MYSQL_TYPE_LONGLONG, false, CT_INT_LONGLONG, _CType::TYPE_LONGLONG,
     sizeof(int64_t), ai_longlong::cast_and_use, "BIGINT", "bigint",
     "float", "value"},
   { MYSQL_TYPE_LONGLONG, true, CT_UINT_LONGLONG, _CType::TYPE_ULONGLONG,
     sizeof(int64_t), ai_ulonglong::cast_and_use, "BIGINT", "bigint",
     "float", "value"},

   { MYSQL_TYPE_FLOAT, false, CT_FLOAT_FLOAT, _CType::TYPE_FLOAT,
     sizeof(float), ai_float::cast_and_use, "FLOAT", "float",
     "float", "value"},
   { MYSQL_TYPE_DOUBLE, false, CT_FLOAT_DOUBLE, _CType::TYPE_DOUBLE,
     sizeof(double), ai_double::cast_and_use, "DOUBLE", "double",
     "float", "value"},

   { MYSQL_TYPE_DATE, false, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "DATE", "date",
     "date", "date-value" },
   { MYSQL_TYPE_TIME, false, CT_TIME_TIME, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "TIME", "time",
     "time", "time-value" },
   { MYSQL_TYPE_DATETIME, false, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "DATETIME", "datetime",
     "date", "date-value" },
   { MYSQL_TYPE_TIMESTAMP, true, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "TIMESTAMP", "timestamp",
     "date", "date-value" },

   { MYSQL_TYPE_VAR_STRING, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "VARCHAR", "varchar",
     "string", nullptr },

   // The following have less common unique names, and use one of the
   // iclass_casters in the above elements.

   // YEAR is a short:
   { MYSQL_TYPE_YEAR, true, CT_INT_SHORT, _CType::TYPE_SHORT,
     sizeof(int16_t), ai_short::cast_and_use, "YEAR", "year",
     "float", "value"},

   // Types that are represented by a string:
   { MYSQL_TYPE_VARCHAR, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "VARCHAR", "varchar",
     "string", nullptr },
   { MYSQL_TYPE_STRING, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "CHAR", "char",
     "string", nullptr },

   // There are no MYSQL_TYPE_TEXTs, only MYSQL_TYPE_BLOBs,
   // despite parameter data_types text/blob, tinytext/tinyblob, etc.
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TEXT", "text",
     "string", nullptr },
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINYTEXT", "tinytext",
     "string", nullptr },
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINYBLOB", "tinyblob",
     nullptr, nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUMTEXT", "mediumtext",
     "string", nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUMBLOB", "mediumblob",
     nullptr, nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONGTEXT", "longtext",
     "string", nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONGBLOB", "longblob",
     nullptr, nullptr },

   { MYSQL_TYPE_ENUM, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "ENUM", "enum" },
   { MYSQL_TYPE_SET, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "SET", "set" },
   { MYSQL_TYPE_DECIMAL, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "DECIMAL", "decimal",
     "float", "value"},
   { MYSQL_TYPE_NEWDECIMAL, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "DECIMAL", "decimal",
     "float", "value"},
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINY_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUM_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONG_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "BLOB", "blob",
     nullptr, nullptr },

   { MYSQL_TYPE_NULL, false, CT_NULL, _CType::TYPE_NULL,
     0, ai_text::cast_and_use, "NULL", "null",
     nullptr, nullptr },

   // skipping MYSQL_TYPE_INT24, MYSQL_TYPE_BIT, and MYSQL_TYPE_GEOMETRY
};

const int CTyper::s_count = sizeof(CTyper::s_types) / sizeof(_CType);
const _CType* CTyper::s_end = &s_types[CTyper::s_count];

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(_CType::Types t)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_stype==t)
         return ptr;
      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown _CType::Types==%c", static_cast<char>(t));
   throw std::runtime_error(buff);
}

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(class_types t)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_ctype==t)
         return ptr;
      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown class_types==%d", t);
   throw std::runtime_error(buff);
}

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(enum_field_types t, bool is_unsigned)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_sqltype==t && ptr->m_is_unsigned==is_unsigned)
         return ptr;

      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown enum_field_types==%d", t);
   throw std::runtime_error(buff);
}

/**
 * @brief A getter function that works with information_schema.PARAMETERS fields.
 *
 * The data_type parameter is sufficient, except for integers that might be
 * unsigned.  If the last three characters of data_type are "int", we look
 * compare the final 8 characters of dtd_identifier with "unsigned" to decide
 * if the type is unsigned.
 *
 * The unsigned characteristic is not important for lengths (uint16_t is the
 * same length as int16_t), so it is OK to
 */
const _CType *CTyper::get(const char *data_type, const char *dtd_identifier)
{
   bool is_unsigned = false;
   const _CType *ptr = s_types;

   if (dtd_identifier && strncmp(dtd_identifier,"tinyint(1)",10)==0)
   {
      // This should be the first in the list, scan list just in case:
      while (ptr < s_end)
      {
         if (0==strcmp("bool", ptr->m_param_data_type))
            return ptr;
         ++ptr;
      }

   }

   // A null dtd_identifier means we're not checking for signed, so check
   // it first as a short-circuit for the conditional:
   if (dtd_identifier && strstr(data_type,"int") && strstr(dtd_identifier,"unsigned"))
      is_unsigned = true;

   while (ptr < s_end)
   {
      if (0==strcmp(data_type, ptr->m_param_data_type))
         if (ptr->m_is_unsigned==is_unsigned)
            return ptr;

      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown data_type==\"%s\"", data_type);
   throw std::runtime_error(buff);
}

/**
 * @brief Make a type string from an array.
 */
void t_make_typestr(const IClass **array,
                    int len_array,
                    const IGeneric_String_Callback &gsc)
{
   const _CType *ct;
   const IClass **alimit = array + len_array;
   int len_typestr = 0;

   for (const IClass **aptr=array; aptr<alimit; aptr++)
   {
      ++len_typestr;

      if ((*aptr)->vtype()==CT_STRING_TEXT)
      {
         size_t len = (*aptr)->data_length();
         size_t comp = 10;
         // count digits needed to represent len, up to 99,999:
         for (int i=1;  i<6;  ++i, comp*=10)
            if (len<comp)
            {
               len_typestr += i;
               break;
            }
         // Longer than 5 digits should leave length unspecified
      }
   }

   if (len_typestr)
   {
      char *typestr = static_cast<char*>(alloca(len_typestr+1));
      char *tptr = typestr;

      for (const IClass **aptr=array; aptr<alimit; aptr++)
      {
         if ((ct=CTyper::get(*aptr)))
         {
            *tptr = ct->get_stype();
            if (*tptr=='s')
            {
               ++tptr;
               size_t len = (*aptr)->data_length();
               // Match limit above, up to 5-digits, to prevent buffer overflow
               if (len < 100000)
                  tptr += sprintf(tptr, "%lu", len);
            }
            else
               ++tptr;
         }
      }

      // Assert accurate length calculation:
      assert(tptr == typestr+len_typestr);

      *tptr = '\0';

      gsc(typestr);
   }
   else
      gsc("");
}

#ifdef INCLUDE_CTYPER_MAIN
#include <stdio.h>
#include "vclasses.cpp"
#include "prandstr.cpp"

int main(int argc, char** argv)
{
   return 0;
}

#endif

<commit_msg>Reorganize code to add (and remove) case for DECIMAL data type (which was handled elsewhere).<commit_after>// -*- compile-command: "g++ -std=c++11 -Wall -Werror -Weffc++ -pedantic -DINCLUDE_CTYPER_MAIN `mysql_config --cflags` -o ctyper ctyper.cpp `mysql_config --libs`" -*-

#include "ctyper.hpp"
#include <assert.h>

CTyper CTyper::s_instance;
const char* _CType::s_allowed_types = "ijklIJKLntdfsb";

/**
 * @brief Array of type bundles so a single search yields complete type information.
 *
 * I had too many switch statements to get iclass_casters, MYSQL_TYPEs,
 * type names, etc.  I created the CTyper class to provide access to these
 * _CType instances so a program can get everything it needs to deal with
 * a data object with a once-and-for-all search.
 *
 * The array elements are arranged so that the first group of elements
 * match to unique class_types (vclasses.hpp) enumerations.
 *
 * Following the first group of unique types are other types that use the
 * same iclass_caster under different names.  Searches using these alternate
 * names will return an appropriate set of values for accessing the data.
 *
 * I used the SQL script get_possible_param_types.sql to create the list of
 * types that I wanted to match.
 */
const _CType CTyper::s_types[] = {
   { MYSQL_TYPE_TINY, false, CT_INT_TINY, _CType::TYPE_TINY,
     sizeof(int8_t), ai_tiny::cast_and_use, "BOOL", "bool",
     "boolean", "boolean-value" },

   { MYSQL_TYPE_TINY, false, CT_INT_TINY, _CType::TYPE_TINY,
     sizeof(int8_t), ai_tiny::cast_and_use, "TINYINT", "tinyint",
     "float", "value"},
   { MYSQL_TYPE_TINY, true, CT_UINT_TINY, _CType::TYPE_UTINY,
     sizeof(int8_t), ai_utiny::cast_and_use, "TINYINT", "tinyint",
     "float", "value"},

   { MYSQL_TYPE_SHORT, false, CT_INT_SHORT, _CType::TYPE_SHORT,
     sizeof(int16_t), ai_short::cast_and_use, "SMALLINT", "shortint",
     "float", "value"},
   { MYSQL_TYPE_SHORT, true, CT_UINT_SHORT, _CType::TYPE_USHORT,
     sizeof(int16_t), ai_ushort::cast_and_use, "SMALLINT", "shortint",
     "float", "value"},

   { MYSQL_TYPE_LONG, false, CT_INT_LONG, _CType::TYPE_LONG,
     sizeof(int32_t), ai_long::cast_and_use, "INT", "int",
     "float", "value"},
   { MYSQL_TYPE_LONG, true, CT_UINT_LONG, _CType::TYPE_ULONG,
     sizeof(int32_t), ai_ulong::cast_and_use, "INT", "int",
     "float", "value"},

   { MYSQL_TYPE_LONGLONG, false, CT_INT_LONGLONG, _CType::TYPE_LONGLONG,
     sizeof(int64_t), ai_longlong::cast_and_use, "BIGINT", "bigint",
     "float", "value"},
   { MYSQL_TYPE_LONGLONG, true, CT_UINT_LONGLONG, _CType::TYPE_ULONGLONG,
     sizeof(int64_t), ai_ulonglong::cast_and_use, "BIGINT", "bigint",
     "float", "value"},

   { MYSQL_TYPE_FLOAT, false, CT_FLOAT_FLOAT, _CType::TYPE_FLOAT,
     sizeof(float), ai_float::cast_and_use, "FLOAT", "float",
     "float", "value"},
   { MYSQL_TYPE_DOUBLE, false, CT_FLOAT_DOUBLE, _CType::TYPE_DOUBLE,
     sizeof(double), ai_double::cast_and_use, "DOUBLE", "double",
     "float", "value"},

   { MYSQL_TYPE_DATE, false, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "DATE", "date",
     "date", "date-value" },
   { MYSQL_TYPE_TIME, false, CT_TIME_TIME, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "TIME", "time",
     "time", "time-value" },
   { MYSQL_TYPE_DATETIME, false, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "DATETIME", "datetime",
     "date", "date-value" },
   { MYSQL_TYPE_TIMESTAMP, true, CT_TIME_DATE, _CType::TYPE_TIME,
     sizeof(MYSQL_TIME), ai_date::cast_and_use, "TIMESTAMP", "timestamp",
     "date", "date-value" },

   { MYSQL_TYPE_VAR_STRING, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "VARCHAR", "varchar",
     "string", nullptr },

   // The following have less common unique names, and use one of the
   // iclass_casters in the above elements.

   // YEAR is a short:
   { MYSQL_TYPE_YEAR, true, CT_INT_SHORT, _CType::TYPE_SHORT,
     sizeof(int16_t), ai_short::cast_and_use, "YEAR", "year",
     "float", "value"},

   // Types that are represented by a string:
   { MYSQL_TYPE_VARCHAR, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "VARCHAR", "varchar",
     "string", nullptr },
   { MYSQL_TYPE_STRING, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "CHAR", "char",
     "string", nullptr },

   // There are no MYSQL_TYPE_TEXTs, only MYSQL_TYPE_BLOBs,
   // despite parameter data_types text/blob, tinytext/tinyblob, etc.
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TEXT", "text",
     "string", nullptr },
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINYTEXT", "tinytext",
     "string", nullptr },
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINYBLOB", "tinyblob",
     nullptr, nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUMTEXT", "mediumtext",
     "string", nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUMBLOB", "mediumblob",
     nullptr, nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONGTEXT", "longtext",
     "string", nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONGBLOB", "longblob",
     nullptr, nullptr },

   { MYSQL_TYPE_ENUM, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "ENUM", "enum" },
   { MYSQL_TYPE_SET, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "SET", "set" },
   { MYSQL_TYPE_DECIMAL, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "DECIMAL", "decimal",
     "float", "value"},
   { MYSQL_TYPE_NEWDECIMAL, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "DECIMAL", "decimal",
     "float", "value"},
   { MYSQL_TYPE_TINY_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "TINY_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_MEDIUM_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "MEDIUM_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_LONG_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "LONG_BLOB", "blob",
     nullptr, nullptr },
   { MYSQL_TYPE_BLOB, false, CT_STRING_TEXT, _CType::TYPE_STRING,
     0, ai_text::cast_and_use, "BLOB", "blob",
     nullptr, nullptr },

   { MYSQL_TYPE_NULL, false, CT_NULL, _CType::TYPE_NULL,
     0, ai_text::cast_and_use, "NULL", "null",
     nullptr, nullptr },

   // skipping MYSQL_TYPE_INT24, MYSQL_TYPE_BIT, and MYSQL_TYPE_GEOMETRY
};

const int CTyper::s_count = sizeof(CTyper::s_types) / sizeof(_CType);
const _CType* CTyper::s_end = &s_types[CTyper::s_count];

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(_CType::Types t)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_stype==t)
         return ptr;
      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown _CType::Types==%c", static_cast<char>(t));
   throw std::runtime_error(buff);
}

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(class_types t)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_ctype==t)
         return ptr;
      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown class_types==%d", t);
   throw std::runtime_error(buff);
}

/**
 * @brief Return a _CType object from the array.  Throw if not found.
 *
 * @todo It would be more efficient to jump out or inline to avoid allocating memory for buff.
 */
const _CType *CTyper::get(enum_field_types t, bool is_unsigned)
{
   const _CType *ptr = s_types;
   while (ptr < s_end)
   {
      if (ptr->m_sqltype==t && ptr->m_is_unsigned==is_unsigned)
         return ptr;

      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown enum_field_types==%d", t);
   throw std::runtime_error(buff);
}

/**
 * @brief A getter function that works with information_schema.PARAMETERS fields.
 *
 * The data_type parameter is sufficient, except for integers that might be
 * unsigned.  If the last three characters of data_type are "int", we look
 * compare the final 8 characters of dtd_identifier with "unsigned" to decide
 * if the type is unsigned.
 *
 * The unsigned characteristic is not important for lengths (uint16_t is the
 * same length as int16_t), so it is OK to
 */
const _CType *CTyper::get(const char *data_type, const char *dtd_identifier)
{
   bool is_unsigned = false;
   const _CType *ptr = s_types;

   if (dtd_identifier)
   {
      if (strncmp(dtd_identifier,"tinyint(1)",10)==0)
      {
         // This should be the first in the list, scan list just in case:
         while (ptr < s_end)
         {
            if (0==strcmp("bool", ptr->m_param_data_type))
               return ptr;
            ++ptr;
         }
      }
      // A null dtd_identifier means we're not checking for signed, so check
      // it first as a short-circuit for the conditional:
      else if (strstr(data_type,"int") && strstr(dtd_identifier,"unsigned"))
         is_unsigned = true;
   }

   while (ptr < s_end)
   {
      if (0==strcmp(data_type, ptr->m_param_data_type))
         if (ptr->m_is_unsigned==is_unsigned)
            return ptr;

      ++ptr;
   }

   char buff[80];
   snprintf(buff, 80, "CTyper attempted to get unknown data_type==\"%s\"", data_type);
   throw std::runtime_error(buff);
}

/**
 * @brief Make a type string from an array.
 */
void t_make_typestr(const IClass **array,
                    int len_array,
                    const IGeneric_String_Callback &gsc)
{
   const _CType *ct;
   const IClass **alimit = array + len_array;
   int len_typestr = 0;

   for (const IClass **aptr=array; aptr<alimit; aptr++)
   {
      ++len_typestr;

      if ((*aptr)->vtype()==CT_STRING_TEXT)
      {
         size_t len = (*aptr)->data_length();
         size_t comp = 10;
         // count digits needed to represent len, up to 99,999:
         for (int i=1;  i<6;  ++i, comp*=10)
            if (len<comp)
            {
               len_typestr += i;
               break;
            }
         // Longer than 5 digits should leave length unspecified
      }
   }

   if (len_typestr)
   {
      char *typestr = static_cast<char*>(alloca(len_typestr+1));
      char *tptr = typestr;

      for (const IClass **aptr=array; aptr<alimit; aptr++)
      {
         if ((ct=CTyper::get(*aptr)))
         {
            *tptr = ct->get_stype();
            if (*tptr=='s')
            {
               ++tptr;
               size_t len = (*aptr)->data_length();
               // Match limit above, up to 5-digits, to prevent buffer overflow
               if (len < 100000)
                  tptr += sprintf(tptr, "%lu", len);
            }
            else
               ++tptr;
         }
      }

      // Assert accurate length calculation:
      assert(tptr == typestr+len_typestr);

      *tptr = '\0';

      gsc(typestr);
   }
   else
      gsc("");
}

#ifdef INCLUDE_CTYPER_MAIN
#include <stdio.h>
#include "vclasses.cpp"
#include "prandstr.cpp"

int main(int argc, char** argv)
{
   return 0;
}

#endif

<|endoftext|>


<commit_before>//
//  Testing.cpp
//  BattleShip
//
//  Created by Erik Talvi on 3/21/14.
//  Copyright (c) 2014 Prodigy. All rights reserved.
//

#define CATCH_CONFIG_MAIN // This tells Catch to provide main() - only do this in one cpp file
#include "catch.hpp"
#include <vector>
#include "ShipStrucs.h"

bool shipExists(std::vector<int> holes)
{
    int temp = holes[0];
    bool verticalBool = true;
    bool horizontalBool = true;

    if (temp > 100 || temp < 1)
    {
        verticalBool = false;
        horizontalBool = false;
    }
    for (int i = 1; i < holes.size(); i++)
    {
        if(holes[i] != temp+1 && horizontalBool)
            horizontalBool = false;

        if(holes[i] != temp+10 && verticalBool)
            verticalBool = false;

        temp = holes[i];

        if (temp > 100 || temp < 1)
        {
            verticalBool = false;
            horizontalBool = false;
        }

    }

    return (verticalBool || horizontalBool);
}

TEST_CASE ( "BATTLESHIP TESTING", "[submarineExists]" )
{
    vector<int> horizontalGood {1,2,3,4,5};
    vector<int> horzontalBad {1,3,5,7,8};
    vector<int> verticalGood {1,11,21,31,41};
    vector<int> verticalBad {1,3,7,6,5};
    vector<int> outOfBounds {-2,-1,0,1,2};
    vector<int> outOfBounds2 {81,91,101};

    REQUIRE( shipExists(horizontalGood) );
    REQUIRE( !shipExists(horzontalBad) );
    REQUIRE( shipExists(verticalGood) );
    REQUIRE( !shipExists(verticalBad) );
    REQUIRE( !shipExists(outOfBounds) );
    REQUIRE( !shipExists(outOfBounds2) );

}

<commit_msg>Refactored shipExists to isLegalShip and made separate function for boundary checking called isOutOfBounds…<commit_after>//
//  Testing.cpp
//  BattleShip
//
//  Created by Erik Talvi on 3/21/14.
//  Copyright (c) 2014 Prodigy. All rights reserved.
//

#define CATCH_CONFIG_MAIN // This tells Catch to provide main() - only do this in one cpp file
#include "catch.hpp"
#include <vector>
#include "ShipStrucs.h"

bool isOutOfBounds(int hole)
{
    return (hole > 100 || hole < 1);

}

bool isLegalShip(std::vector<int> holes)
{
    int temp = holes[0];
    bool isVerticalShip = isOutOfBounds(temp);
    bool isHorizontalShip = isOutOfBounds(temp);

    for (int i = 1; i < holes.size(); i++)
    {
        if(holes[i] != temp+1 && isHorizontalShip)
            isHorizontalShip = false;

        if(holes[i] != temp+10 && isVerticalShip)
            isVerticalShip = false;

        temp = holes[i];

        isVerticalShip = isOutOfBounds(temp);
        isHorizontalShip = isOutOfBounds(temp);

    }

    return (isVerticalShip || isHorizontalShip);
}

TEST_CASE ( "BATTLESHIP TESTING", "[submarineExists]" )
{
    vector<int> horizontalGood {1,2,3,4,5};
    vector<int> horzontalBad {1,3,5,7,8};
    vector<int> verticalGood {1,11,21,31,41};
    vector<int> verticalBad {1,3,7,6,5};
    vector<int> outOfBounds {-2,-1,0,1,2};
    vector<int> outOfBounds2 {81,91,101};

    REQUIRE( isLegalShip(horizontalGood) );
    REQUIRE( !isLegalShip(horzontalBad) );
    REQUIRE( isLegalShip(verticalGood) );
    REQUIRE( !isLegalShip(verticalBad) );
    REQUIRE( !isLegalShip(outOfBounds) );
    REQUIRE( !isLegalShip(outOfBounds2) );

}

<|endoftext|>