<commit_before>/**
 * Provides a class that manages properties for some class (e.g. IEntity). By
 * providing a PropertyManager class, other classes can easily add a flexible
 * property management system if desired.
 *
 * @file include/GQE/Entity/classes/PropertyManager.hpp
 * @author Jacob Dix
 * @date 20120615 - Initial Release
 */
#ifndef PROPERTY_MANAGER_HPP_INCLUDED
#define PROPERTY_MANAGER_HPP_INCLUDED

#include <map>
#include <typeinfo>
#include <GQE/Core/loggers/Log_macros.hpp>
#include <GQE/Entity/interfaces/IProperty.hpp>
#include <GQE/Entity/interfaces/TProperty.hpp>
#include <GQE/Core/Core_types.hpp>
#include <GQE/Entity/Entity_types.hpp>

namespace GQE
{
  /// Provides the PropertyManager class for managing IProperty classes
  class GQE_API PropertyManager
  {
    public:
      /**
       * PropertyManager default constructor
       */
      PropertyManager();

      /**
       * PropertyManager deconstructor
       */
      virtual ~PropertyManager();

      /**
       * HasProperty returs true if thePropertyID specified exists in this
       * PropertyManager.
       * @param[in] thePropertyID to lookup in this PropertyManager
       * @return true if thePropertyID exists, false otherwise
       */
      bool HasID(const typePropertyID thePropertyID);

      /**
       * GetProperty returns the property as type with the ID of thePropertyID.
       * @param[in] thePropertyID is the ID of the property to return.
       * @return the value stored in the found propery in the form of TYPE. If no
       * Property was found it returns the default value the type constructor.
       */
      template<class TYPE>
      TYPE Get(const typePropertyID thePropertyID)
      {
        if(mList.find(thePropertyID) != mList.end())
        {
          if(mList.at(thePropertyID)->GetType()->Name() == typeid(TYPE).name())
            return static_cast<TProperty<TYPE>*>(mList[thePropertyID])->GetValue();
        }
        else
        {
          WLOG() << "PropertyManager:GetProperty() returning blank property("
            << thePropertyID << ") type" << std::endl;
        }
        TYPE anReturn=TYPE();
        return anReturn;
      }

      /**
       * SetProperty sets the property with the ID of thePropertyID to theValue.
       * @param[in] thePropertyID is the ID of the property to set.
       * @param[in] theValue is the value to set.
       */
      template<class TYPE>
      void Set(const typePropertyID thePropertyID, TYPE theValue)
      {
        if(mList.find(thePropertyID) != mList.end())
        {
          if(mList.at(thePropertyID)->GetType()->Name() == typeid(TYPE).name())
          {
            static_cast<TProperty<TYPE>*>(mList[thePropertyID])->SetValue(theValue);
          }
        }
        else
        {
          ELOG() << "PropertyManager:SetProperty() unable to find property("
            << thePropertyID << ")" << std::endl;
        }
      }

      /**
       * AddProperty Creates a Property and addes it to this entity.
       * @param[in] thePropertyID is the ID of the property to create.
       * @param[in] theValue is the inital value to set.
       */
      template<class TYPE>
      void Add(const typePropertyID thePropertyID, TYPE theValue)
      {
        // Only add the property if it doesn't already exist
        if(mList.find(thePropertyID) == mList.end())
        {
          TProperty<TYPE>* anProperty=new(std::nothrow) TProperty<TYPE>(thePropertyID);
          anProperty->SetValue(theValue);
          mList[anProperty->GetID()]=anProperty;
        }
        else
        {
          WLOG() << "PropertyManager:AddProperty() property(" << thePropertyID
            << ") already exists!" << std::endl;
        }
      }

      /**
       * AddProperty gets a premade Property and addes it to this entity.
       * @param[in] theProperty is a pointer to a pre exisiting property.
       */
      void Add(IProperty* theProperty);

      /**
       * Clone is responsible for making a clone of each property in the
       * PropertyManager provided.
       * @param[in] thePropertyManager to clone into ourselves
       */
      void Clone(const PropertyManager& thePropertyManager);

    protected:

    private:
      // Variables
      ///////////////////////////////////////////////////////////////////////////
      /// A map of all Properties available for this PropertyManager class
      std::map<const typePropertyID, IProperty*> mList;
  }; // PropertyManager class
} // namespace GQE

#endif

/**
 * @class GQE::PropertyManager
 * @ingroup Entity
 * The PropertyManager class is responsible for providing management for
 * IProperty based classes used for an IEntity object or some other class.
 *
 * Copyright (c) 2010-2012 Jacob Dix
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
<commit_msg>Reduce the warnings when adding existing properties<commit_after>/**
 * Provides a class that manages properties for some class (e.g. IEntity). By
 * providing a PropertyManager class, other classes can easily add a flexible
 * property management system if desired.
 *
 * @file include/GQE/Entity/classes/PropertyManager.hpp
 * @author Jacob Dix
 * @date 20120615 - Initial Release
 * @date 20120622 - Fix warning and error comments
 */
#ifndef PROPERTY_MANAGER_HPP_INCLUDED
#define PROPERTY_MANAGER_HPP_INCLUDED

#include <map>
#include <typeinfo>
#include <GQE/Core/loggers/Log_macros.hpp>
#include <GQE/Entity/interfaces/IProperty.hpp>
#include <GQE/Entity/interfaces/TProperty.hpp>
#include <GQE/Core/Core_types.hpp>
#include <GQE/Entity/Entity_types.hpp>

namespace GQE
{
  /// Provides the PropertyManager class for managing IProperty classes
  class GQE_API PropertyManager
  {
    public:
      /**
       * PropertyManager default constructor
       */
      PropertyManager();

      /**
       * PropertyManager deconstructor
       */
      virtual ~PropertyManager();

      /**
       * HasProperty returs true if thePropertyID specified exists in this
       * PropertyManager.
       * @param[in] thePropertyID to lookup in this PropertyManager
       * @return true if thePropertyID exists, false otherwise
       */
      bool HasID(const typePropertyID thePropertyID);

      /**
       * GetProperty returns the property as type with the ID of thePropertyID.
       * @param[in] thePropertyID is the ID of the property to return.
       * @return the value stored in the found propery in the form of TYPE. If no
       * Property was found it returns the default value the type constructor.
       */
      template<class TYPE>
      TYPE Get(const typePropertyID thePropertyID)
      {
        if(mList.find(thePropertyID) != mList.end())
        {
          if(mList.at(thePropertyID)->GetType()->Name() == typeid(TYPE).name())
            return static_cast<TProperty<TYPE>*>(mList[thePropertyID])->GetValue();
        }
        else
        {
          WLOG() << "PropertyManager:Get() returning blank property("
            << thePropertyID << ") type" << std::endl;
        }
        TYPE anReturn=TYPE();
        return anReturn;
      }

      /**
       * SetProperty sets the property with the ID of thePropertyID to theValue.
       * @param[in] thePropertyID is the ID of the property to set.
       * @param[in] theValue is the value to set.
       */
      template<class TYPE>
      void Set(const typePropertyID thePropertyID, TYPE theValue)
      {
        if(mList.find(thePropertyID) != mList.end())
        {
          if(mList.at(thePropertyID)->GetType()->Name() == typeid(TYPE).name())
          {
            static_cast<TProperty<TYPE>*>(mList[thePropertyID])->SetValue(theValue);
          }
        }
        else
        {
          ELOG() << "PropertyManager:Set() unable to find property("
            << thePropertyID << ")" << std::endl;
        }
      }

      /**
       * AddProperty Creates a Property and addes it to this entity.
       * @param[in] thePropertyID is the ID of the property to create.
       * @param[in] theValue is the inital value to set.
       */
      template<class TYPE>
      void Add(const typePropertyID thePropertyID, TYPE theValue)
      {
        // Only add the property if it doesn't already exist
        if(mList.find(thePropertyID) == mList.end())
        {
          TProperty<TYPE>* anProperty=new(std::nothrow) TProperty<TYPE>(thePropertyID);
          anProperty->SetValue(theValue);
          mList[anProperty->GetID()]=anProperty;
        }
      }

      /**
       * AddProperty gets a premade Property and addes it to this entity.
       * @param[in] theProperty is a pointer to a pre exisiting property.
       */
      void Add(IProperty* theProperty);

      /**
       * Clone is responsible for making a clone of each property in the
       * PropertyManager provided.
       * @param[in] thePropertyManager to clone into ourselves
       */
      void Clone(const PropertyManager& thePropertyManager);

    protected:

    private:
      // Variables
      ///////////////////////////////////////////////////////////////////////////
      /// A map of all Properties available for this PropertyManager class
      std::map<const typePropertyID, IProperty*> mList;
  }; // PropertyManager class
} // namespace GQE

#endif

/**
 * @class GQE::PropertyManager
 * @ingroup Entity
 * The PropertyManager class is responsible for providing management for
 * IProperty based classes used for an IEntity object or some other class.
 *
 * Copyright (c) 2010-2012 Jacob Dix
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
<|endoftext|>


<commit_before>/*
 * Copyright 2020 INRIA
 */

#ifndef __eigenpy_decomposition_eigen_solver_hpp__
#define __eigenpy_decomposition_eigen_solver_hpp__

#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>

#include "eigenpy/utils/scalar-name.hpp"

namespace eigenpy
{

  template<typename _MatrixType>
  struct EigenSolverVisitor
  : public boost::python::def_visitor< EigenSolverVisitor<_MatrixType> >
  {

    typedef _MatrixType MatrixType;
    typedef typename MatrixType::Scalar Scalar;
    typedef Eigen::EigenSolver<MatrixType> Solver;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      namespace bp = boost::python;
      cl
      .def(bp::init<>("Default constructor"))
      .def(bp::init<Eigen::Index>(bp::arg("size"),
                                  "Default constructor with memory preallocation"))
      .def(bp::init<MatrixType,bp::optional<bool> >(bp::args("matrix","compute_eigen_vectors"),
                                                    "Computes eigendecomposition of given matrix"))

      .def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
           "Returns the eigenvalues of given matrix.",
           bp::return_value_policy<bp::return_by_value>())
      .def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
           "Returns the eigenvectors of given matrix.",
           bp::return_value_policy<bp::return_by_value>())

      .def("compute",&EigenSolverVisitor::compute_proxy<MatrixType>,
           bp::args("self","matrix"),
           "Computes the eigendecomposition of given matrix.",
           bp::return_value_policy<bp::reference_existing_object>())
      .def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, bool))&Solver::compute,
           bp::args("self","matrix","compute_eigen_vectors"),
           "Computes theeigendecomposition of given matrix.",
           bp::return_value_policy<bp::reference_existing_object>())

      .def("getMaxIterations",&Solver::getMaxIterations,bp::arg("self"),
           "Returns the maximum number of iterations.")
      .def("setMaxIterations",&Solver::setMaxIterations,bp::args("self","max_iter"),
           "Sets the maximum number of iterations allowed.",
           bp::return_value_policy<bp::reference_existing_object>())

      .def("pseudoEigenvalueMatrix",&Solver::pseudoEigenvalueMatrix,bp::arg("self"),
           "Returns the block-diagonal matrix in the pseudo-eigendecomposition.")
      .def("pseudoEigenvectors",&Solver::pseudoEigenvectors ,bp::arg("self"),
           "Returns the pseudo-eigenvectors of given matrix.",
           bp::return_value_policy<bp::return_by_value>())

      .def("info",&Solver::info,bp::arg("self"),
           "NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
      ;
    }

    static void expose()
    {
      static const std::string classname = "EigenSolver" + scalar_name<Scalar>::shortname();
      expose(classname);
    }

    static void expose(const std::string & name)
    {
      namespace bp = boost::python;
      bp::class_<Solver>(name.c_str(),
                         bp::no_init)
      .def(EigenSolverVisitor());
    }

  private:

    template<typename MatrixType>
    static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
    {
      return self.compute(matrix);
    }

  };

} // namespace eigenpy

#endif // ifndef __eigenpy_decomposition_eigen_solver_hpp__

<commit_msg>decompositions: fix issue with old Eigen versions<commit_after>/*
 * Copyright 2020 INRIA
 */

#ifndef __eigenpy_decomposition_eigen_solver_hpp__
#define __eigenpy_decomposition_eigen_solver_hpp__

#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>

#include "eigenpy/utils/scalar-name.hpp"

namespace eigenpy
{

  template<typename _MatrixType>
  struct EigenSolverVisitor
  : public boost::python::def_visitor< EigenSolverVisitor<_MatrixType> >
  {

    typedef _MatrixType MatrixType;
    typedef typename MatrixType::Scalar Scalar;
    typedef Eigen::EigenSolver<MatrixType> Solver;

    template<class PyClass>
    void visit(PyClass& cl) const
    {
      namespace bp = boost::python;
      cl
      .def(bp::init<>("Default constructor"))
      .def(bp::init<Eigen::DenseIndex>(bp::arg("size"),
                                       "Default constructor with memory preallocation"))
      .def(bp::init<MatrixType,bp::optional<bool> >(bp::args("matrix","compute_eigen_vectors"),
                                                    "Computes eigendecomposition of given matrix"))

      .def("eigenvalues",&Solver::eigenvalues,bp::arg("self"),
           "Returns the eigenvalues of given matrix.",
           bp::return_value_policy<bp::return_by_value>())
      .def("eigenvectors",&Solver::eigenvectors,bp::arg("self"),
           "Returns the eigenvectors of given matrix.",
           bp::return_value_policy<bp::return_by_value>())

      .def("compute",&EigenSolverVisitor::compute_proxy<MatrixType>,
           bp::args("self","matrix"),
           "Computes the eigendecomposition of given matrix.",
           bp::return_value_policy<bp::reference_existing_object>())
      .def("compute",(Solver & (Solver::*)(const Eigen::EigenBase<MatrixType> & matrix, bool))&Solver::compute,
           bp::args("self","matrix","compute_eigen_vectors"),
           "Computes theeigendecomposition of given matrix.",
           bp::return_value_policy<bp::reference_existing_object>())

      .def("getMaxIterations",&Solver::getMaxIterations,bp::arg("self"),
           "Returns the maximum number of iterations.")
      .def("setMaxIterations",&Solver::setMaxIterations,bp::args("self","max_iter"),
           "Sets the maximum number of iterations allowed.",
           bp::return_value_policy<bp::reference_existing_object>())

      .def("pseudoEigenvalueMatrix",&Solver::pseudoEigenvalueMatrix,bp::arg("self"),
           "Returns the block-diagonal matrix in the pseudo-eigendecomposition.")
      .def("pseudoEigenvectors",&Solver::pseudoEigenvectors ,bp::arg("self"),
           "Returns the pseudo-eigenvectors of given matrix.",
           bp::return_value_policy<bp::return_by_value>())

      .def("info",&Solver::info,bp::arg("self"),
           "NumericalIssue if the input contains INF or NaN values or overflow occured. Returns Success otherwise.")
      ;
    }

    static void expose()
    {
      static const std::string classname = "EigenSolver" + scalar_name<Scalar>::shortname();
      expose(classname);
    }

    static void expose(const std::string & name)
    {
      namespace bp = boost::python;
      bp::class_<Solver>(name.c_str(),
                         bp::no_init)
      .def(EigenSolverVisitor());
    }

  private:

    template<typename MatrixType>
    static Solver & compute_proxy(Solver & self, const Eigen::EigenBase<MatrixType> & matrix)
    {
      return self.compute(matrix);
    }

  };

} // namespace eigenpy

#endif // ifndef __eigenpy_decomposition_eigen_solver_hpp__

<|endoftext|>


<commit_before>#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "kangaru/kangaru.hpp"

TEST_CASE("The definition may not contain virtual members", "[definition]") {
	struct Service {};
	struct Definition : kgr::Service<Service> {
		virtual ~Definition();
	};

	REQUIRE_FALSE(kgr::detail::is_service<Definition>::value);
}

TEST_CASE("The definition may not forward void", "[definition]") {
	struct Definition : kgr::Abstract {
		void forward();
	};

	REQUIRE_FALSE(kgr::detail::is_service<Definition>::value);
}

TEST_CASE("The definition can be construct using emplace", "[definition]") {
	struct Service {};
	struct Definition {
		static std::tuple<> construct() { return {}; }
		void emplace() {}
		Service forward() { return {}; }
	};

	REQUIRE(kgr::detail::is_service_valid<Definition>::value);

	(void) kgr::Container{}.service<Definition>();
}

TEST_CASE("The definition cannot be construct with emplace differing construct", "[definition]") {
	struct Service {};
	struct Definition {
		static auto construct() -> decltype(kgr::inject(int{})) { return kgr::inject(int{}); }
		void emplace() {}
		Service forward() { return {}; }
	};

	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
}

TEST_CASE("The definition cannot be only be construct with emplace if parameters are the same", "[definition]") {
	struct Service {};
	struct Definition {
		static auto construct(double) -> decltype(kgr::inject(int{}, char{})) { return kgr::inject(int{}, char{}); }
		void emplace(int, char) {}
		Service forward() { return {}; }
	};

	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE((kgr::detail::is_service_valid<Definition, double>::value));

	(void) kgr::Container{}.service<Definition>(0.0);
}

namespace template_construct {
struct Service {};
struct Definition {
	template<typename T>
	static auto construct(T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be template", "[definition]") {
	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE((kgr::detail::is_service_valid<Definition, double>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, float>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, int, double>::value));

	kgr::Container c;
	(void) c.service<Definition>(0.0);
	(void) c.service<Definition>(0.0f);
	(void) c.service<Definition>(0);
	(void) c.service<Definition>(std::tuple<>{});
}
}

namespace template_construct_param {
struct Service {};
struct Definition {
	template<typename T>
	static auto construct(int, T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be a mix of non templated and template parameters", "[definition]") {
	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, double>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, float>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, int>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, double>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, int>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, std::tuple<>>::value));

	kgr::Container c;
	(void) c.service<Definition>(0, 0.0);
	(void) c.service<Definition>(0, 0.0f);
	(void) c.service<Definition>(0, 0);
	(void) c.service<Definition>(0, std::tuple<>{});
}
}

namespace template_construct_inject {
struct Service {};
struct Service2 {};
struct Definition2 : kgr::Service<Service2> {};

struct DefinitionA {
	template<typename T>
	static auto construct(kgr::Inject<Definition2>, int, T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

struct DefinitionB {
	template<typename... T>
	static auto construct(kgr::Inject<Definition2>, int, T&&...) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

struct DefinitionC {
	template<typename... T>
	static auto construct(kgr::Inject<Definition2>, DefinitionB, int, T&&...) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be a mix of non templated and template parameters and injected services", "[definition]") {
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, double>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, int>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, double, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, float, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, int, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, std::tuple<>, std::tuple<>>::value));

	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, double, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, float, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, std::tuple<>, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, double, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, float, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, int, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, std::tuple<>, std::tuple<>>::value));

	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, double, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, float, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, std::tuple<>, float>::value));

	kgr::Container c;
	(void) c.service<DefinitionA>(0, 0.0);
	(void) c.service<DefinitionA>(0, 0.0f);
	(void) c.service<DefinitionA>(0, 0);
	(void) c.service<DefinitionA>(0, std::tuple<>{});

	(void) c.service<DefinitionB>(0, 0.0, 0.0f);
	(void) c.service<DefinitionB>(0, 0.0f, 0.0f);
	(void) c.service<DefinitionB>(0, 0, 0.0f);
	(void) c.service<DefinitionB>(0, std::tuple<>{}, 0.0f);
	(void) c.service<DefinitionB>(0, 0.0, std::tuple<>{});
	(void) c.service<DefinitionB>(0, 0.0f, std::tuple<>{});
	(void) c.service<DefinitionB>(0, 0, std::tuple<>{});
	(void) c.service<DefinitionB>(0, std::tuple<>{}, std::tuple<>{});

	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0.0);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0.0f);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, std::tuple<>{});
}
}
<commit_msg>Added more tests for definition<commit_after>#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "kangaru/kangaru.hpp"

TEST_CASE("The definition may not contain virtual members", "[definition]") {
	struct Service {};
	struct Definition : kgr::Service<Service> {
		virtual ~Definition();
	};

	REQUIRE_FALSE(kgr::detail::is_service<Definition>::value);
}

TEST_CASE("The definition may not forward void", "[definition]") {
	struct Definition : kgr::Abstract {
		void forward();
	};

	REQUIRE_FALSE(kgr::detail::is_service<Definition>::value);
}

TEST_CASE("The definition can be construct using emplace", "[definition]") {
	struct Service {};
	struct Definition {
		static std::tuple<> construct() { return {}; }
		void emplace() {}
		Service forward() { return {}; }
	};

	REQUIRE(kgr::detail::is_service_valid<Definition>::value);

	(void) kgr::Container{}.service<Definition>();
}

TEST_CASE("The definition cannot be construct with emplace differing construct", "[definition]") {
	struct Service {};
	struct Definition {
		static auto construct() -> decltype(kgr::inject(int{})) { return kgr::inject(int{}); }
		void emplace() {}
		Service forward() { return {}; }
	};

	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
}

TEST_CASE("The definition cannot be only be construct with emplace if parameters are the same", "[definition]") {
	struct Service {};
	struct Definition {
		static auto construct(double) -> decltype(kgr::inject(int{}, char{})) { return kgr::inject(int{}, char{}); }
		void emplace(int, char) {}
		Service forward() { return {}; }
	};

	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE((kgr::detail::is_service_valid<Definition, double>::value));

	(void) kgr::Container{}.service<Definition>(0.0);
}

namespace template_construct {
struct Service {};
struct Definition {
	template<typename T>
	static auto construct(T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be template", "[definition]") {
	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE((kgr::detail::is_service_valid<Definition, double>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, float>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, int, double>::value));

	kgr::Container c;
	(void) c.service<Definition>(0.0);
	(void) c.service<Definition>(0.0f);
	(void) c.service<Definition>(0);
	(void) c.service<Definition>(std::tuple<>{});
}
}

namespace template_construct_param {
struct Service {};
struct Definition {
	template<typename T>
	static auto construct(int, T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be a mix of non templated and template parameters", "[definition]") {
	REQUIRE_FALSE(kgr::detail::is_service_valid<Definition>::value);
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, double>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, float>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, int>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<Definition, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, double>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, int>::value));
	REQUIRE((kgr::detail::is_service_valid<Definition, int, std::tuple<>>::value));

	kgr::Container c;
	(void) c.service<Definition>(0, 0.0);
	(void) c.service<Definition>(0, 0.0f);
	(void) c.service<Definition>(0, 0);
	(void) c.service<Definition>(0, std::tuple<>{});
}
}

namespace template_construct_inject {
struct Service {};
struct Service2 {};
struct Definition2 : kgr::Service<Service2> {};

struct DefinitionA {
	template<typename T>
	static auto construct(kgr::Inject<Definition2>, int, T&&) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

struct DefinitionB {
	template<typename... T>
	static auto construct(kgr::Inject<Definition2>, int, T&&...) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

struct DefinitionC {
	template<typename... T>
	static auto construct(kgr::Inject<Definition2>, DefinitionB, int, T&&...) -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() {}
	Service forward() { return {}; }
};

TEST_CASE("The construct function can be a mix of non templated and template parameters and injected services", "[definition]") {
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, double>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, int>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionA, int, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, double, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, float, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, int, std::tuple<>>::value));
	REQUIRE_FALSE((kgr::detail::is_service_valid<DefinitionA, int, std::tuple<>, std::tuple<>>::value));

	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, double, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, float, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, std::tuple<>, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, double, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, float, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, int, std::tuple<>>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionB, int, std::tuple<>, std::tuple<>>::value));

	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, double, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, float, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, int, float>::value));
	REQUIRE((kgr::detail::is_service_valid<DefinitionC, DefinitionB, int, std::tuple<>, float>::value));

	kgr::Container c;
	(void) c.service<DefinitionA>(0, 0.0);
	(void) c.service<DefinitionA>(0, 0.0f);
	(void) c.service<DefinitionA>(0, 0);
	(void) c.service<DefinitionA>(0, std::tuple<>{});

	(void) c.service<DefinitionB>(0, 0.0, 0.0f);
	(void) c.service<DefinitionB>(0, 0.0f, 0.0f);
	(void) c.service<DefinitionB>(0, 0, 0.0f);
	(void) c.service<DefinitionB>(0, std::tuple<>{}, 0.0f);
	(void) c.service<DefinitionB>(0, 0.0, std::tuple<>{});
	(void) c.service<DefinitionB>(0, 0.0f, std::tuple<>{});
	(void) c.service<DefinitionB>(0, 0, std::tuple<>{});
	(void) c.service<DefinitionB>(0, std::tuple<>{}, std::tuple<>{});

	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0.0);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0.0f);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, 0);
	(void) c.service<DefinitionC>(DefinitionB{}, 0, std::tuple<>{});
}
}

namespace in_place_constructor {
struct Service {};

bool constructor_called = false;

struct Definition {
	Definition(kgr::in_place_t) { constructor_called = true; }
	static auto construct() -> decltype(kgr::inject()) { return kgr::inject(); }
	Service forward() { return {}; }
};

TEST_CASE("The container call the constructor with the in_place_t constructor", "[definition]") {
	(void) kgr::Container{}.service<Definition>();
	REQUIRE(constructor_called);
}
}

namespace no_in_place {
struct Service {};

bool constructor_called = false;
bool emplace_called = false;

struct Definition {
	Definition() { constructor_called = true; }
	static auto construct() -> decltype(kgr::inject()) { return kgr::inject(); }
	void emplace() { emplace_called = true; }
	Service forward() { return {}; }
};

TEST_CASE("The container call the default if no constructor with the in_place_t constructor is defined", "[definition]") {
	(void) kgr::Container{}.service<Definition>();
	REQUIRE(emplace_called);
	REQUIRE(constructor_called);
}
}

namespace in_place_recieves_injected_parameters {
struct Service {};

bool constructor_called = false;

struct Definition {
	Definition(kgr::in_place_t, int&&, double&) { constructor_called = true; }
	static auto construct(double& a) -> decltype(kgr::inject(int{}, a)) { return kgr::inject(1, a); }
	Service forward() { return {}; }
};

TEST_CASE("The forward injected parameters to the Definition constructor", "[definition]") {
	REQUIRE((kgr::detail::is_service_valid<Definition, double&>::value));
	double a = 0;
	(void) kgr::Container{}.service<Definition>(a);
	REQUIRE(constructor_called);
}
}

namespace definition_constructor_priority {
struct Service {};

bool constructor_called = false;
bool emplace_called = false;

struct Definition {
	Definition(kgr::in_place_t, int, double&) { constructor_called = true; }

	template<typename T>
	static auto construct(int a, T& b) -> decltype(kgr::inject(std::move(a), b)) { return kgr::inject(std::move(a), b); }

	template<typename... Args>
	void emplace(Args&&...) { emplace_called = true; }
	Service forward() { return {}; }
};

TEST_CASE("The container prefer the in_place_t constructor over emplace function", "[definition]") {
	double d = 0;
	(void) kgr::Container{}.service<Definition>(0, d);

	REQUIRE(constructor_called);
	REQUIRE_FALSE(emplace_called);
}
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "test_light.hpp"

/// sequence_generator

TEMPLATE_TEST_CASE_2("sequence/fast_vector_1", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::sequence_generator();

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_vector_2", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::sequence_generator(99);

    REQUIRE(b[0] == 99.0);
    REQUIRE(b[1] == 100.0);
    REQUIRE(b[2] == 101.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_vector_3", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b(etl::sequence_generator(99));

    REQUIRE(b[0] == 99.0);
    REQUIRE(b[1] == 100.0);
    REQUIRE(b[2] == 101.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_1", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = etl::sequence_generator();

    REQUIRE(b(0, 0) == 0.0);
    REQUIRE(b(0, 1) == 1.0);
    REQUIRE(b(1, 0) == 2.0);
    REQUIRE(b(1, 1) == 3.0);
    REQUIRE(b(2, 0) == 4.0);
    REQUIRE(b(2, 1) == 5.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_2", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = 0.1 * etl::sequence_generator();

    REQUIRE(etl::etl_traits<std::decay_t<decltype(0.1 * etl::sequence_generator())>>::is_generator);

    REQUIRE(b(0, 0) == Approx(0.0));
    REQUIRE(b(0, 1) == Approx(0.1));
    REQUIRE(b(1, 0) == Approx(0.2));
    REQUIRE(b(1, 1) == Approx(0.3));
    REQUIRE(b(2, 0) == Approx(0.4));
    REQUIRE(b(2, 1) == Approx(0.5));
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_3", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b(1.0);

    b = 0.1 * etl::sequence_generator() + b;

    REQUIRE(b(0, 0) == Approx(1.0));
    REQUIRE(b(0, 1) == Approx(1.1));
    REQUIRE(b(1, 0) == Approx(1.2));
    REQUIRE(b(1, 1) == Approx(1.3));
    REQUIRE(b(2, 0) == Approx(1.4));
    REQUIRE(b(2, 1) == Approx(1.5));
}

TEMPLATE_TEST_CASE_2("sequence/dyn_vector_1", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3);

    b = etl::sequence_generator();

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/dyn_vector_2", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3, etl::sequence_generator());

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/dyn_matrix_1", "generator", Z, float, double) {
    etl::dyn_matrix<Z> b(3, 2);

    b = etl::sequence_generator();

    REQUIRE(b(0, 0) == 0.0);
    REQUIRE(b(0, 1) == 1.0);
    REQUIRE(b(1, 0) == 2.0);
    REQUIRE(b(1, 1) == 3.0);
    REQUIRE(b(2, 0) == 4.0);
    REQUIRE(b(2, 1) == 5.0);
}

/// normal_generator

//Simply ensures that it compiles

TEMPLATE_TEST_CASE_2("normal/fast_vector_1", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/fast_matrix_1", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/dyn_vector_1", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3);

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/dyn_matrix_1", "generator", Z, float, double) {
    etl::dyn_matrix<Z> b(3, 2);

    b = etl::normal_generator();
}
<commit_msg>New test for generators<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "test_light.hpp"

/// sequence_generator

TEMPLATE_TEST_CASE_2("sequence/fast_vector_1", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::sequence_generator();

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_vector_2", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::sequence_generator(99);

    REQUIRE(b[0] == 99.0);
    REQUIRE(b[1] == 100.0);
    REQUIRE(b[2] == 101.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_vector_3", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b(etl::sequence_generator(99));

    REQUIRE(b[0] == 99.0);
    REQUIRE(b[1] == 100.0);
    REQUIRE(b[2] == 101.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_vector_4", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b(0.5 * etl::sequence_generator(99.0));

    REQUIRE(b[0] == 49.5);
    REQUIRE(b[1] == 50.0);
    REQUIRE(b[2] == 50.5);
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_1", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = etl::sequence_generator();

    REQUIRE(b(0, 0) == 0.0);
    REQUIRE(b(0, 1) == 1.0);
    REQUIRE(b(1, 0) == 2.0);
    REQUIRE(b(1, 1) == 3.0);
    REQUIRE(b(2, 0) == 4.0);
    REQUIRE(b(2, 1) == 5.0);
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_2", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = 0.1 * etl::sequence_generator();

    REQUIRE(etl::etl_traits<std::decay_t<decltype(0.1 * etl::sequence_generator())>>::is_generator);

    REQUIRE(b(0, 0) == Approx(0.0));
    REQUIRE(b(0, 1) == Approx(0.1));
    REQUIRE(b(1, 0) == Approx(0.2));
    REQUIRE(b(1, 1) == Approx(0.3));
    REQUIRE(b(2, 0) == Approx(0.4));
    REQUIRE(b(2, 1) == Approx(0.5));
}

TEMPLATE_TEST_CASE_2("sequence/fast_matrix_3", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b(1.0);

    b = 0.1 * etl::sequence_generator() + b;

    REQUIRE(b(0, 0) == Approx(1.0));
    REQUIRE(b(0, 1) == Approx(1.1));
    REQUIRE(b(1, 0) == Approx(1.2));
    REQUIRE(b(1, 1) == Approx(1.3));
    REQUIRE(b(2, 0) == Approx(1.4));
    REQUIRE(b(2, 1) == Approx(1.5));
}

TEMPLATE_TEST_CASE_2("sequence/dyn_vector_1", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3);

    b = etl::sequence_generator();

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/dyn_vector_2", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3, etl::sequence_generator());

    REQUIRE(b[0] == 0.0);
    REQUIRE(b[1] == 1.0);
    REQUIRE(b[2] == 2.0);
}

TEMPLATE_TEST_CASE_2("sequence/dyn_matrix_1", "generator", Z, float, double) {
    etl::dyn_matrix<Z> b(3, 2);

    b = etl::sequence_generator();

    REQUIRE(b(0, 0) == 0.0);
    REQUIRE(b(0, 1) == 1.0);
    REQUIRE(b(1, 0) == 2.0);
    REQUIRE(b(1, 1) == 3.0);
    REQUIRE(b(2, 0) == 4.0);
    REQUIRE(b(2, 1) == 5.0);
}

/// normal_generator

//Simply ensures that it compiles

TEMPLATE_TEST_CASE_2("normal/fast_vector_1", "generator", Z, float, double) {
    etl::fast_vector<Z, 3> b;

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/fast_matrix_1", "generator", Z, float, double) {
    etl::fast_matrix<Z, 3, 2> b;

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/dyn_vector_1", "generator", Z, float, double) {
    etl::dyn_vector<Z> b(3);

    b = etl::normal_generator();
}

TEMPLATE_TEST_CASE_2("normal/dyn_matrix_1", "generator", Z, float, double) {
    etl::dyn_matrix<Z> b(3, 2);

    b = etl::normal_generator();
}
<|endoftext|>


<commit_before>#include "sh.hpp"

using namespace SH;

int main(int argc, char** argv)
{
  try {
    shSetBackend("arb");

    ShImage image;
    image.loadPng(argv[1]);

    //ShChannel<ShColor3f> data(image.memory(), image.width() * image.height());

#define INDEX_ELEMENTS 3

    ShImage idx_img(image.width(), image.height(), INDEX_ELEMENTS);
    idx_img.memory()->findStorage("host")->dirty();
    for (int y = 0; y < image.height(); ++y) {
      for (int x = 0; x < image.width(); ++x) {
        idx_img(x, y, 0) = (float)x;
        idx_img(x, y, 1) = (float)y;
      }
    }
    ShChannel<ShTexCoord<INDEX_ELEMENTS, SH_TEMP> >
      index(idx_img.memory(), image.width() * image.height());

    ShArrayRect<ShColor3f> picture(image.width(), image.height());
    picture.memory(image.memory());

    ShImage result(image.width(), image.height(), 3);
    ShChannel<ShColor3f> output(result.memory(), image.width() * image.height());

    ShMatrix3x3f sobel_x = ShMatrix3x3f(-1.0, 0.0, +1.0,
                                        -2.0, 0.0, +2.0,
                                        -1.0, 0.0, -1.0);
    ShMatrix3x3f sobel_y = transpose(sobel_x);

    ShProgram invert = SH_BEGIN_PROGRAM("gpu:stream") {
      ShTexCoord<INDEX_ELEMENTS, SH_INPUT> idx;
      ShOutputColor3f outcol;

      ShTexCoord2f t = idx(0,1)

      //      outcol = ShColor3f(1.0, 1.0, 1.0) - picture(idx(0,1));
      outcol = picture(t - ShConstant2f(1.0, 0.0)) - picture(t);
      outcol = dot(outcol,outcol)(0,0,0);
    } SH_END;

    ShStream outstream(output);
    ShEnvironment::backend->execute(invert << index, outstream);

    result.savePng("result.png");
  } catch (const ShException& e) {
    std::cerr << "SH Exception: " << e.message() << std::endl;
    return -1;
  } catch (...) {
    std::cerr << "Unknown exception caught." << std::endl;
    return -1;
  }
}
<commit_msg>fix stream examples<commit_after>#include "sh.hpp"

using namespace SH;

int main(int argc, char** argv)
{
  try {
    shSetBackend("arb");

    ShImage image;
    image.loadPng(argv[1]);

    //ShChannel<ShColor3f> data(image.memory(), image.width() * image.height());

#define INDEX_ELEMENTS 3

    ShImage idx_img(image.width(), image.height(), INDEX_ELEMENTS);
    idx_img.memory()->findStorage("host")->dirty();
    for (int y = 0; y < image.height(); ++y) {
      for (int x = 0; x < image.width(); ++x) {
        idx_img(x, y, 0) = (float)x;
        idx_img(x, y, 1) = (float)y;
      }
    }
    ShChannel<ShTexCoord<INDEX_ELEMENTS, SH_TEMP> >
      index(idx_img.memory(), image.width() * image.height());

    ShTableRect<ShColor3f> picture(image.width(), image.height());
    picture.memory(image.memory());

    ShImage result(image.width(), image.height(), 3);
    ShChannel<ShColor3f> output(result.memory(), image.width() * image.height());

    /*
    ShMatrix3x3f sobel_x = ShMatrix3x3f(-1.0, 0.0, +1.0,
                                        -2.0, 0.0, +2.0,
                                        -1.0, 0.0, -1.0);
    ShMatrix3x3f sobel_y = transpose(sobel_x);
    */
    ShProgram invert = SH_BEGIN_PROGRAM("gpu:stream") {
      ShTexCoord<INDEX_ELEMENTS, SH_INPUT> idx;
      ShOutputColor3f outcol;

      ShTexCoord2f t = idx(0,1);

      //outcol = picture(t - ShConstant2f(1.0, 0.0)) - picture(t);
      //outcol = dot(outcol,outcol)(0,0,0);

      ShAttrib2f l;
      l(0) = t(0)*t(0)/image.width();
      l(1) = t(1)*t(1)/image.height();
      outcol = picture(l);
    } SH_END;

    ShStream outstream(output);
    ShEnvironment::backend->execute(invert << index, outstream);

    result.savePng("result.png");
  } catch (const ShException& e) {
    std::cerr << "SH Exception: " << e.message() << std::endl;
    return -1;
  } catch (...) {
    std::cerr << "Unknown exception caught." << std::endl;
    return -1;
  }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#include <type_safe/strong_typedef.hpp>

#include <catch.hpp>

#include <sstream>

using namespace type_safe;

TEST_CASE("strong_typedef")
{
    SECTION("general")
    {
        // check compilation here
        struct type : strong_typedef<type, int>, strong_typedef_op::equality_comparison<type>
        {
            using strong_typedef::strong_typedef;
        };

        // type + type
        type t1, t2;
        t1 == t2;
        t1 == std::move(t2);
        std::move(t1) == t2;
        std::move(t1) == std::move(t2);

        // type + convert_a
        struct convert_a : type
        {
            using type::type;
        };
        convert_a a;
        t1 == a;
        t1 == std::move(a);
        std::move(t1) == a;
        std::move(t1) == std::move(a);

        // type + convert_b
        struct convert_b
        {
            operator type()
            {
                return type(0);
            }
        };
        convert_b b;
        t1 == b;
        t1 == std::move(b);
        std::move(t1) == b;
        std::move(t1) == std::move(b);
    }
    SECTION("equality_comparison")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::equality_comparison<type>,
                      strong_typedef_op::mixed_equality_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        type b(1);

        REQUIRE(a == a);
        REQUIRE(a == 0);
        REQUIRE(0 == a);
        REQUIRE(!(a == b));

        REQUIRE(a != b);
        REQUIRE(a != 1);
        REQUIRE(1 != a);
        REQUIRE(!(a != a));
    }
    SECTION("relational_comparison")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::relational_comparison<type>,
                      strong_typedef_op::mixed_relational_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        type b(1);

        REQUIRE(a < b);
        REQUIRE(0 < b);
        REQUIRE(a < 1);
        REQUIRE(!(b < a));
        REQUIRE(a <= b);
        REQUIRE(a <= 1);
        REQUIRE(1 <= b);
        REQUIRE(a <= a);
        REQUIRE(b > a);
        REQUIRE(1 > a);
        REQUIRE(b > 0);
        REQUIRE(!(a > b));
        REQUIRE(b >= a);
        REQUIRE(b >= 0);
        REQUIRE(1 >= a);
        REQUIRE(b >= b);
    }
    SECTION("addition")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::addition<type>,
                      strong_typedef_op::mixed_addition<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        a += type(1);
        a = a + type(1);
        a = type(1) + a;
        REQUIRE(static_cast<int>(a) == 3);

        type b(0);
        b += 1;
        b = b + 1;
        b = 1 + b;
        REQUIRE(static_cast<int>(b) == 3);
    }
    SECTION("subtraction")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::subtraction<type>,
                      strong_typedef_op::mixed_subtraction<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        a -= type(1);    // -1
        a = a - type(1); // -2
        a = type(1) - a; // 3
        REQUIRE(static_cast<int>(a) == 3);

        type b(0);
        b -= 1;
        b = b - 1;
        b = 1 - b;
        REQUIRE(static_cast<int>(b) == 3);
    }
    SECTION("multiplication")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::multiplication<type>,
                      strong_typedef_op::mixed_multiplication<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1);
        a *= type(2);
        a = a * type(2);
        a = type(2) * a;
        REQUIRE(static_cast<int>(a) == 8);

        type b(1);
        b *= 2;
        b = b * 2;
        b = 2 * b;
        REQUIRE(static_cast<int>(b) == 8);
    }
    SECTION("division")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::division<type>,
                      strong_typedef_op::mixed_division<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(8);
        a /= type(2);
        a = a / type(2);
        a = type(2) / a;
        REQUIRE(static_cast<int>(a) == 1);

        type b(8);
        b /= 2;
        b = b / 2;
        b = 2 / b;
        REQUIRE(static_cast<int>(b) == 1);
    }
    SECTION("modulo")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::modulo<type>,
                      strong_typedef_op::mixed_modulo<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(11);
        a %= type(6);    // 5
        a = a % type(2); // 1
        a = type(2) % a; // 0
        REQUIRE(static_cast<int>(a) == 0);

        type b(11);
        b %= 6;
        b = b % 2;
        b = 2 % b;
        REQUIRE(static_cast<int>(b) == 0);
    }
    SECTION("increment")
    {
        struct type : strong_typedef<type, int>, strong_typedef_op::increment<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        REQUIRE(static_cast<int>(++a) == 1);
        REQUIRE(static_cast<int>(a++) == 1);
        REQUIRE(static_cast<int>(a) == 2);
    }
    SECTION("decrement")
    {
        struct type : strong_typedef<type, int>, strong_typedef_op::decrement<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        REQUIRE(static_cast<int>(--a) == -1);
        REQUIRE(static_cast<int>(a--) == -1);
        REQUIRE(static_cast<int>(a) == -2);
    }
    SECTION("unary")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::unary_minus<type>,
                      strong_typedef_op::unary_plus<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(2);
        REQUIRE(static_cast<int>(+a) == 2);
        REQUIRE(static_cast<int>(-a) == -2);
    }
    SECTION("complement")
    {
        struct type : strong_typedef<type, unsigned>, strong_typedef_op::complement<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1u);
        REQUIRE(static_cast<unsigned>(~a) == ~1u);

        type b(42u);
        REQUIRE(static_cast<unsigned>(~b) == ~42u);
    }
    SECTION("bitwise")
    {
        struct type : strong_typedef<type, unsigned>,
                      strong_typedef_op::bitwise_or<type>,
                      strong_typedef_op::bitwise_xor<type>,
                      strong_typedef_op::bitwise_and<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0u);

        REQUIRE(static_cast<unsigned>(a | type(3u)) == 3u);
        REQUIRE(static_cast<unsigned>(type(3u) | a) == 3u);
        a |= type(3u);
        REQUIRE(static_cast<unsigned>(a) == 3u);

        REQUIRE(static_cast<unsigned>(a & type(2u)) == 2u);
        REQUIRE(static_cast<unsigned>(type(2u) & a) == 2u);
        a &= type(2u);
        REQUIRE(static_cast<unsigned>(a) == 2u);

        REQUIRE(static_cast<unsigned>(a ^ type(3u)) == 1u);
        REQUIRE(static_cast<unsigned>(type(3u) ^ a) == 1u);
        a ^= type(3u);
        REQUIRE(static_cast<unsigned>(a) == 1u);
    }
    SECTION("bitshift")
    {
        struct type : strong_typedef<type, unsigned>, strong_typedef_op::bitshift<type, unsigned>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1u);

        REQUIRE(static_cast<unsigned>(a << 1u) == 2u);
        a <<= 1u;
        REQUIRE(static_cast<unsigned>(a) == 2u);

        REQUIRE(static_cast<unsigned>(a >> 1u) == 1u);
        a >>= 1u;
        REQUIRE(static_cast<unsigned>(a) == 1u);
    }
    SECTION("dereference")
    {
        struct test
        {
            int a;
        } t{0};

        struct type : strong_typedef<type, test*>, strong_typedef_op::dereference<type, test>
        {
            using strong_typedef::strong_typedef;
        };

        type a(&t);
        REQUIRE((*a).a == 0);
        REQUIRE(a->a == 0);
    }
    SECTION("array subscript")
    {
        int arr[] = {0, 1, 2};

        struct type : strong_typedef<type, int*>, strong_typedef_op::array_subscript<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(arr);
        REQUIRE(a[0] == 0);
        REQUIRE(a[1] == 1);
        REQUIRE(a[2] == 2);
    }
    SECTION("iterator")
    {
        int arr[] = {0, 1, 2};

        struct type : strong_typedef<type, int*>,
                      strong_typedef_op::random_access_iterator<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(arr);
        a += 1;
        REQUIRE(a == type(&arr[1]));

        a -= 1;
        REQUIRE(a == type(&arr[0]));

        a = a + 1;
        a = 1 + a;
        REQUIRE(a == type(&arr[2]));

        a = a - 1;
        REQUIRE(a == type(&arr[1]));

        REQUIRE(a - type(&arr[0]) == 1);
    }
    SECTION("i/o")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::input_operator<type>,
                      strong_typedef_op::output_operator<type>
        {
            using strong_typedef::strong_typedef;
        };

        std::ostringstream out;
        std::istringstream in("1");

        type a(0);
        out << a;
        REQUIRE(out.str() == "0");

        in >> a;
        REQUIRE(static_cast<int>(a) == 1);
    }
}
<commit_msg>Add test case for more strong typedef conversions<commit_after>// Copyright (C) 2016-2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#include <type_safe/strong_typedef.hpp>

#include <catch.hpp>

#include <sstream>

using namespace type_safe;

TEST_CASE("strong_typedef")
{
    // only check compilation here
    SECTION("general")
    {
        struct type : strong_typedef<type, int>, strong_typedef_op::equality_comparison<type>
        {
            using strong_typedef::strong_typedef;
        };

        // type + type
        type t1, t2;
        t1 == t2;
        t1 == std::move(t2);
        std::move(t1) == t2;
        std::move(t1) == std::move(t2);

        // type + convert_a
        struct convert_a : type
        {
            using type::type;
        };
        convert_a a;
        t1 == a;
        t1 == std::move(a);
        std::move(t1) == a;
        std::move(t1) == std::move(a);

        // type + convert_b
        struct convert_b
        {
            operator type()
            {
                return type(0);
            }
        };
        convert_b b;
        t1 == b;
        t1 == std::move(b);
        std::move(t1) == b;
        std::move(t1) == std::move(b);
    }
    SECTION("general mixed")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::mixed_equality_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        int i;

        // type + int
        type t1;
        t1 == i;
        t1 == std::move(i);
        std::move(t1) == i;
        std::move(t1) == std::move(i);

        // type + convert
        struct convert
        {
            operator int()
            {
                return 5;
            }
        };
        convert a;
        t1 == a;
        t1 == std::move(a);
        std::move(t1) == a;
        std::move(t1) == std::move(i);
    }
    SECTION("general mixed + non mixed")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::equality_comparison<type>,
                      strong_typedef_op::mixed_equality_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        // type + type
        type t1, t2;
        t1 == t2;
        t1 == std::move(t2);
        std::move(t1) == t2;
        std::move(t1) == std::move(t2);

        // type + convert_a
        struct convert_a : type
        {
            using type::type;
        };
        convert_a a;
        t1 == a;
        t1 == std::move(a);
        std::move(t1) == a;
        std::move(t1) == std::move(a);

        // type + convert_b
        struct convert_b
        {
            operator type()
            {
                return type(0);
            }
        };
        convert_b b;
        t1 == b;
        t1 == std::move(b);
        std::move(t1) == b;
        std::move(t1) == std::move(b);

        // type + int
        int i;
        t1 == i;
        t1 == std::move(i);
        std::move(t1) == i;
        std::move(t1) == std::move(i);

        // type + convert
        struct convert_c
        {
            operator int()
            {
                return 5;
            }
        };
        convert_c c;
        t1 == c;
        t1 == std::move(c);
        std::move(t1) == c;
        std::move(t1) == std::move(c);
    }
    SECTION("equality_comparison")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::equality_comparison<type>,
                      strong_typedef_op::mixed_equality_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        type b(1);

        REQUIRE(a == a);
        REQUIRE(a == 0);
        REQUIRE(0 == a);
        REQUIRE(!(a == b));

        REQUIRE(a != b);
        REQUIRE(a != 1);
        REQUIRE(1 != a);
        REQUIRE(!(a != a));
    }
    SECTION("relational_comparison")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::relational_comparison<type>,
                      strong_typedef_op::mixed_relational_comparison<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        type b(1);

        REQUIRE(a < b);
        REQUIRE(0 < b);
        REQUIRE(a < 1);
        REQUIRE(!(b < a));
        REQUIRE(a <= b);
        REQUIRE(a <= 1);
        REQUIRE(1 <= b);
        REQUIRE(a <= a);
        REQUIRE(b > a);
        REQUIRE(1 > a);
        REQUIRE(b > 0);
        REQUIRE(!(a > b));
        REQUIRE(b >= a);
        REQUIRE(b >= 0);
        REQUIRE(1 >= a);
        REQUIRE(b >= b);
    }
    SECTION("addition")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::addition<type>,
                      strong_typedef_op::mixed_addition<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        a += type(1);
        a = a + type(1);
        a = type(1) + a;
        REQUIRE(static_cast<int>(a) == 3);

        type b(0);
        b += 1;
        b = b + 1;
        b = 1 + b;
        REQUIRE(static_cast<int>(b) == 3);
    }
    SECTION("subtraction")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::subtraction<type>,
                      strong_typedef_op::mixed_subtraction<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        a -= type(1);    // -1
        a = a - type(1); // -2
        a = type(1) - a; // 3
        REQUIRE(static_cast<int>(a) == 3);

        type b(0);
        b -= 1;
        b = b - 1;
        b = 1 - b;
        REQUIRE(static_cast<int>(b) == 3);
    }
    SECTION("multiplication")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::multiplication<type>,
                      strong_typedef_op::mixed_multiplication<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1);
        a *= type(2);
        a = a * type(2);
        a = type(2) * a;
        REQUIRE(static_cast<int>(a) == 8);

        type b(1);
        b *= 2;
        b = b * 2;
        b = 2 * b;
        REQUIRE(static_cast<int>(b) == 8);
    }
    SECTION("division")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::division<type>,
                      strong_typedef_op::mixed_division<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(8);
        a /= type(2);
        a = a / type(2);
        a = type(2) / a;
        REQUIRE(static_cast<int>(a) == 1);

        type b(8);
        b /= 2;
        b = b / 2;
        b = 2 / b;
        REQUIRE(static_cast<int>(b) == 1);
    }
    SECTION("modulo")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::modulo<type>,
                      strong_typedef_op::mixed_modulo<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(11);
        a %= type(6);    // 5
        a = a % type(2); // 1
        a = type(2) % a; // 0
        REQUIRE(static_cast<int>(a) == 0);

        type b(11);
        b %= 6;
        b = b % 2;
        b = 2 % b;
        REQUIRE(static_cast<int>(b) == 0);
    }
    SECTION("increment")
    {
        struct type : strong_typedef<type, int>, strong_typedef_op::increment<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        REQUIRE(static_cast<int>(++a) == 1);
        REQUIRE(static_cast<int>(a++) == 1);
        REQUIRE(static_cast<int>(a) == 2);
    }
    SECTION("decrement")
    {
        struct type : strong_typedef<type, int>, strong_typedef_op::decrement<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0);
        REQUIRE(static_cast<int>(--a) == -1);
        REQUIRE(static_cast<int>(a--) == -1);
        REQUIRE(static_cast<int>(a) == -2);
    }
    SECTION("unary")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::unary_minus<type>,
                      strong_typedef_op::unary_plus<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(2);
        REQUIRE(static_cast<int>(+a) == 2);
        REQUIRE(static_cast<int>(-a) == -2);
    }
    SECTION("complement")
    {
        struct type : strong_typedef<type, unsigned>, strong_typedef_op::complement<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1u);
        REQUIRE(static_cast<unsigned>(~a) == ~1u);

        type b(42u);
        REQUIRE(static_cast<unsigned>(~b) == ~42u);
    }
    SECTION("bitwise")
    {
        struct type : strong_typedef<type, unsigned>,
                      strong_typedef_op::bitwise_or<type>,
                      strong_typedef_op::bitwise_xor<type>,
                      strong_typedef_op::bitwise_and<type>
        {
            using strong_typedef::strong_typedef;
        };

        type a(0u);

        REQUIRE(static_cast<unsigned>(a | type(3u)) == 3u);
        REQUIRE(static_cast<unsigned>(type(3u) | a) == 3u);
        a |= type(3u);
        REQUIRE(static_cast<unsigned>(a) == 3u);

        REQUIRE(static_cast<unsigned>(a & type(2u)) == 2u);
        REQUIRE(static_cast<unsigned>(type(2u) & a) == 2u);
        a &= type(2u);
        REQUIRE(static_cast<unsigned>(a) == 2u);

        REQUIRE(static_cast<unsigned>(a ^ type(3u)) == 1u);
        REQUIRE(static_cast<unsigned>(type(3u) ^ a) == 1u);
        a ^= type(3u);
        REQUIRE(static_cast<unsigned>(a) == 1u);
    }
    SECTION("bitshift")
    {
        struct type : strong_typedef<type, unsigned>, strong_typedef_op::bitshift<type, unsigned>
        {
            using strong_typedef::strong_typedef;
        };

        type a(1u);

        REQUIRE(static_cast<unsigned>(a << 1u) == 2u);
        a <<= 1u;
        REQUIRE(static_cast<unsigned>(a) == 2u);

        REQUIRE(static_cast<unsigned>(a >> 1u) == 1u);
        a >>= 1u;
        REQUIRE(static_cast<unsigned>(a) == 1u);
    }
    SECTION("dereference")
    {
        struct test
        {
            int a;
        } t{0};

        struct type : strong_typedef<type, test*>, strong_typedef_op::dereference<type, test>
        {
            using strong_typedef::strong_typedef;
        };

        type a(&t);
        REQUIRE((*a).a == 0);
        REQUIRE(a->a == 0);
    }
    SECTION("array subscript")
    {
        int arr[] = {0, 1, 2};

        struct type : strong_typedef<type, int*>, strong_typedef_op::array_subscript<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(arr);
        REQUIRE(a[0] == 0);
        REQUIRE(a[1] == 1);
        REQUIRE(a[2] == 2);
    }
    SECTION("iterator")
    {
        int arr[] = {0, 1, 2};

        struct type : strong_typedef<type, int*>,
                      strong_typedef_op::random_access_iterator<type, int>
        {
            using strong_typedef::strong_typedef;
        };

        type a(arr);
        a += 1;
        REQUIRE(a == type(&arr[1]));

        a -= 1;
        REQUIRE(a == type(&arr[0]));

        a = a + 1;
        a = 1 + a;
        REQUIRE(a == type(&arr[2]));

        a = a - 1;
        REQUIRE(a == type(&arr[1]));

        REQUIRE(a - type(&arr[0]) == 1);
    }
    SECTION("i/o")
    {
        struct type : strong_typedef<type, int>,
                      strong_typedef_op::input_operator<type>,
                      strong_typedef_op::output_operator<type>
        {
            using strong_typedef::strong_typedef;
        };

        std::ostringstream out;
        std::istringstream in("1");

        type a(0);
        out << a;
        REQUIRE(out.str() == "0");

        in >> a;
        REQUIRE(static_cast<int>(a) == 1);
    }
}
<|endoftext|>


<commit_before>#include "corrcheck.h"

int create_database(const std::string& directory)
{
   File* file_list = get_file_list(directory);
    if(file_list == nullptr)
    {
	std::cout << "No files to checksum." << std::endl;
	return FAILURE;
    }

    // checksum all given files
    checksum_files(directory, file_list, true);
    const int result = write_database(directory, file_list);
    delete_file_list(file_list);

    return result;
}

int verify_database(const std::string& directory)
{
    // ensure that the .corrcheckdb file exists here
    FILE* corrcheckdb = fopen(std::string(directory + "/.corrcheckdb").c_str(), "r");
    if(corrcheckdb == nullptr)
    {
	std::cout << "Could not open or find the .corrcheckdb file." << std::endl;
	return FAILURE;
    }

    // structure: <SHA256 checksum> <file name (null-terminated)>
    std::cout << "Reading database..." << std::endl;
    std::map<std::string, unsigned char*> database_files;
    while(!feof(corrcheckdb))
    {
	std::string name;
	unsigned char* hash = new unsigned char[SHA256_DIGEST_LENGTH];
	assert(hash);

	// read hash
	const unsigned int bytes_read = fread(hash, sizeof(unsigned char), SHA256_DIGEST_LENGTH, corrcheckdb);
	if(bytes_read != SHA256_DIGEST_LENGTH && !feof(corrcheckdb))
	{
	    std::cout << "Could not read checksum from database." << std::endl;
	    return FAILURE;
	}
	else if(feof(corrcheckdb))
	    break;

	// read file name
	char read_char;
	do
	{
	    if(fread(&read_char, sizeof(char), 1, corrcheckdb) != 1)
	    {
		std::cout << "Failed while reading file name from database." << std::endl;
		return FAILURE;
	    }
	    if(read_char != '\0') name += read_char;
	}
	while(read_char != '\0');

	database_files[name] = hash;
    }

    int result = SUCCESS;
    File* file_list = get_file_list(directory);
    unsigned int new_files = 0, changed_files = 0;
    if(file_list == nullptr)
	std::cout << "No files to check." << std::endl;
    else
    {
	// run checks on files that are in the database and exist
	checksum_files(directory, file_list);
	File* current = file_list;
	while(current)
	{
	    if(database_files.find(current->name) == database_files.end())
	    {
		std::cout << "NEW:     " << current->name << std::endl;
		new_files++;
		current = current->next;
		continue;
	    }

	    unsigned int i = 0;
	    while(current->checksum[i] == database_files[current->name][i] && i < SHA256_DIGEST_LENGTH) i++;
	    if(i != SHA256_DIGEST_LENGTH)
	    {
		std::cout << "CHANGED: " << current->name << std::endl;
		changed_files++;
	    }

	    current = current->next;
	}
    }

    delete_file_list(file_list);

    if(changed_files > 0)
	std::cout << "File(s) were found that did not match the database checksum(s).\n";

    if(new_files > 0)
    {
	std::cout << "New file(s) were found that were not in the database.\n"
		  << "Consider updating/recreating the database." << std::endl;
    }

    return result;
}

File* get_file_list(const std::string& directory)
{
    File* file_list = nullptr;
    File* last = file_list;
    DIR* dir = opendir(directory.c_str());
    if(dir == nullptr)
    {
	std::cout << "\'" << directory << "\' is not readable." << std::endl;
	return nullptr;
    }

    struct stat st;
    struct dirent* entry = readdir(dir);
    while(entry != nullptr)
    {
	// only add the file to the list if it is not a directory
	lstat(entry->d_name, &st);
	if(!S_ISDIR(st.st_mode) && std::string(entry->d_name).compare(".corrcheckdb") != 0)
	{
	    // null list
	    if(file_list == nullptr)
	    {
		file_list = new File(std::string(entry->d_name));
		last = file_list;
	    }
	    else
	    {
		last->next = new File(std::string(entry->d_name));
		last = last->next;
	    }
	}
	entry = readdir(dir);
    }
    closedir(dir);

    return file_list;
}

void delete_file_list(File* file_list)
{
    File* current = file_list;
    while(current != nullptr)
    {
	File* to_kill = current;
	current = current->next;
	delete to_kill;
    }

    return;
}

void checksum_files(const std::string& directory, File* file_list, bool show_files)
{
    SHA256_CTX sha;
    unsigned char* buffer = new unsigned char[BUFFER_SIZE];
    for(File* current_file = file_list; current_file != nullptr; current_file = current_file->next)
    {
	SHA256_Init(&sha);
	FILE* file = fopen(std::string(directory + "/" + current_file->name).c_str(), "r");

	// hash files in BUFFER_SIZE chunks
	while(!feof(file))
	{
	    const unsigned int bytes_read = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file);
	    SHA256_Update(&sha, buffer, bytes_read);
	}

	// get the final hash
	unsigned char hash[SHA256_DIGEST_LENGTH];
	SHA256_Final(hash, &sha);
	for(unsigned int b = 0; b < SHA256_DIGEST_LENGTH; b++)
	{
	    current_file->checksum[b] = hash[b];
	}

	// show files with their checksums if enabled
	if(show_files)
	{
	    std::cout << current_file->name << " -> ";
	    for(unsigned int i = 0; i < SHA256_DIGEST_LENGTH; i++)
		std::cout << std::hex << (unsigned int) hash[i];
	    std::cout << std::endl;
	}

	fclose(file);
    }

    delete[] buffer;

    return;
}

int write_database(const std::string& directory, const File* file_list)
{
    // write the file names and checksums out
    // format: <checksum> <null-terminated string of name>
    FILE* file = fopen(std::string(directory + "/.corrcheckdb").c_str(), "w");
    if(file == NULL) return FAILURE;

    while(file_list)
    {
	fwrite(file_list->checksum, sizeof(unsigned char), SHA256_DIGEST_LENGTH, file);
	fwrite(file_list->name.c_str(), sizeof(char), file_list->name.length() + 1, file);
	file_list = file_list->next;
    }
    fclose(file);

    return SUCCESS;
}
<commit_msg>Remove leftover 'debug' output.<commit_after>#include "corrcheck.h"

int create_database(const std::string& directory)
{
   File* file_list = get_file_list(directory);
    if(file_list == nullptr)
    {
	std::cout << "No files to checksum." << std::endl;
	return FAILURE;
    }

    // checksum all given files
    checksum_files(directory, file_list, true);
    const int result = write_database(directory, file_list);
    delete_file_list(file_list);

    return result;
}

int verify_database(const std::string& directory)
{
    // ensure that the .corrcheckdb file exists here
    FILE* corrcheckdb = fopen(std::string(directory + "/.corrcheckdb").c_str(), "r");
    if(corrcheckdb == nullptr)
    {
	std::cout << "Could not open or find the .corrcheckdb file." << std::endl;
	return FAILURE;
    }

    // structure: <SHA256 checksum> <file name (null-terminated)>
    std::map<std::string, unsigned char*> database_files;
    while(!feof(corrcheckdb))
    {
	std::string name;
	unsigned char* hash = new unsigned char[SHA256_DIGEST_LENGTH];
	assert(hash);

	// read hash
	const unsigned int bytes_read = fread(hash, sizeof(unsigned char), SHA256_DIGEST_LENGTH, corrcheckdb);
	if(bytes_read != SHA256_DIGEST_LENGTH && !feof(corrcheckdb))
	{
	    std::cout << "Could not read checksum from database." << std::endl;
	    return FAILURE;
	}
	else if(feof(corrcheckdb))
	    break;

	// read file name
	char read_char;
	do
	{
	    if(fread(&read_char, sizeof(char), 1, corrcheckdb) != 1)
	    {
		std::cout << "Failed while reading file name from database." << std::endl;
		return FAILURE;
	    }
	    if(read_char != '\0') name += read_char;
	}
	while(read_char != '\0');

	database_files[name] = hash;
    }

    int result = SUCCESS;
    File* file_list = get_file_list(directory);
    unsigned int new_files = 0, changed_files = 0;
    if(file_list == nullptr)
	std::cout << "No files to check." << std::endl;
    else
    {
	// run checks on files that are in the database and exist
	checksum_files(directory, file_list);
	File* current = file_list;
	while(current)
	{
	    if(database_files.find(current->name) == database_files.end())
	    {
		std::cout << "NEW:     " << current->name << std::endl;
		new_files++;
		current = current->next;
		continue;
	    }

	    unsigned int i = 0;
	    while(current->checksum[i] == database_files[current->name][i] && i < SHA256_DIGEST_LENGTH) i++;
	    if(i != SHA256_DIGEST_LENGTH)
	    {
		std::cout << "CHANGED: " << current->name << std::endl;
		changed_files++;
	    }

	    current = current->next;
	}
    }

    delete_file_list(file_list);

    if(changed_files > 0)
	std::cout << "File(s) were found that did not match the database checksum(s).\n";

    if(new_files > 0)
    {
	std::cout << "New file(s) were found that were not in the database.\n"
		  << "Consider updating/recreating the database." << std::endl;
    }

    return result;
}

File* get_file_list(const std::string& directory)
{
    File* file_list = nullptr;
    File* last = file_list;
    DIR* dir = opendir(directory.c_str());
    if(dir == nullptr)
    {
	std::cout << "\'" << directory << "\' is not readable." << std::endl;
	return nullptr;
    }

    struct stat st;
    struct dirent* entry = readdir(dir);
    while(entry != nullptr)
    {
	// only add the file to the list if it is not a directory
	lstat(entry->d_name, &st);
	if(!S_ISDIR(st.st_mode) && std::string(entry->d_name).compare(".corrcheckdb") != 0)
	{
	    // null list
	    if(file_list == nullptr)
	    {
		file_list = new File(std::string(entry->d_name));
		last = file_list;
	    }
	    else
	    {
		last->next = new File(std::string(entry->d_name));
		last = last->next;
	    }
	}
	entry = readdir(dir);
    }
    closedir(dir);

    return file_list;
}

void delete_file_list(File* file_list)
{
    File* current = file_list;
    while(current != nullptr)
    {
	File* to_kill = current;
	current = current->next;
	delete to_kill;
    }

    return;
}

void checksum_files(const std::string& directory, File* file_list, bool show_files)
{
    SHA256_CTX sha;
    unsigned char* buffer = new unsigned char[BUFFER_SIZE];
    for(File* current_file = file_list; current_file != nullptr; current_file = current_file->next)
    {
	SHA256_Init(&sha);
	FILE* file = fopen(std::string(directory + "/" + current_file->name).c_str(), "r");

	// hash files in BUFFER_SIZE chunks
	while(!feof(file))
	{
	    const unsigned int bytes_read = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file);
	    SHA256_Update(&sha, buffer, bytes_read);
	}

	// get the final hash
	unsigned char hash[SHA256_DIGEST_LENGTH];
	SHA256_Final(hash, &sha);
	for(unsigned int b = 0; b < SHA256_DIGEST_LENGTH; b++)
	{
	    current_file->checksum[b] = hash[b];
	}

	// show files with their checksums if enabled
	if(show_files)
	{
	    std::cout << current_file->name << " -> ";
	    for(unsigned int i = 0; i < SHA256_DIGEST_LENGTH; i++)
		std::cout << std::hex << (unsigned int) hash[i];
	    std::cout << std::endl;
	}

	fclose(file);
    }

    delete[] buffer;

    return;
}

int write_database(const std::string& directory, const File* file_list)
{
    // write the file names and checksums out
    // format: <checksum> <null-terminated string of name>
    FILE* file = fopen(std::string(directory + "/.corrcheckdb").c_str(), "w");
    if(file == NULL) return FAILURE;

    while(file_list)
    {
	fwrite(file_list->checksum, sizeof(unsigned char), SHA256_DIGEST_LENGTH, file);
	fwrite(file_list->name.c_str(), sizeof(char), file_list->name.length() + 1, file);
	file_list = file_list->next;
    }
    fclose(file);

    return SUCCESS;
}
<|endoftext|>